Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 17 May 2010 17:57:43 +0000 (13:57 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 17 May 2010 17:57:43 +0000 (13:57 -0400)
60 files changed:
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_initvals.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/htc_hst.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/hostap/hostap_80211_rx.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.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-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-power.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dump.h
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/wl12xx/wl1271_main.c
include/net/mac80211.h
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/work.c

index 8663660..abd083a 100644 (file)
@@ -110,6 +110,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0409, 0x0249) },
        /* AVM FRITZ!WLAN USB Stick N 2.4 */
        { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
+       /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
+       { USB_DEVICE(0x1668, 0x1200) },
 
        /* terminate */
        {}
index 7f5953f..5f04cf3 100644 (file)
@@ -1932,12 +1932,6 @@ ath5k_tasklet_rx(unsigned long data)
 
                sc->stats.rx_all_count++;
 
-               if (unlikely(rs.rs_more)) {
-                       ATH5K_WARN(sc, "unsupported jumbo\n");
-                       sc->stats.rxerr_jumbo++;
-                       goto next;
-               }
-
                if (unlikely(rs.rs_status)) {
                        if (rs.rs_status & AR5K_RXERR_CRC)
                                sc->stats.rxerr_crc++;
@@ -1977,6 +1971,12 @@ ath5k_tasklet_rx(unsigned long data)
                                        sc->opmode != NL80211_IFTYPE_MONITOR)
                                goto next;
                }
+
+               if (unlikely(rs.rs_more)) {
+                       sc->stats.rxerr_jumbo++;
+                       goto next;
+
+               }
 accept:
                next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
 
index 8a79550..23eb60e 100644 (file)
@@ -38,6 +38,9 @@
 #define AR_SWITCH_TABLE_ALL (0xfff)
 #define AR_SWITCH_TABLE_ALL_S (0)
 
