commit ea45faaa5b3ba8e3d3444f67cad30adf44fb877f Author: Zhu Yi Date: Tue Sep 4 10:45:22 2007 +0800 [V3] Add iwlwifi driver Signed-off-by: Zhu Yi diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 1245b5c..59740e2 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -48,11 +48,7 @@ obj-$(CONFIG_LIBERTAS_USB) += libertas/ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o -# NOTE: We use common code from iwl-base.c to build driver -# specific binaries based on the #define IWL -- the target -# setup below creates a specific driver target from iwl-base.c -# -# NOTE2: iwl-base-XXXX.o has -D"KBUILD_MODNAME=KBUILD_STR(...)" in order to +# NOTE: iwl-base-XXXX.o has -D"KBUILD_MODNAME=KBUILD_STR(...)" in order to # prevent the following kbuild error: # include/linux/pci.h:603: error: `KBUILD_MODNAME' undeclared (first \ # use in this function) @@ -64,7 +60,7 @@ iwl3945-objs = iwl-base-3945.o iwl-3945.o iwl-3945-rs.o CFLAGS_iwl-3945.o = -DIWL=3945 CFLAGS_iwl-3945-rs.o = -DIWL=3945 CFLAGS_iwl-base-3945.o = -DIWL=3945 -D"KBUILD_MODNAME=KBUILD_STR(iwl3945)" -$(obj)/iwl-base-3945.o: $(src)/iwl-base.c FORCE +$(obj)/iwl-base-3945.o: $(src)/iwl3945-base.c FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) @@ -73,6 +69,6 @@ iwl4965-objs = iwl-base-4965.o iwl-4965.o iwl-4965-rs.o CFLAGS_iwl-4965.o = -DIWL=4965 CFLAGS_iwl-4965-rs.o = -DIWL=4965 CFLAGS_iwl-base-4965.o = -DIWL=4965 -D"KBUILD_MODNAME=KBUILD_STR(iwl4965)" -$(obj)/iwl-base-4965.o: $(src)/iwl-base.c FORCE +$(obj)/iwl-base-4965.o: $(src)/iwl4965-base.c FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) diff --git a/drivers/net/wireless/iwl-3945-hw.h b/drivers/net/wireless/iwl-3945-hw.h index 1b5e72f..fb5f064 100644 --- a/drivers/net/wireless/iwl-3945-hw.h +++ b/drivers/net/wireless/iwl-3945-hw.h @@ -79,8 +79,8 @@ static inline int iwl_hw_valid_rtc_data_addr(u32 addr) { - return ((addr >= RTC_DATA_LOWER_BOUND) - && (addr < ALM_RTC_DATA_UPPER_BOUND)); + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < ALM_RTC_DATA_UPPER_BOUND); } /* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE diff --git a/drivers/net/wireless/iwl-3945-rs.c b/drivers/net/wireless/iwl-3945-rs.c index 2eee6c5..f394fd4 100644 --- a/drivers/net/wireless/iwl-3945-rs.c +++ b/drivers/net/wireless/iwl-3945-rs.c @@ -42,9 +42,7 @@ #include "../net/mac80211/ieee80211_rate.h" -#include "iwl-3945-rs.h" #include "iwlwifi.h" -#include "iwl-helpers.h" #define RS_NAME "iwl-3945-rs" @@ -295,8 +293,7 @@ static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, unsigned long flags; if (!retries) { - IWL_DEBUG_RATE("leave: retries == 0 -- should be at " - "least 1\n"); + IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); return; } @@ -359,17 +356,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, static void *rs_alloc(struct ieee80211_local *local) { - IWL_DEBUG_RATE("enter\n"); - IWL_DEBUG_RATE("leave\n"); return local->hw.priv; } -static void rs_free(void *data) -{ - IWL_DEBUG_RATE("enter\n"); - IWL_DEBUG_RATE("leave\n"); -} - static void *rs_alloc_sta(void *priv, gfp_t gfp) { struct iwl_rate_scale_priv *rs_priv; @@ -418,11 +407,6 @@ static void rs_free_sta(void *priv, void *priv_sta) IWL_DEBUG_RATE("leave\n"); } -static void rs_clear(void *priv) -{ - IWL_DEBUG_RATE("NOP\n"); -} - /** * rs_tx_status - Update rate control values based on Tx results * @@ -820,9 +804,9 @@ static struct rate_control_ops rs_ops = { .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, + .clear = NULL, .alloc = rs_alloc, - .free = rs_free, + .free = NULL, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, }; diff --git a/drivers/net/wireless/iwl-3945-rs.h b/drivers/net/wireless/iwl-3945-rs.h index 70dcec4..b926738 100644 --- a/drivers/net/wireless/iwl-3945-rs.h +++ b/drivers/net/wireless/iwl-3945-rs.h @@ -142,37 +142,15 @@ enum { extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; -static inline int iwl_rate_index_from_plcp(int plcp) -{ - int i = 0; - for (i = 0; i < IWL_RATE_COUNT; i++) - if (iwl_rates[i].plcp == plcp) - return i; - return -1; -} - -static inline u8 iwl_rate_get_lowest_plcp(int rate_mask) -{ - u8 i; - - for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl_rates[i].next_ieee) { - if (rate_mask & (1 << i)) - return iwl_rates[i].plcp; - } - - return IWL_RATE_INVALID; -} - static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; + if (rate == IWL_RATE_INVALID) rate = rate_index; return rate; } -#if IWL == 3945 /** * iwl_fill_rs_info - Fill an output text buffer with the rate representation * @@ -209,13 +187,5 @@ extern void iwl_rate_control_register(struct ieee80211_hw *hw); * the driver is unloaded. */ extern void iwl_rate_control_unregister(struct ieee80211_hw *hw); -#else -static inline int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, - u8 sta_id) -{ return -ENOTSUPP; } -static inline void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) {} -static inline void iwl_rate_control_register(struct ieee80211_hw *hw) {} -static inline void iwl_rate_control_unregister(struct ieee80211_hw *hw) {} -#endif /* IWL == 3945 */ #endif diff --git a/drivers/net/wireless/iwl-3945.c b/drivers/net/wireless/iwl-3945.c index bb75836..2ed217c 100644 --- a/drivers/net/wireless/iwl-3945.c +++ b/drivers/net/wireless/iwl-3945.c @@ -720,9 +720,9 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, &val); if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { - iwl_set_bits_mask_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_POWER_SRC_VAUX, - ~APMG_PS_CTRL_REG_MSK_POWER_SRC); + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); iwl_release_restricted_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, @@ -731,9 +731,9 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) } else iwl_release_restricted_access(priv); } else { - iwl_set_bits_mask_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN, - ~APMG_PS_CTRL_REG_MSK_POWER_SRC); + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); iwl_release_restricted_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, @@ -889,12 +889,12 @@ int iwl_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN, - APMG_CLK_REG_VAL_DMA_CLK_RQT | - APMG_CLK_REG_VAL_BSM_CLK_RQT); + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(20); - iwl_set_bits_restricted_reg(priv, ALM_APMG_PCIDEV_STT, - APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE); + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -1099,27 +1099,28 @@ int iwl_hw_nic_reset(struct iwl_priv *priv) rc = iwl_grab_restricted_access(priv); if (!rc) { iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, - APMG_CLK_REG_VAL_BSM_CLK_RQT); + APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - iwl_write_restricted_reg(priv, ALM_APMG_LARC_INT_MSK, 0x0); - iwl_write_restricted_reg(priv, ALM_APMG_LARC_INT, 0xFFFFFFFF); + iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG, + 0xFFFFFFFF); /* enable DMA */ - iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN, - APMG_CLK_REG_VAL_DMA_CLK_RQT | - APMG_CLK_REG_VAL_BSM_CLK_RQT); + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl_set_bits_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ); + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); iwl_release_restricted_access(priv); } diff --git a/drivers/net/wireless/iwl-3945.h b/drivers/net/wireless/iwl-3945.h index 0f4db4c..813902e 100644 --- a/drivers/net/wireless/iwl-3945.h +++ b/drivers/net/wireless/iwl-3945.h @@ -27,23 +27,6 @@ #ifndef __iwl_3945_h__ #define __iwl_3945_h__ -#if IWL != 3945 -/* - * In non IWL == 3945 builds, these must build to nothing in order to allow - * the common code to not have several #if IWL == XXXX / #endif blocks - */ -static inline __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) -{ return 0; } -static inline int iwl3945_init_hw_rate_table(struct iwl_priv *priv) -{ return 0; } -static inline void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) {} -static inline void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) -{} -static inline int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) -{ return 0; } -static inline u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, - u16 tx_rate, u8 flags) { return 0; } -#else /* IWL == 3945 */ /* * Forward declare iwl-3945.c functions for iwl-base.c */ @@ -55,6 +38,4 @@ extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work); 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); -#endif /* IWL == 3945 */ - #endif diff --git a/drivers/net/wireless/iwl-4965-hw.h b/drivers/net/wireless/iwl-4965-hw.h index 858ec55..810e969 100644 --- a/drivers/net/wireless/iwl-4965-hw.h +++ b/drivers/net/wireless/iwl-4965-hw.h @@ -76,8 +76,8 @@ static inline int iwl_hw_valid_rtc_data_addr(u32 addr) { - return ((addr >= RTC_DATA_LOWER_BOUND) - && (addr < KDR_RTC_DATA_UPPER_BOUND)); + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < KDR_RTC_DATA_UPPER_BOUND); } /********************* START TXPOWER *****************************************/ @@ -207,10 +207,8 @@ union iwl_tx_power_dual_stream { /********************* END TXPOWER *****************************************/ /* HT flags */ -#define RXON_FLG_CONTROL_CHANNEL_LOCATION_POS (22) -#define RXON_FLG_CONTROL_CHANNEL_LOCATION_MSK __constant_cpu_to_le32(0x1<<22) -#define RXON_FLG_CONTROL_CHANNEL_LOC_LOW_MSK __constant_cpu_to_le32(0x0<<22) -#define RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK __constant_cpu_to_le32(0x1<<22) +#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22) #define RXON_FLG_HT_OPERATING_MODE_POS (23) @@ -219,7 +217,6 @@ union iwl_tx_power_dual_stream { #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25) -#define RXON_FLG_CHANNEL_MODE_LEGACY_MSK __constant_cpu_to_le32(0x0<<25) #define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25) #define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25) @@ -274,61 +271,7 @@ union iwl_tx_power_dual_stream { #define IWL_FH_REGS_LOWER_BOUND (0x1000) #define IWL_FH_REGS_UPPER_BOUND (0x2000) -/* TFDB Area - TFDs buffer table */ -#define FH_MEM_TFDB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x000) -#define FH_MEM_TFDB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x900) -/* channels 0 - 8 */ -#define FH_MEM_TFDB_CHNL_BUF0(x) (FH_MEM_TFDB_LOWER_BOUND + (x) * 0x100) -#define FH_MEM_TFDB_CHNL_BUF1(x) (FH_MEM_TFDB_LOWER_BOUND + 0x80 + (x) * 0x100) - -/* TFDIB Area - TFD Immediate Buffer */ -#define FH_MEM_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900) -#define FH_MEM_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958) -/* channels 0 - 10 */ -#define FH_MEM_TFDIB_CHNL(x) (FH_MEM_TFDIB_LOWER_BOUND + (x) * 0x8) - -/* TFDIB registers used in Service Mode */ -#define FH_MEM_TFDIB_CHNL9_REG0 (FH_MEM_TFDIB_CHNL(9)) -#define FH_MEM_TFDIB_CHNL9_REG1 (FH_MEM_TFDIB_CHNL(9) + 4) -#define FH_MEM_TFDIB_CHNL10_REG0 (FH_MEM_TFDIB_CHNL(10)) -#define FH_MEM_TFDIB_CHNL10_REG1 (FH_MEM_TFDIB_CHNL(10) + 4) - -/* Tx service channels */ -#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK (0xFFFFFFFF) -#define FH_MEM_TFDIB_DRAM_ADDR_MSB_MASK (0xF00000000) -#define FH_MEM_TFDIB_TB_LENGTH_MASK (0x0001FFFF) /* bits 16:0 */ - -#define FH_MEM_TFDIB_DRAM_ADDR_LSB_BITSHIFT (0) -#define FH_MEM_TFDIB_DRAM_ADDR_MSB_BITSHIFT (32) -#define FH_MEM_TFDIB_TB_LENGTH_BITSHIFT (0) - -#define FH_MEM_TFDIB_REG0_ADDR_MASK (0xFFFFFFFF) -#define FH_MEM_TFDIB_REG1_ADDR_MASK (0xF0000000) -#define FH_MEM_TFDIB_REG1_LENGTH_MASK (0x0001FFFF) - -#define FH_MEM_TFDIB_REG0_ADDR_BITSHIFT (0) -#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT (28) -#define FH_MEM_TFDIB_REG1_LENGTH_BITSHIFT (0) - -/* TRB Area - Transmit Request Buffers */ -#define FH_MEM_TRB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x0958) -#define FH_MEM_TRB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x0980) -/* channels 0 - 8 */ -#define FH_MEM_TRB_CHNL(x) (FH_MEM_TRB_LOWER_BOUND + (x) * 0x4) - #define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) -/* STAGB Area - Scheduler TAG Buffer */ -#define FH_MEM_STAGB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x980) -#define FH_MEM_STAGB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) -/* channels 0 - 8 */ -#define FH_MEM_STAGB_0(x) (FH_MEM_STAGB_LOWER_BOUND + (x) * 0x8) -#define FH_MEM_STAGB_1(x) (FH_MEM_STAGB_LOWER_BOUND + 0x4 + (x) * 0x8) - -/* Tx service channels */ -#define FH_MEM_SRAM_ADDR_9 (FH_MEM_STAGB_LOWER_BOUND + 0x048) -#define FH_MEM_SRAM_ADDR_10 (FH_MEM_STAGB_LOWER_BOUND + 0x04C) - -#define FH_MEM_STAGB_SRAM_ADDR_MASK (0x00FFFFFF) /* CBBC Area - Circular buffers base address cache pointers table */ #define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) @@ -336,64 +279,21 @@ union iwl_tx_power_dual_stream { /* queues 0 - 15 */ #define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) -/* TAGR Area - TAG reconstruct table */ -#define FH_MEM_TAGR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) -#define FH_MEM_TAGR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA70) - -/* TDBGR Area - Tx Debug Registers */ -#define FH_MEM_TDBGR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x0A70) -#define FH_MEM_TDBGR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x0B20) -/* channels 0 - 10 */ -#define FH_MEM_TDBGR_CHNL(x) (FH_MEM_TDBGR_LOWER_BOUND + (x) * 0x10) - -#define FH_MEM_TDBGR_CHNL_REG_0(x) (FH_MEM_TDBGR_CHNL(x)) -#define FH_MEM_TDBGR_CHNL_REG_1(x) (FH_MEM_TDBGR_CHNL_REG_0(x) + 0x4) - -#define FH_MEM_TDBGR_CHNL_BYTES_TO_FIFO_MASK (0x000FFFFF) -#define FH_MEM_TDBGR_CHNL_BYTES_TO_FIFO_BITSHIFT (0) - -/* RDBUF Area */ -#define FH_MEM_RDBUF_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xB80) -#define FH_MEM_RDBUF_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) -#define FH_MEM_RDBUF_CHNL0 (FH_MEM_RDBUF_LOWER_BOUND) - /* RSCSR Area */ #define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) #define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) -#define FH_MEM_RSCSR_CHNL1 (FH_MEM_RSCSR_LOWER_BOUND + 0x020) -/* RSCSR registers used in Normal mode*/ #define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) #define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) -#define FH_RSCSR_CHNL0_RBDCB_RPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c) - -#define FH_RSCSR_FRAME_SIZE_MASK (0x00003FFF) /* bits 0-13 */ -/* RSCSR registers used in Service mode*/ -#define FH_RSCSR_CHNL1_RB_WPTR_REG (FH_MEM_RSCSR_CHNL1) -#define FH_RSCSR_CHNL1_RB_WPTR_OFFSET_REG (FH_MEM_RSCSR_CHNL1 + 0x004) -#define FH_RSCSR_CHNL1_RB_CHUNK_NUM_REG (FH_MEM_RSCSR_CHNL1 + 0x008) -#define FH_RSCSR_CHNL1_SRAM_ADDR_REG (FH_MEM_RSCSR_CHNL1 + 0x00C) /* RCSR Area - Registers address map */ #define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) #define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) -#define FH_MEM_RCSR_CHNL1 (FH_MEM_RCSR_LOWER_BOUND + 0x020) #define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) -#define FH_MEM_RCSR_CHNL0_CREDIT_REG (FH_MEM_RCSR_CHNL0 + 0x004) -#define FH_MEM_RCSR_CHNL0_RBD_STTS_REG (FH_MEM_RCSR_CHNL0 + 0x008) -#define FH_MEM_RCSR_CHNL0_RB_STTS_REG (FH_MEM_RCSR_CHNL0 + 0x00C) -#define FH_MEM_RCSR_CHNL0_RXPD_STTS_REG (FH_MEM_RCSR_CHNL0 + 0x010) - -#define FH_MEM_RCSR_CHNL0_RBD_STTS_FRAME_RB_CNT_MASK (0x7FFFFFF0) /* bits4:30 */ - -/* RCSR registers used in Service mode*/ -#define FH_MEM_RCSR_CHNL1_CONFIG_REG (FH_MEM_RCSR_CHNL1) -#define FH_MEM_RCSR_CHNL1_RB_STTS_REG (FH_MEM_RCSR_CHNL1 + 0x00C) -#define FH_MEM_RCSR_CHNL1_RX_PD_STTS_REG (FH_MEM_RCSR_CHNL1 + 0x010) /* RSSR Area - Rx shared ctrl & status registers */ #define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) @@ -409,10 +309,6 @@ union iwl_tx_power_dual_stream { #define IWL_FH_TCSR_CHNL_NUM (7) #define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) -#define IWL_FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ - (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ - (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) /* TSSR Area - Tx shared status registers */ /* TSSR */ @@ -445,61 +341,6 @@ union iwl_tx_power_dual_stream { (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) -/* SRVC */ -#define IWL_FH_SRVC_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0x9C8) -#define IWL_FH_SRVC_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0x9D0) - -#define IWL_FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ - (IWL_FH_SRVC_LOWER_BOUND + (_chnl - 9) * 0x4) - -/* TFDIB */ -#define IWL_FH_TFDIB_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0x900) -#define IWL_FH_TFDIB_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0x958) - -#define IWL_FH_TFDIB_CTRL0_REG(_chnl) \ - (IWL_FH_TFDIB_LOWER_BOUND + 0x8 * _chnl) -#define IWL_FH_TFDIB_CTRL1_REG(_chnl) \ - (IWL_FH_TFDIB_LOWER_BOUND + 0x8 * _chnl + 0x4) - -#define IWL_FH_SRVC_CHNL (9) -#define IWL_FH_TFDIB_CTRL1_REG_POS_MSB (28) - -/* Debug Monitor Area */ -#define FH_MEM_DM_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEE0) -#define FH_MEM_DM_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEF0) -#define FH_MEM_DM_CONTROL_MASK_REG (FH_MEM_DM_LOWER_BOUND) -#define FH_MEM_DM_CONTROL_START_REG (FH_MEM_DM_LOWER_BOUND + 0x004) -#define FH_MEM_DM_CONTROL_STATUS_REG (FH_MEM_DM_LOWER_BOUND + 0x008) -#define FH_MEM_DM_MONITOR_REG (FH_MEM_DM_LOWER_BOUND + 0x00C) - -#define FH_TB1_ADDR_LOW_MASK (0xFFFFFFFF) /* bits 31:0 */ -#define FH_TB1_ADDR_HIGH_MASK (0xF00000000) /* bits 35:32 */ -#define FH_TB2_ADDR_LOW_MASK (0x0000FFFF) /* bits 15:0 */ -#define FH_TB2_ADDR_HIGH_MASK (0xFFFFF0000) /* bits 35:16 */ - -#define FH_TB1_ADDR_LOW_BITSHIFT (0) -#define FH_TB1_ADDR_HIGH_BITSHIFT (32) -#define FH_TB2_ADDR_LOW_BITSHIFT (0) -#define FH_TB2_ADDR_HIGH_BITSHIFT (16) - -#define FH_TB1_LENGTH_MASK (0x00000FFF) /* bits 11:0 */ -#define FH_TB2_LENGTH_MASK (0x00000FFF) /* bits 11:0 */ - -/* number of FH channels including 2 service mode */ -#define NUM_OF_FH_CHANNELS (10) - -/* ctrl field bitology */ -#define FH_TFD_CTRL_PADDING_MASK (0xC0000000) /* bits 31:30 */ -#define FH_TFD_CTRL_NUMTB_MASK (0x1F000000) /* bits 28:24 */ - -#define FH_TFD_CTRL_PADDING_BITSHIFT (30) -#define FH_TFD_CTRL_NUMTB_BITSHIFT (24) - -#define FH_TFD_GET_NUM_TBS(ctrl) \ - ((ctrl & FH_TFD_CTRL_NUMTB_MASK) >> FH_TFD_CTRL_NUMTB_BITSHIFT) -#define FH_TFD_GET_PADDING(ctrl) \ - ((ctrl & FH_TFD_CTRL_PADDING_MASK) >> FH_TFD_CTRL_PADDING_BITSHIFT) - /* TCSR: tx_config register values */ #define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) #define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) @@ -529,10 +370,6 @@ union iwl_tx_power_dual_stream { #define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) #define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) -/* CBB table */ -#define FH_CBB_ADDR_MASK 0x0FFFFFFF /* bits 27:0 */ -#define FH_CBB_ADDR_BIT_SHIFT (8) - /* RCSR: channel 0 rx_config register defines */ #define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ #define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ @@ -544,22 +381,10 @@ union iwl_tx_power_dual_stream { #define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) #define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16) -#define FH_RCSR_GET_RDBC_SIZE(reg) \ - ((reg & FH_RCSR_RX_CONFIG_RDBC_SIZE_MASK) >> \ - FH_RCSR_RX_CONFIG_RDBC_SIZE_BITSHIFT) - -/* RCSR: channel 1 rx_config register defines */ -#define FH_RCSR_CHNL1_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ -#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_MASK (0x00003000) /* bits 12-13 */ - /* RCSR: rx_config register values */ #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) #define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) -#define FH_RCSR_RX_CONFIG_SINGLE_FRAME_MODE (0x00008000) - -#define FH_RCSR_RX_CONFIG_RDRBD_DISABLE_VAL (0x00000000) -#define FH_RCSR_RX_CONFIG_RDRBD_ENABLE_VAL (0x20000000) #define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) @@ -567,38 +392,9 @@ union iwl_tx_power_dual_stream { #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) -/* RCSR channel 1 config register values */ -#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) -#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_RTC_VAL (0x00002000) -#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_HOST_RTC_VAL (0x00003000) - -/* RCSR: rb status register defines */ -#define FH_RCSR_RB_BYTE_TO_SEND_MASK (0x0001FFFF) /* bits 0-16 */ - /* RSCSR: defs used in normal mode */ #define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */ -/* RSCSR: defs used in service mode */ -#define FH_RSCSR_CHNL1_SRAM_ADDR_MASK (0x00FFFFFF) /* bits 0-23 */ -#define FH_RSCSR_CHNL1_RB_WPTR_MASK (0x0FFFFFFF) /* bits 0-27 */ -#define FH_RSCSR_CHNL1_RB_WPTR_OFFSET_MASK (0x000000FF) /* bits 0-7 */ - -/* RSSR: RX Enable Error IRQ to Driver register defines */ -#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV_NO_RBD (0x00400000) /* bit 22 */ - -#define FH_DRAM2SRAM_DRAM_ADDR_HIGH_MASK (0xFFFFFFF00) /* bits 8-35 */ -#define FH_DRAM2SRAM_DRAM_ADDR_LOW_MASK (0x000000FF) /* bits 0-7 */ - -#define FH_DRAM2SRAM_DRAM_ADDR_HIGH_BITSHIFT (8) /* bits 8-35 */ - -/* RX DRAM status regs definitions */ -#define FH_RX_RB_NUM_MASK (0x00000FFF) /* bits 0-11 */ -#define FH_RX_FRAME_NUM_MASK (0x0FFF0000) /* bits 16-27 */ - -#define FH_RX_RB_NUM_BITSHIFT (0) -#define FH_RX_FRAME_NUM_BITSHIFT (16) - #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 10 @@ -672,46 +468,6 @@ union iwl_tx_power_dual_stream { #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) - - /*IWL4965-END */ - -#define IWL4965_BROADCAST_ID (31) - -#define RX_RES_PHY_CNT 14 - -#define STATISTICS_FLG_CLEAR (0x1) -#define STATISTICS_FLG_DISABLE_NOTIFICATION (0x2) - -#define STATISTICS_REPLY_FLG_CLEAR __constant_cpu_to_le32(0x1) -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(0x4) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) -#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) - - - -struct iwl4965_rx_phy_res { - u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ - u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ - u8 stat_id; /* configurable DSP phy data set ID */ - u8 reserved1; - __le64 timestamp; /* TSF at on air rise */ - __le32 beacon_time_stamp; /* beacon at on-air rise */ - __le16 phy_flags; /* general phy flags: band, modulation, ... */ - __le16 channel; /* channel number */ - __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ - __le32 reserved2; - __le32 rate_n_flags; - __le16 byte_count; /* frame's byte-count */ - __le16 reserved3; -} __attribute__ ((packed)); - -struct iwl4965_rx_mpdu_res_start { - __le16 byte_count; - __le16 reserved; -} __attribute__ ((packed)); - static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; @@ -725,16 +481,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) return cpu_to_le32(flags|(u16)rate); } -#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL_AGC_DB_POS (7) -/* Fixed (non-configurable) rx data from phy */ -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __attribute__ ((packed)); - struct iwl_tfd_frame_data { __le32 tb1_addr; diff --git a/drivers/net/wireless/iwl-4965-rs.c b/drivers/net/wireless/iwl-4965-rs.c index a97914f..9e0ba5f 100644 --- a/drivers/net/wireless/iwl-4965-rs.c +++ b/drivers/net/wireless/iwl-4965-rs.c @@ -42,7 +42,6 @@ #include "../net/mac80211/ieee80211_rate.h" #include "iwlwifi.h" -#include "iwl-4965-rs.h" #include "iwl-helpers.h" #define RS_NAME "iwl-4965-rs" @@ -218,7 +217,9 @@ static int rs_send_lq_cmd(struct iwl_priv *priv, if (flags & CMD_ASYNC) cmd.meta.u.callback = iwl_lq_sync_callback; - if (iwl_is_associated(priv) && priv->lq_mngr.lq_ready) + + if (iwl_is_associated(priv) && priv->assoc_station_added && + priv->lq_mngr.lq_ready) rc = iwl_send_cmd(priv, &cmd); return rc; @@ -616,8 +617,7 @@ static void rs_tx_status(void *priv_rate, u16 fc = le16_to_cpu(hdr->frame_control); s32 tpt = 0; - IWL_DEBUG_RATE("getting frame ack response, update rate " - "scale window\n"); + IWL_DEBUG_RATE("get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return; @@ -784,23 +784,6 @@ static u8 rs_is_other_ant_connected(u8 valid_antenna, return 0; } -#define IWL_LEGACY_SWITCH_ANTENNA 0 -#define IWL_LECACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO 2 - -#define IWL_RS_GOOD_RATIO 12800 - -#define IWL_ACTION_LIMIT 3 -#define IWL_LEGACY_FAILURE_LIMIT 160 -#define IWL_LEGACY_SUCCESS_LIMIT 480 -#define IWL_LEGACY_TABLE_COUNT 160 - -#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL_NONE_LEGACY_TABLE_COUNT 1500 - -#define IWL_RATE_SCALE_SWITCH (10880) - static void rs_set_stay_in_table(u8 is_legacy, struct iwl_rate_scale_priv *lq_data) { @@ -1113,10 +1096,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } -#define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO 1 -#define IWL_SISO_SWITCH_GI 2 - static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, int index) @@ -1208,10 +1187,6 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, return 0; } -#define IWL_MIMO_SWITCH_ANTENNA_A 0 -#define IWL_MIMO_SWITCH_ANTENNA_B 1 -#define IWL_MIMO_SWITCH_GI 2 - static int rs_move_mimo_to_other(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, int index) @@ -1647,6 +1622,8 @@ out: */ if (lq_data->phymode == (u8) MODE_IEEE80211A) sta->txrate = i - IWL_FIRST_OFDM_RATE; + else + sta->txrate = i; sta->antenna_sel_tx = tbl->lq_type; @@ -1850,7 +1827,8 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, crl->lq.sta_id = sta_id; crl->lq.rs_table[0].rate_n_flags = 0; } - priv->lq_mngr.lq_ready = 1; + /* FIXME: this is w/a remove it later */ + priv->assoc_station_added = 1; } for (i = 0; i < mode->num_rates; i++) { @@ -1887,8 +1865,10 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, crl->active_mimo_rate); #endif /*CONFIG_IWLWIFI_HT*/ - if (priv) - rs_initialize_lq(priv, sta); + if (priv->assoc_station_added) + priv->lq_mngr.lq_ready = 1; + + rs_initialize_lq(priv, sta); } static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, @@ -1985,22 +1965,14 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, static void *rs_alloc(struct ieee80211_local *local) { - IWL_DEBUG_RATE("enter\n"); - IWL_DEBUG_RATE("leave\n"); return local->hw.priv; } -static void rs_free(void *data) -{ - IWL_DEBUG_RATE("enter\n"); - IWL_DEBUG_RATE("leave\n"); -} - static void rs_clear(void *priv_rate) { struct iwl_priv *priv = (struct iwl_priv *) priv_rate; - IWL_DEBUG_RATE("NOP\n"); + IWL_DEBUG_RATE("enter\n"); priv->lq_mngr.lq_ready = 0; #ifdef CONFIG_IWLWIFI_HT @@ -2009,6 +1981,8 @@ static void rs_clear(void *priv_rate) iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED); #endif /*CONFIG_IWLWIFI_HT_AGG */ #endif /* CONFIG_IWLWIFI_HT */ + + IWL_DEBUG_RATE("leave\n"); } static void rs_free_sta(void *priv, void *priv_sta) @@ -2029,7 +2003,7 @@ static struct rate_control_ops rs_ops = { .rate_init = rs_rate_init, .clear = rs_clear, .alloc = rs_alloc, - .free = rs_free, + .free = NULL, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, }; @@ -2101,24 +2075,24 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) break; i = j; } - sta_info_put(sta); /* Display the average rate of all samples taken. * * NOTE: We multiple # of samples by 2 since the IEEE measurement * added from iwl_rates is actually 2X the rate */ if (samples) - count += sprintf( - &buf[count], + count += sprintf(&buf[count], "\nAverage rate is %3d.%02dMbs over last %4dms\n" "%3d%% success (%d good packets over %d tries)\n", success / (2 * samples), (success * 5 / samples) % 10, max_time, good * 100 / samples, good, samples); else count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); - count += sprintf(&buf[count], "\nrate scale type %d anntena %d \n", - lq_type, antenna); + count += sprintf(&buf[count], "\nrate scale type %d anntena %d " + "active_search %d rate index %d\n", lq_type, antenna, + rs_priv->search_better_tbl, sta->last_txrate); + sta_info_put(sta); return count; } diff --git a/drivers/net/wireless/iwl-4965-rs.h b/drivers/net/wireless/iwl-4965-rs.h index aa9aae5..35d2044 100644 --- a/drivers/net/wireless/iwl-4965-rs.h +++ b/drivers/net/wireless/iwl-4965-rs.h @@ -27,7 +27,6 @@ #ifndef __iwl_4965_rs_h__ #define __iwl_4965_rs_h__ -#include "iwl-hw.h" #include "iwl-4965.h" struct iwl_rate_info { @@ -171,10 +170,35 @@ enum { #define IWL_MIN_RSSI_VAL -100 #define IWL_MAX_RSSI_VAL 0 -extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; +#define IWL_LEGACY_SWITCH_ANTENNA 0 +#define IWL_LECACY_SWITCH_SISO 1 +#define IWL_LEGACY_SWITCH_MIMO 2 + +#define IWL_RS_GOOD_RATIO 12800 + +#define IWL_ACTION_LIMIT 3 +#define IWL_LEGACY_FAILURE_LIMIT 160 +#define IWL_LEGACY_SUCCESS_LIMIT 480 +#define IWL_LEGACY_TABLE_COUNT 160 + +#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 +#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 +#define IWL_NONE_LEGACY_TABLE_COUNT 1500 + +#define IWL_RATE_SCALE_SWITCH (10880) + +#define IWL_SISO_SWITCH_ANTENNA 0 +#define IWL_SISO_SWITCH_MIMO 1 +#define IWL_SISO_SWITCH_GI 2 + +#define IWL_MIMO_SWITCH_ANTENNA_A 0 +#define IWL_MIMO_SWITCH_ANTENNA_B 1 +#define IWL_MIMO_SWITCH_GI 2 #define LQ_SIZE 2 +extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; + enum iwl_table_type { LQ_NONE, LQ_G, @@ -191,53 +215,17 @@ enum iwl_antenna_type { ANT_BOTH, }; -static inline int iwl_rate_index_from_plcp(int plcp) -{ - int i = 0; - - if (plcp & RATE_MCS_HT_MSK) { - i = (plcp & 0xff); - - if (i >= IWL_RATE_MIMO_6M_PLCP) - i = i - IWL_RATE_MIMO_6M_PLCP; - - i += IWL_FIRST_OFDM_RATE; - /* skip 9M not supported in ht*/ - if (i >= IWL_RATE_9M_INDEX) - i += 1; - if ((i >= IWL_FIRST_OFDM_RATE) && - (i <= IWL_LAST_OFDM_RATE)) - return i; - } else { - for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) - if (iwl_rates[i].plcp == (plcp &0xFF)) - return i; - } - return -1; -} - -static inline u8 iwl_rate_get_lowest_plcp(int rate_mask) -{ - u8 i; - - for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl_rates[i].next_ieee) { - if (rate_mask & (1 << i)) - return iwl_rates[i].plcp; - } - - return IWL_RATE_INVALID; -} - static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; + if (rate == IWL_RATE_INVALID) rate = rate_index; return rate; } -#if IWL == 4965 +extern int iwl_rate_index_from_plcp(int plcp); + /** * iwl_fill_rs_info - Fill an output text buffer with the rate representation * @@ -274,13 +262,5 @@ extern void iwl_rate_control_register(struct ieee80211_hw *hw); * the driver is unloaded. */ extern void iwl_rate_control_unregister(struct ieee80211_hw *hw); -#else -static inline int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, - u8 sta_id) -{ return -ENOTSUPP; } -static inline void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) {} -static inline void iwl_rate_control_register(struct ieee80211_hw *hw) {} -static inline void iwl_rate_control_unregister(struct ieee80211_hw *hw) {} -#endif /* IWL == 4965 */ #endif diff --git a/drivers/net/wireless/iwl-4965.c b/drivers/net/wireless/iwl-4965.c index a78cc8c..68b6d52 100644 --- a/drivers/net/wireless/iwl-4965.c +++ b/drivers/net/wireless/iwl-4965.c @@ -209,14 +209,14 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) iwl_set_bits_mask_restricted_reg( - priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_POWER_SRC_VAUX, - ~APMG_PS_CTRL_REG_MSK_POWER_SRC); + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); } else iwl_set_bits_mask_restricted_reg( - priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN, - ~APMG_PS_CTRL_REG_MSK_POWER_SRC); + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -451,14 +451,14 @@ int iwl_hw_nic_init(struct iwl_priv *priv) iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, - APMG_CLK_REG_VAL_DMA_CLK_RQT | - APMG_CLK_REG_VAL_BSM_CLK_RQT); + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); udelay(20); - iwl_set_bits_restricted_reg(priv, ALM_APMG_PCIDEV_STT, - APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE); + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_restricted_access(priv); iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); @@ -513,12 +513,12 @@ int iwl_hw_nic_init(struct iwl_priv *priv) return rc; } - iwl_read_restricted_reg(priv, ALM_APMG_PS_CTL); - iwl_set_bits_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ); + iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG); + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_restricted_reg(priv, ALM_APMG_PS_CTL, - APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -644,14 +644,14 @@ int iwl_hw_nic_reset(struct iwl_priv *priv) rc = iwl_grab_restricted_access(priv); if (!rc) { - iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN, - APMG_CLK_REG_VAL_DMA_CLK_RQT | - APMG_CLK_REG_VAL_BSM_CLK_RQT); + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl_set_bits_restricted_reg(priv, ALM_APMG_PCIDEV_STT, - APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE); + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_restricted_access(priv); } @@ -1809,20 +1809,6 @@ int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) return -EINVAL; } -#define TX_POWER_IWL_ILLEGAL_VDET -100000 -#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 -#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18 -#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34 -#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17 -#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20 -#define TX_POWER_IWL_NOMINAL_POWER 26 -#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1 -#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7 -#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11 -#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1 -#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) -#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) - static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) { s32 sign = 1; @@ -2520,7 +2506,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, */ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) { - struct iwl_tx_power_table_cmd cmd = { 0 }; + struct iwl_txpowertable_cmd cmd = { 0 }; int rc = 0; u8 band = 0; u8 is_fat = 0; @@ -2540,12 +2526,11 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) is_fat = is_fat_channel(priv->active_rxon.flags); if (is_fat && - (priv->active_rxon.flags & RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK)) + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; cmd.band = band; cmd.channel = priv->active_rxon.channel; - cmd.channel_normal_width = 0; rc = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), @@ -2574,7 +2559,7 @@ int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) is_fat = is_fat_channel(priv->staging_rxon.flags); if (is_fat && - (priv->active_rxon.flags & RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK)) + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; cmd.band = band; @@ -2798,23 +2783,6 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, return 0; } -#define IWL4965_LEGACY_SWITCH_ANTENNA 0 -#define IWL4965_LECACY_SWITCH_SISO 1 -#define IWL4965_LEGACY_SWITCH_MIMO 2 - -#define IWL4965_GOOD_RATIO 12800 - -#define IWL_ACTION_LIMIT 3 -#define IWL4965_LEGACY_FAILURE_LIMIT 160 -#define IWL4965_LEGACY_SUCCESS_LIMIT 480 -#define IWL4965_LEGACY_TABLE_COUNT 160 - -#define IWL4965_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL4965_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL4965_NONE_LEGACY_TABLE_COUNT 1500 - -#define IWL4965_RATE_SCALE_SWITCH (10880) - /* Set up Rx receiver/antenna/chain usage in "staging" RXON image. * This should not be used for scan command ... it puts data in wrong place. */ void iwl4965_set_rxon_chain(struct iwl_priv *priv) @@ -4113,7 +4081,7 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, ack = bitmap0 & (1 << i); IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", ack? "ACK":"NACK", i, idx, agg->start_idx + i); - iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 1, + iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0, agg->rate_n_flags); } @@ -4176,10 +4144,6 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, } -#define STA_MODIFY_ADDBA_TID_MSK 0x08 -#define STA_MODIFY_DELBA_TID_MSK 0x10 -#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) - static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) { iwl_write_restricted_reg(priv, @@ -4189,7 +4153,7 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) } static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, - u16 txq_id) + u16 txq_id) { u32 tbl_dw_addr; u32 tbl_dw; @@ -4201,7 +4165,11 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr); - ((u16 *)&tbl_dw)[txq_id & 0x1] = scd_q2ratid; + + if (txq_id & 0x1) + tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); + else + tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw); @@ -4425,7 +4393,8 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) if (iwl_is_fat_tx_allowed(priv, ht_info)) rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; else - rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY_MSK; + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { IWL_DEBUG_ASSOC("control diff than current %d %d\n", @@ -4435,14 +4404,13 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) return; } - rxon->flags &= ~RXON_FLG_CONTROL_CHANNEL_LOCATION_MSK; - + /* Note: control channel is oposit to extension channel */ switch (ht_info->extension_chan_offset) { case IWL_EXT_CHANNEL_OFFSET_ABOVE: - rxon->flags |= RXON_FLG_CONTROL_CHANNEL_LOC_LOW_MSK; + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); break; case IWL_EXT_CHANNEL_OFFSET_BELOW: - rxon->flags |= RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK; + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; case IWL_EXT_CHANNEL_OFFSET_AUTO: rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; diff --git a/drivers/net/wireless/iwl-4965.h b/drivers/net/wireless/iwl-4965.h index af5215f..4c63b3b 100644 --- a/drivers/net/wireless/iwl-4965.h +++ b/drivers/net/wireless/iwl-4965.h @@ -29,45 +29,6 @@ struct iwl_priv; struct sta_ht_info; -#if IWL != 4965 -/* - * In non IWL == 4965 builds, these must build to nothing in order to allow - * the common code to not have several #if IWL == XXXX / #endif blocks - */ -static inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv) {} - -static inline void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, - int is_ap) {} -static inline void iwl4965_set_rxon_ht(struct iwl_priv *priv, - struct sta_ht_info *ht_info) {} - -static inline void iwl4965_set_rxon_chain(struct iwl_priv *priv) {} -static inline int iwl4965_tx_cmd(struct iwl_priv *priv, - struct iwl_cmd *out_cmd, - u8 sta_id, dma_addr_t txcmd_phys, - struct ieee80211_hdr *hdr, u8 hdr_len, - struct ieee80211_tx_control *ctrl, - void *sta_in) { return 0; } -static inline int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 len) { return 0; } -static inline int iwl4965_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ return 0; } -static inline int iwl4965_alive_notify(struct iwl_priv *priv) { return 0; } -static inline void iwl4965_update_rate_scaling(struct iwl_priv *priv, - u8 mode) {} -static inline void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index) -{} -static inline void iwl4965_chain_noise_reset(struct iwl_priv *priv) {} -static inline void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, - u8 force) {} -static inline int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, - u16 channel, - const struct iwl_eeprom_channel *eeprom_ch, - u8 fat_extension_channel) { return 0; } -static inline void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) {} -#else /* IWL == 4965 */ /* * Forward declare iwl-4965.c functions for iwl-base.c */ @@ -159,6 +120,37 @@ struct iwl_kw { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS (3) +#define TX_POWER_IWL_ILLEGAL_VDET -100000 +#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 +#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18 +#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34 +#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17 +#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20 +#define TX_POWER_IWL_NOMINAL_POWER 26 +#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1 +#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7 +#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11 +#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1 +#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) +#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) + +#define IWL4965_LEGACY_SWITCH_ANTENNA 0 +#define IWL4965_LECACY_SWITCH_SISO 1 +#define IWL4965_LEGACY_SWITCH_MIMO 2 + +#define IWL4965_GOOD_RATIO 12800 + +#define IWL_ACTION_LIMIT 3 +#define IWL4965_LEGACY_FAILURE_LIMIT 160 +#define IWL4965_LEGACY_SUCCESS_LIMIT 480 +#define IWL4965_LEGACY_TABLE_COUNT 160 + +#define IWL4965_NONE_LEGACY_FAILURE_LIMIT 400 +#define IWL4965_NONE_LEGACY_SUCCESS_LIMIT 4500 +#define IWL4965_NONE_LEGACY_TABLE_COUNT 1500 + +#define IWL4965_RATE_SCALE_SWITCH (10880) + struct iwl_traffic_load { unsigned long time_stamp; u32 packet_count[TID_QUEUE_MAX_SIZE]; @@ -363,5 +355,4 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_TIMEOUT 10 #define EEPROM_SEM_RETRY_LIMIT 1000 -#endif /* IWL == 4965 */ #endif /* __iwl_4965_h__ */ diff --git a/drivers/net/wireless/iwl-base.c b/drivers/net/wireless/iwl-base.c deleted file mode 100644 index 4b80728..0000000 --- a/drivers/net/wireless/iwl-base.c +++ /dev/null @@ -1,9643 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -/* - * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets - * by defining IWL to either 3945 or 4965. The Makefile used when building - * the base targets will create base-3945.o and base-4965.o - * - * The eventual goal is to move as many of the #if IWL / #endif blocks out of - * this file and into the hardware specific implementation files (iwl-XXXX.c) - * and leave only the common (non #ifdef sprinkled) code in this file - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "iwlwifi.h" -#include "iwl-helpers.h" - -#ifdef CONFIG_IWLWIFI_DEBUG -u32 iwl_debug_level; -#endif - -/****************************************************************************** - * - * module boiler plate - * - ******************************************************************************/ - -/* module parameters */ -int iwl_param_disable_hw_scan; -int iwl_param_debug; -int iwl_param_disable; /* def: enable radio */ -int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ -int iwl_param_hwcrypto; /* def: using software encryption */ -int iwl_param_qos_enable = 1; -int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; - -/* - * module name, copyright, version, etc. - * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk - */ - -#if IWL == 3945 -#define DRV_DESCRIPTION \ -"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux" -#elif IWL == 4965 -#define DRV_DESCRIPTION \ -"Intel(R) Wireless WiFi Link 4965AGN driver for Linux" -#else -BUILD_BUG() -#endif - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT -#define VS "s" -#else -#define VS -#endif - -#define IWLWIFI_VERSION "0.1.11k" VD VS -#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" -#define DRV_VERSION IWLWIFI_VERSION - -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL3945_UCODE_API "-1" -#define IWL4965_UCODE_API "-1" - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL"); - -__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - -static const struct ieee80211_hw_mode *iwl_get_hw_mode( - struct iwl_priv *priv, int mode) -{ - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; -} - -static int iwl_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static const char *iwl_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - -static void iwl_print_hex_dump(int level, void *p, u32 len) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -#endif -} - -/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** - * DMA services - * - * Theory of operation - * - * A queue is a circular buffers with 'Read' and 'Write' pointers. - * 2 empty entries always kept in the buffer to protect from overflow. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. - * - * The IPW operates with six queues, one receive queue in the device's - * sram, one transmit queue for sending commands to the device firmware, - * and four transmit queues for data. - * - * The four transmit queues allow for performing quality of service (qos) - * transmissions as per the 802.11 protocol. Currently Linux does not - * provide a mechanism to the user for utilizing prioritized queues, so - * we only utilize the first data transmit queue (queue1). - ***************************************************/ - -static int iwl_queue_space(const struct iwl_queue *q) -{ - int s = q->last_used - q->first_empty; - - if (q->last_used > q->first_empty) - s -= q->n_bd; - - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_inc_wrap(int index, int n_bd) -{ - return ++index & (n_bd - 1); -} - -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_dec_wrap(int index, int n_bd) -{ - return --index & (n_bd - 1); -} - -static inline int x2_queue_used(const struct iwl_queue *q, int i) -{ - return q->first_empty > q->last_used ? - (i >= q->last_used && i < q->first_empty) : - !(i < q->last_used && i >= q->first_empty); -} - -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) -{ - if (is_huge) - return q->n_window; - - return index & (q->n_window - 1); -} - -static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, - int count, int slots_num, u32 id) -{ - q->n_bd = count; - q->n_window = slots_num; - q->id = id; - - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ - BUG_ON(!is_power_of_2(count)); - - /* slots_num must be power-of-two size, otherwise - * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); - - q->low_mark = q->n_window / 4; - if (q->low_mark < 4) - q->low_mark = 4; - - q->high_mark = q->n_window / 8; - if (q->high_mark < 2) - q->high_mark = 2; - - q->first_empty = q->last_used = 0; - - return 0; -} - -static int iwl_tx_queue_alloc(struct iwl_priv *priv, - struct iwl_tx_queue *txq, u32 id) -{ - struct pci_dev *dev = priv->pci_dev; - - if (id != IWL_CMD_QUEUE_NUM) { - txq->txb = kmalloc(sizeof(txq->txb[0]) * - TFD_QUEUE_SIZE_MAX, GFP_KERNEL); - if (!txq->txb) { - IWL_ERROR("kmalloc for auxilary BD " - "structures failed\n"); - goto error; - } - } else - txq->txb = NULL; - - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, - &txq->q.dma_addr); - - if (!txq->bd) { - IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); - goto error; - } - txq->q.id = id; - - return 0; - - error: - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - return -ENOMEM; -} - -int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int slots_num, u32 txq_id) -{ - struct pci_dev *dev = priv->pci_dev; - int len; - int rc = 0; - - /* alocate command space + one big command for scan since scan - * command is very huge the system will not have two scan at the - * same time */ - len = sizeof(struct iwl_cmd) * slots_num; - if (txq_id == IWL_CMD_QUEUE_NUM); - len += IWL_MAX_SCAN_SIZE; - txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); - if (!txq->cmd) - return -ENOMEM; - - rc = iwl_tx_queue_alloc(priv, txq, txq_id); - if (rc) { - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - return -ENOMEM; - } - txq->need_update = 0; - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - - iwl_hw_tx_queue_init(priv, txq); - - return 0; -} - -/** - * iwl_tx_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. txq itself is not freed. - * - */ -void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) -{ - struct iwl_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; - int len; - - if (q->n_bd == 0) - return; - - /* first, empty all BD's */ - for (; q->first_empty != q->last_used; - q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) - iwl_hw_txq_free_tfd(priv, txq); - - len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM); - len += IWL_MAX_SCAN_SIZE; - - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - /* free buffers belonging to queue itself */ - if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); - - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - /* 0 fill whole structure */ - memset(txq, 0, sizeof(*txq)); -} - -const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -/*************** STATION TABLE MANAGEMENT **** - * - * NOTE: This needs to be overhauled to better synchronize between - * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c - * - * mac80211 should also be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ - -static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *bssid, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) { - index = IWL_AP_ID; - if ((priv->stations[index].used)) - priv->stations[index].used = 0; - } else if (is_broadcast_ether_addr(bssid)) { - index = IWL_BROADCAST_ID; - if ((priv->stations[index].used)) - priv->stations[index].used = 0; - } else { - for (i = IWL_STA_ID; i < priv->num_stations + IWL_STA_ID; i++) { - if (priv->stations[i].used && - !compare_ether_addr(priv->stations[i].sta.sta.addr, - bssid)) { - index = i; - priv->stations[index].used = 0; - break; - } - } - } - if (index != IWL_INVALID_STATION) { - if (priv->num_stations > 0) - priv->num_stations--; - } - - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} - -static void iwl_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid, int is_ap, u8 flags) -{ - int i = IWL_STATION_COUNT; - int index = IWL_INVALID_STATION; - struct iwl_station_entry *station; - unsigned long flags_spin; -#if IWL == 3945 - u8 rate; -#endif - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) { - index = IWL_AP_ID; - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, - bssid)) - goto done; - } else if (is_broadcast_ether_addr(bssid)) { - index = IWL_BROADCAST_ID; - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, - bssid)) - goto done; - } else { - for (i = IWL_STA_ID; i < priv->num_stations + IWL_STA_ID; i++) { - if (priv->stations[i].used && - !compare_ether_addr(priv->stations[i].sta.sta.addr, - bssid)) - goto done; - - if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; - } - } - - if (index != IWL_INVALID_STATION) - i = index; - - if (i == IWL_STATION_COUNT) { - index = IWL_INVALID_STATION; - goto done; - } - - IWL_DEBUG_ASSOC("Adding STA ID %d: " MAC_FMT "\n", i, MAC_ARG(bssid)); - station = &priv->stations[i]; - - station->used = 1; - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); - memcpy(station->sta.sta.addr, bssid, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = i; - station->sta.station_flags = 0; -#if IWL == 3945 - rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP : - IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag; - - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); - - station->sta.station_flags |= STA_FLG_TX_RATE_MSK; - - station->current_rate.rate_n_flags = - le16_to_cpu(station->sta.rate_n_flags); -#endif - -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT - if (is_ap) { - iwl4965_set_ht_add_station(priv, i); - iwl4965_set_rxon_chain(priv); - } -#endif /*CONFIG_IWLWIFI_HT*/ -#endif - - priv->num_stations++; - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_station(priv, &station->sta, flags); - return i; - - done: - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; -} - -/*************** DRIVER STATUS FUNCTIONS *****/ - -static inline int iwl_is_ready(struct iwl_priv *priv) -{ - /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are - * set but EXIT_PENDING is not */ - return test_bit(STATUS_READY, &priv->status) && - test_bit(STATUS_GEO_CONFIGURED, &priv->status) && - !test_bit(STATUS_EXIT_PENDING, &priv->status); -} - -static inline int iwl_is_alive(struct iwl_priv *priv) -{ - return test_bit(STATUS_ALIVE, &priv->status); -} - -static inline int iwl_is_init(struct iwl_priv *priv) -{ - return test_bit(STATUS_INIT, &priv->status); -} - -static inline int iwl_is_rfkill(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); -} - -static inline int iwl_is_ready_rf(struct iwl_priv *priv) -{ - - if (iwl_is_rfkill(priv)) - return 0; - - return iwl_is_ready(priv); -} - -/*************** HOST COMMAND QUEUE FUNCTIONS *****/ - -#define IWL_CMD(x) case x : return #x - -static const char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IWL_CMD(REPLY_ALIVE); - IWL_CMD(REPLY_ERROR); - IWL_CMD(REPLY_RXON); - IWL_CMD(REPLY_RXON_ASSOC); - IWL_CMD(REPLY_QOS_PARAM); - IWL_CMD(REPLY_RXON_TIMING); - IWL_CMD(REPLY_ADD_STA); - IWL_CMD(REPLY_REMOVE_STA); - IWL_CMD(REPLY_REMOVE_ALL_STA); -#if IWL == 3945 - IWL_CMD(REPLY_3945_RX); -#endif - IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); - IWL_CMD(REPLY_LEDS_CMD); - IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); - IWL_CMD(RADAR_NOTIFICATION); - IWL_CMD(REPLY_QUIET_CMD); - IWL_CMD(REPLY_CHANNEL_SWITCH); - IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); - IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); - IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); - IWL_CMD(POWER_TABLE_CMD); - IWL_CMD(PM_SLEEP_NOTIFICATION); - IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); - IWL_CMD(REPLY_SCAN_CMD); - IWL_CMD(REPLY_SCAN_ABORT_CMD); - IWL_CMD(SCAN_START_NOTIFICATION); - IWL_CMD(SCAN_RESULTS_NOTIFICATION); - IWL_CMD(SCAN_COMPLETE_NOTIFICATION); - IWL_CMD(BEACON_NOTIFICATION); - IWL_CMD(REPLY_TX_BEACON); - IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); - IWL_CMD(QUIET_NOTIFICATION); - IWL_CMD(REPLY_TX_PWR_TABLE_CMD); - IWL_CMD(MEASURE_ABORT_NOTIFICATION); - IWL_CMD(REPLY_BT_CONFIG); - IWL_CMD(REPLY_STATISTICS_CMD); - IWL_CMD(STATISTICS_NOTIFICATION); - IWL_CMD(REPLY_CARD_STATE_CMD); - IWL_CMD(CARD_STATE_NOTIFICATION); - IWL_CMD(MISSED_BEACONS_NOTIFICATION); -#if IWL == 4965 - IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); - IWL_CMD(SENSITIVITY_CMD); - IWL_CMD(REPLY_PHY_CALIBRATION_CMD); - IWL_CMD(REPLY_RX_PHY_CMD); - IWL_CMD(REPLY_RX_MPDU_CMD); - IWL_CMD(REPLY_4965_RX); - IWL_CMD(REPLY_COMPRESSED_BA); -#endif - default: - return "UNKNOWN"; - - } -} - -#define HOST_COMPLETE_TIMEOUT (HZ / 2) - -/** - * iwl_enqueue_hcmd - enqueue a uCode command - * @priv: device private data point - * @cmd: a point to the ucode command structure - * - * The function returns < 0 values to indicate the operation is - * failed. On success, it turns the index (> 0) of command in the - * command queue. - */ -static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - struct iwl_cmd *out_cmd; - u32 idx; - u16 fix_size = (u16)(cmd->meta.len + sizeof(out_cmd->hdr)); - dma_addr_t phys_addr; -#if IWL == 3945 - int pad; - u16 count; -#endif - int rc = 0; - unsigned long flags; - - /* If any of the command structures end up being larger than - * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then - * we will need to increase the size of the TFD entries */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); - - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERROR("No space for Tx\n"); - return -ENOSPC; - } - - spin_lock_irqsave(&priv->hcmd_lock, flags); - - tfd = &txq->bd[q->first_empty]; - memset(tfd, 0, sizeof(*tfd)); - - control_flags = (u32 *) tfd; - - idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); - out_cmd = &txq->cmd[idx]; - - out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); - memcpy(&out_cmd->cmd.payload, cmd->data, cmd->meta.len); - - /* At this point, the out_cmd now has all of the incoming cmd - * information */ - - out_cmd->hdr.flags = 0; - out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->first_empty)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); - - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl_cmd, hdr); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - -#if IWL == 3945 - pad = U32_PAD(out_cmd->meta.len); - count = TFD_CTL_COUNT_GET(*control_flags); - *control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad); -#endif - - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); - - txq->need_update = 1; -#if IWL == 4965 - rc = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - iwl_tx_queue_update_write_ptr(priv, txq); -#elif IWL == 3945 - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - rc = iwl_tx_queue_update_write_ptr(priv, txq); -#endif - - spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return rc ? rc : idx; -} - -static int __iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - int rc; - - cmd->meta.len = cmd->len; - - rc = iwl_enqueue_hcmd(priv, cmd); - if (rc < 0) { - IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), rc); - return -ENOSPC; - } - return rc; -} - -int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - int ret; - - BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); - - /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->meta.flags & CMD_WANT_SKB); - - /* An asynchronous command MUST have a callback. */ - BUG_ON(!cmd->meta.u.callback); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EBUSY; - - ret = __iwl_send_cmd(priv, cmd); - if (ret < 0) - return ret; - - return 0; -} - -int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - int cmd_idx; - int ret; - static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ - - BUG_ON(cmd->meta.flags & CMD_ASYNC); - - /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->meta.u.callback != NULL); - - if (atomic_xchg(&entry, 1)) { - IWL_ERROR("Error sending %s: Already sending a host command\n", - get_cmd_string(cmd->id)); - return -EBUSY; - } - - set_bit(STATUS_HCMD_ACTIVE, &priv->status); - - if (cmd->meta.flags & CMD_WANT_SKB) - cmd->meta.source = &cmd->meta; - - ret = __iwl_send_cmd(priv, cmd); - if (ret < 0) - goto out; - - cmd_idx = ret; - - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - !test_bit(STATUS_HCMD_ACTIVE, &priv->status), - HOST_COMPLETE_TIMEOUT); - if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { - IWL_ERROR("Error sending %s: time out after %dms.\n", - get_cmd_string(cmd->id), - jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - ret = -ETIMEDOUT; - goto cancel; - } - } - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", - get_cmd_string(cmd->id)); - ret = -ECANCELED; - goto fail; - } - if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_DEBUG_INFO("Command %s failed: FW Error\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto fail; - } - if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { - IWL_ERROR("Error: Response NULL in '%s'\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto out; - } - - ret = 0; - goto out; - -cancel: - if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl_cmd *qcmd; - - /* Cancel the CMD_WANT_SKB flag for the cmd in the - * TX cmd queue. Otherwise in case the cmd comes - * in later, it will possibly set an invalid - * address (cmd->meta.source). */ - qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; - qcmd->meta.flags &= ~CMD_WANT_SKB; - } -fail: - if (cmd->meta.u.skb) { - dev_kfree_skb_any(cmd->meta.u.skb); - cmd->meta.u.skb = NULL; - } -out: - atomic_set(&entry, 0); - return ret; -} - -int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - /* A command can not be asynchronous AND expect an SKB to be set. */ - BUG_ON((cmd->meta.flags & CMD_ASYNC) && - (cmd->meta.flags & CMD_WANT_SKB)); - - if (cmd->meta.flags & CMD_ASYNC) - return iwl_send_cmd_async(priv, cmd); - - return iwl_send_cmd_sync(priv, cmd); -} - -int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) -{ - struct iwl_host_cmd cmd = { - .id = id, - .len = len, - .data = data, - }; - - return iwl_send_cmd_sync(priv, &cmd); -} - -static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) -{ - struct iwl_host_cmd cmd = { - .id = id, - .len = sizeof(val), - .data = &val, - }; - - return iwl_send_cmd_sync(priv, &cmd); -} - -int iwl_send_statistics_request(struct iwl_priv *priv) -{ - return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); -} - -/** - * iwl_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling the this fnction -*/ -static int iwl_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 rc; - - /* Remove this station if it happens to already exist */ - iwl_remove_station(priv, addr, is_ap); - - rc = iwl_add_station(priv, addr, is_ap, 0); - - iwl4965_add_station(priv, addr, is_ap); - - return rc; -} - -/** - * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON - * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz - * @channel: Any channel valid for the requested phymode - - * In addition to setting the staging RXON, priv->phymode is also set. - * - * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the phymode - */ -static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) -{ - if (!iwl_get_channel_info(priv, phymode, channel)) { - IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); - return -EINVAL; - } - - if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) - return 0; - - priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) - priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; - else - priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - - priv->phymode = phymode; - - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); - - return 0; -} - -/** - * iwl_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ -static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) -{ - int error = 0; - int counter = 1; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARNING("check 24G fields %d | %d\n", - counter++, error); - } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARNING("check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARNING("check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARNING("check mac addr %d | %d\n", counter++, error); - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARNING("check basic rate %d | %d\n", counter++, error); - - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARNING("check assoc id %d | %d\n", counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARNING("check CCK and short slot %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARNING("check CCK & auto detect %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARNING("check TGG and auto detect %d | %d\n", - counter++, error); - -#if IWL == 3945 - if ((rxon->flags & RXON_FLG_DIS_DIV_MSK)) - error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK | - RXON_FLG_ANT_A_MSK)) == 0); - if (error) - IWL_WARNING("check antenna %d %d\n", counter++, error); -#endif - if (error) - IWL_WARNING("Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); - return -1; - } - return 0; -} - -/** - * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit - * @priv: staging_rxon is comapred to active_rxon - * - * If the RXON structure is changing sufficient to require a new - * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 - * to indicate a new tune is required. - */ -static int iwl_full_rxon_required(struct iwl_priv *priv) -{ - - /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || - compare_ether_addr(priv->staging_rxon.bssid_addr, - priv->active_rxon.bssid_addr) || - compare_ether_addr(priv->staging_rxon.node_addr, - priv->active_rxon.node_addr) || - compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, - priv->active_rxon.wlap_bssid_addr) || - (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || - (priv->staging_rxon.channel != priv->active_rxon.channel) || - (priv->staging_rxon.air_propagation != - priv->active_rxon.air_propagation) || -#if IWL == 4965 - (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != - priv->active_rxon.ofdm_ht_single_stream_basic_rates) || - (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != - priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || - (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || -#endif - (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) - return 1; - - /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can - * be updated with the RXON_ASSOC command -- however only some - * flag transitions are allowed using RXON_ASSOC */ - - /* Check if we are not switching bands */ - if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != - (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) - return 1; - - /* Check if we are switching association toggle */ - if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != - (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) - return 1; - - return 0; -} - -static int iwl_send_rxon_assoc(struct iwl_priv *priv) -{ - int rc = 0; - struct iwl_rx_packet *res = NULL; - struct iwl_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { - .id = REPLY_RXON_ASSOC, - .len = sizeof(rxon_assoc), - .meta.flags = CMD_WANT_SKB, - .data = &rxon_assoc, - }; - const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && -#if IWL == 4965 - (rxon1->ofdm_ht_single_stream_basic_rates == - rxon2->ofdm_ht_single_stream_basic_rates) && - (rxon1->ofdm_ht_dual_stream_basic_rates == - rxon2->ofdm_ht_dual_stream_basic_rates) && - (rxon1->rx_chain == rxon2->rx_chain) && -#endif - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = priv->staging_rxon.flags; - rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; - rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; - rxon_assoc.reserved = 0; -#if IWL == 4965 - rxon_assoc.ofdm_ht_single_stream_basic_rates = - priv->staging_rxon.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; -#endif - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); - rc = -EIO; - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - -/** - * iwl_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is commited to the hardware and - * the active_rxon structure is updated with the new data. This - * function correctly transitions out of the RXON_ASSOC_MSK state if - * a HW tune is required based on the RXON structure changes. - */ -static int iwl_commit_rxon(struct iwl_priv *priv) -{ - /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - int rc = 0; - - if (!iwl_is_alive(priv)) - return -1; - - /* always get timestamp with Rx frame */ - priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - -#if IWL == 3945 - /* select antenna */ - priv->staging_rxon.flags &= - ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); - priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv); -#endif - - rc = iwl_check_rxon_cmd(&priv->staging_rxon); - if (rc) { - IWL_ERROR("Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* If we don't need to send a full RXON, we can use - * iwl_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); - if (rc) { - IWL_ERROR("Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - - return 0; - } - -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_SENSITIVITY - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - if (!priv->error_recovering) - priv->start_calib = 0; - - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWLWIFI_SENSITIVITY */ -#endif /* IWL == 4965 */ - - /* If we are currently associated and the new config requires - * an RXON_ASSOC and the new config wants the associated mask enabled, - * we must clear the associated from the active configuration - * before we apply the new config */ - if (iwl_is_associated(priv) && - (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { - IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), - &priv->active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (rc) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERROR("Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; - } - - /* The RXON bit toggling will have cleared out the - * station table in the uCode, so blank it in the driver - * as well */ - iwl_clear_stations_table(priv); - } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { - /* When switching from non-associated to associated, the - * uCode clears out the station table; so clear it in the - * driver as well */ - iwl_clear_stations_table(priv); - } - - IWL_DEBUG_INFO("Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = " MAC_FMT "\n", - ((priv->staging_rxon.filter_flags & - RXON_FILTER_ASSOC_MSK) ? "" : "out"), - le16_to_cpu(priv->staging_rxon.channel), - MAC_ARG(priv->staging_rxon.bssid_addr)); - - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); - if (rc) { - IWL_ERROR("Error setting new configuration (%d).\n", rc); - return rc; - } - -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_SENSITIVITY - if (!priv->error_recovering) - priv->start_calib = 0; - - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWLWIFI_SENSITIVITY */ -#endif /* IWL == 4965 */ - - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - - /* If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = iwl_hw_reg_send_txpower(priv); - if (rc) { - IWL_ERROR("Error setting Tx power (%d).\n", rc); - return rc; - } - - /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == - IWL_INVALID_STATION) { - IWL_ERROR("Error adding BROADCAST address for transmit.\n"); - return -EIO; - } - - /* If we have set the ASSOC_MSK and we are in BSS mode then - * add the IWL_AP_ID to the station rate table */ - if (iwl_is_associated(priv) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) - == IWL_INVALID_STATION) { - IWL_ERROR("Error adding AP address for transmit.\n"); - return -EIO; - } - } - - /* Init the hardware's rate fallback order based on the - * phymode */ - rc = iwl3945_init_hw_rate_table(priv); - if (rc) { - IWL_ERROR("Error setting HW rate table: %02X\n", rc); - return -EIO; - } - - return 0; -} - -static int iwl_send_bt_config(struct iwl_priv *priv) -{ - struct iwl_bt_cmd bt_cmd = { - .flags = 3, - .lead_time = 0xAA, - .max_kill = 1, - .kill_ack_mask = 0, - .kill_cts_mask = 0, - }; - - return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl_bt_cmd), &bt_cmd); -} - -static int iwl_send_scan_abort(struct iwl_priv *priv) -{ - int rc = 0; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SCAN_ABORT_CMD, - .meta.flags = CMD_WANT_SKB, - }; - - /* If there isn't a scan actively going on in the hardware - * then we are in between scan bands and not actually - * actively scanning, so don't send the abort command */ - if (!test_bit(STATUS_SCAN_HW, &priv->status)) { - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - return 0; - } - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) { - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - return rc; - } - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->u.status != CAN_ABORT_STATUS) { - /* The scan abort will return 1 for success or - * 2 for "failure". A failure condition can be - * due to simply not being in an active scan which - * can occur if we send the scan abort before we - * the microcode has notified us that a scan is - * completed. */ - IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - clear_bit(STATUS_SCAN_HW, &priv->status); - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - -static int iwl_card_state_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct sk_buff *skb) -{ - return 1; -} - -/* - * CARD_STATE_CMD - * - * Use: Sets the internal card state to enable, disable, or halt - * - * When in the 'enable' state the card operates as normal. - * When in the 'disable' state, the card enters into a low power mode. - * When in the 'halt' state, the card is shut down and must be fully - * restarted to come back on. - */ -static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_CARD_STATE_CMD, - .len = sizeof(u32), - .data = &flags, - .meta.flags = meta_flag, - }; - - if (meta_flag & CMD_ASYNC) - cmd.meta.u.callback = iwl_card_state_sync_callback; - - return iwl_send_cmd(priv, &cmd); -} - -static int iwl_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) -{ - struct iwl_rx_packet *res = NULL; - - if (!skb) { - IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); - return 1; - } - - res = (struct iwl_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - return 1; - } - - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - break; - default: - break; - } - - /* We didn't cache the SKB; let the caller free it */ - return 1; -} - -int iwl_send_add_station(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags) -{ - struct iwl_rx_packet *res = NULL; - int rc = 0; - struct iwl_host_cmd cmd = { - .id = REPLY_ADD_STA, - .len = sizeof(struct iwl_addsta_cmd), - .meta.flags = flags, - .data = sta, - }; - - if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_add_sta_sync_callback; - else - cmd.meta.flags |= CMD_WANT_SKB; - - rc = iwl_send_cmd(priv, &cmd); - - if (rc || (flags & CMD_ASYNC)) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - rc = -EIO; - } - - if (rc == 0) { - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); - break; - default: - rc = -EIO; - IWL_WARNING("REPLY_ADD_STA failed\n"); - break; - } - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - -static int iwl_update_sta_key_info(struct iwl_priv *priv, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - __le16 key_flags = 0; - - switch (keyconf->alg) { - case ALG_CCMP: - key_flags |= STA_KEY_FLG_CCMP; - key_flags |= cpu_to_le16( - keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - break; - case ALG_TKIP: - case ALG_WEP: - return -EINVAL; - default: - return -EINVAL; - } - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].keyinfo.alg = keyconf->alg; - priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; - memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, - keyconf->keylen); - - memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, - keyconf->keylen); - priv->stations[sta_id].sta.key.key_flags = key_flags; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - spin_unlock_irqrestore(&priv->sta_lock, flags); - - IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); - return 0; -} - -static void iwl_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", - priv->frames_count); - - while (!list_empty(&priv->free_frames)) { - element = priv->free_frames.next; - list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); - priv->frames_count--; - } - - if (priv->frames_count) { - IWL_WARNING("%d frames still in use. Did we lose one?\n", - priv->frames_count); - priv->frames_count = 0; - } -} - -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - struct list_head *element; - if (list_empty(&priv->free_frames)) { - frame = kzalloc(sizeof(*frame), GFP_KERNEL); - if (!frame) { - IWL_ERROR("Could not allocate frame!\n"); - return NULL; - } - - priv->frames_count++; - return frame; - } - - element = priv->free_frames.next; - list_del(element); - return list_entry(element, struct iwl_frame, list); -} - -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) -{ - memset(frame, 0, sizeof(*frame)); - list_add(&frame->list, &priv->free_frames); -} - -unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left) -{ - - if (!iwl_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) - return 0; - - if (priv->ibss_beacon->len > left) - return 0; - - memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); - - return priv->ibss_beacon->len; -} - -static int iwl_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - unsigned int frame_size; - int rc; - u8 rate; - - frame = iwl_get_free_frame(priv); - - if (!frame) { - IWL_ERROR("Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } - - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } - - frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); - - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); - - iwl_free_frame(priv, frame); - - return rc; -} - -/****************************************************************************** - * - * EEPROM related functions - * - ******************************************************************************/ - -static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) -{ - memcpy(mac, priv->eeprom.mac_address, 6); -} - -/** - * iwl_eeprom_init - read EEPROM contents - * - * Load the EEPROM from adapter into priv->eeprom - * - * NOTE: This routine uses the non-debug IO access functions. - */ -int iwl_eeprom_init(struct iwl_priv *priv) -{ - u16 *e = (u16 *)&priv->eeprom; - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - u32 r; - int sz = sizeof(priv->eeprom); - int rc; - int i; - u16 addr; - - /* The EEPROM structure has several padding buffers within it - * and when adding new EEPROM maps is subject to programmer errors - * which may be very difficult to identify without explicitly - * checking the resulting size of the eeprom map. */ - BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); - - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { - IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); - return -ENOENT; - } - - rc = iwl_eeprom_aqcuire_semaphore(priv); - if (rc < 0) { - IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); - return -ENOENT; - } - - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl_read_restricted(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } - - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { - IWL_ERROR("Time out reading EEPROM[%d]", addr); - rc = -ETIMEDOUT; - goto done; - } - e[addr / 2] = le16_to_cpu(r >> 16); - } - rc = 0; - -done: - iwl_eeprom_release_semaphore(priv); - return rc; -} - -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUG - -/** - * iwl_report_frame - dump frame to syslog during debug sessions - * - * hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type - * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) - * is 3945-specific and gives bad output for 4965. Need to split the - * functionality, keep common stuff here. - */ -void iwl_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - u16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - /* MAC header */ - fc = le16_to_cpu(header->frame_control); - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - u32 rate; - - if (hundred) - title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) - title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate = iwl_rate_index_from_plcp(rate_sym); - if (rate == -1) - rate = 0; - else - rate = iwl_rates[rate].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, fc, header->addr1[5], - length, rssi, channel, rate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); -} -#endif - -static void iwl_unset_hw_setting(struct iwl_priv *priv) -{ - if (priv->hw_setting.shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl_shared), - priv->hw_setting.shared_virt, - priv->hw_setting.shared_phys); -} - -/** - * iwl_supported_rate_to_ie - fill in the supported rate in IE field - * - * return : set the bit for each supported rate insert in ie - */ -static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, - u16 basic_rate, int max_count) -{ - u16 ret_rates = 0, bit; - int i; - u8 *rates; - - rates = &(ie[1]); - - for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { - if (bit & supported_rate) { - ret_rates |= bit; - rates[*ie] = iwl_rates[i].ieee | - ((bit & basic_rate) ? 0x80 : 0x00); - *ie = *ie + 1; - if (*ie >= max_count) - break; - } - } - - return ret_rates; -} - -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT -void static iwl_set_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_capability *ht_cap, - u8 use_wide_chan); -#endif -#endif - -/** - * iwl_fill_probe_req - fill in all required fields and IE for probe request - */ -static u16 iwl_fill_probe_req(struct iwl_priv *priv, - struct ieee80211_mgmt *frame, - int left, int is_direct) -{ - int len = 0; - u8 *pos = NULL; - u16 ret_rates; - - /* Make sure there is enough space for the probe request, - * two mandatory IEs and the data */ - left -= 24; - if (left < 0) - return 0; - len += 24; - - frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); - memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); - frame->seq_ctrl = 0; - - /* fill in our indirect SSID IE */ - /* ...next IE... */ - - left -= 2; - if (left < 0) - return 0; - len += 2; - pos = &(frame->u.probe_req.variable[0]); - *pos++ = WLAN_EID_SSID; - *pos++ = 0; - - /* fill in our direct SSID IE... */ - if (is_direct) { - /* ...next IE... */ - left -= 2 + priv->essid_len; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SSID; - *pos++ = priv->essid_len; - memcpy(pos, priv->essid, priv->essid_len); - pos += priv->essid_len; - len += 2 + priv->essid_len; - } - - /* fill in supported rate */ - /* ...next IE... */ - left -= 2; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SUPP_RATES; - *pos = 0; - ret_rates = priv->active_rate = priv->rates_mask; - priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - - iwl_supported_rate_to_ie(pos, priv->active_rate, - priv->active_rate_basic, left); - len += 2 + *pos; - pos += (*pos) + 1; - ret_rates = ~ret_rates & priv->active_rate; - - if (ret_rates == 0) - goto fill_end; - - /* fill in supported extended rate */ - /* ...next IE... */ - left -= 2; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos = 0; - iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left); - if (*pos > 0) - len += 2 + *pos; -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT - if (is_direct && priv->is_ht_enabled) { - u8 use_wide_chan = 1; - - if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) - use_wide_chan = 0; - pos += (*pos) + 1; - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_capability); - iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos, - use_wide_chan); - len += 2 + sizeof(struct ieee80211_ht_capability); - } -#endif /*CONFIG_IWLWIFI_HT */ -#endif - - fill_end: - return (u16)len; -} - -/* - * QoS support -*/ -#ifdef CONFIG_IWLWIFI_QOS -static int iwl_send_qos_params_command(struct iwl_priv *priv, - struct iwl_qosparam_cmd *qos) -{ - - return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, - sizeof(struct iwl_qosparam_cmd), qos); -} - -static void iwl_reset_qos(struct iwl_priv *priv) -{ - u16 cw_min = 15; - u16 cw_max = 1023; - u8 aifs = 2; - u8 is_legacy = 0; - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.qos_active = 0; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = IPW_QOS_WMM; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else { - if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { - cw_min = 31; - is_legacy = 1; - } - } - - if (priv->qos_data.qos_active) - aifs = 3; - - priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; - priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; - - if (priv->qos_data.qos_active) { - i = 1; - priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = 7; - priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - - i = 2; - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16((cw_min + 1) / 2 - 1); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = 2; - if (is_legacy) - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(6016); - else - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(3008); - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - - i = 3; - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16((cw_min + 1) / 4 - 1); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16((cw_max + 1) / 2 - 1); - priv->qos_data.def_qos_parm.ac[i].aifsn = 2; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - if (is_legacy) - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(3264); - else - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(1504); - } else { - for (i = 1; i < 4; i++) { - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; - priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - } - } - IWL_DEBUG_QOS("set QoS to default \n"); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwl_activate_qos(struct iwl_priv *priv, u8 force) -{ - unsigned long flags; - - if (priv == NULL) - return; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!priv->qos_data.qos_enable) - return; - - spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.def_qos_parm.qos_flags = 0; - - if (priv->qos_data.qos_cap.q_AP.queue_request && - !priv->qos_data.qos_cap.q_AP.txop_request) - priv->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_TXOP_TYPE_MSK; - - if (priv->qos_data.qos_active) - priv->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (force || iwl_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", - priv->qos_data.qos_active); - - iwl_send_qos_params_command(priv, - &(priv->qos_data.def_qos_parm)); - } -} - -#endif /* CONFIG_IWLWIFI_QOS */ -/* - * Power management (not Tx power!) functions - */ -#define MSEC_TO_USEC 1024 - -#if IWL == 3945 -#define NOSLP __constant_cpu_to_le32(0) -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK -#elif IWL == 4965 -#define NOSLP __constant_cpu_to_le16(0), 0, 0 -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 -#endif -#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) -#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ - __constant_cpu_to_le32(X1), \ - __constant_cpu_to_le32(X2), \ - __constant_cpu_to_le32(X3), \ - __constant_cpu_to_le32(X4)} - - -/* default power management (not Tx power) table values */ -/* for tim 0-10 */ -static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} -}; - -/* for tim > 10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), - SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), - SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), - SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), - SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} -}; - -int iwl_power_init_handle(struct iwl_priv *priv) -{ - int rc = 0, i; - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; - u16 pci_pm; - - IWL_DEBUG_POWER("Initialize power \n"); - - pow_data = &(priv->power_data); - - memset(pow_data, 0, sizeof(*pow_data)); - - pow_data->active_index = IWL_POWER_RANGE_0; - pow_data->dtim_val = 0xffff; - - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - - rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); - if (rc != 0) - return 0; - else { - struct iwl_powertable_cmd *cmd; - - IWL_DEBUG_POWER("adjust power command flags\n"); - - for (i = 0; i < IWL_POWER_AC; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (pci_pm & 0x1) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } - } - return rc; -} - -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u32 mode) -{ - int rc = 0, i; - u8 skip; - u32 max_sleep = 0; - struct iwl_power_vec_entry *range; - u8 period = 0; - struct iwl_power_mgr *pow_data; - - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER("Error invalid power mode \n"); - return -1; - } - pow_data = &(priv->power_data); - - if (pow_data->active_index == IWL_POWER_RANGE_0) - range = &pow_data->pwr_range_0[0]; - else - range = &pow_data->pwr_range_1[1]; - - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); - -#ifdef IWL_MAC80211_DISABLE - if (priv->assoc_network != NULL) { - unsigned long flags; - - period = priv->assoc_network->tim.tim_period; - } -#endif /*IWL_MAC80211_DISABLE */ - skip = range[mode].no_dtim; - - if (period == 0) { - period = 1; - skip = 0; - } - - if (skip == 0) { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } - - for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); - } - - IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); - IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); - IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); - IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", - le32_to_cpu(cmd->sleep_interval[0]), - le32_to_cpu(cmd->sleep_interval[1]), - le32_to_cpu(cmd->sleep_interval[2]), - le32_to_cpu(cmd->sleep_interval[3]), - le32_to_cpu(cmd->sleep_interval[4])); - - return rc; -} - -static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) -{ - u32 final_mode = mode; - int rc; - struct iwl_powertable_cmd cmd; - - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuosly aware mode"), - * else user level */ - switch (mode) { - case IWL_POWER_BATTERY: - final_mode = IWL_POWER_INDEX_3; - break; - case IWL_POWER_AC: - final_mode = IWL_POWER_MODE_CAM; - break; - default: - final_mode = mode; - break; - } - -#if IWL == 4965 - cmd.keep_alive_beacons = 0; -#endif - - iwl_update_power_cmd(priv, &cmd, final_mode); - - rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - else - set_bit(STATUS_POWER_PMI, &priv->status); - - return rc; -} - -int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) -{ - /* Filter incoming packets to determine if they are targeted toward - * this network, discarding packets coming from ourselves */ - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr2, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr3, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr3, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr2, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - } - - return 1; -} - -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x - -const char *iwl_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_ENTRY(SHORT_LIMIT); - TX_STATUS_ENTRY(LONG_LIMIT); - TX_STATUS_ENTRY(FIFO_UNDERRUN); - TX_STATUS_ENTRY(MGMNT_ABORT); - TX_STATUS_ENTRY(NEXT_FRAG); - TX_STATUS_ENTRY(LIFE_EXPIRE); - TX_STATUS_ENTRY(DEST_PS); - TX_STATUS_ENTRY(ABORTED); - TX_STATUS_ENTRY(BT_RETRY); - TX_STATUS_ENTRY(STA_INVALID); - TX_STATUS_ENTRY(FRAG_DROPPED); - TX_STATUS_ENTRY(TID_DISABLE); - TX_STATUS_ENTRY(FRAME_FLUSHED); - TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); - TX_STATUS_ENTRY(TX_LOCKED); - TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} - -/** - * iwl_scan_cancel - Cancel any currently executing HW scan - * - * NOTE: priv->mutex is not required before calling this function - */ -static int iwl_scan_cancel(struct iwl_priv *priv) -{ - if (!test_bit(STATUS_SCAN_HW, &priv->status)) { - clear_bit(STATUS_SCANNING, &priv->status); - return 0; - } - - if (test_bit(STATUS_SCANNING, &priv->status)) { - if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Queuing scan abort.\n"); - set_bit(STATUS_SCAN_ABORTING, &priv->status); - queue_work(priv->workqueue, &priv->abort_scan); - - } else - IWL_DEBUG_SCAN("Scan abort already in progress.\n"); - - return test_bit(STATUS_SCANNING, &priv->status); - } - - return 0; -} - -/** - * iwl_scan_cancel_timeout - Cancel any currently executing HW scan - * @ms: amount of time to wait (in milliseconds) for scan to abort - * - * NOTE: priv->mutex must be held before calling this function - */ -static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) -{ - unsigned long now = jiffies; - int ret; - - ret = iwl_scan_cancel(priv); - if (ret && ms) { - mutex_unlock(&priv->mutex); - while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && - test_bit(STATUS_SCANNING, &priv->status)) - msleep(1); - mutex_lock(&priv->mutex); - - return test_bit(STATUS_SCANNING, &priv->status); - } - - return ret; -} - -static void iwl_sequence_reset(struct iwl_priv *priv) -{ - /* Reset ieee stats */ - - /* We don't reset the net_device_stats (ieee->stats) on - * re-association */ - - priv->last_seq_num = -1; - priv->last_frag_num = -1; - priv->last_packet_time = 0; - - iwl_scan_cancel(priv); -} - -#if IWL == 4965 -#define MAX_UCODE_BEACON_INTERVAL 4096 -#else -#define MAX_UCODE_BEACON_INTERVAL 1024 -#endif -#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) - -static __le16 iwl_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - return cpu_to_le16(new_val); -} - -static void iwl_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 interval_tm_unit; - u64 tsf, result; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1); - priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); - - priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; - - tsf = priv->timestamp1; - tsf = ((tsf << 32) | priv->timestamp0); - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - - priv->rxon_timing.atim_window = 0; - } else { - priv->rxon_timing.beacon_interval = - iwl_adjust_beacon_interval(conf->beacon_int); - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); - - IWL_DEBUG_ASSOC - ("beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - -static int iwl_scan_initiate(struct iwl_priv *priv) -{ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); - return -EIO; - } - - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN("Scan already in progress.\n"); - return -EAGAIN; - } - - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Scan request while abort pending. " - "Queuing.\n"); - return -EAGAIN; - } - - IWL_DEBUG_INFO("Starting scan...\n"); - priv->scan_bands = 2; - set_bit(STATUS_SCANNING, &priv->status); - priv->scan_start = jiffies; - priv->scan_pass_start = priv->scan_start; - - queue_work(priv->workqueue, &priv->request_scan); - - return 0; -} - -static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) -{ - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - - if (hw_decrypt) - rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; - else - rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; - - return 0; -} - -static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) -{ - if (phymode == MODE_IEEE80211A) { - priv->staging_rxon.flags &= - ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK - | RXON_FLG_CCK_MSK); - priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; - } else { - /* Copied from iwl_bg_post_associate() */ - if (priv->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 == IEEE80211_IF_TYPE_IBSS) - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; - priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; - } -} - -/* - * initilize rxon structure with default values fromm eeprom - */ -static void iwl_connection_init_rx_config(struct iwl_priv *priv) -{ - const struct iwl_channel_info *ch_info; - - memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; - break; - - case IEEE80211_IF_TYPE_STA: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; - priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; - break; - - case IEEE80211_IF_TYPE_IBSS: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; - priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; - priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | - RXON_FILTER_ACCEPT_GRP_MSK; - break; - - case IEEE80211_IF_TYPE_MNTR: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; - priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; - break; - } - -#if 0 - /* TODO: Figure out when short_preamble would be set and cache from - * that */ - if (!hw_to_local(priv->hw)->short_preamble) - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; -#endif - - ch_info = iwl_get_channel_info(priv, priv->phymode, - le16_to_cpu(priv->staging_rxon.channel)); - - if (!ch_info) - ch_info = &priv->channel_info[0]; - - /* - * in some case A channels are all non IBSS - * in this case force B/G channel - */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !(is_channel_ibss(ch_info))) - ch_info = &priv->channel_info[0]; - - priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); - if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; - else - priv->phymode = MODE_IEEE80211G; - - iwl_set_flags_for_phymode(priv, priv->phymode); - - priv->staging_rxon.ofdm_basic_rates = - (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; - priv->staging_rxon.cck_basic_rates = - (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - -#if IWL == 4965 - priv->staging_rxon.flags |= RXON_FLG_CHANNEL_MODE_LEGACY_MSK; - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); - priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; - priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; - iwl4965_set_rxon_chain(priv); -#endif -} - -static int iwl_set_mode(struct iwl_priv *priv, int mode) -{ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - if (mode == IEEE80211_IF_TYPE_IBSS) { - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, - priv->phymode, - le16_to_cpu(priv->staging_rxon.channel)); - - if (!ch_info || !is_channel_ibss(ch_info)) { - IWL_ERROR("channel %d not IBSS channel\n", - le16_to_cpu(priv->staging_rxon.channel)); - return -EINVAL; - } - } - - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARNING("Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); - return -EAGAIN; - } - - priv->iw_mode = mode; - - iwl_connection_init_rx_config(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - iwl_clear_stations_table(priv); - - iwl_commit_rxon(priv); - - return 0; -} - -static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, - struct sk_buff *skb_frag, - int last_frag) -{ - struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; - - switch (keyinfo->alg) { - case ALG_CCMP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; - - cmd->cmd.tx.hdr[0].frame_control |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - /* XXX: ACK flag must be set for CCMP even if it - * is a multicast/broadcast packet, because CCMP - * group communication encrypted by GTK is - * actually done by the AP. */ - cmd->cmd.tx.tx_flags |= TX_CMD_FLG_ACK_MSK; - memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); - break; - case ALG_TKIP: -#if 0 - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; - - if (last_frag) - memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, - 8); - else - memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); - - cmd->cmd.tx.hdr[0].frame_control |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - /* XXX: ACK flag must be set for CCMP even if it - * is a multicast/broadcast packet, because CCMP - * group communication encrypted by GTK is - * actually done by the AP. */ - cmd->cmd.tx.tx_flags |= TX_CMD_FLG_ACK_MSK; -#endif - break; - case ALG_WEP: - cmd->cmd.tx.sec_ctl = 1 | /* WEP */ - (ctl->key_idx & 0x3) << 6; - - if (keyinfo->keylen == 13) - cmd->cmd.tx.sec_ctl |= (1 << 3); /* 128-bit */ - - memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); - - cmd->cmd.tx.hdr[0].frame_control |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->key_idx); - break; - - case ALG_NONE: - IWL_DEBUG_TX("Tx packet in the clear " - "(encrypt requested).\n"); - break; - - default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); - break; - } - -} - -/* - * handle build REPLY_TX command notification. - */ -static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) -{ - __le16 *qc; - u16 fc = le16_to_cpu(hdr->frame_control); - __le32 tx_flags = cmd->cmd.tx.tx_flags; - - cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { - tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) - tx_flags |= TX_CMD_FLG_TSF_MSK; - } else { - tx_flags &= (~TX_CMD_FLG_ACK_MSK); - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) - tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); - tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } - - if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) - tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(3); - else - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(2); - } else - cmd->cmd.tx.timeout.pm_frame_timeout = 0; - - cmd->cmd.tx.driver_txop = 0; - cmd->cmd.tx.tx_flags = tx_flags; - cmd->cmd.tx.next_frame_len = 0; -} - -static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - - /* If this frame is broadcast or not data then use the broadcast - * station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) - return IWL_BROADCAST_ID; - - switch (priv->iw_mode) { - - /* If this frame is part of a BSS network (we're a station), then - * we use the AP's station id */ - case IEEE80211_IF_TYPE_STA: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: - sta_id = iwl_hw_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - return IWL_BROADCAST_ID; - - /* If this frame is part of a IBSS network, then we use the - * target specific station id */ - case IEEE80211_IF_TYPE_IBSS: - sta_id = iwl_hw_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " - "Defaulting to broadcast...\n", - MAC_ARG(hdr->addr1)); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); - return IWL_BROADCAST_ID; - - default: - IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); - return IWL_BROADCAST_ID; - } -} - -/* - * start REPLY_TX command process - */ -static int iwl_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - int txq_id = ctl->queue; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; - dma_addr_t phys_addr; - dma_addr_t txcmd_phys; - struct iwl_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 id, hdr_len, unicast; - u8 sta_id; - u16 seq_number = 0; - u16 fc; - __le16 *qc; - u8 wait_write_ptr = 0; - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_DROP("Dropping - RF KILL\n"); - goto drop_unlock; - } - - if (!priv->interface_id) { - IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); - goto drop_unlock; - } - - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { - IWL_ERROR("ERROR: No TX rate available.\n"); - goto drop_unlock; - } - - unicast = !is_multicast_ether_addr(hdr->addr1); - id = 0; - - fc = le16_to_cpu(hdr->frame_control); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (ieee80211_is_auth(fc)) - IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) - IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) - IWL_DEBUG_TX("Sending REASSOC frame\n"); -#endif - - if (!iwl_is_associated(priv) && - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); - goto drop_unlock; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - hdr_len = ieee80211_get_hdrlen(fc); - sta_id = iwl_get_sta_id(priv, hdr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); - goto drop; - } - - IWL_DEBUG_RATE("station Id %d\n", sta_id); - - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); - seq_number = priv->stations[sta_id].tid[tid].seq_number & - IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = cpu_to_le16(seq_number) | - (hdr->seq_ctrl & - __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); - seq_number += 0x10; -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG - /* aggregation is on for this */ - if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) - txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ -#endif - } - txq = &priv->txq[txq_id]; - q = &txq->q; - - spin_lock_irqsave(&priv->lock, flags); - - tfd = &txq->bd[q->first_empty]; - memset(tfd, 0, sizeof(*tfd)); - control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->first_empty, 0); - - memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->first_empty].skb[0] = skb; - memcpy(&(txq->txb[q->first_empty].status.control), - ctl, sizeof(struct ieee80211_tx_contr