+#define LE16(x) __constant_cpu_to_le16(x)
+#define LE32(x) __constant_cpu_to_le32(x)
+
 static const struct ar9300_eeprom ar9300_default = {
        .eepromVersion = 2,
        .templateVersion = 2,
@@ -45,7 +48,7 @@ static const struct ar9300_eeprom ar9300_default = {
        .custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        .baseEepHeader = {
-               .regDmn = {0, 0x1f},
+               .regDmn = { LE16(0), LE16(0x1f) },
                .txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
                .opCapFlags = {
                        .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A,
@@ -76,15 +79,15 @@ static const struct ar9300_eeprom ar9300_default = {
        .modalHeader2G = {
        /* ar9300_modal_eep_header  2g */
                /* 4 idle,t1,t2,b(4 bits per setting) */
-               .antCtrlCommon = 0x110,
+               .antCtrlCommon = LE32(0x110),
                /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
-               .antCtrlCommon2 = 0x22222,
+               .antCtrlCommon2 = LE32(0x22222),
 
                /*
                 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
                 * rx1, rx12, b (2 bits each)
                 */
-               .antCtrlChain = {0x150, 0x150, 0x150},
+               .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
 
                /*
                 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
@@ -287,12 +290,12 @@ static const struct ar9300_eeprom ar9300_default = {
         },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
-               .antCtrlCommon = 0x110,
+               .antCtrlCommon = LE32(0x110),
                /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
-               .antCtrlCommon2 = 0x22222,
+               .antCtrlCommon2 = LE32(0x22222),
                 /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
                .antCtrlChain = {
-                       0x000, 0x000, 0x000,
+                       LE16(0x000), LE16(0x000), LE16(0x000),
                },
                 /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
                .xatten1DB = {0, 0, 0},
@@ -620,9 +623,9 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
        case EEP_MAC_MSW:
                return eep->macAddr[4] << 8 | eep->macAddr[5];
        case EEP_REG_0:
-               return pBase->regDmn[0];
+               return le16_to_cpu(pBase->regDmn[0]);
        case EEP_REG_1:
-               return pBase->regDmn[1];
+               return le16_to_cpu(pBase->regDmn[1]);
        case EEP_OP_CAP:
                return pBase->deviceCap;
        case EEP_OP_MODE:
@@ -640,93 +643,80 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
                /* Bit 4 is internal regulator flag */
                return (pBase->featureEnable & 0x10) >> 4;
        case EEP_SWREG:
-               return pBase->swreg;
+               return le32_to_cpu(pBase->swreg);
        default:
                return 0;
        }
 }
 
-#ifdef __BIG_ENDIAN
-static void ar9300_swap_eeprom(struct ar9300_eeprom *eep)
+static bool ar9300_eeprom_read_byte(struct ath_common *common, int address,
+                                   u8 *buffer)
 {
-       u32 dword;
-       u16 word;
-       int i;
-
-       word = swab16(eep->baseEepHeader.regDmn[0]);
-       eep->baseEepHeader.regDmn[0] = word;
-
-       word = swab16(eep->baseEepHeader.regDmn[1]);
-       eep->baseEepHeader.regDmn[1] = word;
-
-       dword = swab32(eep->baseEepHeader.swreg);
-       eep->baseEepHeader.swreg = dword;
+       u16 val;
 
-       dword = swab32(eep->modalHeader2G.antCtrlCommon);
-       eep->modalHeader2G.antCtrlCommon = dword;
+       if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+               return false;
 
-       dword = swab32(eep->modalHeader2G.antCtrlCommon2);
-       eep->modalHeader2G.antCtrlCommon2 = dword;
+       *buffer = (val >> (8 * (address % 2))) & 0xff;
+       return true;
+}
 
-       dword = swab32(eep->modalHeader5G.antCtrlCommon);
-       eep->modalHeader5G.antCtrlCommon = dword;
+static bool ar9300_eeprom_read_word(struct ath_common *common, int address,
+                                   u8 *buffer)
+{
+       u16 val;
 
-       dword = swab32(eep->modalHeader5G.antCtrlCommon2);
-       eep->modalHeader5G.antCtrlCommon2 = dword;
+       if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+               return false;
 
-       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-               word = swab16(eep->modalHeader2G.antCtrlChain[i]);
-               eep->modalHeader2G.antCtrlChain[i] = word;
+       buffer[0] = val >> 8;
+       buffer[1] = val & 0xff;
 
-               word = swab16(eep->modalHeader5G.antCtrlChain[i]);
-               eep->modalHeader5G.antCtrlChain[i] = word;
-       }
+       return true;
 }
-#endif
 
-static bool ar9300_hw_read_eeprom(struct ath_hw *ah,
-                                 long address, u8 *buffer, int many)
+static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
+                              int count)
 {
-       int i;
-       u8 value[2];
-       unsigned long eepAddr;
-       unsigned long byteAddr;
-       u16 *svalue;
        struct ath_common *common = ath9k_hw_common(ah);
+       int i;
 
-       if ((address < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) {
+       if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
                ath_print(common, ATH_DBG_EEPROM,
                          "eeprom address not in range\n");
                return false;
        }
 
-       for (i = 0; i < many; i++) {
-               eepAddr = (u16) (address + i) / 2;
-               byteAddr = (u16) (address + i) % 2;
-               svalue = (u16 *) value;
-               if (!ath9k_hw_nvram_read(common, eepAddr, svalue)) {
-                       ath_print(common, ATH_DBG_EEPROM,
-                                 "unable to read eeprom region\n");
-                       return false;
-               }
-               *svalue = le16_to_cpu(*svalue);
-               buffer[i] = value[byteAddr];
+       /*
+        * Since we're reading the bytes in reverse order from a little-endian
+        * word stream, an even address means we only use the lower half of
+        * the 16-bit word at that address
+        */
+       if (address % 2 == 0) {
+               if (!ar9300_eeprom_read_byte(common, address--, buffer++))
+                       goto error;
+
+               count--;
        }
 
-       return true;
-}
+       for (i = 0; i < count / 2; i++) {
+               if (!ar9300_eeprom_read_word(common, address, buffer))
+                       goto error;
 
-static bool ar9300_read_eeprom(struct ath_hw *ah,
-                              int address, u8 *buffer, int many)
-{
-       int it;
+               address -= 2;
+               buffer += 2;
+       }
+
+       if (count % 2)
+               if (!ar9300_eeprom_read_byte(common, address, buffer))
+                       goto error;
 
-       for (it = 0; it < many; it++)
-               if (!ar9300_hw_read_eeprom(ah,
-                                          (address - it),
-                                          (buffer + it), 1))
-                       return false;
        return true;
+
+error:
+       ath_print(common, ATH_DBG_EEPROM,
+                 "unable to read eeprom region at offset %d\n", address);
+       return false;
 }
 
 static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
@@ -927,30 +917,13 @@ fail:
  */
 static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
 {
-       u8 *mptr = NULL;
-       int mdata_size;
+       u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep;
 
-       mptr = (u8 *) &ah->eeprom.ar9300_eep;
-       mdata_size = sizeof(struct ar9300_eeprom);
+       if (ar9300_eeprom_restore_internal(ah, mptr,
+                       sizeof(struct ar9300_eeprom)) < 0)
+               return false;
 
-       if (mptr && mdata_size > 0) {
-               /* At this point, mptr points to the eeprom data structure
-                * in it's "default" state. If this is big endian, swap the
-                * data structures back to "little endian"
-                */
-               /* First swap, default to Little Endian */
-#ifdef __BIG_ENDIAN
-               ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
-#endif
-               if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0)
-                       return true;
-
-               /* Second Swap, back to Big Endian */
-#ifdef __BIG_ENDIAN
-               ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
-#endif
-       }
-       return false;
+       return true;
 }
 
 /* XXX: review hardware docs */
@@ -998,21 +971,25 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
 static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
 {
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le32 val;
 
        if (is2ghz)
-               return eep->modalHeader2G.antCtrlCommon;
+               val = eep->modalHeader2G.antCtrlCommon;
        else
-               return eep->modalHeader5G.antCtrlCommon;
+               val = eep->modalHeader5G.antCtrlCommon;
+       return le32_to_cpu(val);
 }
 
 static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
 {
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le32 val;
 
        if (is2ghz)
-               return eep->modalHeader2G.antCtrlCommon2;
+               val = eep->modalHeader2G.antCtrlCommon2;
        else
-               return eep->modalHeader5G.antCtrlCommon2;
+               val = eep->modalHeader5G.antCtrlCommon2;
+       return le32_to_cpu(val);
 }
 
 static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
@@ -1020,15 +997,16 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
                                        bool is2ghz)
 {
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le16 val = 0;
 
        if (chain >= 0 && chain < AR9300_MAX_CHAINS) {
                if (is2ghz)
-                       return eep->modalHeader2G.antCtrlChain[chain];
+                       val = eep->modalHeader2G.antCtrlChain[chain];
                else
-                       return eep->modalHeader5G.antCtrlChain[chain];
+                       val = eep->modalHeader5G.antCtrlChain[chain];
        }
 
-       return 0;
+       return le16_to_cpu(val);
 }
 
 static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
index d8c0318..23fb353 100644 (file)
@@ -169,7 +169,7 @@ enum CompressAlgorithm {
 };
 
 struct ar9300_base_eep_hdr {
-       u16 regDmn[2];
+       __le16 regDmn[2];
        /* 4 bits tx and 4 bits rx */
        u8 txrxMask;
        struct eepFlags opCapFlags;
@@ -199,16 +199,16 @@ struct ar9300_base_eep_hdr {
        u8 rxBandSelectGpio;
        u8 txrxgain;
        /* SW controlled internal regulator fields */
-       u32 swreg;
+       __le32 swreg;
 } __packed;
 
 struct ar9300_modal_eep_header {
        /* 4 idle, t1, t2, b (4 bits per setting) */
-       u32 antCtrlCommon;
+       __le32 antCtrlCommon;
        /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
-       u32 antCtrlCommon2;
+       __le32 antCtrlCommon2;
        /* 6 idle, t, r, rx1, rx12, b (2 bits each) */
-       u16 antCtrlChain[AR9300_MAX_CHAINS];
+       __le16 antCtrlChain[AR9300_MAX_CHAINS];
        /* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
        u8 xatten1DB[AR9300_MAX_CHAINS];
        /* 3  xatten1_margin for merlin (0xa20c/b20c 16:12 */
index ef6116e..db019dd 100644 (file)
@@ -25,8 +25,11 @@ static const u32 ar9300_2p0_radio_postamble[][5] = {
        {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
        {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
        {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
        {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
        {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
@@ -97,13 +100,13 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016048, 0x60001a61, 0x60001a61, 0x60001a61, 0x60001a61},
+       {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
        {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016448, 0x60001a61, 0x60001a61, 0x60001a61, 0x60001a61},
+       {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
        {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016848, 0x60001a61, 0x60001a61, 0x60001a61, 0x60001a61},
+       {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
@@ -129,7 +132,7 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016040, 0x7f80fff8},
        {0x0001604c, 0x76d005b5},
        {0x00016050, 0x556cf031},
-       {0x00016054, 0x43449440},
+       {0x00016054, 0x13449440},
        {0x00016058, 0x0c51c92c},
        {0x0001605c, 0x3db7fffc},
        {0x00016060, 0xfffffffc},
@@ -152,12 +155,11 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016100, 0x3fffbe01},
        {0x00016104, 0xfff80000},
        {0x00016108, 0x00080010},
-       {0x00016140, 0x10804008},
        {0x00016144, 0x02084080},
        {0x00016148, 0x00000000},
        {0x00016280, 0x058a0001},
        {0x00016284, 0x3d840208},
-       {0x00016288, 0x01a20408},
+       {0x00016288, 0x05a20408},
        {0x0001628c, 0x00038c07},
        {0x00016290, 0x40000004},
        {0x00016294, 0x458aa14f},
@@ -190,7 +192,7 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016440, 0x7f80fff8},
        {0x0001644c, 0x76d005b5},
        {0x00016450, 0x556cf031},
-       {0x00016454, 0x43449440},
+       {0x00016454, 0x13449440},
        {0x00016458, 0x0c51c92c},
        {0x0001645c, 0x3db7fffc},
        {0x00016460, 0xfffffffc},
@@ -199,7 +201,6 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016500, 0x3fffbe01},
        {0x00016504, 0xfff80000},
        {0x00016508, 0x00080010},
-       {0x00016540, 0x10804008},
        {0x00016544, 0x02084080},
        {0x00016548, 0x00000000},
        {0x00016780, 0x00000000},
@@ -231,7 +232,7 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016840, 0x7f80fff8},
        {0x0001684c, 0x76d005b5},
        {0x00016850, 0x556cf031},
-       {0x00016854, 0x43449440},
+       {0x00016854, 0x13449440},
        {0x00016858, 0x0c51c92c},
        {0x0001685c, 0x3db7fffc},
        {0x00016860, 0xfffffffc},
@@ -240,7 +241,6 @@ static const u32 ar9300_2p0_radio_core[][2] = {
        {0x00016900, 0x3fffbe01},
        {0x00016904, 0xfff80000},
        {0x00016908, 0x00080010},
-       {0x00016940, 0x10804008},
        {0x00016944, 0x02084080},
        {0x00016948, 0x00000000},
        {0x00016b80, 0x00000000},
@@ -588,12 +588,12 @@ static const u32 ar9200_merlin_2p0_radio_core[][2] = {
 
 static const u32 ar9300_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a800b},
+       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
        {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
        {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
-       {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x00000b9c},
+       {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
        {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
        {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
@@ -604,8 +604,8 @@ static const u32 ar9300_2p0_baseband_postamble[][5] = {
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-       {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
-       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
+       {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
        {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
        {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
@@ -674,7 +674,7 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
        {0x00009d10, 0x01834061},
        {0x00009d14, 0x00c0040b},
        {0x00009d18, 0x00000000},
-       {0x00009e08, 0x0038233c},
+       {0x00009e08, 0x0038230c},
        {0x00009e24, 0x990bb515},
        {0x00009e28, 0x0c6f0000},
        {0x00009e30, 0x06336f77},
@@ -901,13 +901,13 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
        {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
        {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
        {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-       {0x00016048, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
+       {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
        {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
        {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-       {0x00016448, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
+       {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
        {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
        {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-       {0x00016848, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
+       {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
        {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
 };
 
@@ -979,13 +979,13 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
        {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
        {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016048, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
+       {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
        {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016448, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
+       {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
        {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016848, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
+       {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
@@ -995,22 +995,22 @@ static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
        {0x0000a004, 0x00030002},
        {0x0000a008, 0x00050004},
        {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x01800082},
-       {0x0000a014, 0x01820181},
-       {0x0000a018, 0x01840183},
-       {0x0000a01c, 0x01880185},
-       {0x0000a020, 0x018a0189},
-       {0x0000a024, 0x02850284},
-       {0x0000a028, 0x02890288},
-       {0x0000a02c, 0x028b028a},
-       {0x0000a030, 0x028d028c},
-       {0x0000a034, 0x02910290},
-       {0x0000a038, 0x02930292},
-       {0x0000a03c, 0x03910390},
-       {0x0000a040, 0x03930392},
-       {0x0000a044, 0x03950394},
-       {0x0000a048, 0x00000396},
-       {0x0000a04c, 0x00000000},
+       {0x0000a010, 0x00830082},
+       {0x0000a014, 0x01810180},
+       {0x0000a018, 0x01830182},
+       {0x0000a01c, 0x01850184},
+       {0x0000a020, 0x01890188},
+       {0x0000a024, 0x018b018a},
+       {0x0000a028, 0x018d018c},
+       {0x0000a02c, 0x01910190},
+       {0x0000a030, 0x01930192},
+       {0x0000a034, 0x01950194},
+       {0x0000a038, 0x038a0196},
+       {0x0000a03c, 0x038c038b},
+       {0x0000a040, 0x0390038d},
+       {0x0000a044, 0x03920391},
+       {0x0000a048, 0x03940393},
+       {0x0000a04c, 0x03960395},
        {0x0000a050, 0x00000000},
        {0x0000a054, 0x00000000},
        {0x0000a058, 0x00000000},
@@ -1023,14 +1023,14 @@ static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
        {0x0000a074, 0x00000000},
        {0x0000a078, 0x00000000},
        {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x21212128},
-       {0x0000a088, 0x21212121},
-       {0x0000a08c, 0x1c1c1c21},
-       {0x0000a090, 0x1c1c1c1c},
-       {0x0000a094, 0x17171c1c},
-       {0x0000a098, 0x02020212},
-       {0x0000a09c, 0x02020202},
+       {0x0000a080, 0x22222229},
+       {0x0000a084, 0x1d1d1d1d},
+       {0x0000a088, 0x1d1d1d1d},
+       {0x0000a08c, 0x1d1d1d1d},
+       {0x0000a090, 0x171d1d1d},
+       {0x0000a094, 0x11111717},
+       {0x0000a098, 0x00030311},
+       {0x0000a09c, 0x00000000},
        {0x0000a0a0, 0x00000000},
        {0x0000a0a4, 0x00000000},
        {0x0000a0a8, 0x00000000},
@@ -1040,26 +1040,26 @@ static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
        {0x0000a0b8, 0x00000000},
        {0x0000a0bc, 0x00000000},
        {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x011f0100},
-       {0x0000a0c8, 0x011d011e},
-       {0x0000a0cc, 0x011b011c},
+       {0x0000a0c4, 0x01000101},
+       {0x0000a0c8, 0x011e011f},
+       {0x0000a0cc, 0x011c011d},
        {0x0000a0d0, 0x02030204},
        {0x0000a0d4, 0x02010202},
        {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x021d021e},
-       {0x0000a0e0, 0x03010302},
-       {0x0000a0e4, 0x031f0300},
-       {0x0000a0e8, 0x0402031e},
+       {0x0000a0dc, 0x0302021e},
+       {0x0000a0e0, 0x03000301},
+       {0x0000a0e4, 0x031e031f},
+       {0x0000a0e8, 0x0402031d},
        {0x0000a0ec, 0x04000401},
        {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x05010502},
-       {0x0000a0f8, 0x051f0500},
-       {0x0000a0fc, 0x0602051e},
-       {0x0000a100, 0x06000601},
-       {0x0000a104, 0x061e061f},
-       {0x0000a108, 0x0703061d},
-       {0x0000a10c, 0x07010702},
-       {0x0000a110, 0x00000700},
+       {0x0000a0f4, 0x0502041d},
+       {0x0000a0f8, 0x05000501},
+       {0x0000a0fc, 0x051e051f},
+       {0x0000a100, 0x06010602},
+       {0x0000a104, 0x061f0600},
+       {0x0000a108, 0x061d061e},
+       {0x0000a10c, 0x07020703},
+       {0x0000a110, 0x07000701},
        {0x0000a114, 0x00000000},
        {0x0000a118, 0x00000000},
        {0x0000a11c, 0x00000000},
@@ -1072,26 +1072,26 @@ static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
        {0x0000a138, 0x00000000},
        {0x0000a13c, 0x00000000},
        {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x011f0100},
-       {0x0000a148, 0x011d011e},
-       {0x0000a14c, 0x011b011c},
+       {0x0000a144, 0x01000101},
+       {0x0000a148, 0x011e011f},
+       {0x0000a14c, 0x011c011d},
        {0x0000a150, 0x02030204},
        {0x0000a154, 0x02010202},
        {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x021d021e},
-       {0x0000a160, 0x03010302},
-       {0x0000a164, 0x031f0300},
-       {0x0000a168, 0x0402031e},
+       {0x0000a15c, 0x0302021e},
+       {0x0000a160, 0x03000301},
+       {0x0000a164, 0x031e031f},
+       {0x0000a168, 0x0402031d},
        {0x0000a16c, 0x04000401},
        {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x05010502},
-       {0x0000a178, 0x051f0500},
-       {0x0000a17c, 0x0602051e},
-       {0x0000a180, 0x06000601},
-       {0x0000a184, 0x061e061f},
-       {0x0000a188, 0x0703061d},
-       {0x0000a18c, 0x07010702},
-       {0x0000a190, 0x00000700},
+       {0x0000a174, 0x0502041d},
+       {0x0000a178, 0x05000501},
+       {0x0000a17c, 0x051e051f},
+       {0x0000a180, 0x06010602},
+       {0x0000a184, 0x061f0600},
+       {0x0000a188, 0x061d061e},
+       {0x0000a18c, 0x07020703},
+       {0x0000a190, 0x07000701},
        {0x0000a194, 0x00000000},
        {0x0000a198, 0x00000000},
        {0x0000a19c, 0x00000000},
@@ -1317,13 +1317,13 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016048, 0x64001a61, 0x64001a61, 0x64001a61, 0x64001a61},
+       {0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
        {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016448, 0x64001a61, 0x64001a61, 0x64001a61, 0x64001a61},
+       {0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
        {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
        {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016848, 0x64001a61, 0x64001a61, 0x64001a61, 0x64001a61},
+       {0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
@@ -1497,22 +1497,22 @@ static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
        {0x0000a004, 0x00030002},
        {0x0000a008, 0x00050004},
        {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x01800082},
-       {0x0000a014, 0x01820181},
-       {0x0000a018, 0x01840183},
-       {0x0000a01c, 0x01880185},
-       {0x0000a020, 0x018a0189},
-       {0x0000a024, 0x02850284},
-       {0x0000a028, 0x02890288},
-       {0x0000a02c, 0x03850384},
-       {0x0000a030, 0x03890388},
-       {0x0000a034, 0x038b038a},
-       {0x0000a038, 0x038d038c},
-       {0x0000a03c, 0x03910390},
-       {0x0000a040, 0x03930392},
-       {0x0000a044, 0x03950394},
-       {0x0000a048, 0x00000396},
-       {0x0000a04c, 0x00000000},
+       {0x0000a010, 0x00830082},
+       {0x0000a014, 0x01810180},
+       {0x0000a018, 0x01830182},
+       {0x0000a01c, 0x01850184},
+       {0x0000a020, 0x01890188},
+       {0x0000a024, 0x018b018a},
+       {0x0000a028, 0x018d018c},
+       {0x0000a02c, 0x03820190},
+       {0x0000a030, 0x03840383},
+       {0x0000a034, 0x03880385},
+       {0x0000a038, 0x038a0389},
+       {0x0000a03c, 0x038c038b},
+       {0x0000a040, 0x0390038d},
+       {0x0000a044, 0x03920391},
+       {0x0000a048, 0x03940393},
+       {0x0000a04c, 0x03960395},
        {0x0000a050, 0x00000000},
        {0x0000a054, 0x00000000},
        {0x0000a058, 0x00000000},
@@ -1525,15 +1525,15 @@ static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
        {0x0000a074, 0x00000000},
        {0x0000a078, 0x00000000},
        {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x28282828},
-       {0x0000a088, 0x28282828},
-       {0x0000a08c, 0x28282828},
-       {0x0000a090, 0x28282828},
-       {0x0000a094, 0x21212128},
-       {0x0000a098, 0x171c1c1c},
-       {0x0000a09c, 0x02020212},
-       {0x0000a0a0, 0x00000202},
+       {0x0000a080, 0x29292929},
+       {0x0000a084, 0x29292929},
+       {0x0000a088, 0x29292929},
+       {0x0000a08c, 0x29292929},
+       {0x0000a090, 0x22292929},
+       {0x0000a094, 0x1d1d2222},
+       {0x0000a098, 0x0c111117},
+       {0x0000a09c, 0x00030303},
+       {0x0000a0a0, 0x00000000},
        {0x0000a0a4, 0x00000000},
        {0x0000a0a8, 0x00000000},
        {0x0000a0ac, 0x00000000},
@@ -1542,26 +1542,26 @@ static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
        {0x0000a0b8, 0x00000000},
        {0x0000a0bc, 0x00000000},
        {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x011f0100},
-       {0x0000a0c8, 0x011d011e},
-       {0x0000a0cc, 0x011b011c},
+       {0x0000a0c4, 0x01000101},
+       {0x0000a0c8, 0x011e011f},
+       {0x0000a0cc, 0x011c011d},
        {0x0000a0d0, 0x02030204},
        {0x0000a0d4, 0x02010202},
        {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x021d021e},
-       {0x0000a0e0, 0x03010302},
-       {0x0000a0e4, 0x031f0300},
-       {0x0000a0e8, 0x0402031e},
+       {0x0000a0dc, 0x0302021e},
+       {0x0000a0e0, 0x03000301},
+       {0x0000a0e4, 0x031e031f},
+       {0x0000a0e8, 0x0402031d},
        {0x0000a0ec, 0x04000401},
        {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x05010502},
-       {0x0000a0f8, 0x051f0500},
-       {0x0000a0fc, 0x0602051e},
-       {0x0000a100, 0x06000601},
-       {0x0000a104, 0x061e061f},
-       {0x0000a108, 0x0703061d},
-       {0x0000a10c, 0x07010702},
-       {0x0000a110, 0x00000700},
+       {0x0000a0f4, 0x0502041d},
+       {0x0000a0f8, 0x05000501},
+       {0x0000a0fc, 0x051e051f},
+       {0x0000a100, 0x06010602},
+       {0x0000a104, 0x061f0600},
+       {0x0000a108, 0x061d061e},
+       {0x0000a10c, 0x07020703},
+       {0x0000a110, 0x07000701},
        {0x0000a114, 0x00000000},
        {0x0000a118, 0x00000000},
        {0x0000a11c, 0x00000000},
@@ -1574,26 +1574,26 @@ static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
        {0x0000a138, 0x00000000},
        {0x0000a13c, 0x00000000},
        {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x011f0100},
-       {0x0000a148, 0x011d011e},
-       {0x0000a14c, 0x011b011c},
+       {0x0000a144, 0x01000101},
+       {0x0000a148, 0x011e011f},
+       {0x0000a14c, 0x011c011d},
        {0x0000a150, 0x02030204},
        {0x0000a154, 0x02010202},
        {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x021d021e},
-       {0x0000a160, 0x03010302},
-       {0x0000a164, 0x031f0300},
-       {0x0000a168, 0x0402031e},
+       {0x0000a15c, 0x0302021e},
+       {0x0000a160, 0x03000301},
+       {0x0000a164, 0x031e031f},
+       {0x0000a168, 0x0402031d},
        {0x0000a16c, 0x04000401},
        {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x05010502},
-       {0x0000a178, 0x051f0500},
-       {0x0000a17c, 0x0602051e},
-       {0x0000a180, 0x06000601},
-       {0x0000a184, 0x061e061f},
-       {0x0000a188, 0x0703061d},
-       {0x0000a18c, 0x07010702},
-       {0x0000a190, 0x00000700},
+       {0x0000a174, 0x0502041d},
+       {0x0000a178, 0x05000501},
+       {0x0000a17c, 0x051e051f},
+       {0x0000a180, 0x06010602},
+       {0x0000a184, 0x061f0600},
+       {0x0000a188, 0x061d061e},
+       {0x0000a18c, 0x07020703},
+       {0x0000a190, 0x07000701},
        {0x0000a194, 0x00000000},
        {0x0000a198, 0x00000000},
        {0x0000a19c, 0x00000000},
@@ -1620,7 +1620,7 @@ static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
        {0x0000a1f0, 0x00000396},
        {0x0000a1f4, 0x00000396},
        {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000296},
+       {0x0000a1fc, 0x00000196},
        {0x0000b000, 0x00010000},
        {0x0000b004, 0x00030002},
        {0x0000b008, 0x00050004},
index 64e30cd..29898f8 100644 (file)
@@ -78,6 +78,90 @@ static const struct file_operations fops_debug = {
 
 #define DMA_BUF_LEN 1024
 
+static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long mask;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &mask))
+               return -EINVAL;
+
+       common->tx_chainmask = mask;
+       sc->sc_ah->caps.tx_chainmask = mask;
+       return count;
+}
+
+static const struct file_operations fops_tx_chainmask = {
+       .read = read_file_tx_chainmask,
+       .write = write_file_tx_chainmask,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+
+static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long mask;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &mask))
+               return -EINVAL;
+
+       common->rx_chainmask = mask;
+       sc->sc_ah->caps.rx_chainmask = mask;
+       return count;
+}
+
+static const struct file_operations fops_rx_chainmask = {
+       .read = read_file_rx_chainmask,
+       .write = write_file_rx_chainmask,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
@@ -711,6 +795,86 @@ static const struct file_operations fops_recv = {
        .owner = THIS_MODULE
 };
 
+static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long regidx;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &regidx))
+               return -EINVAL;
+
+       sc->debug.regidx = regidx;
+       return count;
+}
+
+static const struct file_operations fops_regidx = {
+       .read = read_file_regidx,
+       .write = write_file_regidx,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+static ssize_t read_file_regval(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_hw *ah = sc->sc_ah;
+       char buf[32];
+       unsigned int len;
+       u32 regval;
+
+       regval = REG_READ_D(ah, sc->debug.regidx);
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_hw *ah = sc->sc_ah;
+       unsigned long regval;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &regval))
+               return -EINVAL;
+
+       REG_WRITE_D(ah, sc->debug.regidx, regval);
+       return count;
+}
+
+static const struct file_operations fops_regval = {
+       .read = read_file_regval,
+       .write = write_file_regval,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -722,54 +886,55 @@ int ath9k_init_debug(struct ath_hw *ah)
        sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
                                                      ath9k_debugfs_root);
        if (!sc->debug.debugfs_phy)
-               goto err;
+               return -ENOMEM;
 
 #ifdef CONFIG_ATH_DEBUG
-       sc->debug.debugfs_debug = debugfs_create_file("debug",
-               S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
-       if (!sc->debug.debugfs_debug)
+       if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_debug))
                goto err;
 #endif
 
-       sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
-                                      sc->debug.debugfs_phy, sc, &fops_dma);
-       if (!sc->debug.debugfs_dma)
+       if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_dma))
+               goto err;
+
+       if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_interrupt))
+               goto err;
+
+       if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_rcstat))
+               goto err;
+
+       if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_wiphy))
+               goto err;
+
+       if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_xmit))
                goto err;
 
-       sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_interrupt);
-       if (!sc->debug.debugfs_interrupt)
+       if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_recv))
                goto err;
 
-       sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
-                                                 S_IRUSR,
-                                                 sc->debug.debugfs_phy,
-                                                 sc, &fops_rcstat);
-       if (!sc->debug.debugfs_rcstat)
+       if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
                goto err;
 
-       sc->debug.debugfs_wiphy = debugfs_create_file(
-               "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
-               &fops_wiphy);
-       if (!sc->debug.debugfs_wiphy)
+       if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
                goto err;
 
-       sc->debug.debugfs_xmit = debugfs_create_file("xmit",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_xmit);
-       if (!sc->debug.debugfs_xmit)
+       if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_regidx))
                goto err;
 
-       sc->debug.debugfs_recv = debugfs_create_file("recv",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_recv);
-       if (!sc->debug.debugfs_recv)
+       if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_regval))
                goto err;
 
+       sc->debug.regidx = 0;
        return 0;
 err:
        ath9k_exit_debug(ah);
@@ -781,14 +946,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_softc *sc = (struct ath_softc *) common->priv;
 
-       debugfs_remove(sc->debug.debugfs_recv);
-       debugfs_remove(sc->debug.debugfs_xmit);
-       debugfs_remove(sc->debug.debugfs_wiphy);
-       debugfs_remove(sc->debug.debugfs_rcstat);
-       debugfs_remove(sc->debug.debugfs_interrupt);
-       debugfs_remove(sc->debug.debugfs_dma);
-       debugfs_remove(sc->debug.debugfs_debug);
-       debugfs_remove(sc->debug.debugfs_phy);
+       debugfs_remove_recursive(sc->debug.debugfs_phy);
 }
 
 int ath9k_debug_create_root(void)
index c545960..5147b87 100644 (file)
@@ -153,13 +153,7 @@ struct ath_stats {
 
 struct ath9k_debug {
        struct dentry *debugfs_phy;
-       struct dentry *debugfs_debug;
-       struct dentry *debugfs_dma;
-       struct dentry *debugfs_interrupt;
-       struct dentry *debugfs_rcstat;
-       struct dentry *debugfs_wiphy;
-       struct dentry *debugfs_xmit;
-       struct dentry *debugfs_recv;
+       u32 regidx;
        struct ath_stats stats;
 };
 
index 74872ca..46dc41a 100644 (file)
@@ -735,6 +735,14 @@ err:
        return -ENOMEM;
 }
 
+static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
+{
+       usb_kill_anchored_urbs(&hif_dev->regout_submitted);
+       ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+       ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
+       ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
+}
+
 static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
 {
        int transfer, err;
@@ -794,14 +802,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
                goto err_fw_req;
        }
 
-       /* Download firmware */
-       ret = ath9k_hif_usb_download_fw(hif_dev);
-       if (ret) {
-               dev_err(&hif_dev->udev->dev,
-                       "ath9k_htc: Firmware - %s download failed\n", fw_name);
-               goto err_fw_download;
-       }
-
        /* Alloc URBs */
        ret = ath9k_hif_usb_alloc_urbs(hif_dev);
        if (ret) {
@@ -810,25 +810,25 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
                goto err_urb;
        }
 
+       /* Download firmware */
+       ret = ath9k_hif_usb_download_fw(hif_dev);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Firmware - %s download failed\n", fw_name);
+               goto err_fw_download;
+       }
+
        return 0;
 
-err_urb:
-       /* Nothing */
 err_fw_download:
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+err_urb:
        release_firmware(hif_dev->firmware);
 err_fw_req:
        hif_dev->firmware = NULL;
        return ret;
 }
 
-static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
-{
-       usb_kill_anchored_urbs(&hif_dev->regout_submitted);
-       ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
-       ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
-       ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
-}
-
 static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
 {
        ath9k_hif_usb_dealloc_urbs(hif_dev);
@@ -859,21 +859,21 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
 #endif
        usb_set_intfdata(interface, hif_dev);
 
+       hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
+                                                &hif_dev->udev->dev);
+       if (hif_dev->htc_handle == NULL) {
+               ret = -ENOMEM;
+               goto err_htc_hw_alloc;
+       }
+
        ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
        if (ret) {
                ret = -EINVAL;
                goto err_hif_init_usb;
        }
 
-       hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev);
-       if (hif_dev->htc_handle == NULL) {
-               ret = -ENOMEM;
-               goto err_htc_hw_alloc;
-       }
-
-       ret = ath9k_htc_hw_init(&hif_usb, hif_dev->htc_handle, hif_dev,
-                               &hif_dev->udev->dev, hif_dev->device_id,
-                               ATH9K_HIF_USB);
+       ret = ath9k_htc_hw_init(hif_dev->htc_handle,
+                               &hif_dev->udev->dev, hif_dev->device_id);
        if (ret) {
                ret = -EINVAL;
                goto err_htc_hw_init;
@@ -884,10 +884,10 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
        return 0;
 
 err_htc_hw_init:
-       ath9k_htc_hw_free(hif_dev->htc_handle);
-err_htc_hw_alloc:
        ath9k_hif_usb_dev_deinit(hif_dev);
 err_hif_init_usb:
+       ath9k_htc_hw_free(hif_dev->htc_handle);
+err_htc_hw_alloc:
        usb_set_intfdata(interface, NULL);
        kfree(hif_dev);
        usb_put_dev(udev);
index 17111fc..dc01507 100644 (file)
@@ -81,6 +81,11 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 {
        int time_left;
 
+       if (atomic_read(&priv->htc->tgt_ready) > 0) {
+               atomic_dec(&priv->htc->tgt_ready);
+               return 0;
+       }
+
        /* Firmware can take up to 50ms to get ready, to be safe use 1 second */
        time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
        if (!time_left) {
@@ -88,6 +93,8 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
                return -ETIMEDOUT;
        }
 
+       atomic_dec(&priv->htc->tgt_ready);
+
        return 0;
 }
 
index 6c386da..9d371c1 100644 (file)
@@ -1452,6 +1452,8 @@ static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
        struct ath9k_htc_priv *priv = hw->priv;
        int ret;
 
+       mutex_lock(&priv->mutex);
+
        switch (cmd) {
        case STA_NOTIFY_ADD:
                ret = ath9k_htc_add_station(priv, vif, sta);
@@ -1464,6 +1466,8 @@ static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
        default:
                break;
        }
+
+       mutex_unlock(&priv->mutex);
 }
 
 static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
index 7bf6ce1..064397f 100644 (file)
@@ -39,7 +39,7 @@ static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
 {
        enum htc_endpoint_id avail_epid;
 
-       for (avail_epid = ENDPOINT_MAX; avail_epid > ENDPOINT0; avail_epid--)
+       for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
                if (endpoint[avail_epid].service_id == 0)
                        return &endpoint[avail_epid];
        return NULL;
@@ -95,6 +95,7 @@ static void htc_process_target_rdy(struct htc_target *target,
        endpoint = &target->endpoint[ENDPOINT0];
        endpoint->service_id = HTC_CTRL_RSVD_SVC;
        endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
+       atomic_inc(&target->tgt_ready);
        complete(&target->target_wait);
 }
 
@@ -116,7 +117,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
                max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
                endpoint = &target->endpoint[epid];
 
-               for (tepid = ENDPOINT_MAX; tepid > ENDPOINT0; tepid--) {
+               for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
                        tmp_endpoint = &target->endpoint[tepid];
                        if (tmp_endpoint->service_id == service_id) {
                                tmp_endpoint->service_id = 0;
@@ -124,7 +125,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
                        }
                }
 
-               if (!tmp_endpoint)
+               if (tepid == ENDPOINT0)
                        return;
 
                endpoint->service_id = service_id;
@@ -297,7 +298,7 @@ void htc_stop(struct htc_target *target)
        enum htc_endpoint_id epid;
        struct htc_endpoint *endpoint;
 
-       for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+       for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
                endpoint = &target->endpoint[epid];
                if (endpoint->service_id != 0)
                        target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
@@ -309,7 +310,7 @@ void htc_start(struct htc_target *target)
        enum htc_endpoint_id epid;
        struct htc_endpoint *endpoint;
 
-       for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+       for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
                endpoint = &target->endpoint[epid];
                if (endpoint->service_id != 0)
                        target->hif->start(target->hif_dev,
@@ -425,29 +426,19 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
        }
 }
 
-struct htc_target *ath9k_htc_hw_alloc(void *hif_handle)
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+                                     struct ath9k_htc_hif *hif,
+                                     struct device *dev)
 {
+       struct htc_endpoint *endpoint;
        struct htc_target *target;
 
        target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
-       if (!target)
+       if (!target) {
                printk(KERN_ERR "Unable to allocate memory for"
                        "target device\n");
-
-       return target;
-}
-
-void ath9k_htc_hw_free(struct htc_target *htc)
-{
-       kfree(htc);
-}
-
-int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
-                     void *hif_handle, struct device *dev, u16 devid,
-                     enum ath9k_hif_transports transport)
-{
-       struct htc_endpoint *endpoint;
-       int err = 0;
+               return NULL;
+       }
 
        init_completion(&target->target_wait);
        init_completion(&target->cmd_wait);
@@ -461,8 +452,20 @@ int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
        endpoint->ul_pipeid = hif->control_ul_pipe;
        endpoint->dl_pipeid = hif->control_dl_pipe;
 
-       err = ath9k_htc_probe_device(target, dev, devid);
-       if (err) {
+       atomic_set(&target->tgt_ready, 0);
+
+       return target;
+}
+
+void ath9k_htc_hw_free(struct htc_target *htc)
+{
+       kfree(htc);
+}
+
+int ath9k_htc_hw_init(struct htc_target *target,
+                     struct device *dev, u16 devid)
+{
+       if (ath9k_htc_probe_device(target, dev, devid)) {
                printk(KERN_ERR "Failed to initialize the device\n");
                return -ENODEV;
        }
index ea50ab0..faba679 100644 (file)
@@ -123,9 +123,6 @@ struct htc_endpoint {
 #define HTC_CONTROL_BUFFER_SIZE        \
        (HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
 
-#define NUM_CONTROL_BUFFERS 8
-#define HST_ENDPOINT_MAX 8
-
 struct htc_control_buf {
        struct htc_packet htc_pkt;
        u8 buf[HTC_CONTROL_BUFFER_SIZE];
@@ -139,7 +136,7 @@ struct htc_target {
        struct ath9k_htc_priv *drv_priv;
        struct device *dev;
        struct ath9k_htc_hif *hif;
-       struct htc_endpoint endpoint[HST_ENDPOINT_MAX];
+       struct htc_endpoint endpoint[ENDPOINT_MAX];
        struct completion target_wait;
        struct completion cmd_wait;
        struct list_head list;
@@ -147,6 +144,7 @@ struct htc_target {
        u16 credits;
        u16 credit_size;
        u8 htc_flags;
+       atomic_t tgt_ready;
 };
 
 enum htc_msg_id {
@@ -236,11 +234,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
                               struct sk_buff *skb, bool txok);
 
-struct htc_target *ath9k_htc_hw_alloc(void *hif_handle);
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+                                     struct ath9k_htc_hif *hif,
+                                     struct device *dev);
 void ath9k_htc_hw_free(struct htc_target *htc);
-int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
-                     void *hif_handle, struct device *dev, u16 devid,
-                     enum ath9k_hif_transports transport);
+int ath9k_htc_hw_init(struct htc_target *target,
+                     struct device *dev, u16 devid);
 void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
 
 #endif /* HTC_HST_H */
index ac60c4e..ba13913 100644 (file)
@@ -150,11 +150,9 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc,
 static void ath_rx_addbuffer_edma(struct ath_softc *sc,
                                  enum ath9k_rx_qtype qtype, int size)
 {
-       struct ath_rx_edma *rx_edma;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        u32 nbuf = 0;
 
-       rx_edma = &sc->rx.rx_edma[qtype];
        if (list_empty(&sc->rx.rxbuf)) {
                ath_print(common, ATH_DBG_QUEUE, "No free rx buf available\n");
                return;
@@ -718,6 +716,7 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
                __skb_unlink(skb, &rx_edma->rx_fifo);
                list_add_tail(&bf->list, &sc->rx.rxbuf);
                ath_rx_edma_buf_link(sc, qtype);
+               return true;
        }
        skb_queue_tail(&rx_edma->rx_buffers, skb);
 
index f4c5612..e0b3e8d 100644 (file)
@@ -355,8 +355,7 @@ static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
                list_del(&bss->list);
                local->num_bss_info--;
        } else {
-               bss = (struct hostap_bss_info *)
-                       kmalloc(sizeof(*bss), GFP_ATOMIC);
+               bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
                if (bss == NULL)
                        return NULL;
        }
index 9a08230..a85e43a 100644 (file)
@@ -3039,8 +3039,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
            p->length > 1024 || !p->pointer)
                return -EINVAL;
 
-       param = (struct prism2_download_param *)
-               kmalloc(p->length, GFP_KERNEL);
+       param = kmalloc(p->length, GFP_KERNEL);
        if (param == NULL)
                return -ENOMEM;
 
index fb59af2..6be2992 100644 (file)
@@ -212,7 +212,7 @@ static struct iwl_lib_ops iwl1000_lib = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -224,7 +224,6 @@ static struct iwl_lib_ops iwl1000_lib = {
 };
 
 static const struct iwl_ops iwl1000_ops = {
-       .ucode = &iwlagn_ucode,
        .lib = &iwl1000_lib,
        .hcmd = &iwlagn_hcmd,
        .utils = &iwlagn_hcmd_utils,
@@ -260,6 +259,9 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 128,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
@@ -289,6 +291,9 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 128,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
index 99b876a..068f7f8 100644 (file)
@@ -391,6 +391,67 @@ static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
 }
 #endif
 
+/**
+ * iwl3945_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       bool rc = true;
+       struct iwl3945_notif_statistics current_stat;
+       int combined_plcp_delta;
+       unsigned int plcp_msec;
+       unsigned long plcp_received_jiffies;
+
+       memcpy(&current_stat, pkt->u.raw, sizeof(struct
+                       iwl3945_notif_statistics));
+       /*
+        * check for plcp_err and trigger radio reset if it exceeds
+        * the plcp error threshold plcp_delta.
+        */
+       plcp_received_jiffies = jiffies;
+       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+                                       (long) priv->plcp_jiffies);
+       priv->plcp_jiffies = plcp_received_jiffies;
+       /*
+        * check to make sure plcp_msec is not 0 to prevent division
+        * by zero.
+        */
+       if (plcp_msec) {
+               combined_plcp_delta =
+                       (le32_to_cpu(current_stat.rx.ofdm.plcp_err) -
+                       le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err));
+
+               if ((combined_plcp_delta > 0) &&
+                       ((combined_plcp_delta * 100) / plcp_msec) >
+                       priv->cfg->plcp_delta_threshold) {
+                       /*
+                        * if plcp_err exceed the threshold, the following
+                        * data is printed in csv format:
+                        *    Text: plcp_err exceeded %d,
+                        *    Received ofdm.plcp_err,
+                        *    Current ofdm.plcp_err,
+                        *    combined_plcp_delta,
+                        *    plcp_msec
+                        */
+                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+                               "%u, %d, %u mSecs\n",
+                               priv->cfg->plcp_delta_threshold,
+                               le32_to_cpu(current_stat.rx.ofdm.plcp_err),
+                               combined_plcp_delta, plcp_msec);
+                       /*
+                        * Reset the RF radio due to the high plcp
+                        * error rate
+                        */
+                       rc = false;
+               }
+       }
+       return rc;
+}
+
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                struct iwl_rx_mem_buffer *rxb)
 {
@@ -402,6 +463,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
 #ifdef CONFIG_IWLWIFI_DEBUG
        iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
 #endif
+       iwl_recover_from_statistics(priv, pkt);
 
        memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
 }
@@ -885,7 +947,8 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                       tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
 }
 
-u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+                          u16 tx_rate, u8 flags)
 {
        unsigned long flags_spin;
        struct iwl_station_entry *station;
@@ -1715,6 +1778,11 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
        int ref_temp;
        int temperature = priv->temperature;
 
+       if (priv->disable_tx_power_cal ||
+           test_bit(STATUS_SCANNING, &priv->status)) {
+               /* do not perform tx power calibration */
+               return 0;
+       }
        /* set up new Tx power info for each and every channel, 2.4 and 5.x */
        for (i = 0; i < priv->channel_count; i++) {
                ch_info = &priv->channel_info[i];
@@ -1925,7 +1993,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                                  "configuration (%d).\n", rc);
                        return rc;
                }
-               iwl_clear_ucode_stations(priv, false);
+               iwl_clear_ucode_stations(priv);
                iwl_restore_stations(priv);
        }
 
@@ -1958,7 +2026,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
        if (!new_assoc) {
-               iwl_clear_ucode_stations(priv, false);
+               iwl_clear_ucode_stations(priv);
                iwl_restore_stations(priv);
        }
 
@@ -2391,6 +2459,30 @@ static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
        return (u16)sizeof(struct iwl3945_addsta_cmd);
 }
 
+static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
+                                      struct ieee80211_vif *vif, bool add)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       int ret;
+
+       if (add) {
+               ret = iwl_add_bssid_station(priv, vif->bss_conf.bssid, false,
+                                           &vif_priv->ibss_bssid_sta_id);
+               if (ret)
+                       return ret;
+
+               iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
+                                (priv->band == IEEE80211_BAND_5GHZ) ?
+                                IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+                                CMD_ASYNC);
+               iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
+
+               return 0;
+       }
+
+       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+                                 vif->bss_conf.bssid);
+}
 
 /**
  * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
@@ -2720,51 +2812,12 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
        return 0;
 }
 
-#define IWL3945_UCODE_GET(item)                                                \
-static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       return le32_to_cpu(ucode->u.v1.item);                           \
-}
-
-static u32 iwl3945_ucode_get_header_size(u32 api_ver)
-{
-       return UCODE_HEADER_SIZE(1);
-}
-static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       return 0;
-}
-static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       return (u8 *) ucode->u.v1.data;
-}
-
-IWL3945_UCODE_GET(inst_size);
-IWL3945_UCODE_GET(data_size);
-IWL3945_UCODE_GET(init_size);
-IWL3945_UCODE_GET(init_data_size);
-IWL3945_UCODE_GET(boot_size);
-
 static struct iwl_hcmd_ops iwl3945_hcmd = {
        .rxon_assoc = iwl3945_send_rxon_assoc,
        .commit_rxon = iwl3945_commit_rxon,
        .send_bt_config = iwl_send_bt_config,
 };
 
-static struct iwl_ucode_ops iwl3945_ucode = {
-       .get_header_size = iwl3945_ucode_get_header_size,
-       .get_build = iwl3945_ucode_get_build,
-       .get_inst_size = iwl3945_ucode_get_inst_size,
-       .get_data_size = iwl3945_ucode_get_data_size,
-       .get_init_size = iwl3945_ucode_get_init_size,
-       .get_init_data_size = iwl3945_ucode_get_init_data_size,
-       .get_boot_size = iwl3945_ucode_get_boot_size,
-       .get_data = iwl3945_ucode_get_data,
-};
-
 static struct iwl_lib_ops iwl3945_lib = {
        .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2798,7 +2851,8 @@ static struct iwl_lib_ops iwl3945_lib = {
        .post_associate = iwl3945_post_associate,
        .isr = iwl_isr_legacy,
        .config_ap = iwl3945_config_ap,
-       .add_bcast_station = iwl3945_add_bcast_station,
+       .manage_ibss_station = iwl3945_manage_ibss_station,
+       .check_plcp_health = iwl3945_good_plcp_health,
 
        .debugfs_ops = {
                .rx_stats_read = iwl3945_ucode_rx_stats_read,
@@ -2815,7 +2869,6 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
 };
 
 static const struct iwl_ops iwl3945_ops = {
-       .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
        .utils = &iwl3945_hcmd_utils,
@@ -2840,9 +2893,10 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .tx_power_by_driver = true,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2860,9 +2914,10 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .tx_power_by_driver = true,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
index 643adb6..bb2aeeb 100644 (file)
@@ -106,7 +106,12 @@ struct iwl3945_rs_sta {
 };
 
 
+/*
+ * The common struct MUST be first because it is shared between
+ * 3945 and agn!
+ */
 struct iwl3945_sta_priv {
+       struct iwl_station_priv_common common;
        struct iwl3945_rs_sta rs_sta;
 };
 
@@ -211,13 +216,6 @@ extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                                       char **buf, bool display);
 extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
 
-/*
- * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
- * call this... todo... fix that.
-*/
-extern u8 iwl3945_sync_station(struct iwl_priv *priv, int sta_id,
-                          u16 tx_rate, u8 flags);
-
 /******************************************************************************
  *
  * Functions implemented in iwl-[34]*.c which are forward declared here
@@ -268,8 +266,10 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
 extern void iwl3945_disable_events(struct iwl_priv *priv);
 extern int iwl4965_get_temperature(const struct iwl_priv *priv);
-extern void iwl3945_post_associate(struct iwl_priv *priv);
-extern void iwl3945_config_ap(struct iwl_priv *priv);
+extern void iwl3945_post_associate(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif);
+extern void iwl3945_config_ap(struct iwl_priv *priv,
+                             struct ieee80211_vif *vif);
 
 /**
  * iwl3945_hw_find_station - Find station id for a given BSSID
@@ -288,8 +288,6 @@ extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
 extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
 extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
 extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
-extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
-                u16 tx_rate, u8 flags);
 
 extern const struct iwl_channel_info *iwl3945_get_channel_info(
        const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
@@ -297,7 +295,7 @@ extern const struct iwl_channel_info *iwl3945_get_channel_info(
 extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate);
 
 /* scanning */
-void iwl3945_request_scan(struct iwl_priv *priv);
+void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
 
 /* Requires full declaration of iwl_priv before including */
 #include "iwl-io.h"
index 136c290..d3afdda 100644 (file)
@@ -1953,6 +1953,60 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
        return 0;
 }
 
+static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+       int i;
+       int start = 0;
+       int ret = IWL_INVALID_STATION;
+       unsigned long flags;
+
+       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+           (priv->iw_mode == NL80211_IFTYPE_AP))
+               start = IWL_STA_ID;
+
+       if (is_broadcast_ether_addr(addr))
+               return priv->hw_params.bcast_sta_id;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       for (i = start; i < priv->hw_params.max_stations; i++)
+               if (priv->stations[i].used &&
+                   (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+                                        addr))) {
+                       ret = i;
+                       goto out;
+               }
+
+       IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n",
+                             addr, priv->num_stations);
+
+ out:
+       /*
+        * It may be possible that more commands interacting with stations
+        * arrive before we completed processing the adding of
+        * station
+        */
+       if (ret != IWL_INVALID_STATION &&
+           (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) ||
+            ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) &&
+             (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) {
+               IWL_ERR(priv, "Requested station info for sta %d before ready.\n",
+                       ret);
+               ret = IWL_INVALID_STATION;
+       }
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return ret;
+}
+
+static int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+               return IWL_AP_ID;
+       } else {
+               u8 *da = ieee80211_get_DA(hdr);
+               return iwl_find_station(priv, da);
+       }
+}
+
 /**
  * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
  */
@@ -2112,34 +2166,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->txpower_work);
 }
 
-#define IWL4965_UCODE_GET(item)                                                \
-static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       return le32_to_cpu(ucode->u.v1.item);                           \
-}
-
-static u32 iwl4965_ucode_get_header_size(u32 api_ver)
-{
-       return UCODE_HEADER_SIZE(1);
-}
-static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       return 0;
-}
-static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       return (u8 *) ucode->u.v1.data;
-}
-
-IWL4965_UCODE_GET(inst_size);
-IWL4965_UCODE_GET(data_size);
-IWL4965_UCODE_GET(init_size);
-IWL4965_UCODE_GET(init_data_size);
-IWL4965_UCODE_GET(boot_size);
-
 static struct iwl_hcmd_ops iwl4965_hcmd = {
        .rxon_assoc = iwl4965_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
@@ -2147,16 +2173,6 @@ static struct iwl_hcmd_ops iwl4965_hcmd = {
        .send_bt_config = iwl_send_bt_config,
 };
 
-static struct iwl_ucode_ops iwl4965_ucode = {
-       .get_header_size = iwl4965_ucode_get_header_size,
-       .get_build = iwl4965_ucode_get_build,
-       .get_inst_size = iwl4965_ucode_get_inst_size,
-       .get_data_size = iwl4965_ucode_get_data_size,
-       .get_init_size = iwl4965_ucode_get_init_size,
-       .get_init_data_size = iwl4965_ucode_get_init_data_size,
-       .get_boot_size = iwl4965_ucode_get_boot_size,
-       .get_data = iwl4965_ucode_get_data,
-};
 static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
        .get_hcmd_size = iwl4965_get_hcmd_size,
        .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2218,7 +2234,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .temperature = iwl4965_temperature_calib,
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -2228,7 +2244,6 @@ static struct iwl_lib_ops iwl4965_lib = {
 };
 
 static const struct iwl_ops iwl4965_ops = {
-       .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
        .utils = &iwl4965_hcmd_utils,
@@ -2262,7 +2277,10 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .temperature_kelvin = true,
        .max_event_log_size = 512,
-
+       .tx_power_by_driver = true,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
        /*
         * Force use of chains B and C for scan RX on 5 GHz band
         * because the device has off-channel reception on chain A.
index 115d3ea..a28af7e 100644 (file)
@@ -351,7 +351,7 @@ static struct iwl_lib_ops iwl5000_lib = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -413,7 +413,7 @@ static struct iwl_lib_ops iwl5150_lib = {
                .temperature = iwl5150_temperature,
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -425,7 +425,6 @@ static struct iwl_lib_ops iwl5150_lib = {
 };
 
 static const struct iwl_ops iwl5000_ops = {
-       .ucode = &iwlagn_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwlagn_hcmd,
        .utils = &iwlagn_hcmd_utils,
@@ -433,7 +432,6 @@ static const struct iwl_ops iwl5000_ops = {
 };
 
 static const struct iwl_ops iwl5150_ops = {
-       .ucode = &iwlagn_ucode,
        .lib = &iwl5150_lib,
        .hcmd = &iwlagn_hcmd,
        .utils = &iwlagn_hcmd_utils,
@@ -466,6 +464,9 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
@@ -494,6 +495,9 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -520,6 +524,9 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -548,6 +555,9 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -576,6 +586,9 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -604,6 +617,9 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
@@ -630,6 +646,9 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
index 7acef70..9fbf54c 100644 (file)
 #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
 #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
 
-#define IWL6000G2_FW_PRE "iwlwifi-6005-"
-#define _IWL6000G2_MODULE_FIRMWARE(api) IWL6000G2_FW_PRE #api ".ucode"
-#define IWL6000G2_MODULE_FIRMWARE(api) _IWL6000G2_MODULE_FIRMWARE(api)
+#define IWL6000G2A_FW_PRE "iwlwifi-6000g2a-"
+#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
+#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
+
 
 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -316,7 +317,7 @@ static struct iwl_lib_ops iwl6000_lib = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -328,7 +329,6 @@ static struct iwl_lib_ops iwl6000_lib = {
 };
 
 static const struct iwl_ops iwl6000_ops = {
-       .ucode = &iwlagn_ucode,
        .lib = &iwl6000_lib,
        .hcmd = &iwlagn_hcmd,
        .utils = &iwlagn_hcmd_utils,
@@ -389,7 +389,7 @@ static struct iwl_lib_ops iwl6050_lib = {
                .set_ct_kill = iwl6000_set_ct_threshold,
                .set_calib_version = iwl6050_set_calib_version,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -401,19 +401,16 @@ static struct iwl_lib_ops iwl6050_lib = {
 };
 
 static const struct iwl_ops iwl6050_ops = {
-       .ucode = &iwlagn_ucode,
        .lib = &iwl6050_lib,
        .hcmd = &iwlagn_hcmd,
        .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
-/*
- * "i": Internal configuration, use internal Power Amplifier
- */
-struct iwl_cfg iwl6000g2_2agn_cfg = {
-       .name = "6000 Series 2x2 AGN Gen2",
-       .fw_name_pre = IWL6000G2_FW_PRE,
+
+struct iwl_cfg iwl6000g2a_2agn_cfg = {
+       .name = "6000 Series 2x2 AGN Gen2a",
+       .fw_name_pre = IWL6000G2A_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
@@ -442,9 +439,15 @@ struct iwl_cfg iwl6000g2_2agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
 struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
        .fw_name_pre = IWL6000_FW_PRE,
@@ -477,6 +480,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -509,6 +515,9 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -541,6 +550,9 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
@@ -575,6 +587,9 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .chain_noise_scale = 1500,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -607,6 +622,9 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .chain_noise_scale = 1500,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -641,8 +659,11 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL6000G2_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
index f249b70..48c023b 100644 (file)
@@ -709,6 +709,22 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
                         delta_tx->agg.rx_ba_rsp_cnt,
                         max_tx->agg.rx_ba_rsp_cnt);
 
+       if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "tx power: (1/2 dB step)\n");
+               if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna A: 0x%X\n",
+                                       tx->tx_power.ant_a);
+               if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna B: 0x%X\n",
+                                       tx->tx_power.ant_b);
+               if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna C: 0x%X\n",
+                                       tx->tx_power.ant_c);
+       }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
index a273474..637d7b6 100644 (file)
@@ -38,6 +38,7 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-agn.h"
+#include "iwl-sta.h"
 
 static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
 {
@@ -1113,8 +1114,9 @@ void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
 }
 
 static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    struct iwl_scan_channel *scan_ch)
+                                          struct ieee80211_vif *vif,
+                                          enum ieee80211_band band,
+                                          struct iwl_scan_channel *scan_ch)
 {
        const struct ieee80211_supported_band *sband;
        const struct iwl_channel_info *ch_info;
@@ -1130,7 +1132,7 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
        }
 
        active_dwell = iwl_get_active_dwell_time(priv, band, 0);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
@@ -1179,6 +1181,7 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
 }
 
 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)
@@ -1196,7 +1199,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                return 0;
 
        active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
@@ -1256,7 +1259,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
        return added;
 }
 
-void iwlagn_request_scan(struct iwl_priv *priv)
+void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
@@ -1342,7 +1345,7 @@ void iwlagn_request_scan(struct iwl_priv *priv)
 
                IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
                spin_lock_irqsave(&priv->lock, flags);
-               interval = priv->beacon_int;
+               interval = vif ? vif->bss_conf.beacon_int : 0;
                spin_unlock_irqrestore(&priv->lock, flags);
 
                scan->suspend_time = 0;
@@ -1473,12 +1476,12 @@ void iwlagn_request_scan(struct iwl_priv *priv)
 
        if (priv->is_internal_short_scan) {
                scan->channel_count =
-                       iwl_get_single_channel_for_scan(priv, band,
+                       iwl_get_single_channel_for_scan(priv, vif, band,
                                (void *)&scan->data[le16_to_cpu(
                                scan->tx_cmd.len)]);
        } else {
                scan->channel_count =
-                       iwl_get_channels_for_scan(priv, band,
+                       iwl_get_channels_for_scan(priv, vif, band,
                                is_active, n_probes,
                                (void *)&scan->data[le16_to_cpu(
                                scan->tx_cmd.len)]);
@@ -1513,3 +1516,15 @@ void iwlagn_request_scan(struct iwl_priv *priv)
        /* inform mac80211 scan aborted */
        queue_work(priv->workqueue, &priv->scan_completed);
 }
+
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       if (add)
+               return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true,
+                                            &vif_priv->ibss_bssid_sta_id);
+       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+                                 vif->bss_conf.bssid);
+}
index c2a5c85..c402bfc 100644 (file)
@@ -566,11 +566,11 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        hdr_len = ieee80211_hdrlen(fc);
 
-       /* Find (or create) index into station table for destination station */
-       if (info->flags & IEEE80211_TX_CTL_INJECTED)
+       /* Find index into station table for destination station */
+       if (!info->control.sta)
                sta_id = priv->hw_params.bcast_sta_id;
        else
-               sta_id = iwl_get_sta_id(priv, hdr);
+               sta_id = iwl_sta_id(info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -961,7 +961,8 @@ static int iwlagn_txq_ctx_activate_free(struct iwl_priv *priv)
        return -1;
 }
 
-int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
        int sta_id;
        int tx_fifo;
@@ -975,9 +976,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
                return tx_fifo;
 
        IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
-                       __func__, ra, tid);
+                       __func__, sta->addr, tid);
 
-       sta_id = iwl_find_station(priv, ra);
+       sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Start AGG on invalid station\n");
                return -ENXIO;
@@ -1011,7 +1012,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
        if (tid_data->tfds_in_queue == 0) {
                IWL_DEBUG_HT(priv, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
-               ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
        } else {
                IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
                             tid_data->tfds_in_queue);
@@ -1020,23 +1021,19 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
        return ret;
 }
 
-int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid)
 {
        int tx_fifo_id, txq_id, sta_id, ssn = -1;
        struct iwl_tid_data *tid_data;
        int write_ptr, read_ptr;
        unsigned long flags;
 
-       if (!ra) {
-               IWL_ERR(priv, "ra = NULL\n");
-               return -EINVAL;
-       }
-
        tx_fifo_id = get_fifo_from_tid(tid);
        if (unlikely(tx_fifo_id < 0))
                return tx_fifo_id;
 
-       sta_id = iwl_find_station(priv, ra);
+       sta_id = iwl_sta_id(sta);
 
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
@@ -1046,7 +1043,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
        if (priv->stations[sta_id].tid[tid].agg.state ==
                                IWL_EMPTYING_HW_QUEUE_ADDBA) {
                IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
                return 0;
        }
@@ -1083,7 +1080,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
                                                   tx_fifo_id);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 
        return 0;
 }
index ae476c2..637286c 100644 (file)
@@ -52,6 +52,37 @@ static const s8 iwlagn_default_queue_to_tx_fifo[] = {
        IWL_TX_FIFO_UNUSED,
 };
 
+static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
+       {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
+        0, COEX_UNASSOC_IDLE_FLAGS},
+       {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP,
+        0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
+       {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP,
+        0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
+       {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP,
+        0, COEX_CALIBRATION_FLAGS},
+       {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP,
+        0, COEX_PERIODIC_CALIBRATION_FLAGS},
+       {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP,
+        0, COEX_CONNECTION_ESTAB_FLAGS},
+       {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP,
+        0, COEX_ASSOCIATED_IDLE_FLAGS},
+       {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP,
+        0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
+       {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP,
+        0, COEX_ASSOC_AUTO_SCAN_FLAGS},
+       {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP,
+        0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
+       {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS},
+       {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS},
+       {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP,
+        0, COEX_STAND_ALONE_DEBUG_FLAGS},
+       {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP,
+        0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
+       {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS},
+       {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
+};
+
 /*
  * ucode
  */
@@ -151,55 +182,6 @@ int iwlagn_load_ucode(struct iwl_priv *priv)
        return ret;
 }
 
-#define IWL_UCODE_GET(item)                                            \
-static u32 iwlagn_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       if (api_ver <= 2)                                               \
-               return le32_to_cpu(ucode->u.v1.item);                   \
-       return le32_to_cpu(ucode->u.v2.item);                           \
-}
-
-static u32 iwlagn_ucode_get_header_size(u32 api_ver)
-{
-       if (api_ver <= 2)
-               return UCODE_HEADER_SIZE(1);
-       return UCODE_HEADER_SIZE(2);
-}
-
-static u32 iwlagn_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       if (api_ver <= 2)
-               return 0;
-       return le32_to_cpu(ucode->u.v2.build);
-}
-
-static u8 *iwlagn_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       if (api_ver <= 2)
-               return (u8 *) ucode->u.v1.data;
-       return (u8 *) ucode->u.v2.data;
-}
-
-IWL_UCODE_GET(inst_size);
-IWL_UCODE_GET(data_size);
-IWL_UCODE_GET(init_size);
-IWL_UCODE_GET(init_data_size);
-IWL_UCODE_GET(boot_size);
-
-struct iwl_ucode_ops iwlagn_ucode = {
-       .get_header_size = iwlagn_ucode_get_header_size,
-       .get_build = iwlagn_ucode_get_build,
-       .get_inst_size = iwlagn_ucode_get_inst_size,
-       .get_data_size = iwlagn_ucode_get_data_size,
-       .get_init_size = iwlagn_ucode_get_init_size,
-       .get_init_data_size = iwlagn_ucode_get_init_data_size,
-       .get_boot_size = iwlagn_ucode_get_boot_size,
-       .get_data = iwlagn_ucode_get_data,
-};
-
 /*
  *  Calibration
  */
@@ -320,6 +302,33 @@ restart:
        queue_work(priv->workqueue, &priv->restart);
 }
 
+static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
+{
+       struct iwl_wimax_coex_cmd coex_cmd;
+
+       if (priv->cfg->support_wimax_coexist) {
+               /* UnMask wake up src at associated sleep */
+               coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
+
+               /* UnMask wake up src at unassociated sleep */
+               coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK;
+               memcpy(coex_cmd.sta_prio, cu_priorities,
+                       sizeof(struct iwl_wimax_coex_event_entry) *
+                        COEX_NUM_OF_EVENTS);
+
+               /* enabling the coexistence feature */
+               coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK;
+
+               /* enabling the priorities tables */
+               coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK;
+       } else {
+               /* coexistence is disabled */
+               memset(&coex_cmd, 0, sizeof(coex_cmd));
+       }
+       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
+                               sizeof(coex_cmd), &coex_cmd);
+}
+
 int iwlagn_alive_notify(struct iwl_priv *priv)
 {
        u32 a;
@@ -407,7 +416,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_send_wimax_coex(priv);
+       iwlagn_send_wimax_coex(priv);
 
        iwlagn_set_Xtal_calib(priv);
        iwl_send_calib_results(priv);
index a672d33..dc747ad 100644 (file)
@@ -157,7 +157,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
                        return ret;
                }
-               iwl_clear_ucode_stations(priv, false);
+               iwl_clear_ucode_stations(priv);
                iwl_restore_stations(priv);
                ret = iwl_restore_default_wep_keys(priv);
                if (ret) {
@@ -189,7 +189,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                }
                IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
                memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-               iwl_clear_ucode_stations(priv, false);
+               iwl_clear_ucode_stations(priv);
                iwl_restore_stations(priv);
                ret = iwl_restore_default_wep_keys(priv);
                if (ret) {
@@ -1506,9 +1506,13 @@ static void iwl_nic_start(struct iwl_priv *priv)
        iwl_write32(priv, CSR_RESET, 0);
 }
 
+struct iwlagn_ucode_capabilities {
+       u32 max_probe_length;
+};
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwl_mac_setup_register(struct iwl_priv *priv);
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa);
 
 static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
 {
@@ -1535,6 +1539,199 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
                                       iwl_ucode_callback);
 }
 
+struct iwlagn_firmware_pieces {
+       const void *inst, *data, *init, *init_data, *boot;
+       size_t inst_size, data_size, init_size, init_data_size, boot_size;
+
+       u32 build;
+};
+
+static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+                                      const struct firmware *ucode_raw,
+                                      struct iwlagn_firmware_pieces *pieces)
+{
+       struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+       u32 api_ver, hdr_size;
+       const u8 *src;
+
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(priv->ucode_ver);
+
+       switch (api_ver) {
+       default:
+               /*
+                * 4965 doesn't revision the firmware file format
+                * along with the API version, it always uses v1
+                * file format.
+                */
+               if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
+                               CSR_HW_REV_TYPE_4965) {
+                       hdr_size = 28;
+                       if (ucode_raw->size < hdr_size) {
+                               IWL_ERR(priv, "File size too small!\n");
+                               return -EINVAL;
+                       }
+                       pieces->build = le32_to_cpu(ucode->u.v2.build);
+                       pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+                       pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+                       pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+                       pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+                       pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
+                       src = ucode->u.v2.data;
+                       break;
+               }
+               /* fall through for 4965 */
+       case 0:
+       case 1:
+       case 2:
+               hdr_size = 24;
+               if (ucode_raw->size < hdr_size) {
+                       IWL_ERR(priv, "File size too small!\n");
+                       return -EINVAL;
+               }
+               pieces->build = 0;
+               pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+               pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+               pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+               pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
+               pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
+               src = ucode->u.v1.data;
+               break;
+       }
+
+       /* Verify size of file vs. image size info in file's header */
+       if (ucode_raw->size != hdr_size + pieces->inst_size +
+                               pieces->data_size + pieces->init_size +
+                               pieces->init_data_size + pieces->boot_size) {
+
+               IWL_ERR(priv,
+                       "uCode file size %d does not match expected size\n",
+                       (int)ucode_raw->size);
+               return -EINVAL;
+       }
+
+       pieces->inst = src;
+       src += pieces->inst_size;
+       pieces->data = src;
+       src += pieces->data_size;
+       pieces->init = src;
+       src += pieces->init_size;
+       pieces->init_data = src;
+       src += pieces->init_data_size;
+       pieces->boot = src;
+       src += pieces->boot_size;
+
+       return 0;
+}
+
+static int iwlagn_wanted_ucode_alternative = 1;
+
+static int iwlagn_load_firmware(struct iwl_priv *priv,
+                               const struct firmware *ucode_raw,
+                               struct iwlagn_firmware_pieces *pieces,
+                               struct iwlagn_ucode_capabilities *capa)
+{
+       struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
+       struct iwl_ucode_tlv *tlv;
+       size_t len = ucode_raw->size;
+       const u8 *data;
+       int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
+       u64 alternatives;
+
+       if (len < sizeof(*ucode))
+               return -EINVAL;
+
+       if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
+               return -EINVAL;
+
+       /*
+        * Check which alternatives are present, and "downgrade"
+        * when the chosen alternative is not present, warning
+        * the user when that happens. Some files may not have
+        * any alternatives, so don't warn in that case.
+        */
+       alternatives = le64_to_cpu(ucode->alternatives);
+       tmp = wanted_alternative;
+       if (wanted_alternative > 63)
+               wanted_alternative = 63;
+       while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
+               wanted_alternative--;
+       if (wanted_alternative && wanted_alternative != tmp)
+               IWL_WARN(priv,
+                        "uCode alternative %d not available, choosing %d\n",
+                        tmp, wanted_alternative);
+
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       pieces->build = le32_to_cpu(ucode->build);
+       data = ucode->data;
+
+       len -= sizeof(*ucode);
+
+       while (len >= sizeof(*tlv)) {
+               u32 tlv_len;
+               enum iwl_ucode_tlv_type tlv_type;
+               u16 tlv_alt;
+               const u8 *tlv_data;
+
+               len -= sizeof(*tlv);
+               tlv = (void *)data;
+
+               tlv_len = le32_to_cpu(tlv->length);
+               tlv_type = le16_to_cpu(tlv->type);
+               tlv_alt = le16_to_cpu(tlv->alternative);
+               tlv_data = tlv->data;
+
+               if (len < tlv_len)
+                       return -EINVAL;
+               len -= ALIGN(tlv_len, 4);
+               data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+
+               /*
+                * Alternative 0 is always valid.
+                *
+                * Skip alternative TLVs that are not selected.
+                */
+               if (tlv_alt != 0 && tlv_alt != wanted_alternative)
+                       continue;
+
+               switch (tlv_type) {
+               case IWL_UCODE_TLV_INST:
+                       pieces->inst = tlv_data;
+                       pieces->inst_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_DATA:
+                       pieces->data = tlv_data;
+                       pieces->data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT:
+                       pieces->init = tlv_data;
+                       pieces->init_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT_DATA:
+                       pieces->init_data = tlv_data;
+                       pieces->init_data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_BOOT:
+                       pieces->boot = tlv_data;
+                       pieces->boot_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_PROBE_MAX_LEN:
+                       if (tlv_len != 4)
+                               return -EINVAL;
+                       capa->max_probe_length =
+                               le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (len)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -1545,14 +1742,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 {
        struct iwl_priv *priv = context;
        struct iwl_ucode_header *ucode;
+       int err;
+       struct iwlagn_firmware_pieces pieces;
        const unsigned int api_max = priv->cfg->ucode_api_max;
        const unsigned int api_min = priv->cfg->ucode_api_min;
-       u8 *src;
-       size_t len;
-       u32 api_ver, build;
-       u32 inst_size, data_size, init_size, init_data_size, boot_size;
-       int err;
-       u16 eeprom_ver;
+       u32 api_ver;
+       char buildstr[25];
+       u32 build;
+       struct iwlagn_ucode_capabilities ucode_capa = {
+               .max_probe_length = 200,
+       };
+
+       memset(&pieces, 0, sizeof(pieces));
 
        if (!ucode_raw) {
                IWL_ERR(priv, "request for firmware file '%s' failed.\n",
@@ -1563,8 +1764,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
                       priv->firmware_name, ucode_raw->size);
 
-       /* Make sure that we got at least the v1 header! */
-       if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
+       /* Make sure that we got at least the API version number */
+       if (ucode_raw->size < 4) {
                IWL_ERR(priv, "File size way too small!\n");
                goto try_again;
        }
@@ -1572,21 +1773,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Data from ucode file:  header followed by uCode images */
        ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
-       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       if (ucode->ver)
+               err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+       else
+               err = iwlagn_load_firmware(priv, ucode_raw, &pieces,
+                                          &ucode_capa);
+
+       if (err)
+               goto try_again;
+
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
-       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
-       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
-       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
-       init_data_size =
-               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
-       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
-       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
-
-       /* api_ver should match the api version forming part of the
-        * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firmware header from here on forward */
+       build = pieces.build;
 
+       /*
+        * api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+        * on the API version read from firmware header from here on forward
+        */
        if (api_ver < api_min || api_ver > api_max) {
                IWL_ERR(priv, "Driver unable to support your firmware API. "
                          "Driver supports v%u, firmware is v%u.\n",
@@ -1600,40 +1803,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                          "from http://www.intellinuxwireless.org.\n",
                          api_max, api_ver);
 
-       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u\n",
-              IWL_UCODE_MAJOR(priv->ucode_ver),
-              IWL_UCODE_MINOR(priv->ucode_ver),
-              IWL_UCODE_API(priv->ucode_ver),
-              IWL_UCODE_SERIAL(priv->ucode_ver));
+       if (build)
+               sprintf(buildstr, " build %u", build);
+       else
+               buildstr[0] = '\0';
+
+       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
+                IWL_UCODE_MAJOR(priv->ucode_ver),
+                IWL_UCODE_MINOR(priv->ucode_ver),
+                IWL_UCODE_API(priv->ucode_ver),
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        snprintf(priv->hw->wiphy->fw_version,
                 sizeof(priv->hw->wiphy->fw_version),
-                "%u.%u.%u.%u",
+                "%u.%u.%u.%u%s",
                 IWL_UCODE_MAJOR(priv->ucode_ver),
                 IWL_UCODE_MINOR(priv->ucode_ver),
                 IWL_UCODE_API(priv->ucode_ver),
-                IWL_UCODE_SERIAL(priv->ucode_ver));
-
-       if (build)
-               IWL_DEBUG_INFO(priv, "Build %u\n", build);
-
-       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-       IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-                      ? "OTP" : "EEPROM", eeprom_ver);
-
-       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-                      priv->ucode_ver);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
-                      inst_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n",
-                      data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n",
-                      init_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n",
-                      init_data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
-                      boot_size);
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        /*
         * For any of the failures below (before allocating pci memory)
@@ -1641,43 +1830,47 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
         * user just got a corrupted version of the latest API.
         */
 
-       /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size !=
-               priv->cfg->ops->ucode->get_header_size(api_ver) +
-               inst_size + data_size + init_size +
-               init_data_size + boot_size) {
-
-               IWL_DEBUG_INFO(priv,
-                       "uCode file size %d does not match expected size\n",
-                       (int)ucode_raw->size);
-               goto try_again;
-       }
+       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+                      priv->ucode_ver);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+                      pieces.inst_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+                      pieces.data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+                      pieces.init_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+                      pieces.init_data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
+                      pieces.boot_size);
 
        /* Verify that uCode images will fit in card's SRAM */
-       if (inst_size > priv->hw_params.max_inst_size) {
-               IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
-                              inst_size);
+       if (pieces.inst_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+                       pieces.inst_size);
                goto try_again;
        }
 
-       if (data_size > priv->hw_params.max_data_size) {
-               IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
-                               data_size);
+       if (pieces.data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+                       pieces.data_size);
                goto try_again;
        }
-       if (init_size > priv->hw_params.max_inst_size) {
-               IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
-                       init_size);
+
+       if (pieces.init_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+                       pieces.init_size);
                goto try_again;
        }
-       if (init_data_size > priv->hw_params.max_data_size) {
-               IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
-                     init_data_size);
+
+       if (pieces.init_data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+                       pieces.init_data_size);
                goto try_again;
        }
-       if (boot_size > priv->hw_params.max_bsm_size) {
-               IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
-                       boot_size);
+
+       if (pieces.boot_size > priv->hw_params.max_bsm_size) {
+               IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
+                       pieces.boot_size);
                goto try_again;
        }
 
@@ -1686,13 +1879,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       priv->ucode_code.len = inst_size;
+       priv->ucode_code.len = pieces.inst_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
-       priv->ucode_data.len = data_size;
+       priv->ucode_data.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
-       priv->ucode_data_backup.len = data_size;
+       priv->ucode_data_backup.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
        if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
@@ -1700,11 +1893,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
-       if (init_size && init_data_size) {
-               priv->ucode_init.len = init_size;
+       if (pieces.init_size && pieces.init_data_size) {
+               priv->ucode_init.len = pieces.init_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
 
-               priv->ucode_init_data.len = init_data_size;
+               priv->ucode_init_data.len = pieces.init_data_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
 
                if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
@@ -1712,8 +1905,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        }
 
        /* Bootstrap (instructions only, no data) */
-       if (boot_size) {
-               priv->ucode_boot.len = boot_size;
+       if (pieces.boot_size) {
+               priv->ucode_boot.len = pieces.boot_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
                if (!priv->ucode_boot.v_addr)
@@ -1723,51 +1916,48 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
-       len = inst_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
-       memcpy(priv->ucode_code.v_addr, src, len);
-       src += len;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
+                       pieces.inst_size);
+       memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
 
        IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
-       /* Runtime data (2nd block)
-        * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-       len = data_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
-       memcpy(priv->ucode_data.v_addr, src, len);
-       memcpy(priv->ucode_data_backup.v_addr, src, len);
-       src += len;
-
-       /* Initialization instructions (3rd block) */
-       if (init_size) {
-               len = init_size;
+       /*
+        * Runtime data
+        * NOTE:  Copy into backup buffer will be done in iwl_up()
+        */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
+                       pieces.data_size);
+       memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
+       memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
+
+       /* Initialization instructions */
+       if (pieces.init_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
-                               len);
-               memcpy(priv->ucode_init.v_addr, src, len);
-               src += len;
+                               pieces.init_size);
+               memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
        }
 
-       /* Initialization data (4th block) */
-       if (init_data_size) {
-               len = init_data_size;
+       /* Initialization data */
+       if (pieces.init_data_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
-                              len);
-               memcpy(priv->ucode_init_data.v_addr, src, len);
-               src += len;
+                              pieces.init_data_size);
+               memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
+                      pieces.init_data_size);
        }
 
-       /* Bootstrap instructions (5th block) */
-       len = boot_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
-       memcpy(priv->ucode_boot.v_addr, src, len);
+       /* Bootstrap instructions */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
+                       pieces.boot_size);
+       memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
 
        /**************************************************
         * This is still part of probe() in a sense...
         *
         * 9. Setup and register with mac80211 and debugfs
         **************************************************/
-       err = iwl_mac_setup_register(priv);
+       err = iwl_mac_setup_register(priv, &ucode_capa);
        if (err)
                goto out_unbind;
 
@@ -1777,6 +1967,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
        /* We have our copies now, allow OS release its copies */
        release_firmware(ucode_raw);
+       complete(&priv->_agn.firmware_loading_complete);
        return;
 
  try_again:
@@ -1790,6 +1981,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        IWL_ERR(priv, "failed to allocate pci memory\n");
        iwl_dealloc_ucode_pci(priv);
  out_unbind:
+       complete(&priv->_agn.firmware_loading_complete);
        device_release_driver(&priv->pci_dev->dev);
        release_firmware(ucode_raw);
 }
@@ -2165,7 +2357,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, priv->iw_mode);
+               iwl_connection_init_rx_config(priv, NULL);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2212,7 +2404,9 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_ucode_stations(priv, true);
+       iwl_clear_ucode_stations(priv);
+       iwl_dealloc_bcast_station(priv);
+       iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2359,6 +2553,10 @@ static int __iwl_up(struct iwl_priv *priv)
                return -EIO;
        }
 
+       ret = iwl_alloc_bcast_station(priv, true);
+       if (ret)
+               return ret;
+
        iwl_prepare_card_hw(priv);
 
        if (!priv->hw_ready) {
@@ -2538,12 +2736,15 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-void iwl_post_associate(struct iwl_priv *priv)
+void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
 
-       if (priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (!vif || !priv->is_open)
+               return;
+
+       if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
        }
@@ -2551,10 +2752,6 @@ void iwl_post_associate(struct iwl_priv *priv)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-
-       if (!priv->vif || !priv->is_open)
-               return;
-
        iwl_scan_cancel_timeout(priv, 200);
 
        conf = ieee80211_get_hw_conf(priv->hw);
@@ -2562,7 +2759,7 @@ void iwl_post_associate(struct iwl_priv *priv)
        priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        iwlcore_commit_rxon(priv);
 
-       iwl_setup_rxon_timing(priv);
+       iwl_setup_rxon_timing(priv, vif);
        ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                              sizeof(priv->rxon_timing), &priv->rxon_timing);
        if (ret)
@@ -2576,49 +2773,41 @@ void iwl_post_associate(struct iwl_priv *priv)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
-                       priv->assoc_id, priv->beacon_int);
+                       vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-       if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+       if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
        }
 
        iwlcore_commit_rxon(priv);
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       priv->assoc_id, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
 
-       switch (priv->iw_mode) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                break;
-
        case NL80211_IFTYPE_ADHOC:
-
-               /* assume default assoc id */
-               priv->assoc_id = 1;
-
-               iwl_add_local_station(priv, priv->bssid, true);
                iwl_send_beacon_cmd(priv);
-
                break;
-
        default:
                IWL_ERR(priv, "%s Should not be called in %d mode\n",
-                         __func__, priv->iw_mode);
+                         __func__, vif->type);
                break;
        }
 
@@ -2646,7 +2835,8 @@ void iwl_post_associate(struct iwl_priv *priv)
  * Not a mac80211 entry point function, but it fits in with all the
  * other mac80211 functions grouped here.
  */
-static int iwl_mac_setup_register(struct iwl_priv *priv)
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa)
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
@@ -2666,6 +2856,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
                             IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
        hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
@@ -2681,7 +2873,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
        /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
 
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
@@ -2794,7 +2986,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return NETDEV_TX_OK;
 }
 
-void iwl_config_ap(struct iwl_priv *priv)
+void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int ret = 0;
 
@@ -2809,7 +3001,7 @@ void iwl_config_ap(struct iwl_priv *priv)
                iwlcore_commit_rxon(priv);
 
                /* RXON Timing */
-               iwl_setup_rxon_timing(priv);
+               iwl_setup_rxon_timing(priv, vif);
                ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                                sizeof(priv->rxon_timing), &priv->rxon_timing);
                if (ret)
@@ -2823,9 +3015,10 @@ void iwl_config_ap(struct iwl_priv *priv)
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-               /* FIXME: what should be the assoc_id for AP? */
-               priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               priv->staging_rxon.assoc_id = 0;
+
+               if (vif->bss_conf.assoc_capability &
+                                               WLAN_CAPABILITY_SHORT_PREAMBLE)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
@@ -2833,22 +3026,21 @@ void iwl_config_ap(struct iwl_priv *priv)
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-                       if (priv->assoc_capability &
-                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
+                       if (vif->bss_conf.assoc_capability &
+                                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 
-                       if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_add_bcast_station(priv);
        }
        iwl_send_beacon_cmd(priv);
 
@@ -2867,8 +3059,7 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
        struct iwl_priv *priv = hw->priv;
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       iwl_update_tkip_key(priv, keyconf,
-                           sta ? sta->addr : iwl_bcast_addr,
+       iwl_update_tkip_key(priv, keyconf, sta,
                            iv32, phase1key);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2880,7 +3071,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
-       const u8 *addr;
        int ret;
        u8 sta_id;
        bool is_default_wep_key = false;
@@ -2891,13 +3081,17 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
                return -EOPNOTSUPP;
        }
-       addr = sta ? sta->addr : iwl_bcast_addr;
-       sta_id = iwl_find_station(priv, addr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                  addr);
-               return -EINVAL;
 
+       if (sta) {
+               sta_id = iwl_sta_id(sta);
+
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
+                                          sta->addr);
+                       return -EINVAL;
+               }
+       } else {
+               sta_id = priv->hw_params.bcast_sta_id;
        }
 
        mutex_lock(&priv->mutex);
@@ -2946,8 +3140,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
-                            enum ieee80211_ampdu_mlme_action action,
-                            struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+                               enum ieee80211_ampdu_mlme_action action,
+                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
        struct iwl_priv *priv = hw->priv;
        int ret;
@@ -2961,17 +3155,17 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
                IWL_DEBUG_HT(priv, "start Rx\n");
-               return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
+               return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
        case IEEE80211_AMPDU_RX_STOP:
                IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta->addr, tid);
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                        return 0;
                else
                        return ret;
        case IEEE80211_AMPDU_TX_START:
                IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwlagn_tx_agg_start(priv, sta->addr, tid, ssn);
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
                if (ret == 0) {
                        priv->_agn.agg_tids_count++;
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -2980,7 +3174,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                return ret;
        case IEEE80211_AMPDU_TX_STOP:
                IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwlagn_tx_agg_stop(priv, sta->addr, tid);
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
                if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) {
                        priv->_agn.agg_tids_count--;
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -3022,7 +3216,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
                if (!sta_priv->asleep)
                        break;
                sta_priv->asleep = false;
-               sta_id = iwl_find_station(priv, sta->addr);
+               sta_id = iwl_sta_id(sta);
                if (sta_id != IWL_INVALID_STATION)
                        iwl_sta_modify_ps_wake(priv, sta_id);
                break;
@@ -3037,10 +3231,12 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        int ret;
        u8 sta_id;
 
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
+
        IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
                        sta->addr);
 
@@ -3057,12 +3253,14 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
                return ret;
        }
 
+       sta_priv->common.sta_id = sta_id;
+
        /* Initialize rate scaling */
        IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl_rs_rate_init(priv, sta, sta_id);
 
-       return ret;
+       return 0;
 }
 
 /*****************************************************************************
@@ -3587,6 +3785,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        iwl_power_initialize(priv);
        iwl_tt_initialize(priv);
 
+       init_completion(&priv->_agn.firmware_loading_complete);
+
        err = iwl_request_firmware(priv, true);
        if (err)
                goto out_remove_sysfs;
@@ -3627,6 +3827,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
        if (!priv)
                return;
 
+       wait_for_completion(&priv->_agn.firmware_loading_complete);
+
        IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
 
        iwl_dbgfs_unregister(priv);
@@ -3784,11 +3986,10 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
 
-/* 6x00 Series Gen2 */
-       {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2_2agn_cfg)},
+/* 6x00 Series Gen2a */
+       {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
 
 /* 6x50 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -3901,3 +4102,8 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
 module_param_named(
        disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
+                  S_IRUGO);
+MODULE_PARM_DESC(ucode_alternative,
+                "specify ucode alternative to use from ucode file");
index cfee999..2d74805 100644 (file)
@@ -66,7 +66,6 @@
 #include "iwl-dev.h"
 
 extern struct iwl_mod_params iwlagn_mod_params;
-extern struct iwl_ucode_ops iwlagn_ucode;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
 extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
 
@@ -136,9 +135,10 @@ void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
 void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                              struct ieee80211_tx_info *info);
 int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-int iwlagn_tx_agg_start(struct iwl_priv *priv,
-                       const u8 *ra, u16 tid, u16 *ssn);
-int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
+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);
 int iwlagn_txq_check_empty(struct iwl_priv *priv,
                           int sta_id, u8 tid, int txq_id);
 void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
@@ -172,6 +172,10 @@ static inline bool iwl_is_tx_success(u32 status)
 }
 
 /* scan */
-void iwlagn_request_scan(struct iwl_priv *priv);
+void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+
+/* station mgmt */
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add);
 
 #endif /* __iwl_agn_h__ */
index 0086019..9aab020 100644 (file)
@@ -2668,7 +2668,6 @@ struct iwl_ssid_ie {
 #define IWL_GOOD_CRC_TH_NEVER          cpu_to_le16(0xffff)
 #define IWL_MAX_SCAN_SIZE 1024
 #define IWL_MAX_CMD_SIZE 4096
-#define IWL_MAX_PROBE_REQUEST          200
 
 /*
  * REPLY_SCAN_CMD = 0x80 (command)
@@ -3128,6 +3127,11 @@ struct statistics_tx {
        __le32 cts_timeout_collision;
        __le32 ack_or_ba_timeout_collision;
        struct statistics_tx_non_phy_agg agg;
+       /*
+        * "tx_power" are optional parameters provided by uCode,
+        * 6000 series is the only device provide the information,
+        * Those are reserved fields for all the other devices
+        */
        struct statistics_tx_power tx_power;
        __le32 reserved1;
 } __attribute__ ((packed));
index 4cdf4d3..e390868 100644 (file)
@@ -68,37 +68,6 @@ static bool bt_coex_active = true;
 module_param(bt_coex_active, bool, S_IRUGO);
 MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
 
-static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
-       {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
-        0, COEX_UNASSOC_IDLE_FLAGS},
-       {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP,
-        0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
-       {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP,
-        0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
-       {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP,
-        0, COEX_CALIBRATION_FLAGS},
-       {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP,
-        0, COEX_PERIODIC_CALIBRATION_FLAGS},
-       {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP,
-        0, COEX_CONNECTION_ESTAB_FLAGS},
-       {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP,
-        0, COEX_ASSOCIATED_IDLE_FLAGS},
-       {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP,
-        0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
-       {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP,
-        0, COEX_ASSOC_AUTO_SCAN_FLAGS},
-       {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP,
-        0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
-       {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS},
-       {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS},
-       {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP,
-        0, COEX_STAND_ALONE_DEBUG_FLAGS},
-       {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP,
-        0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
-       {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS},
-       {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
-};
-
 #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
                                    IWL_RATE_SISO_##s##M_PLCP, \
@@ -512,7 +481,7 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
        return new_val;
 }
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv)
+void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        u64 tsf;
        s32 interval_tm, rem;
@@ -526,15 +495,14 @@ void iwl_setup_rxon_timing(struct iwl_priv *priv)
        priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
        priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
 
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               beacon_int = priv->beacon_int;
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               beacon_int = priv->vif->bss_conf.beacon_int;
+       beacon_int = vif->bss_conf.beacon_int;
 
+       if (vif->type == NL80211_IFTYPE_ADHOC) {
                /* TODO: we need to get atim_window from upper stack
                 * for now we set to 0 */
                priv->rxon_timing.atim_window = 0;
+       } else {
+               priv->rxon_timing.atim_window = 0;
        }
 
        beacon_int = iwl_adjust_beacon_interval(beacon_int,
@@ -926,8 +894,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
 }
 EXPORT_SYMBOL(iwl_set_rxon_channel);
 
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-                           enum ieee80211_band band)
+static void iwl_set_flags_for_band(struct iwl_priv *priv,
+                                  enum ieee80211_band band,
+                                  struct ieee80211_vif *vif)
 {
        if (band == IEEE80211_BAND_5GHZ) {
                priv->staging_rxon.flags &=
@@ -936,12 +905,12 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
                priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
                /* Copied from iwl_post_associate() */
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif && vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif && vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
                priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -953,13 +922,18 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
 /*
  * initialize rxon structure with default values from eeprom
  */
-void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif)
 {
        const struct iwl_channel_info *ch_info;
+       enum nl80211_iftype type = NL80211_IFTYPE_STATION;
+
+       if (vif)
+               type = vif->type;
 
        memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-       switch (mode) {
+       switch (type) {
        case NL80211_IFTYPE_AP:
                priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
                break;
@@ -977,7 +951,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
                break;
 
        default:
-               IWL_ERR(priv, "Unsupported interface type %d\n", mode);
+               IWL_ERR(priv, "Unsupported interface type %d\n", type);
                break;
        }
 
@@ -999,7 +973,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
        priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
        priv->band = ch_info->band;
 
-       iwl_set_flags_for_band(priv, priv->band);
+       iwl_set_flags_for_band(priv, priv->band, vif);
 
        priv->staging_rxon.ofdm_basic_rates =
            (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -1100,6 +1074,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+       IWL_ERR(priv, "Loaded firmware version: %s\n",
+               priv->hw->wiphy->fw_version);
+
        priv->cfg->ops->lib->dump_nic_error_log(priv);
        if (priv->cfg->ops->lib->dump_csr)
                priv->cfg->ops->lib->dump_csr(priv);
@@ -1286,41 +1263,33 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
                          u64 multicast)
 {
        struct iwl_priv *priv = hw->priv;
-       __le32 *filter_flags = &priv->staging_rxon.filter_flags;
+       __le32 filter_or = 0, filter_nand = 0;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
 
        IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
                        changed_flags, *total_flags);
 
-       if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
-               if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
-                       *filter_flags |= RXON_FILTER_PROMISC_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
-       }
-       if (changed_flags & FIF_ALLMULTI) {
-               if (*total_flags & FIF_ALLMULTI)
-                       *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
-       }
-       if (changed_flags & FIF_CONTROL) {
-               if (*total_flags & FIF_CONTROL)
-                       *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
-       }
-       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-               if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-                       *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
-       }
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK);
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
 
-       /* We avoid iwl_commit_rxon here to commit the new filter flags
-        * since mac80211 will call ieee80211_hw_config immediately.
-        * (mc_list is not supported at this time). Otherwise, we need to
-        * queue a background iwl_commit_rxon work.
-        */
+#undef CHK
+
+       mutex_lock(&priv->mutex);
+
+       priv->staging_rxon.filter_flags &= ~filter_nand;
+       priv->staging_rxon.filter_flags |= filter_or;
+
+       iwlcore_commit_rxon(priv);
+
+       mutex_unlock(&priv->mutex);
 
        *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
@@ -1772,10 +1741,11 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 EXPORT_SYMBOL(iwl_mac_conf_tx);
 
 static void iwl_ht_conf(struct iwl_priv *priv,
-                       struct ieee80211_bss_conf *bss_conf)
+                       struct ieee80211_vif *vif)
 {
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
        struct ieee80211_sta *sta;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
        IWL_DEBUG_MAC80211(priv, "enter:\n");
 
@@ -1789,10 +1759,10 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 
        ht_conf->single_chain_sufficient = false;
 
-       switch (priv->iw_mode) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                rcu_read_lock();
-               sta = ieee80211_find_sta(priv->vif, priv->bssid);
+               sta = ieee80211_find_sta(vif, bss_conf->bssid);
                if (sta) {
                        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
                        int maxstreams;
@@ -1830,7 +1800,6 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 
 static inline void iwl_set_no_assoc(struct iwl_priv *priv)
 {
-       priv->assoc_id = 0;
        iwl_led_disassociate(priv);
        /*
         * inform the ucode that there is no longer an
@@ -1858,14 +1827,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       if (changes & BSS_CHANGED_BEACON &&
-           priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
                dev_kfree_skb(priv->ibss_beacon);
                priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
        }
 
        if (changes & BSS_CHANGED_BEACON_INT) {
-               priv->beacon_int = bss_conf->beacon_int;
                /* TODO: in AP mode, do something to make this take effect */
        }
 
@@ -1885,8 +1852,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                }
 
                /* mac80211 only sets assoc when in STATION mode */
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
-                   bss_conf->assoc) {
+               if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
                        memcpy(priv->staging_rxon.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
 
@@ -1904,7 +1870,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
         * mac80211 decides to do both changes at once because
         * it will invoke post_associate.
         */
-       if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
            changes & BSS_CHANGED_BEACON) {
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 
@@ -1947,7 +1913,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changes & BSS_CHANGED_HT) {
-               iwl_ht_conf(priv, bss_conf);
+               iwl_ht_conf(priv, vif);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -1956,20 +1922,17 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
        if (changes & BSS_CHANGED_ASSOC) {
                IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
                if (bss_conf->assoc) {
-                       priv->assoc_id = bss_conf->aid;
-                       priv->beacon_int = bss_conf->beacon_int;
                        priv->timestamp = bss_conf->timestamp;
-                       priv->assoc_capability = bss_conf->assoc_capability;
 
                        iwl_led_associate(priv);
 
                        if (!iwl_is_rfkill(priv))
-                               priv->cfg->ops->lib->post_associate(priv);
+                               priv->cfg->ops->lib->post_associate(priv, vif);
                } else
                        iwl_set_no_assoc(priv);
        }
 
-       if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+       if (changes && iwl_is_associated(priv) && bss_conf->aid) {
                IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
                                   changes);
                ret = iwl_send_rxon_assoc(priv);
@@ -1986,11 +1949,20 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        memcpy(priv->staging_rxon.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
-                       iwlcore_config_ap(priv);
+                       iwlcore_config_ap(priv, vif);
                } else
                        iwl_set_no_assoc(priv);
        }
 
+       if (changes & BSS_CHANGED_IBSS) {
+               ret = priv->cfg->ops->lib->manage_ibss_station(priv, vif,
+                                                       bss_conf->ibss_joined);
+               if (ret)
+                       IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+                               bss_conf->ibss_joined ? "add" : "remove",
+                               bss_conf->bssid);
+       }
+
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2017,14 +1989,13 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        priv->ibss_beacon = skb;
 
-       priv->assoc_id = 0;
        timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
        priv->timestamp = le64_to_cpu(timestamp);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->cfg->ops->lib->post_associate(priv);
+       priv->cfg->ops->lib->post_associate(priv, priv->vif);
 
        return 0;
 }
@@ -2032,7 +2003,7 @@ EXPORT_SYMBOL(iwl_mac_beacon_update);
 
 static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-       iwl_connection_init_rx_config(priv, vif->type);
+       iwl_connection_init_rx_config(priv, vif);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2072,9 +2043,6 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        if (err)
                goto out_err;
 
-       /* Add the broadcast address so we can send broadcast frames */
-       priv->cfg->ops->lib->add_bcast_station(priv);
-
        goto out;
 
  out_err:
@@ -2097,8 +2065,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       iwl_clear_ucode_stations(priv, true);
-
        if (iwl_is_ready_rf(priv)) {
                iwl_scan_cancel_timeout(priv, 100);
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -2204,7 +2170,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_rxon_channel(priv, conf->channel);
                iwl_set_rxon_ht(priv, ht_conf);
 
-               iwl_set_flags_for_band(priv, conf->channel->band);
+               iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
                spin_unlock_irqrestore(&priv->lock, flags);
                if (iwl_is_associated(priv) &&
                    (le16_to_cpu(priv->active_rxon.channel) != ch) &&
@@ -2287,8 +2253,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        spin_lock_irqsave(&priv->lock, flags);
-       priv->assoc_id = 0;
-       priv->assoc_capability = 0;
 
        /* new association get rid of ibss beacon skb */
        if (priv->ibss_beacon)
@@ -2296,7 +2260,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 
        priv->ibss_beacon = NULL;
 
-       priv->beacon_int = priv->vif->bss_conf.beacon_int;
        priv->timestamp = 0;
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -2343,34 +2306,6 @@ void iwl_free_txq_mem(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_free_txq_mem);
 
-int iwl_send_wimax_coex(struct iwl_priv *priv)
-{
-       struct iwl_wimax_coex_cmd coex_cmd;
-
-       if (priv->cfg->support_wimax_coexist) {
-               /* UnMask wake up src at associated sleep */
-               coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
-
-               /* UnMask wake up src at unassociated sleep */
-               coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK;
-               memcpy(coex_cmd.sta_prio, cu_priorities,
-                       sizeof(struct iwl_wimax_coex_event_entry) *
-                        COEX_NUM_OF_EVENTS);
-
-               /* enabling the coexistence feature */
-               coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK;
-
-               /* enabling the priorities tables */
-               coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK;
-       } else {
-               /* coexistence is disabled */
-               memset(&coex_cmd, 0, sizeof(coex_cmd));
-       }
-       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
-                               sizeof(coex_cmd), &coex_cmd);
-}
-EXPORT_SYMBOL(iwl_send_wimax_coex);
-
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
 #define IWL_TRAFFIC_DUMP_SIZE  (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
index 7273609..7e5a5ba 100644 (file)
@@ -106,7 +106,7 @@ struct iwl_hcmd_utils_ops {
                        __le32 *tx_flags);
        int  (*calc_rssi)(struct iwl_priv *priv,
                          struct iwl_rx_phy_res *rx_resp);
-       void (*request_scan)(struct iwl_priv *priv);
+       void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
 };
 
 struct iwl_apm_ops {
@@ -131,17 +131,6 @@ struct iwl_temp_ops {
        void (*set_calib_version)(struct iwl_priv *priv);
 };
 
-struct iwl_ucode_ops {
-       u32 (*get_header_size)(u32);
-       u32 (*get_build)(const struct iwl_ucode_header *, u32);
-       u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
-       u8 * (*get_data)(const struct iwl_ucode_header *, u32);
-};
-
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
@@ -191,8 +180,9 @@ struct iwl_lib_ops {
        /* power */
        int (*send_tx_power) (struct iwl_priv *priv);
        void (*update_chain_flags)(struct iwl_priv *priv);
-       void (*post_associate) (struct iwl_priv *priv);
-       void (*config_ap) (struct iwl_priv *priv);
+       void (*post_associate)(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif);
+       void (*config_ap)(struct iwl_priv *priv, struct ieee80211_vif *vif);
        irqreturn_t (*isr) (int irq, void *data);
 
        /* eeprom operations (as defined in iwl-eeprom.h) */
@@ -201,7 +191,8 @@ struct iwl_lib_ops {
        /* temperature */
        struct iwl_temp_ops temp_ops;
        /* station management */
-       void (*add_bcast_station)(struct iwl_priv *priv);
+       int (*manage_ibss_station)(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif, bool add);
        /* recover from tx queue stall */
        void (*recover_from_tx_stall)(unsigned long data);
        /* check for plcp health */
@@ -220,7 +211,6 @@ struct iwl_led_ops {
 };
 
 struct iwl_ops {
-       const struct iwl_ucode_ops *ucode;
        const struct iwl_lib_ops *lib;
        const struct iwl_hcmd_ops *hcmd;
        const struct iwl_hcmd_utils_ops *utils;
@@ -257,6 +247,18 @@ struct iwl_mod_params {
  * @support_wimax_coexist: support wimax/wifi co-exist
  * @plcp_delta_threshold: plcp error rate threshold used to trigger
  *     radio tuning when there is a high receiving plcp error rate
+ * @chain_noise_scale: default chain noise scale used for gain computation
+ * @monitor_recover_period: default timer used to check stuck queues
+ * @temperature_kelvin: temperature report by uCode in kelvin
+ * @max_event_log_size: size of event log buffer size for ucode event logging
+ * @tx_power_by_driver: tx power calibration performed by driver
+ *     instead of uCode
+ * @ucode_tracing: support ucode continuous tracing
+ * @sensitivity_calib_by_driver: driver has the capability to perform
+ *     sensitivity calibration operation
+ * @chain_noise_calib_by_driver: driver has the capability to perform
+ *     chain noise calibration operation
+ * @scan_antennas: available antenna for scan operation
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -319,6 +321,10 @@ struct iwl_cfg {
        u32 monitor_recover_period;
        bool temperature_kelvin;
        u32 max_event_log_size;
+       const bool tx_power_by_driver;
+       const bool ucode_tracing;
+       const bool sensitivity_calib_by_driver;
+       const bool chain_noise_calib_by_driver;
        u8 scan_antennas[IEEE80211_NUM_BANDS];
 };
 
@@ -340,8 +346,8 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
 u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
                         struct ieee80211_sta_ht_cap *sta_ht_inf);
-void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
-void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode);
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif);
 int iwl_set_decrypted_flag(struct iwl_priv *priv,
                           struct ieee80211_hdr *hdr,
                           u32 decrypt_res,
@@ -351,7 +357,7 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
                          unsigned int changed_flags,
                          unsigned int *total_flags, u64 multicast);
 int iwl_set_hw_params(struct iwl_priv *priv);
-void iwl_post_associate(struct iwl_priv *priv);
+void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
@@ -363,13 +369,12 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif);
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_config_ap(struct iwl_priv *priv);
+void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
 int iwl_alloc_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
 void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                                __le32 *tx_flags);
-int iwl_send_wimax_coex(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
 void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -448,6 +453,8 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
                                 struct iwl_rx_packet *pkt);
 bool iwl_good_ack_health(struct iwl_priv *priv,
                                 struct iwl_rx_packet *pkt);
+void iwl_recover_from_statistics(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt);
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
 void iwl_reply_statistics(struct iwl_priv *priv,
@@ -515,6 +522,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
                    struct cfg80211_scan_request *req);
+void iwl_bg_start_internal_scan(struct work_struct *work);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
@@ -524,7 +532,8 @@ 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);
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif);
 void iwl_bg_scan_check(struct work_struct *data);
 void iwl_bg_abort_scan(struct work_struct *work);
 void iwl_bg_scan_completed(struct work_struct *work);
@@ -688,7 +697,7 @@ extern int iwl_send_lq_cmd(struct iwl_priv *priv,
 void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv);
+void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
 static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
 {
        return priv->cfg->ops->hcmd->rxon_assoc(priv);
@@ -697,9 +706,10 @@ static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
 {
        return priv->cfg->ops->hcmd->commit_rxon(priv);
 }
-static inline void iwlcore_config_ap(struct iwl_priv *priv)
+static inline void iwlcore_config_ap(struct iwl_priv *priv,
+                                    struct ieee80211_vif *vif)
 {
-       priv->cfg->ops->lib->config_ap(priv);
+       priv->cfg->ops->lib->config_ap(priv, vif);
 }
 static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
                        struct iwl_priv *priv, enum ieee80211_band band)
index 4aabb54..9659c5d 100644 (file)
@@ -1220,46 +1220,6 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
        return ret;
 }
 
-static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       char buf[128];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-       struct statistics_tx *tx;
-
-       if (!iwl_is_alive(priv))
-               pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
-       else {
-               tx = &priv->statistics.tx;
-               if (tx->tx_power.ant_a ||
-                   tx->tx_power.ant_b ||
-                   tx->tx_power.ant_c) {
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "tx power: (1/2 dB step)\n");
-                       if ((priv->cfg->valid_tx_ant & ANT_A) &&
-                           tx->tx_power.ant_a)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna A: 0x%X\n",
-                                               tx->tx_power.ant_a);
-                       if ((priv->cfg->valid_tx_ant & ANT_B) &&
-                           tx->tx_power.ant_b)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna B: 0x%X\n",
-                                               tx->tx_power.ant_b);
-                       if ((priv->cfg->valid_tx_ant & ANT_C) &&
-                           tx->tx_power.ant_c)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna C: 0x%X\n",
-                                               tx->tx_power.ant_c);
-               } else
-                       pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
 static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
                                                    char __user *user_buf,
                                                    size_t count, loff_t *ppos)
@@ -1571,7 +1531,6 @@ DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
 DEBUGFS_READ_FILE_OPS(sensitivity);
 DEBUGFS_READ_FILE_OPS(chain_noise);
-DEBUGFS_READ_FILE_OPS(tx_power);
 DEBUGFS_READ_FILE_OPS(power_save_status);
 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
@@ -1618,8 +1577,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+       if (!priv->cfg->broken_powersave) {
+               DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
+                                S_IWUSR | S_IRUSR);
+               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(rx_statistics, dir_debug, S_IRUSR);
@@ -1627,7 +1589,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
@@ -1640,18 +1601,21 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
 
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
+       if (priv->cfg->sensitivity_calib_by_driver)
                DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+       if (priv->cfg->chain_noise_calib_by_driver)
                DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+       if (priv->cfg->ucode_tracing)
                DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-       }
        DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal);
-       DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
-                        &priv->disable_chain_noise_cal);
-       if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
-           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+       if (priv->cfg->sensitivity_calib_by_driver)
+               DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
+                                &priv->disable_sens_cal);
+       if (priv->cfg->chain_noise_calib_by_driver)
+               DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
+                                &priv->disable_chain_noise_cal);
+       if (priv->cfg->tx_power_by_driver)
                DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
                                &priv->disable_tx_power_cal);
        return 0;
index 58c69a5..f3f3473 100644 (file)
@@ -57,8 +57,8 @@ extern struct iwl_cfg iwl5100_bgn_cfg;
 extern struct iwl_cfg iwl5100_abg_cfg;
 extern struct iwl_cfg iwl5150_agn_cfg;
 extern struct iwl_cfg iwl5150_abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2agn_cfg;
-extern struct iwl_cfg iwl6000g2_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2abg_cfg;
 extern struct iwl_cfg iwl6000i_2bg_cfg;
 extern struct iwl_cfg iwl6000_3agn_cfg;
@@ -497,20 +497,38 @@ struct iwl_station_entry {
        struct iwl_link_quality_cmd *lq;
 };
 
+struct iwl_station_priv_common {
+       u8 sta_id;
+};
+
 /*
  * iwl_station_priv: Driver's private station information
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is places in that
  * space.
+ *
+ * The common struct MUST be first because it is shared between
+ * 3945 and agn!
  */
 struct iwl_station_priv {
+       struct iwl_station_priv_common common;
        struct iwl_lq_sta lq_sta;
        atomic_t pending_frames;
        bool client;
        bool asleep;
 };
 
+/**
+ * struct iwl_vif_priv - driver's private per-interface information
+ *
+ * When mac80211 allocates a virtual interface, it can allocate
+ * space for us to put data into.
+ */
+struct iwl_vif_priv {
+       u8 ibss_bssid_sta_id;
+};
+
 /* one for each uCode image (inst/data, boot/init/runtime) */
 struct fw_desc {
        void *v_addr;           /* access by driver */
@@ -518,7 +536,7 @@ struct fw_desc {
        u32 len;                /* bytes */
 };
 
-/* uCode file layout */
+/* v1/v2 uCode file layout */
 struct iwl_ucode_header {
        __le32 ver;     /* major/minor/API/serial */
        union {
@@ -541,7 +559,62 @@ struct iwl_ucode_header {
                } v2;
        } u;
 };
-#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
+
+/*
+ * new TLV uCode file layout
+ *
+ * The new TLV file format contains TLVs, that each specify
+ * some piece of data. To facilitate "groups", for example
+ * different instruction image with different capabilities,
+ * bundled with the same init image, an alternative mechanism
+ * is provided:
+ * When the alternative field is 0, that means that the item
+ * is always valid. When it is non-zero, then it is only
+ * valid in conjunction with items of the same alternative,
+ * in which case the driver (user) selects one alternative
+ * to use.
+ */
+
+enum iwl_ucode_tlv_type {
+       IWL_UCODE_TLV_INVALID           = 0, /* unused */
+       IWL_UCODE_TLV_INST              = 1,
+       IWL_UCODE_TLV_DATA              = 2,
+       IWL_UCODE_TLV_INIT              = 3,
+       IWL_UCODE_TLV_INIT_DATA         = 4,
+       IWL_UCODE_TLV_BOOT              = 5,
+       IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
+};
+
+struct iwl_ucode_tlv {
+       __le16 type;            /* see above */
+       __le16 alternative;     /* see comment */
+       __le32 length;          /* not including type/length fields */
+       u8 data[0];
+} __attribute__ ((packed));
+
+#define IWL_TLV_UCODE_MAGIC    0x0a4c5749
+
+struct iwl_tlv_ucode_header {
+       /*
+        * The TLV style ucode header is distinguished from
+        * the v1/v2 style header by first four bytes being
+        * zero, as such is an invalid combination of
+        * major/minor/API/serial versions.
+        */
+       __le32 zero;
+       __le32 magic;
+       u8 human_readable[64];
+       __le32 ver;             /* major/minor/API/serial */
+       __le32 build;
+       __le64 alternatives;    /* bitmask of valid alternatives */
+       /*
+        * The data contained herein has a TLV layout,
+        * see above for the TLV header and types.
+        * Note that each TLV is padded to a length
+        * that is a multiple of 4 for alignment.
+        */
+       u8 data[0];
+};
 
 struct iwl4965_ibss_seq {
        u8 mac[ETH_ALEN];
@@ -1155,8 +1228,7 @@ struct iwl_priv {
 #endif
 
        /* context information */
-       u8 bssid[ETH_ALEN];
-       u16 rts_threshold;
+       u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
        u8 mac_addr[ETH_ALEN];
 
        /*station table variables */
@@ -1189,7 +1261,6 @@ struct iwl_priv {
 
        /* Last Rx'd beacon timestamp */
        u64 timestamp;
-       u16 beacon_int;
        struct ieee80211_vif *vif;
 
        union {
@@ -1242,6 +1313,8 @@ struct iwl_priv {
 
                        struct iwl_rx_phy_res last_phy_res;
                        bool last_phy_res_valid;
+
+                       struct completion firmware_loading_complete;
                } _agn;
 #endif
        };
@@ -1249,10 +1322,6 @@ struct iwl_priv {
        struct iwl_hw_params hw_params;
 
        u32 inta_mask;
-       /* Current association information needed to configure the
-        * hardware */
-       u16 assoc_id;
-       u16 assoc_capability;
 
        struct iwl_qos_info qos_data;
 
index fb5bb48..ee11452 100644 (file)
@@ -590,9 +590,16 @@ int iwl_eeprom_init(struct iwl_priv *priv)
                        e[addr / 2] = cpu_to_le16(r >> 16);
                }
        }
+
+       IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
+                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                      ? "OTP" : "EEPROM",
+                      iwl_eeprom_query16(priv, EEPROM_VERSION));
+
        ret = 0;
 done:
        priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+
 err:
        if (ret)
                iwl_eeprom_free(priv);
index 581c683..cda6a94 100644 (file)
@@ -318,10 +318,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
        update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
                        priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
 
-       if (priv->vif)
-               dtimper = priv->hw->conf.ps_dtim_period;
-       else
-               dtimper = 1;
+       dtimper = priv->hw->conf.ps_dtim_period ?: 1;
 
        if (priv->cfg->broken_powersave)
                iwl_power_sleep_cam_cmd(priv, &cmd);
index 267eb89..0a5d7cf 100644 (file)
@@ -398,7 +398,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_good_plcp_health);
 
-static void iwl_recover_from_statistics(struct iwl_priv *priv,
+void iwl_recover_from_statistics(struct iwl_priv *priv,
                                struct iwl_rx_packet *pkt)
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -413,9 +413,11 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv,
                                 */
                                IWL_ERR(priv, "low ack count detected, "
                                        "restart firmware\n");
-                               iwl_force_reset(priv, IWL_FW_RESET);
+                               if (!iwl_force_reset(priv, IWL_FW_RESET))
+                                       return;
                        }
-               } else if (priv->cfg->ops->lib->check_plcp_health) {
+               }
+               if (priv->cfg->ops->lib->check_plcp_health) {
                        if (!priv->cfg->ops->lib->check_plcp_health(
                            priv, pkt)) {
                                /*
@@ -427,6 +429,7 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv,
                }
        }
 }
+EXPORT_SYMBOL(iwl_recover_from_statistics);
 
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb)
index d12fd55..107e173 100644 (file)
@@ -265,7 +265,8 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_get_active_dwell_time);
 
 u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band)
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif)
 {
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
@@ -275,7 +276,7 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                /* If we're associated, we clamp the maximum passive
                 * dwell time to be 98% of the beacon interval (minus
                 * 2 * channel tune time) */
-               passive = priv->beacon_int;
+               passive = vif ? vif->bss_conf.beacon_int : 0;
                if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
                        passive = IWL_PASSIVE_DWELL_BASE;
                passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
@@ -295,7 +296,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_init_scan_params);
 
-static int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        WARN_ON(!mutex_is_locked(&priv->mutex));
 
@@ -307,7 +308,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
        if (WARN_ON(!priv->cfg->ops->utils->request_scan))
                return -EOPNOTSUPP;
 
-       priv->cfg->ops->utils->request_scan(priv);
+       priv->cfg->ops->utils->request_scan(priv, vif);
 
        return 0;
 }
@@ -348,7 +349,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
        priv->scan_band = req->channels[0]->band;
        priv->scan_request = req;
 
-       ret = iwl_scan_initiate(priv);
+       ret = iwl_scan_initiate(priv, vif);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -368,7 +369,7 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
        queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
-static void iwl_bg_start_internal_scan(struct work_struct *work)
+void iwl_bg_start_internal_scan(struct work_struct *work)
 {
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, start_internal_scan);
@@ -399,10 +400,11 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
        if (WARN_ON(!priv->cfg->ops->utils->request_scan))
                goto unlock;
 
-       priv->cfg->ops->utils->request_scan(priv);
+       priv->cfg->ops->utils->request_scan(priv, NULL);
  unlock:
        mutex_unlock(&priv->mutex);
 }
+EXPORT_SYMBOL(iwl_bg_start_internal_scan);
 
 void iwl_bg_scan_check(struct work_struct *data)
 {
index db93447..85ed235 100644 (file)
 #include "iwl-core.h"
 #include "iwl-sta.h"
 
-u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
-{
-       int i;
-       int start = 0;
-       int ret = IWL_INVALID_STATION;
-       unsigned long flags;
-
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
-           (priv->iw_mode == NL80211_IFTYPE_AP))
-               start = IWL_STA_ID;
-
-       if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       for (i = start; i < priv->hw_params.max_stations; i++)
-               if (priv->stations[i].used &&
-                   (!compare_ether_addr(priv->stations[i].sta.sta.addr,
-                                        addr))) {
-                       ret = i;
-                       goto out;
-               }
-
-       IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n",
-                             addr, priv->num_stations);
-
- out:
-       /*
-        * It may be possible that more commands interacting with stations
-        * arrive before we completed processing the adding of
-        * station
-        */
-       if (ret != IWL_INVALID_STATION &&
-           (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) ||
-            ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) &&
-             (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) {
-               IWL_ERR(priv, "Requested station info for sta %d before ready.\n",
-                       ret);
-               ret = IWL_INVALID_STATION;
-       }
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL(iwl_find_station);
-
-int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
-{
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               return IWL_AP_ID;
-       } else {
-               u8 *da = ieee80211_get_DA(hdr);
-               return iwl_find_station(priv, da);
-       }
-}
-EXPORT_SYMBOL(iwl_get_ra_sta_id);
-
 /* priv->sta_lock must be held */
 static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 {
@@ -340,10 +284,12 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
        station->sta.sta.sta_id = sta_id;
        station->sta.station_flags = 0;
 
-       /* BCAST station and IBSS stations do not work in HT mode */
-       if (sta_id != priv->hw_params.bcast_sta_id &&
-           priv->iw_mode != NL80211_IFTYPE_ADHOC)
-               iwl_set_ht_add_station(priv, sta_id, ht_info);
+       /*
+        * OK to call unconditionally, since local stations (IBSS BSSID
+        * STA and broadcast STA) pass in a NULL ht_info, and mac80211
+        * doesn't allow HT IBSS.
+        */
+       iwl_set_ht_add_station(priv, sta_id, ht_info);
 
        /* 3945 only */
        rate = (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -418,20 +364,21 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
 }
 EXPORT_SYMBOL(iwl_add_station_common);
 
-static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
+static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
+                                                    u8 sta_id)
 {
        int i, r;
-       struct iwl_link_quality_cmd link_cmd = {
-               .reserved1 = 0,
-       };
+       struct iwl_link_quality_cmd *link_cmd;
        u32 rate_flags;
-       int ret = 0;
 
+       link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
+       if (!link_cmd) {
+               IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
+               return NULL;
+       }
        /* Set up the rate scaling to start at selected rate, fall back
         * all the way down to 1M in IEEE order, and then spin on 1M */
-       if (is_ap)
-               r = IWL_RATE_54M_INDEX;
-       else if (priv->band == IEEE80211_BAND_5GHZ)
+       if (priv->band == IEEE80211_BAND_5GHZ)
                r = IWL_RATE_6M_INDEX;
        else
                r = IWL_RATE_1M_INDEX;
@@ -444,49 +391,48 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
                rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
                                RATE_MCS_ANT_POS;
 
-               link_cmd.rs_table[i].rate_n_flags =
+               link_cmd->rs_table[i].rate_n_flags =
                        iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
                r = iwl_get_prev_ieee_rate(r);
        }
 
-       link_cmd.general_params.single_stream_ant_msk =
+       link_cmd->general_params.single_stream_ant_msk =
                                first_antenna(priv->hw_params.valid_tx_ant);
 
-       link_cmd.general_params.dual_stream_ant_msk =
+       link_cmd->general_params.dual_stream_ant_msk =
                priv->hw_params.valid_tx_ant &
                ~first_antenna(priv->hw_params.valid_tx_ant);
-       if (!link_cmd.general_params.dual_stream_ant_msk) {
-               link_cmd.general_params.dual_stream_ant_msk = ANT_AB;
+       if (!link_cmd->general_params.dual_stream_ant_msk) {
+               link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
        } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
-               link_cmd.general_params.dual_stream_ant_msk =
+               link_cmd->general_params.dual_stream_ant_msk =
                        priv->hw_params.valid_tx_ant;
        }
 
-       link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
-       link_cmd.agg_params.agg_time_limit =
+       link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       link_cmd->agg_params.agg_time_limit =
                cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 
-       /* Update the rate scaling for control frame Tx to AP */
-       link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
+       link_cmd->sta_id = sta_id;
 
-       ret = iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD,
-                              sizeof(link_cmd), &link_cmd);
-       if (ret)
-               IWL_ERR(priv, "REPLY_TX_LINK_QUALITY_CMD failed (%d)\n", ret);
+       return link_cmd;
 }
 
 /*
- * iwl_add_local_stations - Add stations not requested by mac80211
- *
- * This will be either the broadcast station or the bssid station needed by
- * ad-hoc.
+ * iwl_add_bssid_station - Add the special IBSS BSSID station
  *
  * Function sleeps.
  */
-int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs)
+int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
+                         u8 *sta_id_r)
 {
        int ret;
        u8 sta_id;
+       struct iwl_link_quality_cmd *link_cmd;
+       unsigned long flags;
+
+       if (*sta_id_r)
+               *sta_id_r = IWL_INVALID_STATION;
 
        ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
        if (ret) {
@@ -494,12 +440,34 @@ int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs)
                return ret;
        }
 
-       if (init_rs)
+       if (sta_id_r)
+               *sta_id_r = sta_id;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       priv->stations[sta_id].used |= IWL_STA_LOCAL;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       if (init_rs) {
                /* Set up default rate scaling table in device's station table */
-               iwl_sta_init_lq(priv, addr, false);
+               link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+               if (!link_cmd) {
+                       IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n",
+                               addr);
+                       return -ENOMEM;
+               }
+
+               ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true);
+               if (ret)
+                       IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
+
+               spin_lock_irqsave(&priv->sta_lock, flags);
+               priv->stations[sta_id].lq = link_cmd;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+       }
+
        return 0;
 }
-EXPORT_SYMBOL(iwl_add_local_station);
+EXPORT_SYMBOL(iwl_add_bssid_station);
 
 /**
  * iwl_sta_ucode_deactivate - deactivate ucode status for a station
@@ -509,7 +477,8 @@ EXPORT_SYMBOL(iwl_add_local_station);
 static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
 {
        /* Ucode must be active and driver must be non active */
-       if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE)
+       if ((priv->stations[sta_id].used &
+            (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE)
                IWL_ERR(priv, "removed non active STA %u\n", sta_id);
 
        priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
@@ -574,18 +543,16 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 /**
  * iwl_remove_station - Remove driver's knowledge of station.
  */
-static int iwl_remove_station(struct iwl_priv *priv, struct ieee80211_sta *sta)
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr)
 {
-       int sta_id = IWL_INVALID_STATION;
-       int i, ret = -EINVAL;
-       unsigned long flags;
-       bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION;
        struct iwl_station_entry *station;
+       unsigned long flags;
 
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_INFO(priv,
                        "Unable to remove station %pM, device not ready.\n",
-                       sta->addr);
+                       addr);
                /*
                 * It is typical for stations to be removed when we are
                 * going down. Return success since device will be down
@@ -594,37 +561,30 @@ static int iwl_remove_station(struct iwl_priv *priv, struct ieee80211_sta *sta)
                return 0;
        }
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
-
-       if (is_ap)
-               sta_id = IWL_AP_ID;
-       else
-               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
-                       if (priv->stations[i].used &&
-                           !compare_ether_addr(priv->stations[i].sta.sta.addr,
-                                               sta->addr)) {
-                               sta_id = i;
-                               break;
-                       }
+       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
+                       sta_id, addr);
 
-       if (unlikely(sta_id == IWL_INVALID_STATION))
-               goto out;
+       if (WARN_ON(sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
 
-       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
-               sta_id, sta->addr);
+       spin_lock_irqsave(&priv->sta_lock, flags);
 
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
                IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
-                               sta->addr);
-               goto out;
+                               addr);
+               goto out_err;
        }
 
        if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
                IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
-                               sta->addr);
-               goto out;
+                               addr);
+               goto out_err;
        }
 
+       if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
+               kfree(priv->stations[sta_id].lq);
+               priv->stations[sta_id].lq = NULL;
+       }
 
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
 
@@ -635,56 +595,35 @@ static int iwl_remove_station(struct iwl_priv *priv, struct ieee80211_sta *sta)
        station = &priv->stations[sta_id];
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       ret = iwl_send_remove_station(priv, station);
-       return ret;
-out:
+       return iwl_send_remove_station(priv, station);
+out_err:
        spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
+       return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(iwl_remove_station);
 
 /**
- * iwl_clear_ucode_stations() - clear entire station table driver and/or ucode
- * @priv:
- * @force: If set then the uCode station table needs to be cleared here. If
- *         not set then the uCode station table has already been cleared,
- *         for example after sending it a RXON command without ASSOC bit
- *         set, and we just need to change driver state here.
+ * iwl_clear_ucode_stations - clear ucode station table bits
+ *
+ * This function clears all the bits in the driver indicating
+ * which stations are active in the ucode. Call when something
+ * other than explicit station management would cause this in
+ * the ucode, e.g. unassociated RXON.
  */
-void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force)
+void iwl_clear_ucode_stations(struct iwl_priv *priv)
 {
        int i;
        unsigned long flags_spin;
        bool cleared = false;
 
-       IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver%s\n",
-                       force ? " and ucode" : "");
-
-       if (force) {
-               if (!iwl_is_ready(priv)) {
-                       /*
-                        * If device is not ready at this point the station
-                        * table is likely already empty (uCode not ready
-                        * to receive station requests) or will soon be
-                        * due to interface going down.
-                        */
-                       IWL_DEBUG_INFO(priv, "Unable to remove stations from device - device not ready\n");
-               } else {
-                       iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL);
-               }
-       }
+       IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
 
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
-       if (force) {
-               IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n");
-               priv->num_stations = 0;
-               memset(priv->stations, 0, sizeof(priv->stations));
-       } else {
-               for (i = 0; i < priv->hw_params.max_stations; i++) {
-                       if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
-                               IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
-                               priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
-                               cleared = true;
-                       }
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
+                       IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
+                       priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+                       cleared = true;
                }
        }
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -1027,18 +966,23 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 
 void iwl_update_tkip_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *keyconf,
-                       const u8 *addr, u32 iv32, u16 *phase1key)
+                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
 {
-       u8 sta_id = IWL_INVALID_STATION;
+       u8 sta_id;
        unsigned long flags;
        int i;
 
-       sta_id = iwl_find_station(priv, addr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                  addr);
-               return;
-       }
+       if (sta) {
+               sta_id = iwl_sta_id(sta);
+
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
+                                          sta->addr);
+                       return;
+               }
+       } else
+               sta_id = priv->hw_params.bcast_sta_id;
+
 
        if (iwl_scan_cancel(priv)) {
                /* cancel scan failed, just live w/ bad key and rely
@@ -1178,6 +1122,39 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
 #endif
 
 /**
+ * is_lq_table_valid() - Test one aspect of LQ cmd for validity
+ *
+ * It sometimes happens when a HT rate has been in use and we
+ * loose connectivity with AP then mac80211 will first tell us that the
+ * current channel is not HT anymore before removing the station. In such a
+ * scenario the RXON flags will be updated to indicate we are not
+ * communicating HT anymore, but the LQ command may still contain HT rates.
+ * Test for this to prevent driver from sending LQ command between the time
+ * RXON flags are updated and when LQ command is updated.
+ */
+static bool is_lq_table_valid(struct iwl_priv *priv,
+                             struct iwl_link_quality_cmd *lq)
+{
+       int i;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+
+       if (ht_conf->is_ht)
+               return true;
+
+       IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
+                      priv->active_rxon.channel);
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+               if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
+                       IWL_DEBUG_INFO(priv,
+                                      "index %d of LQ expects HT channel\n",
+                                      i);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
  * iwl_send_lq_cmd() - Send link quality command
  * @init: This command is sent as part of station initialization right
  *        after station has been added.
@@ -1206,8 +1183,12 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
        iwl_dump_lq_cmd(priv, lq);
        BUG_ON(init && (cmd.flags & CMD_ASYNC));
 
-       ret = iwl_send_cmd(priv, &cmd);
-       if (ret || (cmd.flags & CMD_ASYNC))
+       if (is_lq_table_valid(priv, lq))
+               ret = iwl_send_cmd(priv, &cmd);
+       else
+               ret = -EINVAL;
+
+       if (cmd.flags & CMD_ASYNC)
                return ret;
 
        if (init) {
@@ -1217,92 +1198,72 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
                priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
                spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
        }
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(iwl_send_lq_cmd);
 
 /**
- * iwl_add_bcast_station - add broadcast station into station table.
+ * iwl_alloc_bcast_station - add broadcast station into driver's station table.
+ *
+ * This adds the broadcast station into the driver's station table
+ * and marks it driver active, so that it will be restored to the
+ * device at the next best time.
  */
-void iwl_add_bcast_station(struct iwl_priv *priv)
+int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
 {
-       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
-       iwl_add_local_station(priv, iwl_bcast_addr, true);
-}
-EXPORT_SYMBOL(iwl_add_bcast_station);
+       struct iwl_link_quality_cmd *link_cmd;
+       unsigned long flags;
+       u8 sta_id;
 
-/**
- * iwl3945_add_bcast_station - add broadcast station into station table.
- */
-void iwl3945_add_bcast_station(struct iwl_priv *priv)
-{
-       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
-       iwl_add_local_station(priv, iwl_bcast_addr, false);
-       /*
-        * It is assumed that when station is added more initialization
-        * needs to be done, but for 3945 it is not the case and we can
-        * just release station table access right here.
-        */
-       priv->stations[priv->hw_params.bcast_sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Unable to prepare broadcast station\n");
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-}
-EXPORT_SYMBOL(iwl3945_add_bcast_station);
+               return -EINVAL;
+       }
 
-/**
- * iwl_get_sta_id - Find station's index within station table
- *
- * If new IBSS station, create new entry in station table
- */
-int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
-{
-       int sta_id;
-       __le16 fc = hdr->frame_control;
+       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+       priv->stations[sta_id].used |= IWL_STA_BCAST;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       /* If this frame is broadcast or management, use broadcast station id */
-       if (!ieee80211_is_data(fc) ||  is_multicast_ether_addr(hdr->addr1))
-               return priv->hw_params.bcast_sta_id;
+       if (init_lq) {
+               link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+               if (!link_cmd) {
+                       IWL_ERR(priv,
+                               "Unable to initialize rate scaling for bcast station.\n");
+                       return -ENOMEM;
+               }
 
-       switch (priv->iw_mode) {
+               spin_lock_irqsave(&priv->sta_lock, flags);
+               priv->stations[sta_id].lq = link_cmd;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+       }
 
-       /* If we are a client station in a BSS network, use the special
-        * AP station entry (that's the only station we communicate with) */
-       case NL80211_IFTYPE_STATION:
-               /*
-                * If addition of station not complete yet, which means
-                * that rate scaling has not been initialized, then return
-                * the broadcast station.
-                */
-               if (!(priv->stations[IWL_AP_ID].used & IWL_STA_UCODE_ACTIVE))
-                       return priv->hw_params.bcast_sta_id;
-               return IWL_AP_ID;
-
-       /* If we are an AP, then find the station, or use BCAST */
-       case NL80211_IFTYPE_AP:
-               sta_id = iwl_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-               return priv->hw_params.bcast_sta_id;
-
-       /* If this frame is going out to an IBSS network, find the station,
-        * or create a new station table entry */
-       case NL80211_IFTYPE_ADHOC:
-               sta_id = iwl_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-
-               IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
-                              "Defaulting to broadcast...\n",
-                              hdr->addr1);
-               iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
-               return priv->hw_params.bcast_sta_id;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
 
-       default:
-               IWL_WARN(priv, "Unknown mode of operation: %d\n",
-                       priv->iw_mode);
-               return priv->hw_params.bcast_sta_id;
+void iwl_dealloc_bcast_station(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (!(priv->stations[i].used & IWL_STA_BCAST))
+                       continue;
+
+               priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+               priv->num_stations--;
+               BUG_ON(priv->num_stations < 0);
+               kfree(priv->stations[i].lq);
+               priv->stations[i].lq = NULL;
        }
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
-EXPORT_SYMBOL(iwl_get_sta_id);
+EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
 
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
@@ -1322,13 +1283,13 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 }
 EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
 
-int iwl_sta_rx_agg_start(struct iwl_priv *priv,
-                        const u8 *addr, int tid, u16 ssn)
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn)
 {
        unsigned long flags;
        int sta_id;
 
-       sta_id = iwl_find_station(priv, addr);
+       sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
 
@@ -1341,16 +1302,17 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-                                       CMD_ASYNC);
+                               CMD_ASYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_start);
 
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid)
 {
        unsigned long flags;
        int sta_id;
 
-       sta_id = iwl_find_station(priv, addr);
+       sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
                return -ENXIO;
@@ -1402,14 +1364,16 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
 
 int iwl_mac_sta_remove(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct ieee80211_sta *sta)
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta)
 {
-       int ret;
        struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv;
+       int ret;
+
        IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
                        sta->addr);
-       ret = iwl_remove_station(priv, sta);
+       ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr);
        if (ret)
                IWL_ERR(priv, "Error removing station %pM\n",
                        sta->addr);
index 42cd2f4..c2a453a 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef __iwl_sta_h__
 #define __iwl_sta_h__
 
+#include "iwl-dev.h"
+
 #define HW_KEY_DYNAMIC 0
 #define HW_KEY_DEFAULT 1
 
 #define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
 #define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
                                            being activated */
+#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
+                               (this is for the IBSS BSSID stations) */
+#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
 
 
-/**
- * iwl_find_station - Find station id for a given BSSID
- * @bssid: MAC address of station ID to find
- */
-u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
-
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
@@ -55,28 +54,57 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
                           struct ieee80211_key_conf *key, u8 sta_id);
 void iwl_update_tkip_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *keyconf,
-                       const u8 *addr, u32 iv32, u16 *phase1key);
+                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
 
-void iwl_add_bcast_station(struct iwl_priv *priv);
-void iwl3945_add_bcast_station(struct iwl_priv *priv);
 void iwl_restore_stations(struct iwl_priv *priv);
-void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force);
+void iwl_clear_ucode_stations(struct iwl_priv *priv);
+int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
+void iwl_dealloc_bcast_station(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
-int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs);
+int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
+                         u8 *sta_id_r);
 int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
                                  bool is_ap,
                                  struct ieee80211_sta_ht_cap *ht_info,
                                  u8 *sta_id_r);
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr);
 int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
 void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
-int iwl_sta_rx_agg_start(struct iwl_priv *priv,
-                        const u8 *addr, int tid, u16 ssn);
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid);
 void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+
+/**
+ * iwl_clear_driver_stations - clear knowledge of all stations from driver
+ * @priv: iwl priv struct
+ *
+ * This is called during iwl_down() to make sure that in the case
+ * we're coming there from a hardware restart mac80211 will be
+ * able to reconfigure stations -- if we're getting there in the
+ * normal down flow then the stations will already be cleared.
+ */
+static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       memset(priv->stations, 0, sizeof(priv->stations));
+       priv->num_stations = 0;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+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;
+}
 #endif /* __iwl_sta_h__ */
index c7e1d7d..935e643 100644 (file)
@@ -509,11 +509,11 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        hdr_len = ieee80211_hdrlen(fc);
 
-       /* Find (or create) index into station table for destination station */
-       if (info->flags & IEEE80211_TX_CTL_INJECTED)
+       /* Find index into station table for destination station */
+       if (!info->control.sta)
                sta_id = priv->hw_params.bcast_sta_id;
        else
-               sta_id = iwl_get_sta_id(priv, hdr);
+               sta_id = iwl_sta_id(info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -1848,7 +1848,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
 static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                                         enum ieee80211_band band,
                                     u8 is_active, u8 n_probes,
-                                    struct iwl3945_scan_channel *scan_ch)
+                                    struct iwl3945_scan_channel *scan_ch,
+                                    struct ieee80211_vif *vif)
 {
        struct ieee80211_channel *chan;
        const struct ieee80211_supported_band *sband;
@@ -1862,7 +1863,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                return 0;
 
        active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
@@ -2110,6 +2111,28 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
        iwl_write32(priv, CSR_RESET, 0);
 }
 
+#define IWL3945_UCODE_GET(item)                                                \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode)\
+{                                                                      \
+       return le32_to_cpu(ucode->u.v1.item);                           \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+       return 24;
+}
+
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode)
+{
+       return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
 /**
  * iwl3945_read_ucode - Read uCode images from disk file.
  *
@@ -2158,7 +2181,7 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
                goto error;
 
        /* Make sure that we got at least our header! */
-       if (ucode_raw->size <  priv->cfg->ops->ucode->get_header_size(1)) {
+       if (ucode_raw->size <  iwl3945_ucode_get_header_size(1)) {
                IWL_ERR(priv, "File size way too small!\n");
                ret = -EINVAL;
                goto err_release;
@@ -2169,13 +2192,12 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
        priv->ucode_ver = le32_to_cpu(ucode->ver);
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
-       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
-       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
-       init_data_size =
-               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
-       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
-       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
+       inst_size = iwl3945_ucode_get_inst_size(ucode);
+       data_size = iwl3945_ucode_get_data_size(ucode);
+       init_size = iwl3945_ucode_get_init_size(ucode);
+       init_data_size = iwl3945_ucode_get_init_data_size(ucode);
+       boot_size = iwl3945_ucode_get_boot_size(ucode);
+       src = iwl3945_ucode_get_data(ucode);
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
@@ -2224,7 +2246,7 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
 
        /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
+       if (ucode_raw->size != iwl3945_ucode_get_header_size(api_ver) +
                inst_size + data_size + init_size +
                init_data_size + boot_size) {
 
@@ -2523,7 +2545,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, priv->iw_mode);
+               iwl_connection_init_rx_config(priv, NULL);
        }
 
        /* Configure Bluetooth device coexistence support */
@@ -2562,7 +2584,9 @@ static void __iwl3945_down(struct iwl_priv *priv)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
        /* Station information will now be cleared in device */
-       iwl_clear_ucode_stations(priv, true);
+       iwl_clear_ucode_stations(priv);
+       iwl_dealloc_bcast_station(priv);
+       iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2643,6 +2667,10 @@ static int __iwl3945_up(struct iwl_priv *priv)
 {
        int rc, i;
 
+       rc = iwl_alloc_bcast_station(priv, false);
+       if (rc)
+               return rc;
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
                return -EIO;
@@ -2791,7 +2819,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
 
 }
 
-void iwl3945_request_scan(struct iwl_priv *priv)
+void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
@@ -2872,7 +2900,7 @@ void iwl3945_request_scan(struct iwl_priv *priv)
                IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
 
                spin_lock_irqsave(&priv->lock, flags);
-               interval = priv->beacon_int;
+               interval = vif ? vif->bss_conf.beacon_int : 0;
                spin_unlock_irqrestore(&priv->lock, flags);
 
                scan->suspend_time = 0;
@@ -2967,7 +2995,7 @@ void iwl3945_request_scan(struct iwl_priv *priv)
 
        scan->channel_count =
                iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
-                       (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+                       (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
 
        if (scan->channel_count == 0) {
                IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
@@ -3040,26 +3068,25 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
        mutex_unlock(&priv->mutex);
 }
 
-void iwl3945_post_associate(struct iwl_priv *priv)
+void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
        struct ieee80211_conf *conf = NULL;
 
-       if (priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (!vif || !priv->is_open)
+               return;
+
+       if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
        }
 
-
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       priv->assoc_id, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!priv->vif || !priv->is_open)
-               return;
-
        iwl_scan_cancel_timeout(priv, 200);
 
        conf = ieee80211_get_hw_conf(priv->hw);
@@ -3068,7 +3095,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
        iwlcore_commit_rxon(priv);
 
        memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-       iwl_setup_rxon_timing(priv);
+       iwl_setup_rxon_timing(priv, vif);
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                              sizeof(priv->rxon_timing), &priv->rxon_timing);
        if (rc)
@@ -3077,51 +3104,38 @@ void iwl3945_post_associate(struct iwl_priv *priv)
 
        priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
-                       priv->assoc_id, priv->beacon_int);
+                       vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-       if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+       if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
        }
 
        iwlcore_commit_rxon(priv);
 
-       switch (priv->iw_mode) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
                break;
-
        case NL80211_IFTYPE_ADHOC:
-
-               priv->assoc_id = 1;
-               iwl_add_local_station(priv, priv->bssid, false);
-               iwl3945_sync_sta(priv, IWL_STA_ID,
-                               (priv->band == IEEE80211_BAND_5GHZ) ?
-                               IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
-                                CMD_ASYNC);
-               iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
-
                iwl3945_send_beacon_cmd(priv);
-
                break;
-
        default:
-                IWL_ERR(priv, "%s Should not be called in %d mode\n",
-                          __func__, priv->iw_mode);
+               IWL_ERR(priv, "%s Should not be called in %d mode\n",
+                       __func__, vif->type);
                break;
        }
 }
@@ -3245,7 +3259,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return NETDEV_TX_OK;
 }
 
-void iwl3945_config_ap(struct iwl_priv *priv)
+void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
 
@@ -3261,7 +3275,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
 
                /* RXON Timing */
                memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-               iwl_setup_rxon_timing(priv);
+               iwl_setup_rxon_timing(priv, vif);
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                                      sizeof(priv->rxon_timing),
                                      &priv->rxon_timing);
@@ -3269,9 +3283,10 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               /* FIXME: what should be the assoc_id for AP? */
-               priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               priv->staging_rxon.assoc_id = 0;
+
+               if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_PREAMBLE)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
@@ -3279,22 +3294,21 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-                       if (priv->assoc_capability &
-                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
+                       if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_SLOT_TIME)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 
-                       if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_add_local_station(priv, iwl_bcast_addr, false);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3309,7 +3323,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                               struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
-       const u8 *addr;
        int ret = 0;
        u8 sta_id = IWL_INVALID_STATION;
        u8 static_key;
@@ -3321,15 +3334,19 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       addr = sta ? sta->addr : iwl_bcast_addr;
        static_key = !iwl_is_associated(priv);
 
        if (!static_key) {
-               sta_id = iwl_find_station(priv, addr);
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                           addr);
-                       return -EINVAL;
+               if (!sta) {
+                       sta_id = priv->hw_params.bcast_sta_id;
+               } else {
+                       sta_id = iwl_sta_id(sta);
+                       if (sta_id == IWL_INVALID_STATION) {
+                               IWL_DEBUG_MAC80211(priv,
+                                                  "leave - %pM not in station map.\n",
+                                                  sta->addr);
+                               return -EINVAL;
+                       }
                }
        }
 
@@ -3366,10 +3383,13 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
                               struct ieee80211_sta *sta)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl3945_sta_priv *sta_priv = (void *)sta->drv_priv;
        int ret;
-       bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        u8 sta_id;
 
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
+
        IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
                        sta->addr);
 
@@ -3382,16 +3402,14 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
                return ret;
        }
 
+       sta_priv->common.sta_id = sta_id;
+
        /* Initialize rate scaling */
        IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl3945_rs_rate_init(priv, sta, sta_id);
 
        return 0;
-
-
-
-       return ret;
 }
 /*****************************************************************************
  *
@@ -3740,6 +3758,7 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
        INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
        INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
        INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
        INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
 
        iwl3945_hw_setup_deferred_work(priv);
@@ -3762,6 +3781,7 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work_sync(&priv->init_alive_start);
        cancel_delayed_work(&priv->scan_check);
        cancel_delayed_work(&priv->alive_start);
+       cancel_work_sync(&priv->start_internal_scan);
        cancel_work_sync(&priv->beacon_update);
        if (priv->cfg->ops->lib->recover_from_tx_stall)
                del_timer_sync(&priv->monitor_recover);
@@ -3864,6 +3884,8 @@ err:
        return ret;
 }
 
+#define IWL3945_MAX_PROBE_REQUEST      200
+
 static int iwl3945_setup_mac(struct iwl_priv *priv)
 {
        int ret;
@@ -3871,6 +3893,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        hw->rate_control_algorithm = "iwl-3945-rs";
        hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
@@ -3889,7 +3912,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
        /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+       hw->wiphy->max_scan_ie_len = IWL3945_MAX_PROBE_REQUEST - 24 - 2;
 
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
index 6126c0a..4ba7b03 100644 (file)
@@ -1007,15 +1007,15 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
-       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-       rt2x00_desc_write(entry_priv->desc, 1, word);
+       rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length);
@@ -1040,6 +1040,11 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
        rt2x00_desc_write(txd, 4, word);
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1055,6 +1060,12 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
                           test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
@@ -1077,15 +1088,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * Replace rt2x00lib allocated descriptor with the
-        * pointer to the _real_ hardware descriptor.
-        * After that, map the beacon to DMA and update the
-        * descriptor.
-        */
-       memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry_priv->desc;
-
        rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
index 2e4f461..89d132d 100644 (file)
@@ -1165,15 +1165,15 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
-       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-       rt2x00_desc_write(entry_priv->desc, 1, word);
+       rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
@@ -1194,6 +1194,11 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
        rt2x00_desc_write(txd, 10, word);
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1212,6 +1217,12 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
@@ -1234,15 +1245,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * Replace rt2x00lib allocated descriptor with the
-        * pointer to the _real_ hardware descriptor.
-        * After that, map the beacon to DMA and update the
-        * descriptor.
-        */
-       memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry_priv->desc;
-
        rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
index e88d703..9ae96a6 100644 (file)
@@ -1034,12 +1034,30 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(txd, 0, &word);
+       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
+       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_OFDM,
+                          (txdesc->rate_mode == RATE_MODE_OFDM));
+       rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+                          test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
+       rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
+       rt2x00_desc_write(txd, 0, word);
+
        rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
        rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
@@ -1059,23 +1077,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                _rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
        }
 
-       rt2x00_desc_read(txd, 0, &word);
-       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
-       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_OFDM,
-                          (txdesc->rate_mode == RATE_MODE_OFDM));
-       rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
-                          test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
-       rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
-       rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
-       rt2x00_desc_write(txd, 0, word);
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
@@ -1089,19 +1095,11 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
        int length;
        u16 reg, reg0;
 
        /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
-
-       /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
         */
@@ -1110,6 +1108,11 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 
        /*
+        * Take the descriptor in front of the skb into account.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+
+       /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
         * to the driver to determine what the length should be.
index 7d4778d..b2f2327 100644 (file)
@@ -633,7 +633,8 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
@@ -657,15 +658,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
-                          rt2x00dev->ops->extra_tx_headroom);
+       rt2x00_set_field32(&word, TXD_W1_SD_LEN0, TXWI_DESC_SIZE);
        rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
        rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
-                          skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom);
+                          skbdesc->skb_dma + TXWI_DESC_SIZE);
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 3, &word);
@@ -673,6 +673,12 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
        rt2x00_desc_write(txd, 3, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
index 8ad0669..0f8b84b 100644 (file)
@@ -400,7 +400,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txi = skbdesc->desc;
+       __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
        u32 word;
 
        /*
@@ -422,6 +422,12 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_desc_write(txi, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txi;
+       skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
 }
 
 /*
index 9569fb4..47bbc09 100644 (file)
@@ -156,10 +156,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
                            enum rt2x00_dump_type type, struct sk_buff *skb)
 {
        struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
-       struct skb_frame_desc *desc = get_skb_frame_desc(skb);
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct sk_buff *skbcopy;
        struct rt2x00dump_hdr *dump_hdr;
        struct timeval timestamp;
+       u32 data_len;
 
        do_gettimeofday(&timestamp);
 
@@ -171,7 +172,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
                return;
        }
 
-       skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + skb->len,
+       data_len = skb->len;
+       if (skbdesc->flags & SKBDESC_DESC_IN_SKB)
+               data_len -= skbdesc->desc_len;
+
+       skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,
                            GFP_ATOMIC);
        if (!skbcopy) {
                DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
@@ -181,18 +186,20 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
        dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
        dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
        dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
-       dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
-       dump_hdr->data_length = cpu_to_le32(skb->len);
+       dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len);
+       dump_hdr->data_length = cpu_to_le32(data_len);
        dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
        dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
        dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
        dump_hdr->type = cpu_to_le16(type);
-       dump_hdr->queue_index = desc->entry->queue->qid;
-       dump_hdr->entry_index = desc->entry->entry_idx;
+       dump_hdr->queue_index = skbdesc->entry->queue->qid;
+       dump_hdr->entry_index = skbdesc->entry->entry_idx;
        dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
        dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
 
-       memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
+       if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB))
+               memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc,
+                      skbdesc->desc_len);
        memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len);
 
        skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
index 727019a..ed303b4 100644 (file)
  *     the tx event which has either succeeded or failed. A frame
  *     with this type should also have been reported with as a
  *     %DUMP_FRAME_TX frame.
+ * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
+ *     hardware.
  */
 enum rt2x00_dump_type {
        DUMP_FRAME_RXDONE = 1,
        DUMP_FRAME_TX = 2,
        DUMP_FRAME_TXDONE = 3,
+       DUMP_FRAME_BEACON = 4,
 };
 
 /**
index 4b941e9..a016f7c 100644 (file)
@@ -67,8 +67,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
                            struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc;
 
        /*
         * This should not happen, we already checked the entry
@@ -83,13 +81,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
                return -EINVAL;
        }
 
-       /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->desc = entry_priv->desc;
-       skbdesc->desc_len = entry->queue->desc_size;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
index 089a12c..20dbdd6 100644 (file)
@@ -421,6 +421,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
 {
        struct data_queue *queue = entry->queue;
        struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       enum rt2x00_dump_type dump_type;
 
        rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
 
@@ -428,7 +429,9 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
         * All processing on the frame has been completed, this means
         * it is now ready to be dumped to userspace through debugfs.
         */
-       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+       dump_type = (txdesc->queue == QID_BEACON) ?
+                                       DUMP_FRAME_BEACON : DUMP_FRAME_TX;
+       rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
 }
 
 static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -553,7 +556,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        struct rt2x00_intf *intf = vif_to_intf(vif);
        struct skb_frame_desc *skbdesc;
        struct txentry_desc txdesc;
-       __le32 desc[16];
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
@@ -586,19 +588,10 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
 
        /*
-        * For the descriptor we use a local array from where the
-        * driver can move it to the correct location required for
-        * the hardware.
-        */
-       memset(desc, 0, sizeof(desc));
-
-       /*
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(intf->beacon->skb);
        memset(skbdesc, 0, sizeof(*skbdesc));
-       skbdesc->desc = desc;
-       skbdesc->desc_len = intf->beacon->queue->desc_size;
        skbdesc->entry = intf->beacon;
 
        /*
index 36a957a..f791708 100644 (file)
@@ -94,12 +94,15 @@ enum data_queue_qid {
  *     mac80211 but was stripped for processing by the driver.
  * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
  *     don't try to pass it back.
+ * @SKBDESC_DESC_IN_SKB: The descriptor is at the start of the
+ *     skb, instead of in the desc field.
  */
 enum skb_frame_desc_flags {
        SKBDESC_DMA_MAPPED_RX = 1 << 0,
        SKBDESC_DMA_MAPPED_TX = 1 << 1,
        SKBDESC_IV_STRIPPED = 1 << 2,
        SKBDESC_NOT_MAC80211 = 1 << 3,
+       SKBDESC_DESC_IN_SKB = 1 << 4,
 };
 
 /**
index da111c0..bd1546b 100644 (file)
@@ -222,7 +222,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc;
        u32 length;
 
        /*
@@ -232,13 +231,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
        memset(entry->skb->data, 0, entry->queue->desc_size);
 
        /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->desc = entry->skb->data;
-       skbdesc->desc_len = entry->queue->desc_size;
-
-       /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
         * to the driver to determine what the length should be.
index 86c75b9..2e3076f 100644 (file)
@@ -1764,7 +1764,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
@@ -1802,18 +1803,23 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       rt2x00_desc_read(txd, 6, &word);
-       rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                          skbdesc->skb_dma);
-       rt2x00_desc_write(txd, 6, word);
+       if (txdesc->queue != QID_BEACON) {
+               rt2x00_desc_read(txd, 6, &word);
+               rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+                                  skbdesc->skb_dma);
+               rt2x00_desc_write(txd, 6, word);
 
-       if (skbdesc->desc_len > TXINFO_SIZE) {
                rt2x00_desc_read(txd, 11, &word);
                rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0,
                                   txdesc->length);
                rt2x00_desc_write(txd, 11, word);
        }
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1838,6 +1844,13 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len =
+               (txdesc->queue == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
 }
 
 /*
@@ -1847,7 +1860,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
                                 struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        unsigned int beacon_base;
        u32 reg;
 
@@ -1863,11 +1876,9 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
         * Write entire beacon with descriptor to register.
         */
        beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-       rt2x00pci_register_multiwrite(rt2x00dev,
-                                     beacon_base,
-                                     skbdesc->desc, skbdesc->desc_len);
-       rt2x00pci_register_multiwrite(rt2x00dev,
-                                     beacon_base + skbdesc->desc_len,
+       rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
+                                     entry_priv->desc, TXINFO_SIZE);
+       rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
                                      entry->skb->data, entry->skb->len);
 
        /*
index 11c1307..e35bd19 100644 (file)
@@ -1441,12 +1441,38 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(txd, 0, &word);
+       rt2x00_set_field32(&word, TXD_W0_BURST,
+                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_OFDM,
+                          (txdesc->rate_mode == RATE_MODE_OFDM));
+       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+       rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+                          test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+                          test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W0_BURST2,
+                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
+       rt2x00_desc_write(txd, 0, word);
+
        rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
@@ -1475,31 +1501,11 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       rt2x00_desc_read(txd, 0, &word);
-       rt2x00_set_field32(&word, TXD_W0_BURST,
-                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_VALID, 1);
-       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_OFDM,
-                          (txdesc->rate_mode == RATE_MODE_OFDM));
-       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-       rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
-                          test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
-                          test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
-       rt2x00_set_field32(&word, TXD_W0_BURST2,
-                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
-       rt2x00_desc_write(txd, 0, word);
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
@@ -1509,18 +1515,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
                                 struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
 
        /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
-
-       /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
         */
@@ -1529,6 +1527,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
        rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
        /*
+        * Take the descriptor in front of the skb into account.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+
+       /*
         * Write entire beacon with descriptor to register.
         */
        beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
index 5bb9e3f..b7d9137 100644 (file)
@@ -467,6 +467,7 @@ static void wl1271_irq_work(struct work_struct *work)
                intr = le32_to_cpu(wl->fw_status->intr);
                if (!intr) {
                        wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
+                       spin_lock_irqsave(&wl->wl_lock, flags);
                        continue;
                }
 
@@ -852,7 +853,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
                if (wl == wl_temp)
                        break;
        }
-       if (wl == NULL)
+       if (wl != wl_temp)
                return NOTIFY_DONE;
 
        /* Get the interface IP address for the device. "ifa" will become
@@ -1558,8 +1559,6 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        default:
                wl1271_error("Unsupported key cmd 0x%x", cmd);
                ret = -EOPNOTSUPP;
-               goto out_sleep;
-
                break;
        }
 
index ac45c5b..5be900d 100644 (file)
@@ -712,6 +712,28 @@ struct ieee80211_conf {
 };
 
 /**
+ * struct ieee80211_channel_switch - holds the channel switch data
+ *
+ * The information provided in this structure is required for channel switch
+ * operation.
+ *
+ * @timestamp: value in microseconds of the 64-bit Time Synchronization
+ *     Function (TSF) timer when the frame containing the channel switch
+ *     announcement was received. This is simply the rx.mactime parameter
+ *     the driver passed into mac80211.
+ * @block_tx: Indicates whether transmission must be blocked before the
+ *     scheduled channel switch, as indicated by the AP.
+ * @channel: the new channel to switch to
+ * @count: the number of TBTT's until the channel switch event
+ */
+struct ieee80211_channel_switch {
+       u64 timestamp;
+       bool block_tx;
+       struct ieee80211_channel *channel;
+       u8 count;
+};
+
+/**
  * struct ieee80211_vif - per-interface data
  *
  * Data in this structure is continually present for driver
@@ -1631,6 +1653,11 @@ enum ieee80211_ampdu_mlme_action {
  * @flush: Flush all pending frames from the hardware queue, making sure
  *     that the hardware queues are empty. If the parameter @drop is set
  *     to %true, pending frames may be dropped. The callback can sleep.
+ *
+ * @channel_switch: Drivers that need (or want) to offload the channel
+ *     switch operation for CSAs received from the AP may implement this
+ *     callback. They must then call ieee80211_chswitch_done() to indicate
+ *     completion of the channel switch.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1694,6 +1721,8 @@ struct ieee80211_ops {
        int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
 #endif
        void (*flush)(struct ieee80211_hw *hw, bool drop);
+       void (*channel_switch)(struct ieee80211_hw *hw,
+                              struct ieee80211_channel_switch *ch_switch);
 };
 
 /**
@@ -2444,6 +2473,16 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp);
 
+/**
+ * ieee80211_chswitch_done - Complete channel switch process
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @success: make the channel switch successful or not
+ *
+ * Complete the channel switch post-process: set the new operational channel
+ * and wake up the suspended queues.
+ */
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
+
 /* Rate control API */
 
 /**
index ee8b63f..4f22713 100644 (file)
@@ -371,4 +371,15 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop)
        if (local->ops->flush)
                local->ops->flush(&local->hw, drop);
 }
+
+static inline void drv_channel_switch(struct ieee80211_local *local,
+                                    struct ieee80211_channel_switch *ch_switch)
+{
+       might_sleep();
+
+       local->ops->channel_switch(&local->hw, ch_switch);
+
+       trace_drv_channel_switch(local, ch_switch);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index ce734b5..6a9b234 100644 (file)
@@ -774,6 +774,34 @@ TRACE_EVENT(drv_flush,
        )
 );
 
+TRACE_EVENT(drv_channel_switch,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_channel_switch *ch_switch),
+
+       TP_ARGS(local, ch_switch),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, timestamp)
+               __field(bool, block_tx)
+               __field(u16, freq)
+               __field(u8, count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->timestamp = ch_switch->timestamp;
+               __entry->block_tx = ch_switch->block_tx;
+               __entry->freq = ch_switch->channel->center_freq;
+               __entry->count = ch_switch->count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " new freq:%u count:%d",
+               LOCAL_PR_ARG, __entry->freq, __entry->count
+       )
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
@@ -992,6 +1020,27 @@ TRACE_EVENT(api_sta_block_awake,
        )
 );
 
+TRACE_EVENT(api_chswitch_done,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+
+       TP_ARGS(sdata, success),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(bool, success)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->success = success;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " success=%d",
+               VIF_PR_ARG, __entry->success
+       )
+);
+
 /*
  * Tracing for internal functions
  * (which may also be called in response to driver calls)
index 7ef7798..1a9e2da 100644 (file)
@@ -998,7 +998,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
                                  unsigned long data, void *dummy);
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_channel_sw_ie *sw_elem,
-                                     struct ieee80211_bss *bss);
+                                     struct ieee80211_bss *bss,
+                                     u64 timestamp);
 void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 
index 3093e46..c6c1f49 100644 (file)
@@ -342,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
                goto out;
 
        sdata->local->oper_channel = sdata->local->csa_channel;
-       ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!sdata->local->ops->channel_switch) {
+               /* call "hw_config" only if doing sw channel switch */
+               ieee80211_hw_config(sdata->local,
+                       IEEE80211_CONF_CHANGE_CHANNEL);
+       }
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
        ifmgd->associated->channel = sdata->local->oper_channel;
@@ -354,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        mutex_unlock(&ifmgd->mtx);
 }
 
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+
+       trace_api_chswitch_done(sdata, success);
+       if (!success) {
+               /*
+                * If the channel switch was not successful, stay
+                * around on the old channel. We currently lack
+                * good handling of this situation, possibly we
+                * should just drop the association.
+                */
+               sdata->local->csa_channel = sdata->local->oper_channel;
+       }
+
+       ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+}
+EXPORT_SYMBOL(ieee80211_chswitch_done);
+
 static void ieee80211_chswitch_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
@@ -370,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_channel_sw_ie *sw_elem,
-                                     struct ieee80211_bss *bss)
+                                     struct ieee80211_bss *bss,
+                                     u64 timestamp)
 {
        struct cfg80211_bss *cbss =
                container_of((void *)bss, struct cfg80211_bss, priv);
@@ -398,10 +426,29 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        sdata->local->csa_channel = new_ch;
 
+       if (sdata->local->ops->channel_switch) {
+               /* use driver's channel switch callback */
+               struct ieee80211_channel_switch ch_switch;
+               memset(&ch_switch, 0, sizeof(ch_switch));
+               ch_switch.timestamp = timestamp;
+               if (sw_elem->mode) {
+                       ch_switch.block_tx = true;
+                       ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+               }
+               ch_switch.channel = new_ch;
+               ch_switch.count = sw_elem->count;
+               ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+               drv_channel_switch(sdata->local, &ch_switch);
+               return;
+       }
+
+       /* channel switch handled in software */
        if (sw_elem->count <= 1) {
                ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
        } else {
-               ieee80211_stop_queues_by_reason(&sdata->local->hw,
+               if (sw_elem->mode)
+                       ieee80211_stop_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
                ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
                mod_timer(&ifmgd->chswitch_timer,
@@ -1317,7 +1364,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                                        ETH_ALEN) == 0)) {
                struct ieee80211_channel_sw_ie *sw_elem =
                        (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
-               ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
+               ieee80211_sta_process_chanswitch(sdata, sw_elem,
+                                                bss, rx_status->mactime);
        }
 }
 
@@ -1649,7 +1697,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
                        ieee80211_sta_process_chanswitch(sdata,
                                        &mgmt->u.action.u.chan_switch.sw_elem,
-                                       (void *)ifmgd->associated->priv);
+                                       (void *)ifmgd->associated->priv,
+                                       rx_status->mactime);
                        break;
                }
                mutex_unlock(&ifmgd->mtx);
index 9a08f2c..6e2a7bc 100644 (file)
@@ -1253,6 +1253,12 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        if (skb_linearize(rx->skb))
                return RX_DROP_UNUSABLE;
 
+       /*
+        *  skb_linearize() might change the skb->data and
+        *  previously cached variables (in this case, hdr) need to
+        *  be refreshed with the new data.
+        */
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
        seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
        if (frag == 0) {
index 3dd0760..be3d4a6 100644 (file)
@@ -33,6 +33,7 @@
 #define IEEE80211_MAX_PROBE_TRIES 5
 
 enum work_action {
+       WORK_ACT_MISMATCH,
        WORK_ACT_NONE,
        WORK_ACT_TIMEOUT,
        WORK_ACT_DONE,
@@ -585,7 +586,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
        u16 auth_alg, auth_transaction, status_code;
 
        if (wk->type != IEEE80211_WORK_AUTH)
-               return WORK_ACT_NONE;
+               return WORK_ACT_MISMATCH;
 
        if (len < 24 + 6)
                return WORK_ACT_NONE;
@@ -636,6 +637,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
        struct ieee802_11_elems elems;
        u8 *pos;
 
+       if (wk->type != IEEE80211_WORK_ASSOC)
+               return WORK_ACT_MISMATCH;
+
        /*
         * AssocResp and ReassocResp have identical structure, so process both
         * of them in this function.
@@ -691,6 +695,12 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
 
        ASSERT_WORK_MTX(local);
 
+       if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
+               return WORK_ACT_MISMATCH;
+
+       if (len < 24 + 12)
+               return WORK_ACT_NONE;
+
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
        if (baselen > len)
                return WORK_ACT_NONE;
@@ -705,7 +715,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_work *wk;
-       enum work_action rma = WORK_ACT_NONE;
+       enum work_action rma;
        u16 fc;
 
        rx_status = (struct ieee80211_rx_status *) skb->cb;
@@ -752,7 +762,17 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                        break;
                default:
                        WARN_ON(1);
+                       rma = WORK_ACT_NONE;
                }
+
+               /*
+                * We've either received an unexpected frame, or we have
+                * multiple work items and need to match the frame to the
+                * right one.
+                */
+               if (rma == WORK_ACT_MISMATCH)
+                       continue;
+
                /*
                 * We've processed this frame for that work, so it can't
                 * belong to another work struct.
@@ -762,6 +782,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        }
 
        switch (rma) {
+       case WORK_ACT_MISMATCH:
+               /* ignore this unmatched frame */
+               break;
        case WORK_ACT_NONE:
                break;
        case WORK_ACT_DONE: