diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
73 files changed, 6208 insertions, 20988 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index ed424574160e..ad3bdba6beed 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,14 +1,52 @@ -config IWLWIFI - tristate "Intel Wireless Wifi" +config IWLAGN + tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) " depends on PCI && MAC80211 select FW_LOADER + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + select MAC80211_LEDS + ---help--- + Select to build the driver supporting the: + + Intel Wireless WiFi Link Next-Gen AGN + + This option enables support for use with the following hardware: + Intel Wireless WiFi Link 6250AGN Adapter + Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN) + Intel WiFi Link 1000BGN + Intel Wireless WiFi 5150AGN + Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN + Intel 6005 Series Wi-Fi Adapters + Intel 6030 Series Wi-Fi Adapters + Intel Wireless WiFi Link 6150BGN 2 Adapter + Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) + Intel 2000 Series Wi-Fi Adapters + + + This driver uses the kernel's mac80211 subsystem. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + <http://intellinuxwireless.org/>. + + The microcode is typically installed in /lib/firmware. You can + look in the hotplug script /etc/hotplug/firmware.agent to + determine which directory FIRMWARE_DIR is set to when the script + runs. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/kbuild/modules.txt>. The + module will be called iwlagn. menu "Debugging Options" - depends on IWLWIFI + depends on IWLAGN config IWLWIFI_DEBUG - bool "Enable full debugging output in iwlagn and iwl3945 drivers" - depends on IWLWIFI + bool "Enable full debugging output in the iwlagn driver" + depends on IWLAGN ---help--- This option will enable debug tracing output for the iwlwifi drivers @@ -33,7 +71,7 @@ config IWLWIFI_DEBUG config IWLWIFI_DEBUGFS bool "iwlagn debugfs support" - depends on IWLWIFI && MAC80211_DEBUGFS + depends on IWLAGN && MAC80211_DEBUGFS ---help--- Enable creation of debugfs files for the iwlwifi drivers. This is a low-impact option that allows getting insight into the @@ -41,13 +79,13 @@ config IWLWIFI_DEBUGFS config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE bool "Experimental uCode support" - depends on IWLWIFI && IWLWIFI_DEBUG + depends on IWLAGN && IWLWIFI_DEBUG ---help--- Enable use of experimental ucode for testing and debugging. config IWLWIFI_DEVICE_TRACING bool "iwlwifi device access tracing" - depends on IWLWIFI + depends on IWLAGN depends on EVENT_TRACING help Say Y here to trace all commands, including TX frames and IO @@ -64,73 +102,29 @@ config IWLWIFI_DEVICE_TRACING occur. endmenu -config IWLAGN - tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)" - depends on IWLWIFI - ---help--- - Select to build the driver supporting the: - - Intel Wireless WiFi Link Next-Gen AGN - - This driver uses the kernel's mac80211 subsystem. - - In order to use this driver, you will need a microcode (uCode) - image for it. You can obtain the microcode from: - - <http://intellinuxwireless.org/>. - - The microcode is typically installed in /lib/firmware. You can - look in the hotplug script /etc/hotplug/firmware.agent to - determine which directory FIRMWARE_DIR is set to when the script - runs. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt>. The - module will be called iwlagn. - - -config IWL4965 - bool "Intel Wireless WiFi 4965AGN" +config IWLWIFI_DEVICE_SVTOOL + bool "iwlwifi device svtool support" depends on IWLAGN - ---help--- - This option enables support for Intel Wireless WiFi Link 4965AGN + select NL80211_TESTMODE + help + This option enables the svtool support for iwlwifi device through + NL80211_TESTMODE. svtool is a software validation tool that runs in + the user space and interacts with the device in the kernel space + through the generic netlink message via NL80211_TESTMODE channel. -config IWL5000 - bool "Intel Wireless-N/Advanced-N/Ultimate-N WiFi Link" +config IWL_P2P + bool "iwlwifi experimental P2P support" depends on IWLAGN - ---help--- - This option enables support for use with the following hardware: - Intel Wireless WiFi Link 6250AGN Adapter - Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN) - Intel WiFi Link 1000BGN - Intel Wireless WiFi 5150AGN - Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN - Intel 6000 Gen 2 Series Wi-Fi Adapters (6000G2A and 6000G2B) - Intel WIreless WiFi Link 6050BGN Gen 2 Adapter - Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) - -config IWL3945 - tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" - depends on IWLWIFI - ---help--- - Select to build the driver supporting the: - - Intel PRO/Wireless 3945ABG/BG Network Connection - - This driver uses the kernel's mac80211 subsystem. - - In order to use this driver, you will need a microcode (uCode) - image for it. You can obtain the microcode from: + help + This option enables experimental P2P support for some devices + based on microcode support. Since P2P support is still under + development, this option may even enable it for some devices + now that turn out to not support it in the future due to + microcode restrictions. - <http://intellinuxwireless.org/>. + To determine if your microcode supports the experimental P2P + offered by this option, check if the driver advertises AP + support when it is loaded. - The microcode is typically installed in /lib/firmware. You can - look in the hotplug script /etc/hotplug/firmware.agent to - determine which directory FIRMWARE_DIR is set to when the script - runs. + Say Y only if you want to experiment with P2P. - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt>. The - module will be called iwl3945. diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 93380f97835f..822660483f9f 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,35 +1,23 @@ -obj-$(CONFIG_IWLWIFI) += iwlcore.o -iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o -iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o -iwlcore-objs += iwl-scan.o iwl-led.o -iwlcore-$(CONFIG_IWL3945) += iwl-legacy.o -iwlcore-$(CONFIG_IWL4965) += iwl-legacy.o -iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o -iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o - -# If 3945 is selected only, iwl-legacy.o will be added -# to iwlcore-m above, but it needs to be built in. -iwlcore-objs += $(iwlcore-m) - -CFLAGS_iwl-devtrace.o := -I$(src) - # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o -iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o +iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o -iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o -iwlagn-$(CONFIG_IWL4965) += iwl-4965.o -iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o -iwlagn-$(CONFIG_IWL5000) += iwl-5000.o -iwlagn-$(CONFIG_IWL5000) += iwl-6000.o -iwlagn-$(CONFIG_IWL5000) += iwl-1000.o +iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o +iwlagn-objs += iwl-rx.o iwl-tx.o iwl-sta.o +iwlagn-objs += iwl-scan.o iwl-led.o +iwlagn-objs += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o +iwlagn-objs += iwl-5000.o +iwlagn-objs += iwl-6000.o +iwlagn-objs += iwl-1000.o +iwlagn-objs += iwl-2000.o + +iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o +iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o -# 3945 -obj-$(CONFIG_IWL3945) += iwl3945.o -iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o -iwl3945-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-3945-debugfs.o +CFLAGS_iwl-devtrace.o := -I$(src) ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index ba78bc8a259f..b4c81931e136 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -45,11 +45,9 @@ #include "iwl-agn.h" #include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-agn-led.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ -#define IWL1000_UCODE_API_MAX 3 +#define IWL1000_UCODE_API_MAX 5 #define IWL100_UCODE_API_MAX 5 /* Lowest firmware API version supported */ @@ -57,12 +55,10 @@ #define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" -#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" -#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL100_FW_PRE "iwlwifi-100-" -#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" -#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api) +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" /* @@ -124,10 +120,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -141,7 +137,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -176,24 +171,13 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) static struct iwl_lib_ops iwl1000_lib = { .set_hw_params = iwl1000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { @@ -208,47 +192,21 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_5_CHANNELS, EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS + EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, - .check_ack_health = iwl_good_ack_health, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl1000_base_params = { @@ -256,8 +214,6 @@ static struct iwl_base_params iwl1000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, @@ -267,9 +223,6 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, @@ -283,7 +236,6 @@ static struct iwl_ht_params iwl1000_ht_params = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_BLINK @@ -305,7 +257,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c new file mode 100644 index 000000000000..89b8da7a6c8b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -0,0 +1,470 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <net/mac80211.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-sta.h" +#include "iwl-agn.h" +#include "iwl-helpers.h" +#include "iwl-agn-hw.h" +#include "iwl-6000-hw.h" + +/* Highest firmware API version supported */ +#define IWL2030_UCODE_API_MAX 5 +#define IWL2000_UCODE_API_MAX 5 +#define IWL105_UCODE_API_MAX 5 + +/* Lowest firmware API version supported */ +#define IWL2030_UCODE_API_MIN 5 +#define IWL2000_UCODE_API_MIN 5 +#define IWL105_UCODE_API_MIN 5 + +#define IWL2030_FW_PRE "iwlwifi-2030-" +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" + +#define IWL2000_FW_PRE "iwlwifi-2000-" +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" + +#define IWL105_FW_PRE "iwlwifi-105-" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" + +static void iwl2000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +/* NIC configuration for 2000 series */ +static void iwl2000_nic_config(struct iwl_priv *priv) +{ + u16 radio_cfg; + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + if (priv->cfg->iq_invert) + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + + if (priv->cfg->disable_otp_refresh) + iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010); +} + +static struct iwl_sensitivity_ranges iwl2000_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 110, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 97, + .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) +{ + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = + iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + priv->cfg->base_params->num_of_queues * + sizeof(struct iwlagn_scd_bc_tbl); + priv->hw_params.tfd_size = sizeof(struct iwl_tfd); + priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; + + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; + + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + if (priv->cfg->rx_with_siso_diversity) + priv->hw_params.rx_chains_num = 1; + else + priv->hw_params.rx_chains_num = + num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + + iwl2000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + /* Set initial calibration set */ + priv->hw_params.sens = &iwl2000_sensitivity; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); + if (priv->cfg->need_dc_calib) + priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX); + if (priv->cfg->need_temp_offset_calib) + priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); + + priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + + return 0; +} + +static int iwl2030_hw_channel_switch(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch) +{ + /* + * MULTI-FIXME + * See iwl_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl6000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + u32 switch_time_in_usec, ucode_switch_time; + u16 ch; + u32 tsf_low; + u8 switch_count; + u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); + struct ieee80211_vif *vif = ctx->vif; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SYNC, + .data = &cmd, + }; + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + ch = ch_switch->channel->hw_value; + IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", + ctx->active.channel, ch); + cmd.channel = cpu_to_le16(ch); + cmd.rxon_flags = ctx->staging.flags; + cmd.rxon_filter_flags = ctx->staging.filter_flags; + switch_count = ch_switch->count; + tsf_low = ch_switch->timestamp & 0x0ffffffff; + /* + * calculate the ucode channel switch time + * adding TSF as one of the factor for when to switch + */ + if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { + if (switch_count > ((priv->ucode_beacon_time - tsf_low) / + beacon_interval)) { + switch_count -= (priv->ucode_beacon_time - + tsf_low) / beacon_interval; + } else + switch_count = 0; + } + if (switch_count <= 1) + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + else { + switch_time_in_usec = + vif->bss_conf.beacon_int * switch_count * TIME_UNIT; + ucode_switch_time = iwl_usecs_to_beacons(priv, + switch_time_in_usec, + beacon_interval); + cmd.switch_time = iwl_add_beacon_time(priv, + priv->ucode_beacon_time, + ucode_switch_time, + beacon_interval); + } + IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", + cmd.switch_time); + ch_info = iwl_get_channel_info(priv, priv->band, ch); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + ctx->active.channel, ch); + return -EFAULT; + } + priv->switch_rxon.channel = cmd.channel; + priv->switch_rxon.switch_in_progress = true; + + return iwl_send_cmd_sync(priv, &hcmd); +} + +static struct iwl_lib_ops iwl2000_lib = { + .set_hw_params = iwl2000_hw_set_hw_params, + .txq_set_sched = iwlagn_txq_set_sched, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_bt_setup_deferred_work, + .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl2030_hw_channel_switch, + .apm_ops = { + .init = iwl_apm_init, + .config = iwl2000_nic_config, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + }, + .query_addr = iwlagn_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +}; + +static const struct iwl_ops iwl2000_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +}; + +static const struct iwl_ops iwl2030_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, +}; + +static const struct iwl_ops iwl105_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +}; + +static const struct iwl_ops iwl135_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, +}; + +static struct iwl_base_params iwl2000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .adv_thermal_throttle = true, + .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, +}; + + +static struct iwl_base_params iwl2030_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 57, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .adv_thermal_throttle = true, + .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, +}; + +static struct iwl_ht_params iwl2000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ +}; + +static struct iwl_bt_params iwl2030_bt_params = { + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .advanced_bt_coexist = true, + .agg_time_limit = BT_AGG_THRESHOLD_DEF, + .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, + .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, + .bt_sco_disable = true, + .bt_session_2 = true, +}; + +#define IWL_DEVICE_2000 \ + .fw_name_pre = IWL2000_FW_PRE, \ + .ucode_api_max = IWL2000_UCODE_API_MAX, \ + .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2000_ops, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .iq_invert = true, \ + .disable_otp_refresh = true \ + +struct iwl_cfg iwl2000_2bgn_cfg = { + .name = "2000 Series 2x2 BGN", + IWL_DEVICE_2000, + .ht_params = &iwl2000_ht_params, +}; + +struct iwl_cfg iwl2000_2bg_cfg = { + .name = "2000 Series 2x2 BG", + IWL_DEVICE_2000, +}; + +#define IWL_DEVICE_2030 \ + .fw_name_pre = IWL2030_FW_PRE, \ + .ucode_api_max = IWL2030_UCODE_API_MAX, \ + .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2030_ops, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .iq_invert = true \ + +struct iwl_cfg iwl2030_2bgn_cfg = { + .name = "2000 Series 2x2 BGN/BT", + IWL_DEVICE_2030, + .ht_params = &iwl2000_ht_params, +}; + +struct iwl_cfg iwl2030_2bg_cfg = { + .name = "2000 Series 2x2 BG/BT", + IWL_DEVICE_2030, +}; + +#define IWL_DEVICE_105 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl105_ops, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +struct iwl_cfg iwl105_bg_cfg = { + .name = "105 Series 1x1 BG", + IWL_DEVICE_105, +}; + +struct iwl_cfg iwl105_bgn_cfg = { + .name = "105 Series 1x1 BGN", + IWL_DEVICE_105, + .ht_params = &iwl2000_ht_params, +}; + +#define IWL_DEVICE_135 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl135_ops, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +struct iwl_cfg iwl135_bg_cfg = { + .name = "105 Series 1x1 BG/BT", + IWL_DEVICE_135, +}; + +struct iwl_cfg iwl135_bgn_cfg = { + .name = "105 Series 1x1 BGN/BT", + IWL_DEVICE_135, + .ht_params = &iwl2000_ht_params, +}; + +MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c deleted file mode 100644 index ef0835b01b6b..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c +++ /dev/null @@ -1,522 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include "iwl-3945-debugfs.h" - - -static int iwl3945_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) -{ - int p = 0; - - p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", - le32_to_cpu(priv->_3945.statistics.flag)); - if (le32_to_cpu(priv->_3945.statistics.flag) & - UCODE_STATISTICS_CLEAR_MSK) - p += scnprintf(buf + p, bufsz - p, - "\tStatistics have been cleared\n"); - p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", - (le32_to_cpu(priv->_3945.statistics.flag) & - UCODE_STATISTICS_FREQUENCY_MSK) - ? "2.4 GHz" : "5.2 GHz"); - p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", - (le32_to_cpu(priv->_3945.statistics.flag) & - UCODE_STATISTICS_NARROW_BAND_MSK) - ? "enabled" : "disabled"); - return p; -} - -ssize_t iwl3945_ucode_rx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct iwl39_statistics_rx_phy) * 40 + - sizeof(struct iwl39_statistics_rx_non_phy) * 40 + 400; - ssize_t ret; - struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct iwl39_statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; - struct iwl39_statistics_rx_non_phy *general, *accum_general; - struct iwl39_statistics_rx_non_phy *delta_general, *max_general; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * The statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - ofdm = &priv->_3945.statistics.rx.ofdm; - cck = &priv->_3945.statistics.rx.cck; - general = &priv->_3945.statistics.rx.general; - accum_ofdm = &priv->_3945.accum_statistics.rx.ofdm; - accum_cck = &priv->_3945.accum_statistics.rx.cck; - accum_general = &priv->_3945.accum_statistics.rx.general; - delta_ofdm = &priv->_3945.delta_statistics.rx.ofdm; - delta_cck = &priv->_3945.delta_statistics.rx.cck; - delta_general = &priv->_3945.delta_statistics.rx.general; - max_ofdm = &priv->_3945.max_delta.rx.ofdm; - max_cck = &priv->_3945.max_delta.rx.cck; - max_general = &priv->_3945.max_delta.rx.general; - - pos += iwl3945_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" - "acumulative delta max\n", - "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "ina_cnt:", le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", "overrun_err:", - le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, delta_ofdm->overrun_err, - max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "early_overrun_err:", - le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "crc32_good:", le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, delta_ofdm->crc32_good, - max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", "false_alarm_cnt:", - le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_sync_err_cnt:", - le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sfd_timeout:", - le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, - delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_timeout:", - le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, - delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "unresponded_rts:", - le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "rxe_frame_lmt_ovrun:", - le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sent_ack_cnt:", - le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, - delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sent_cts_cnt:", - le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, - delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" - "acumulative delta max\n", - "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "overrun_err:", - le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, - delta_cck->overrun_err, max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "early_overrun_err:", - le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, - max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "false_alarm_cnt:", - le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_sync_err_cnt:", - le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sfd_timeout:", - le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, - delta_cck->sfd_timeout, max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "fina_timeout:", - le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, - delta_cck->fina_timeout, max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "unresponded_rts:", - le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, - delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "rxe_frame_lmt_ovrun:", - le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sent_ack_cnt:", - le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, - delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sent_cts_cnt:", - le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, - delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" - "acumulative delta max\n", - "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "bogus_cts:", - le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, - delta_general->bogus_cts, max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "bogus_ack:", - le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, - delta_general->bogus_ack, max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "non_bssid_frames:", - le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "filtered_frames:", - le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "non_channel_beacons:", - le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl3945_ucode_tx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct iwl39_statistics_tx) * 48) + 250; - ssize_t ret; - struct iwl39_statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * The statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - tx = &priv->_3945.statistics.tx; - accum_tx = &priv->_3945.accum_statistics.tx; - delta_tx = &priv->_3945.delta_statistics.tx; - max_tx = &priv->_3945.max_delta.tx; - pos += iwl3945_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" - "acumulative delta max\n", - "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "preamble:", - le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "rx_detected_cnt:", - le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "bt_prio_defer_cnt:", - le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "bt_prio_kill_cnt:", - le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "few_bytes_cnt:", - le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "ack_timeout:", - le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "expected_ack_cnt:", - le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "actual_ack_cnt:", - le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl3945_ucode_general_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct iwl39_statistics_general) * 10 + 300; - ssize_t ret; - struct iwl39_statistics_general *general, *accum_general; - struct iwl39_statistics_general *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct iwl39_statistics_div *div, *accum_div, *delta_div, *max_div; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * The statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - general = &priv->_3945.statistics.general; - dbg = &priv->_3945.statistics.general.dbg; - div = &priv->_3945.statistics.general.div; - accum_general = &priv->_3945.accum_statistics.general; - delta_general = &priv->_3945.delta_statistics.general; - max_general = &priv->_3945.max_delta.general; - accum_dbg = &priv->_3945.accum_statistics.general.dbg; - delta_dbg = &priv->_3945.delta_statistics.general.dbg; - max_dbg = &priv->_3945.max_delta.general.dbg; - accum_div = &priv->_3945.accum_statistics.general.div; - delta_div = &priv->_3945.delta_statistics.general.div; - max_div = &priv->_3945.max_delta.general.div; - pos += iwl3945_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" - "acumulative delta max\n", - "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "burst_check:", - le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "burst_count:", - le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "sleep_time:", - le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "slots_out:", - le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "slots_idle:", - le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); - pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n", - le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - " %-30s %10u %10u %10u %10u\n", - "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h deleted file mode 100644 index 70809c53c215..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h +++ /dev/null @@ -1,60 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" - -#ifdef CONFIG_IWLWIFI_DEBUGFS -ssize_t iwl3945_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl3945_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl3945_ucode_general_stats_read(struct file *file, - char __user *user_buf, size_t count, - loff_t *ppos); -#else -static ssize_t iwl3945_ucode_rx_stats_read(struct file *file, - char __user *user_buf, size_t count, - loff_t *ppos) -{ - return 0; -} -static ssize_t iwl3945_ucode_tx_stats_read(struct file *file, - char __user *user_buf, size_t count, - loff_t *ppos) -{ - return 0; -} -static ssize_t iwl3945_ucode_general_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h deleted file mode 100644 index 2c9ed2b502a3..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h +++ /dev/null @@ -1,188 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#ifndef __iwl_3945_fh_h__ -#define __iwl_3945_fh_h__ - -/************************************/ -/* iwl3945 Flow Handler Definitions */ -/************************************/ - -/** - * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) - * Addresses are offsets from device's PCI hardware base address. - */ -#define FH39_MEM_LOWER_BOUND (0x0800) -#define FH39_MEM_UPPER_BOUND (0x1000) - -#define FH39_CBCC_TABLE (FH39_MEM_LOWER_BOUND + 0x140) -#define FH39_TFDB_TABLE (FH39_MEM_LOWER_BOUND + 0x180) -#define FH39_RCSR_TABLE (FH39_MEM_LOWER_BOUND + 0x400) -#define FH39_RSSR_TABLE (FH39_MEM_LOWER_BOUND + 0x4c0) -#define FH39_TCSR_TABLE (FH39_MEM_LOWER_BOUND + 0x500) -#define FH39_TSSR_TABLE (FH39_MEM_LOWER_BOUND + 0x680) - -/* TFDB (Transmit Frame Buffer Descriptor) */ -#define FH39_TFDB(_ch, buf) (FH39_TFDB_TABLE + \ - ((_ch) * 2 + (buf)) * 0x28) -#define FH39_TFDB_CHNL_BUF_CTRL_REG(_ch) (FH39_TFDB_TABLE + 0x50 * (_ch)) - -/* CBCC channel is [0,2] */ -#define FH39_CBCC(_ch) (FH39_CBCC_TABLE + (_ch) * 0x8) -#define FH39_CBCC_CTRL(_ch) (FH39_CBCC(_ch) + 0x00) -#define FH39_CBCC_BASE(_ch) (FH39_CBCC(_ch) + 0x04) - -/* RCSR channel is [0,2] */ -#define FH39_RCSR(_ch) (FH39_RCSR_TABLE + (_ch) * 0x40) -#define FH39_RCSR_CONFIG(_ch) (FH39_RCSR(_ch) + 0x00) -#define FH39_RCSR_RBD_BASE(_ch) (FH39_RCSR(_ch) + 0x04) -#define FH39_RCSR_WPTR(_ch) (FH39_RCSR(_ch) + 0x20) -#define FH39_RCSR_RPTR_ADDR(_ch) (FH39_RCSR(_ch) + 0x24) - -#define FH39_RSCSR_CHNL0_WPTR (FH39_RCSR_WPTR(0)) - -/* RSSR */ -#define FH39_RSSR_CTRL (FH39_RSSR_TABLE + 0x000) -#define FH39_RSSR_STATUS (FH39_RSSR_TABLE + 0x004) - -/* TCSR */ -#define FH39_TCSR(_ch) (FH39_TCSR_TABLE + (_ch) * 0x20) -#define FH39_TCSR_CONFIG(_ch) (FH39_TCSR(_ch) + 0x00) -#define FH39_TCSR_CREDIT(_ch) (FH39_TCSR(_ch) + 0x04) -#define FH39_TCSR_BUFF_STTS(_ch) (FH39_TCSR(_ch) + 0x08) - -/* TSSR */ -#define FH39_TSSR_CBB_BASE (FH39_TSSR_TABLE + 0x000) -#define FH39_TSSR_MSG_CONFIG (FH39_TSSR_TABLE + 0x008) -#define FH39_TSSR_TX_STATUS (FH39_TSSR_TABLE + 0x010) - - -/* DBM */ - -#define FH39_SRVC_CHNL (6) - -#define FH39_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20) -#define FH39_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4) - -#define FH39_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000) - -#define FH39_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000) - -#define FH39_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000) - -#define FH39_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000) - -#define FH39_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000) - -#define FH39_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000) - -#define FH39_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) -#define FH39_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) - -#define FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) - -#define FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) - -#define FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) - -#define FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) - -#define FH39_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000) - -#define FH39_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) - -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) - -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) - -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) - -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) -#define FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) - -#define FH39_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_ch) (BIT(_ch) << 24) -#define FH39_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_ch) (BIT(_ch) << 16) - -#define FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_ch) \ - (FH39_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_ch) | \ - FH39_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_ch)) - -#define FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) - -struct iwl3945_tfd_tb { - __le32 addr; - __le32 len; -} __packed; - -struct iwl3945_tfd { - __le32 control_flags; - struct iwl3945_tfd_tb tbs[4]; - u8 __pad[28]; -} __packed; - - -#endif /* __iwl_3945_fh_h__ */ - diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h deleted file mode 100644 index 65b5834da28c..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ /dev/null @@ -1,294 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -/* - * Please use this file (iwl-3945-hw.h) only for hardware-related definitions. - * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-3945.h for driver implementation definitions. - */ - -#ifndef __iwl_3945_hw__ -#define __iwl_3945_hw__ - -#include "iwl-eeprom.h" - -/* RSSI to dBm */ -#define IWL39_RSSI_OFFSET 95 - -#define IWL_DEFAULT_TX_POWER 0x0F - -/* - * EEPROM related constants, enums, and structures. - */ -#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7) - -/* - * Mapping of a Tx power level, at factory calibration temperature, - * to a radio/DSP gain table index. - * One for each of 5 "sample" power levels in each band. - * v_det is measured at the factory, using the 3945's built-in power amplifier - * (PA) output voltage detector. This same detector is used during Tx of - * long packets in normal operation to provide feedback as to proper output - * level. - * Data copied from EEPROM. - * DO NOT ALTER THIS STRUCTURE!!! - */ -struct iwl3945_eeprom_txpower_sample { - u8 gain_index; /* index into power (gain) setup table ... */ - s8 power; /* ... for this pwr level for this chnl group */ - u16 v_det; /* PA output voltage */ -} __packed; - -/* - * Mappings of Tx power levels -> nominal radio/DSP gain table indexes. - * One for each channel group (a.k.a. "band") (1 for BG, 4 for A). - * Tx power setup code interpolates between the 5 "sample" power levels - * to determine the nominal setup for a requested power level. - * Data copied from EEPROM. - * DO NOT ALTER THIS STRUCTURE!!! - */ -struct iwl3945_eeprom_txpower_group { - struct iwl3945_eeprom_txpower_sample samples[5]; /* 5 power levels */ - s32 a, b, c, d, e; /* coefficients for voltage->power - * formula (signed) */ - s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on - * frequency (signed) */ - s8 saturation_power; /* highest power possible by h/w in this - * band */ - u8 group_channel; /* "representative" channel # in this band */ - s16 temperature; /* h/w temperature at factory calib this band - * (signed) */ -} __packed; - -/* - * Temperature-based Tx-power compensation data, not band-specific. - * These coefficients are use to modify a/b/c/d/e coeffs based on - * difference between current temperature and factory calib temperature. - * Data copied from EEPROM. - */ -struct iwl3945_eeprom_temperature_corr { - u32 Ta; - u32 Tb; - u32 Tc; - u32 Td; - u32 Te; -} __packed; - -/* - * EEPROM map - */ -struct iwl3945_eeprom { - u8 reserved0[16]; - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; - u16 version; /* abs.ofs: 136 */ - u8 sku_cap; /* abs.ofs: 138 */ - u8 leds_mode; /* abs.ofs: 139 */ - u16 oem_mode; - u16 wowlan_mode; /* abs.ofs: 142 */ - u16 leds_time_interval; /* abs.ofs: 144 */ - u8 leds_off_time; /* abs.ofs: 146 */ - u8 leds_on_time; /* abs.ofs: 147 */ - u8 almgor_m_version; /* abs.ofs: 148 */ - u8 antenna_switch_type; /* abs.ofs: 149 */ - u8 reserved6[42]; - u8 sku_id[4]; /* abs.ofs: 192 */ - -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by 3945 or 4965 has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ - u16 band_1_count; /* abs.ofs: 196 */ - struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 198 */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ - u16 band_2_count; /* abs.ofs: 226 */ - struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ - u16 band_3_count; /* abs.ofs: 254 */ - struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ - u16 band_4_count; /* abs.ofs: 280 */ - struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ - u16 band_5_count; /* abs.ofs: 304 */ - struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - - u8 reserved9[194]; - -/* - * 3945 Txpower calibration data. - */ -#define IWL_NUM_TX_CALIB_GROUPS 5 - struct iwl3945_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; -/* abs.ofs: 512 */ - struct iwl3945_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ - u8 reserved16[172]; /* fill out to full 1024 byte block */ -} __packed; - -#define IWL3945_EEPROM_IMG_SIZE 1024 - -/* End of EEPROM */ - -#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ -#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ - -/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */ -#define IWL39_NUM_QUEUES 5 -#define IWL39_CMD_QUEUE_NUM 4 - -#define IWL_DEFAULT_TX_RETRY 15 - -/*********************************************/ - -#define RFD_SIZE 4 -#define NUM_TFD_CHUNKS 4 - -#define RX_QUEUE_SIZE 256 -#define RX_QUEUE_MASK 255 -#define RX_QUEUE_SIZE_LOG 8 - -#define U32_PAD(n) ((4-(n))&0x3) - -#define TFD_CTL_COUNT_SET(n) (n << 24) -#define TFD_CTL_COUNT_GET(ctl) ((ctl >> 24) & 7) -#define TFD_CTL_PAD_SET(n) (n << 28) -#define TFD_CTL_PAD_GET(ctl) (ctl >> 28) - -/* Sizes and addresses for instruction and data memory (SRAM) in - * 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ -#define IWL39_RTC_INST_LOWER_BOUND (0x000000) -#define IWL39_RTC_INST_UPPER_BOUND (0x014000) - -#define IWL39_RTC_DATA_LOWER_BOUND (0x800000) -#define IWL39_RTC_DATA_UPPER_BOUND (0x808000) - -#define IWL39_RTC_INST_SIZE (IWL39_RTC_INST_UPPER_BOUND - \ - IWL39_RTC_INST_LOWER_BOUND) -#define IWL39_RTC_DATA_SIZE (IWL39_RTC_DATA_UPPER_BOUND - \ - IWL39_RTC_DATA_LOWER_BOUND) - -#define IWL39_MAX_INST_SIZE IWL39_RTC_INST_SIZE -#define IWL39_MAX_DATA_SIZE IWL39_RTC_DATA_SIZE - -/* Size of uCode instruction memory in bootstrap state machine */ -#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE - -static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr) -{ - return (addr >= IWL39_RTC_DATA_LOWER_BOUND) && - (addr < IWL39_RTC_DATA_UPPER_BOUND); -} - -/* Base physical address of iwl3945_shared is provided to FH_TSSR_CBB_BASE - * and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */ -struct iwl3945_shared { - __le32 tx_base_ptr[8]; -} __packed; - -static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags) -{ - return le16_to_cpu(rate_n_flags) & 0xFF; -} - -static inline u16 iwl3945_hw_get_rate_n_flags(__le16 rate_n_flags) -{ - return le16_to_cpu(rate_n_flags); -} - -static inline __le16 iwl3945_hw_set_rate_n_flags(u8 rate, u16 flags) -{ - return cpu_to_le16((u16)rate|flags); -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c deleted file mode 100644 index abe2b739c4dc..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ /dev/null @@ -1,91 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/mac80211.h> -#include <linux/etherdevice.h> -#include <asm/unaligned.h> - -#include "iwl-commands.h" -#include "iwl-3945.h" -#include "iwl-core.h" -#include "iwl-dev.h" -#include "iwl-3945-led.h" - - -/* Send led command */ -static int iwl3945_send_led_cmd(struct iwl_priv *priv, - struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - - return iwl_send_cmd(priv, &cmd); -} - -/* Set led on command */ -static int iwl3945_led_on(struct iwl_priv *priv) -{ - struct iwl_led_cmd led_cmd = { - .id = IWL_LED_LINK, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl3945_send_led_cmd(priv, &led_cmd); -} - -/* Set led off command */ -static int iwl3945_led_off(struct iwl_priv *priv) -{ - struct iwl_led_cmd led_cmd = { - .id = IWL_LED_LINK, - .on = 0, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - IWL_DEBUG_LED(priv, "led off\n"); - return iwl3945_send_led_cmd(priv, &led_cmd); -} - -const struct iwl_led_ops iwl3945_led_ops = { - .cmd = iwl3945_send_led_cmd, - .on = iwl3945_led_on, - .off = iwl3945_led_off, -}; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h deleted file mode 100644 index ce990adc51e7..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_3945_led_h__ -#define __iwl_3945_led_h__ - -extern const struct iwl_led_ops iwl3945_led_ops; - -#endif /* __iwl_3945_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c deleted file mode 100644 index 1f3e7e34fbc7..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ /dev/null @@ -1,995 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/slab.h> -#include <linux/wireless.h> -#include <net/mac80211.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/delay.h> - -#include <linux/workqueue.h> - -#include "iwl-commands.h" -#include "iwl-3945.h" -#include "iwl-sta.h" - -#define RS_NAME "iwl-3945-rs" - -static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT_3945] = { - 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202 -}; - -static s32 iwl3945_expected_tpt_g_prot[IWL_RATE_COUNT_3945] = { - 7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125 -}; - -static s32 iwl3945_expected_tpt_a[IWL_RATE_COUNT_3945] = { - 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186 -}; - -static s32 iwl3945_expected_tpt_b[IWL_RATE_COUNT_3945] = { - 7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -struct iwl3945_tpt_entry { - s8 min_rssi; - u8 index; -}; - -static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = { - {-60, IWL_RATE_54M_INDEX}, - {-64, IWL_RATE_48M_INDEX}, - {-72, IWL_RATE_36M_INDEX}, - {-80, IWL_RATE_24M_INDEX}, - {-84, IWL_RATE_18M_INDEX}, - {-85, IWL_RATE_12M_INDEX}, - {-87, IWL_RATE_9M_INDEX}, - {-89, IWL_RATE_6M_INDEX} -}; - -static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { - {-60, IWL_RATE_54M_INDEX}, - {-64, IWL_RATE_48M_INDEX}, - {-68, IWL_RATE_36M_INDEX}, - {-80, IWL_RATE_24M_INDEX}, - {-84, IWL_RATE_18M_INDEX}, - {-85, IWL_RATE_12M_INDEX}, - {-86, IWL_RATE_11M_INDEX}, - {-88, IWL_RATE_5M_INDEX}, - {-90, IWL_RATE_2M_INDEX}, - {-92, IWL_RATE_1M_INDEX} -}; - -#define IWL_RATE_MAX_WINDOW 62 -#define IWL_RATE_FLUSH (3*HZ) -#define IWL_RATE_WIN_FLUSH (HZ/2) -#define IWL39_RATE_HIGH_TH 11520 -#define IWL_SUCCESS_UP_TH 8960 -#define IWL_SUCCESS_DOWN_TH 10880 -#define IWL_RATE_MIN_FAILURE_TH 6 -#define IWL_RATE_MIN_SUCCESS_TH 8 -#define IWL_RATE_DECREASE_TH 1920 -#define IWL_RATE_RETRY_TH 15 - -static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, enum ieee80211_band band) -{ - u32 index = 0; - u32 table_size = 0; - struct iwl3945_tpt_entry *tpt_table = NULL; - - if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) - rssi = IWL_MIN_RSSI_VAL; - - switch (band) { - case IEEE80211_BAND_2GHZ: - tpt_table = iwl3945_tpt_table_g; - table_size = ARRAY_SIZE(iwl3945_tpt_table_g); - break; - - case IEEE80211_BAND_5GHZ: - tpt_table = iwl3945_tpt_table_a; - table_size = ARRAY_SIZE(iwl3945_tpt_table_a); - break; - - default: - BUG(); - break; - } - - while ((index < table_size) && (rssi < tpt_table[index].min_rssi)) - index++; - - index = min(index, (table_size - 1)); - - return tpt_table[index].index; -} - -static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window) -{ - window->data = 0; - window->success_counter = 0; - window->success_ratio = -1; - window->counter = 0; - window->average_tpt = IWL_INVALID_VALUE; - window->stamp = 0; -} - -/** - * iwl3945_rate_scale_flush_windows - flush out the rate scale windows - * - * Returns the number of windows that have gathered data but were - * not flushed. If there were any that were not flushed, then - * reschedule the rate flushing routine. - */ -static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta) -{ - int unflushed = 0; - int i; - unsigned long flags; - struct iwl_priv *priv __maybe_unused = rs_sta->priv; - - /* - * For each rate, if we have collected data on that rate - * and it has been more than IWL_RATE_WIN_FLUSH - * since we flushed, clear out the gathered statistics - */ - for (i = 0; i < IWL_RATE_COUNT_3945; i++) { - if (!rs_sta->win[i].counter) - continue; - - spin_lock_irqsave(&rs_sta->lock, flags); - if (time_after(jiffies, rs_sta->win[i].stamp + - IWL_RATE_WIN_FLUSH)) { - IWL_DEBUG_RATE(priv, "flushing %d samples of rate " - "index %d\n", - rs_sta->win[i].counter, i); - iwl3945_clear_window(&rs_sta->win[i]); - } else - unflushed++; - spin_unlock_irqrestore(&rs_sta->lock, flags); - } - - return unflushed; -} - -#define IWL_RATE_FLUSH_MAX 5000 /* msec */ -#define IWL_RATE_FLUSH_MIN 50 /* msec */ -#define IWL_AVERAGE_PACKETS 1500 - -static void iwl3945_bg_rate_scale_flush(unsigned long data) -{ - struct iwl3945_rs_sta *rs_sta = (void *)data; - struct iwl_priv *priv __maybe_unused = rs_sta->priv; - int unflushed = 0; - unsigned long flags; - u32 packet_count, duration, pps; - - IWL_DEBUG_RATE(priv, "enter\n"); - - unflushed = iwl3945_rate_scale_flush_windows(rs_sta); - - spin_lock_irqsave(&rs_sta->lock, flags); - - /* Number of packets Rx'd since last time this timer ran */ - packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1; - - rs_sta->last_tx_packets = rs_sta->tx_packets + 1; - - if (unflushed) { - duration = - jiffies_to_msecs(jiffies - rs_sta->last_partial_flush); - - IWL_DEBUG_RATE(priv, "Tx'd %d packets in %dms\n", - packet_count, duration); - - /* Determine packets per second */ - if (duration) - pps = (packet_count * 1000) / duration; - else - pps = 0; - - if (pps) { - duration = (IWL_AVERAGE_PACKETS * 1000) / pps; - if (duration < IWL_RATE_FLUSH_MIN) - duration = IWL_RATE_FLUSH_MIN; - else if (duration > IWL_RATE_FLUSH_MAX) - duration = IWL_RATE_FLUSH_MAX; - } else - duration = IWL_RATE_FLUSH_MAX; - - rs_sta->flush_time = msecs_to_jiffies(duration); - - IWL_DEBUG_RATE(priv, "new flush period: %d msec ave %d\n", - duration, packet_count); - - mod_timer(&rs_sta->rate_scale_flush, jiffies + - rs_sta->flush_time); - - rs_sta->last_partial_flush = jiffies; - } else { - rs_sta->flush_time = IWL_RATE_FLUSH; - rs_sta->flush_pending = 0; - } - /* If there weren't any unflushed entries, we don't schedule the timer - * to run again */ - - rs_sta->last_flush = jiffies; - - spin_unlock_irqrestore(&rs_sta->lock, flags); - - IWL_DEBUG_RATE(priv, "leave\n"); -} - -/** - * iwl3945_collect_tx_data - Update the success/failure sliding window - * - * We keep a sliding window of the last 64 packets transmitted - * at this rate. window->data contains the bitmask of successful - * packets. - */ -static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, - struct iwl3945_rate_scale_data *window, - int success, int retries, int index) -{ - unsigned long flags; - s32 fail_count; - struct iwl_priv *priv __maybe_unused = rs_sta->priv; - - if (!retries) { - IWL_DEBUG_RATE(priv, "leave: retries == 0 -- should be at least 1\n"); - return; - } - - spin_lock_irqsave(&rs_sta->lock, flags); - - /* - * Keep track of only the latest 62 tx frame attempts in this rate's - * history window; anything older isn't really relevant any more. - * If we have filled up the sliding window, drop the oldest attempt; - * if the oldest attempt (highest bit in bitmap) shows "success", - * subtract "1" from the success counter (this is the main reason - * we keep these bitmaps!). - * */ - while (retries > 0) { - if (window->counter >= IWL_RATE_MAX_WINDOW) { - - /* remove earliest */ - window->counter = IWL_RATE_MAX_WINDOW - 1; - - if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1))) { - window->data &= ~(1ULL << (IWL_RATE_MAX_WINDOW - 1)); - window->success_counter--; - } - } - - /* Increment frames-attempted counter */ - window->counter++; - - /* Shift bitmap by one frame (throw away oldest history), - * OR in "1", and increment "success" if this - * frame was successful. */ - window->data <<= 1; - if (success > 0) { - window->success_counter++; - window->data |= 0x1; - success--; - } - - retries--; - } - - /* Calculate current success ratio, avoid divide-by-0! */ - if (window->counter > 0) - window->success_ratio = 128 * (100 * window->success_counter) - / window->counter; - else - window->success_ratio = IWL_INVALID_VALUE; - - fail_count = window->counter - window->success_counter; - - /* Calculate average throughput, if we have enough history. */ - if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || - (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) - window->average_tpt = ((window->success_ratio * - rs_sta->expected_tpt[index] + 64) / 128); - else - window->average_tpt = IWL_INVALID_VALUE; - - /* Tag this window as having been updated */ - window->stamp = jiffies; - - spin_unlock_irqrestore(&rs_sta->lock, flags); - -} - -/* - * Called after adding a new station to initialize rate scaling - */ -void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id) -{ - struct ieee80211_hw *hw = priv->hw; - struct ieee80211_conf *conf = &priv->hw->conf; - struct iwl3945_sta_priv *psta; - struct iwl3945_rs_sta *rs_sta; - struct ieee80211_supported_band *sband; - int i; - - IWL_DEBUG_INFO(priv, "enter\n"); - if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id) - goto out; - - psta = (struct iwl3945_sta_priv *) sta->drv_priv; - rs_sta = &psta->rs_sta; - sband = hw->wiphy->bands[conf->channel->band]; - - rs_sta->priv = priv; - - rs_sta->start_rate = IWL_RATE_INVALID; - - /* default to just 802.11b */ - rs_sta->expected_tpt = iwl3945_expected_tpt_b; - - rs_sta->last_partial_flush = jiffies; - rs_sta->last_flush = jiffies; - rs_sta->flush_time = IWL_RATE_FLUSH; - rs_sta->last_tx_packets = 0; - - rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; - rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush; - - for (i = 0; i < IWL_RATE_COUNT_3945; i++) - iwl3945_clear_window(&rs_sta->win[i]); - - /* TODO: what is a good starting rate for STA? About middle? Maybe not - * the lowest or the highest rate.. Could consider using RSSI from - * previous packets? Need to have IEEE 802.1X auth succeed immediately - * after assoc.. */ - - for (i = sband->n_bitrates - 1; i >= 0; i--) { - if (sta->supp_rates[sband->band] & (1 << i)) { - rs_sta->last_txrate_idx = i; - break; - } - } - - priv->_3945.sta_supp_rates = sta->supp_rates[sband->band]; - /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (sband->band == IEEE80211_BAND_5GHZ) { - rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - priv->_3945.sta_supp_rates = priv->_3945.sta_supp_rates << - IWL_FIRST_OFDM_RATE; - } - -out: - priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; - - IWL_DEBUG_INFO(priv, "leave\n"); -} - -static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - return hw->priv; -} - -/* rate scale requires free function to be implemented */ -static void rs_free(void *priv) -{ - return; -} - -static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - struct iwl3945_rs_sta *rs_sta; - struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; - struct iwl_priv *priv __maybe_unused = iwl_priv; - - IWL_DEBUG_RATE(priv, "enter\n"); - - rs_sta = &psta->rs_sta; - - spin_lock_init(&rs_sta->lock); - init_timer(&rs_sta->rate_scale_flush); - - IWL_DEBUG_RATE(priv, "leave\n"); - - return rs_sta; -} - -static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - struct iwl3945_rs_sta *rs_sta = priv_sta; - - /* - * Be careful not to use any members of iwl3945_rs_sta (like trying - * to use iwl_priv to print out debugging) since it may not be fully - * initialized at this point. - */ - del_timer_sync(&rs_sta->rate_scale_flush); -} - - -/** - * rs_tx_status - Update rate control values based on Tx results - * - * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by - * the hardware for each rate. - */ -static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - s8 retries = 0, current_count; - int scale_rate_index, first_index, last_index; - unsigned long flags; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct iwl3945_rs_sta *rs_sta = priv_sta; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - IWL_DEBUG_RATE(priv, "enter\n"); - - retries = info->status.rates[0].count; - /* Sanity Check for retries */ - if (retries > IWL_RATE_RETRY_TH) - retries = IWL_RATE_RETRY_TH; - - first_index = sband->bitrates[info->status.rates[0].idx].hw_value; - if ((first_index < 0) || (first_index >= IWL_RATE_COUNT_3945)) { - IWL_DEBUG_RATE(priv, "leave: Rate out of bounds: %d\n", first_index); - return; - } - - if (!priv_sta) { - IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); - return; - } - - /* Treat uninitialized rate scaling data same as non-existing. */ - if (!rs_sta->priv) { - IWL_DEBUG_RATE(priv, "leave: STA priv data uninitialized!\n"); - return; - } - - - rs_sta->tx_packets++; - - scale_rate_index = first_index; - last_index = first_index; - - /* - * Update the window for each rate. We determine which rates - * were Tx'd based on the total number of retries vs. the number - * of retries configured for each rate -- currently set to the - * priv value 'retry_rate' vs. rate specific - * - * On exit from this while loop last_index indicates the rate - * at which the frame was finally transmitted (or failed if no - * ACK) - */ - while (retries > 1) { - if ((retries - 1) < priv->retry_rate) { - current_count = (retries - 1); - last_index = scale_rate_index; - } else { - current_count = priv->retry_rate; - last_index = iwl3945_rs_next_rate(priv, - scale_rate_index); - } - - /* Update this rate accounting for as many retries - * as was used for it (per current_count) */ - iwl3945_collect_tx_data(rs_sta, - &rs_sta->win[scale_rate_index], - 0, current_count, scale_rate_index); - IWL_DEBUG_RATE(priv, "Update rate %d for %d retries.\n", - scale_rate_index, current_count); - - retries -= current_count; - - scale_rate_index = last_index; - } - - - /* Update the last index window with success/failure based on ACK */ - IWL_DEBUG_RATE(priv, "Update rate %d with %s.\n", - last_index, - (info->flags & IEEE80211_TX_STAT_ACK) ? - "success" : "failure"); - iwl3945_collect_tx_data(rs_sta, - &rs_sta->win[last_index], - info->flags & IEEE80211_TX_STAT_ACK, 1, last_index); - - /* We updated the rate scale window -- if its been more than - * flush_time since the last run, schedule the flush - * again */ - spin_lock_irqsave(&rs_sta->lock, flags); - - if (!rs_sta->flush_pending && - time_after(jiffies, rs_sta->last_flush + - rs_sta->flush_time)) { - - rs_sta->last_partial_flush = jiffies; - rs_sta->flush_pending = 1; - mod_timer(&rs_sta->rate_scale_flush, - jiffies + rs_sta->flush_time); - } - - spin_unlock_irqrestore(&rs_sta->lock, flags); - - IWL_DEBUG_RATE(priv, "leave\n"); -} - -static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, - u8 index, u16 rate_mask, enum ieee80211_band band) -{ - u8 high = IWL_RATE_INVALID; - u8 low = IWL_RATE_INVALID; - struct iwl_priv *priv __maybe_unused = rs_sta->priv; - - /* 802.11A walks to the next literal adjacent rate in - * the rate table */ - if (unlikely(band == IEEE80211_BAND_5GHZ)) { - int i; - u32 mask; - - /* Find the previous rate that is in the rate mask */ - i = index - 1; - for (mask = (1 << i); i >= 0; i--, mask >>= 1) { - if (rate_mask & mask) { - low = i; - break; - } - } - - /* Find the next rate that is in the rate mask */ - i = index + 1; - for (mask = (1 << i); i < IWL_RATE_COUNT_3945; - i++, mask <<= 1) { - if (rate_mask & mask) { - high = i; - break; - } - } - - return (high << 8) | low; - } - - low = index; - while (low != IWL_RATE_INVALID) { - if (rs_sta->tgg) - low = iwl3945_rates[low].prev_rs_tgg; - else - low = iwl3945_rates[low].prev_rs; - if (low == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << low)) - break; - IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low); - } - - high = index; - while (high != IWL_RATE_INVALID) { - if (rs_sta->tgg) - high = iwl3945_rates[high].next_rs_tgg; - else - high = iwl3945_rates[high].next_rs; - if (high == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << high)) - break; - IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high); - } - - return (high << 8) | low; -} - -/** - * rs_get_rate - find the rate for the requested packet - * - * Returns the ieee80211_rate structure allocated by the driver. - * - * The rate control algorithm has no internal mapping between hw_mode's - * rate ordering and the rate ordering used by the rate control algorithm. - * - * The rate control algorithm uses a single table of rates that goes across - * the entire A/B/G spectrum vs. being limited to just one particular - * hw_mode. - * - * As such, we can't convert the index obtained below into the hw_mode's - * rate table and must reference the driver allocated rate table - * - */ -static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, - void *priv_sta, struct ieee80211_tx_rate_control *txrc) -{ - struct ieee80211_supported_band *sband = txrc->sband; - struct sk_buff *skb = txrc->skb; - u8 low = IWL_RATE_INVALID; - u8 high = IWL_RATE_INVALID; - u16 high_low; - int index; - struct iwl3945_rs_sta *rs_sta = priv_sta; - struct iwl3945_rate_scale_data *window = NULL; - int current_tpt = IWL_INVALID_VALUE; - int low_tpt = IWL_INVALID_VALUE; - int high_tpt = IWL_INVALID_VALUE; - u32 fail_count; - s8 scale_action = 0; - unsigned long flags; - u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; - s8 max_rate_idx = -1; - struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - IWL_DEBUG_RATE(priv, "enter\n"); - - /* Treat uninitialized rate scaling data same as non-existing. */ - if (rs_sta && !rs_sta->priv) { - IWL_DEBUG_RATE(priv, "Rate scaling information not initialized yet.\n"); - priv_sta = NULL; - } - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - rate_mask = sta->supp_rates[sband->band]; - - /* get user max rate if set */ - max_rate_idx = txrc->max_rate_idx; - if ((sband->band == IEEE80211_BAND_5GHZ) && (max_rate_idx != -1)) - max_rate_idx += IWL_FIRST_OFDM_RATE; - if ((max_rate_idx < 0) || (max_rate_idx >= IWL_RATE_COUNT)) - max_rate_idx = -1; - - index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT_3945 - 1); - - if (sband->band == IEEE80211_BAND_5GHZ) - rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; - - spin_lock_irqsave(&rs_sta->lock, flags); - - /* for recent assoc, choose best rate regarding - * to rssi value - */ - if (rs_sta->start_rate != IWL_RATE_INVALID) { - if (rs_sta->start_rate < index && - (rate_mask & (1 << rs_sta->start_rate))) - index = rs_sta->start_rate; - rs_sta->start_rate = IWL_RATE_INVALID; - } - - /* force user max rate if set by user */ - if ((max_rate_idx != -1) && (max_rate_idx < index)) { - if (rate_mask & (1 << max_rate_idx)) - index = max_rate_idx; - } - - window = &(rs_sta->win[index]); - - fail_count = window->counter - window->success_counter; - - if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { - spin_unlock_irqrestore(&rs_sta->lock, flags); - - IWL_DEBUG_RATE(priv, "Invalid average_tpt on rate %d: " - "counter: %d, success_counter: %d, " - "expected_tpt is %sNULL\n", - index, - window->counter, - window->success_counter, - rs_sta->expected_tpt ? "not " : ""); - - /* Can't calculate this yet; not enough history */ - window->average_tpt = IWL_INVALID_VALUE; - goto out; - - } - - current_tpt = window->average_tpt; - - high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, - sband->band); - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - /* If user set max rate, dont allow higher than user constrain */ - if ((max_rate_idx != -1) && (max_rate_idx < high)) - high = IWL_RATE_INVALID; - - /* Collect Measured throughputs of adjacent rates */ - if (low != IWL_RATE_INVALID) - low_tpt = rs_sta->win[low].average_tpt; - - if (high != IWL_RATE_INVALID) - high_tpt = rs_sta->win[high].average_tpt; - - spin_unlock_irqrestore(&rs_sta->lock, flags); - - scale_action = 0; - - /* Low success ratio , need to drop the rate */ - if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { - IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n"); - scale_action = -1; - /* No throughput measured yet for adjacent rates, - * try increase */ - } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) { - - if (high != IWL_RATE_INVALID && window->success_ratio >= IWL_RATE_INCREASE_TH) - scale_action = 1; - else if (low != IWL_RATE_INVALID) - scale_action = 0; - - /* Both adjacent throughputs are measured, but neither one has - * better throughput; we're using the best rate, don't change - * it! */ - } else if ((low_tpt != IWL_INVALID_VALUE) && - (high_tpt != IWL_INVALID_VALUE) && - (low_tpt < current_tpt) && (high_tpt < current_tpt)) { - - IWL_DEBUG_RATE(priv, "No action -- low [%d] & high [%d] < " - "current_tpt [%d]\n", - low_tpt, high_tpt, current_tpt); - scale_action = 0; - - /* At least one of the rates has better throughput */ - } else { - if (high_tpt != IWL_INVALID_VALUE) { - - /* High rate has better throughput, Increase - * rate */ - if (high_tpt > current_tpt && - window->success_ratio >= IWL_RATE_INCREASE_TH) - scale_action = 1; - else { - IWL_DEBUG_RATE(priv, - "decrease rate because of high tpt\n"); - scale_action = 0; - } - } else if (low_tpt != IWL_INVALID_VALUE) { - if (low_tpt > current_tpt) { - IWL_DEBUG_RATE(priv, - "decrease rate because of low tpt\n"); - scale_action = -1; - } else if (window->success_ratio >= IWL_RATE_INCREASE_TH) { - /* Lower rate has better - * throughput,decrease rate */ - scale_action = 1; - } - } - } - - /* Sanity check; asked for decrease, but success rate or throughput - * has been good at old rate. Don't change it. */ - if ((scale_action == -1) && (low != IWL_RATE_INVALID) && - ((window->success_ratio > IWL_RATE_HIGH_TH) || - (current_tpt > (100 * rs_sta->expected_tpt[low])))) - scale_action = 0; - - switch (scale_action) { - case -1: - - /* Decrese rate */ - if (low != IWL_RATE_INVALID) - index = low; - break; - - case 1: - /* Increase rate */ - if (high != IWL_RATE_INVALID) - index = high; - - break; - - case 0: - default: - /* No change */ - break; - } - - IWL_DEBUG_RATE(priv, "Selected %d (action %d) - low %d high %d\n", - index, scale_action, low, high); - - out: - - rs_sta->last_txrate_idx = index; - if (sband->band == IEEE80211_BAND_5GHZ) - info->control.rates[0].idx = rs_sta->last_txrate_idx - - IWL_FIRST_OFDM_RATE; - else - info->control.rates[0].idx = rs_sta->last_txrate_idx; - - IWL_DEBUG_RATE(priv, "leave: %d\n", index); -} - -#ifdef CONFIG_MAC80211_DEBUGFS -static int iwl3945_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - char *buff; - int desc = 0; - int j; - ssize_t ret; - struct iwl3945_rs_sta *lq_sta = file->private_data; - - buff = kmalloc(1024, GFP_KERNEL); - if (!buff) - return -ENOMEM; - - desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n" - "rate=0x%X flush time %d\n", - lq_sta->tx_packets, - lq_sta->last_txrate_idx, - lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time)); - for (j = 0; j < IWL_RATE_COUNT_3945; j++) { - desc += sprintf(buff+desc, - "counter=%d success=%d %%=%d\n", - lq_sta->win[j].counter, - lq_sta->win[j].success_counter, - lq_sta->win[j].success_ratio); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - kfree(buff); - return ret; -} - -static const struct file_operations rs_sta_dbgfs_stats_table_ops = { - .read = iwl3945_sta_dbgfs_stats_table_read, - .open = iwl3945_open_file_generic, - .llseek = default_llseek, -}; - -static void iwl3945_add_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct iwl3945_rs_sta *lq_sta = priv_sta; - - lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", 0600, dir, - lq_sta, &rs_sta_dbgfs_stats_table_ops); - -} - -static void iwl3945_remove_debugfs(void *priv, void *priv_sta) -{ - struct iwl3945_rs_sta *lq_sta = priv_sta; - debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); -} -#endif - -/* - * Initialization of rate scaling information is done by driver after - * the station is added. Since mac80211 calls this function before a - * station is added we ignore it. - */ -static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta) -{ -} - -static struct rate_control_ops rs_ops = { - .module = NULL, - .name = RS_NAME, - .tx_status = rs_tx_status, - .get_rate = rs_get_rate, - .rate_init = rs_rate_init_stub, - .alloc = rs_alloc, - .free = rs_free, - .alloc_sta = rs_alloc_sta, - .free_sta = rs_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = iwl3945_add_debugfs, - .remove_sta_debugfs = iwl3945_remove_debugfs, -#endif - -}; -void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) -{ - struct iwl_priv *priv = hw->priv; - s32 rssi = 0; - unsigned long flags; - struct iwl3945_rs_sta *rs_sta; - struct ieee80211_sta *sta; - struct iwl3945_sta_priv *psta; - - IWL_DEBUG_RATE(priv, "enter\n"); - - rcu_read_lock(); - - sta = ieee80211_find_sta(priv->contexts[IWL_RXON_CTX_BSS].vif, - priv->stations[sta_id].sta.sta.addr); - if (!sta) { - IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n"); - rcu_read_unlock(); - return; - } - - psta = (void *) sta->drv_priv; - rs_sta = &psta->rs_sta; - - spin_lock_irqsave(&rs_sta->lock, flags); - - rs_sta->tgg = 0; - switch (priv->band) { - case IEEE80211_BAND_2GHZ: - /* TODO: this always does G, not a regression */ - if (priv->contexts[IWL_RXON_CTX_BSS].active.flags & - RXON_FLG_TGG_PROTECT_MSK) { - rs_sta->tgg = 1; - rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot; - } else - rs_sta->expected_tpt = iwl3945_expected_tpt_g; - break; - - case IEEE80211_BAND_5GHZ: - rs_sta->expected_tpt = iwl3945_expected_tpt_a; - break; - case IEEE80211_NUM_BANDS: - BUG(); - break; - } - - spin_unlock_irqrestore(&rs_sta->lock, flags); - - rssi = priv->_3945.last_rx_rssi; - if (rssi == 0) - rssi = IWL_MIN_RSSI_VAL; - - IWL_DEBUG_RATE(priv, "Network RSSI: %d\n", rssi); - - rs_sta->start_rate = iwl3945_get_rate_index_by_rssi(rssi, priv->band); - - IWL_DEBUG_RATE(priv, "leave: rssi %d assign rate index: " - "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, - iwl3945_rates[rs_sta->start_rate].plcp); - rcu_read_unlock(); -} - -int iwl3945_rate_control_register(void) -{ - return ieee80211_rate_control_register(&rs_ops); -} - -void iwl3945_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&rs_ops); -} - - diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c deleted file mode 100644 index 39b6f16c87fa..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ /dev/null @@ -1,2753 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <linux/firmware.h> -#include <linux/etherdevice.h> -#include <asm/unaligned.h> -#include <net/mac80211.h> - -#include "iwl-fh.h" -#include "iwl-3945-fh.h" -#include "iwl-commands.h" -#include "iwl-sta.h" -#include "iwl-3945.h" -#include "iwl-eeprom.h" -#include "iwl-core.h" -#include "iwl-helpers.h" -#include "iwl-led.h" -#include "iwl-3945-led.h" -#include "iwl-3945-debugfs.h" -#include "iwl-legacy.h" - -#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ - [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ - IWL_RATE_##r##M_IEEE, \ - IWL_RATE_##ip##M_INDEX, \ - IWL_RATE_##in##M_INDEX, \ - IWL_RATE_##rp##M_INDEX, \ - IWL_RATE_##rn##M_INDEX, \ - IWL_RATE_##pp##M_INDEX, \ - IWL_RATE_##np##M_INDEX, \ - IWL_RATE_##r##M_INDEX_TABLE, \ - IWL_RATE_##ip##M_INDEX_TABLE } - -/* - * Parameter order: - * rate, prev rate, next rate, prev tgg rate, next tgg rate - * - * If there isn't a valid next or previous rate then INV is used which - * maps to IWL_RATE_INVALID - * - */ -const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = { - IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */ - IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */ - IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */ - IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18), /* 11mbps */ - IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11), /* 6mbps */ - IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11), /* 9mbps */ - IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18), /* 12mbps */ - IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24), /* 18mbps */ - IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36), /* 24mbps */ - IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48), /* 36mbps */ - IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54), /* 48mbps */ - IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */ -}; - -static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) -{ - u8 rate = iwl3945_rates[rate_index].prev_ieee; - - if (rate == IWL_RATE_INVALID) - rate = rate_index; - return rate; -} - -/* 1 = enable the iwl3945_disable_events() function */ -#define IWL_EVT_DISABLE (0) -#define IWL_EVT_DISABLE_SIZE (1532/32) - -/** - * iwl3945_disable_events - Disable selected events in uCode event log - * - * Disable an event by writing "1"s into "disable" - * bitmap in SRAM. Bit position corresponds to Event # (id/type). - * Default values of 0 enable uCode events to be logged. - * Use for only special debugging. This function is just a placeholder as-is, - * you'll need to provide the special bits! ... - * ... and set IWL_EVT_DISABLE to 1. */ -void iwl3945_disable_events(struct iwl_priv *priv) -{ - int i; - u32 base; /* SRAM address of event log header */ - u32 disable_ptr; /* SRAM address of event-disable bitmap array */ - u32 array_size; /* # of u32 entries in array */ - static const u32 evt_disable[IWL_EVT_DISABLE_SIZE] = { - 0x00000000, /* 31 - 0 Event id numbers */ - 0x00000000, /* 63 - 32 */ - 0x00000000, /* 95 - 64 */ - 0x00000000, /* 127 - 96 */ - 0x00000000, /* 159 - 128 */ - 0x00000000, /* 191 - 160 */ - 0x00000000, /* 223 - 192 */ - 0x00000000, /* 255 - 224 */ - 0x00000000, /* 287 - 256 */ - 0x00000000, /* 319 - 288 */ - 0x00000000, /* 351 - 320 */ - 0x00000000, /* 383 - 352 */ - 0x00000000, /* 415 - 384 */ - 0x00000000, /* 447 - 416 */ - 0x00000000, /* 479 - 448 */ - 0x00000000, /* 511 - 480 */ - 0x00000000, /* 543 - 512 */ - 0x00000000, /* 575 - 544 */ - 0x00000000, /* 607 - 576 */ - 0x00000000, /* 639 - 608 */ - 0x00000000, /* 671 - 640 */ - 0x00000000, /* 703 - 672 */ - 0x00000000, /* 735 - 704 */ - 0x00000000, /* 767 - 736 */ - 0x00000000, /* 799 - 768 */ - 0x00000000, /* 831 - 800 */ - 0x00000000, /* 863 - 832 */ - 0x00000000, /* 895 - 864 */ - 0x00000000, /* 927 - 896 */ - 0x00000000, /* 959 - 928 */ - 0x00000000, /* 991 - 960 */ - 0x00000000, /* 1023 - 992 */ - 0x00000000, /* 1055 - 1024 */ - 0x00000000, /* 1087 - 1056 */ - 0x00000000, /* 1119 - 1088 */ - 0x00000000, /* 1151 - 1120 */ - 0x00000000, /* 1183 - 1152 */ - 0x00000000, /* 1215 - 1184 */ - 0x00000000, /* 1247 - 1216 */ - 0x00000000, /* 1279 - 1248 */ - 0x00000000, /* 1311 - 1280 */ - 0x00000000, /* 1343 - 1312 */ - 0x00000000, /* 1375 - 1344 */ - 0x00000000, /* 1407 - 1376 */ - 0x00000000, /* 1439 - 1408 */ - 0x00000000, /* 1471 - 1440 */ - 0x00000000, /* 1503 - 1472 */ - }; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!iwl3945_hw_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return; - } - - disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32))); - array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32))); - - if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { - IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n", - disable_ptr); - for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) - iwl_write_targ_mem(priv, - disable_ptr + (i * sizeof(u32)), - evt_disable[i]); - - } else { - IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n"); - IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n"); - IWL_DEBUG_INFO(priv, " in SRAM at 0x%x, size %d u32s\n", - disable_ptr, array_size); - } - -} - -static int iwl3945_hwrate_to_plcp_idx(u8 plcp) -{ - int idx; - - for (idx = 0; idx < IWL_RATE_COUNT_3945; idx++) - if (iwl3945_rates[idx].plcp == plcp) - return idx; - return -1; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x - -static const char *iwl3945_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_3945_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"; -} -#else -static inline const char *iwl3945_get_tx_fail_reason(u32 status) -{ - return ""; -} -#endif - -/* - * get ieee prev rate from rate scale table. - * for A and B mode we need to overright prev - * value - */ -int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate) -{ - int next_rate = iwl3945_get_prev_ieee_rate(rate); - - switch (priv->band) { - case IEEE80211_BAND_5GHZ: - if (rate == IWL_RATE_12M_INDEX) - next_rate = IWL_RATE_9M_INDEX; - else if (rate == IWL_RATE_6M_INDEX) - next_rate = IWL_RATE_6M_INDEX; - break; - case IEEE80211_BAND_2GHZ: - if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) && - iwl_is_associated(priv, IWL_RXON_CTX_BSS)) { - if (rate == IWL_RATE_11M_INDEX) - next_rate = IWL_RATE_5M_INDEX; - } - break; - - default: - break; - } - - return next_rate; -} - - -/** - * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd - * - * When FW advances 'R' index, all entries between old and new 'R' index - * need to be reclaimed. As result, some free space forms. If there is - * enough free space (> low mark), wake the stack that feeds us. - */ -static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, - int txq_id, int index) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - struct iwl_tx_info *tx_info; - - BUG_ON(txq_id == IWL39_CMD_QUEUE_NUM); - - for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - - tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb); - tx_info->skb = NULL; - priv->cfg->ops->lib->txq_free_tfd(priv, txq); - } - - if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && - (txq_id != IWL39_CMD_QUEUE_NUM) && - priv->mac80211_registered) - iwl_wake_queue(priv, txq); -} - -/** - * iwl3945_rx_reply_tx - Handle Tx response - */ -static void iwl3945_rx_reply_tx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_info *info; - struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->status); - int rate_idx; - int fail; - - if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { - IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - txq->time_stamp = jiffies; - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); - ieee80211_tx_info_clear_status(info); - - /* Fill the MRR chain with some info about on-chip retransmissions */ - rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - - fail = tx_resp->failure_frame; - - info->status.rates[0].idx = rate_idx; - info->status.rates[0].count = fail + 1; /* add final attempt */ - - /* tx_status->rts_retry_count = tx_resp->failure_rts; */ - info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? - IEEE80211_TX_STAT_ACK : 0; - - IWL_DEBUG_TX(priv, "Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", - txq_id, iwl3945_get_tx_fail_reason(status), status, - tx_resp->rate, tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY(priv, "Tx queue reclaim %d\n", index); - iwl3945_tx_queue_reclaim(priv, txq_id, index); - - if (status & TX_ABORT_REQUIRED_MSK) - IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n"); -} - - - -/***************************************************************************** - * - * Intel PRO/Wireless 3945ABG/BG Network Connection - * - * RX handler implementations - * - *****************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUGFS -/* - * based on the assumption of all statistics counter are in DWORD - * FIXME: This function is for debugging, do not deal with - * the case of counters roll-over. - */ -static void iwl3945_accumulative_statistics(struct iwl_priv *priv, - __le32 *stats) -{ - int i; - __le32 *prev_stats; - u32 *accum_stats; - u32 *delta, *max_delta; - - prev_stats = (__le32 *)&priv->_3945.statistics; - accum_stats = (u32 *)&priv->_3945.accum_statistics; - delta = (u32 *)&priv->_3945.delta_statistics; - max_delta = (u32 *)&priv->_3945.max_delta; - - for (i = sizeof(__le32); i < sizeof(struct iwl3945_notif_statistics); - i += sizeof(__le32), stats++, prev_stats++, delta++, - max_delta++, accum_stats++) { - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { - *delta = (le32_to_cpu(*stats) - - le32_to_cpu(*prev_stats)); - *accum_stats += *delta; - if (*delta > *max_delta) - *max_delta = *delta; - } - } - - /* reset accumulative statistics for "no-counter" type statistics */ - priv->_3945.accum_statistics.general.temperature = - priv->_3945.statistics.general.temperature; - priv->_3945.accum_statistics.general.ttl_timestamp = - priv->_3945.statistics.general.ttl_timestamp; -} -#endif - -void iwl3945_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - - IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl3945_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); -#ifdef CONFIG_IWLWIFI_DEBUGFS - iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw); -#endif - iwl_recover_from_statistics(priv, pkt); - - memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics)); -} - -void iwl3945_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - __le32 *flag = (__le32 *)&pkt->u.raw; - - if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - memset(&priv->_3945.accum_statistics, 0, - sizeof(struct iwl3945_notif_statistics)); - memset(&priv->_3945.delta_statistics, 0, - sizeof(struct iwl3945_notif_statistics)); - memset(&priv->_3945.max_delta, 0, - sizeof(struct iwl3945_notif_statistics)); -#endif - IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); - } - iwl3945_hw_rx_statistics(priv, rxb); -} - - -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ - -/* This is necessary only for a number of statistics, see the caller. */ -static int iwl3945_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 NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ - /* packets to our IBSS update information */ - return !compare_ether_addr(header->addr3, priv->bssid); - case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ - /* packets to our IBSS update information */ - return !compare_ether_addr(header->addr2, priv->bssid); - default: - return 1; - } -} - -static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); - struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - u16 len = le16_to_cpu(rx_hdr->len); - struct sk_buff *skb; - __le16 fc = hdr->frame_control; - - /* We received data from the HW, so stop the watchdog */ - if (unlikely(len + IWL39_RX_FRAME_SIZE > - PAGE_SIZE << priv->hw_params.rx_page_order)) { - IWL_DEBUG_DROP(priv, "Corruption detected!\n"); - return; - } - - /* We only process data packets if the interface is open */ - if (unlikely(!priv->is_open)) { - IWL_DEBUG_DROP_LIMIT(priv, - "Dropping packet while interface is not open.\n"); - return; - } - - skb = dev_alloc_skb(128); - if (!skb) { - IWL_ERR(priv, "dev_alloc_skb failed\n"); - return; - } - - if (!iwl3945_mod_params.sw_crypto) - iwl_set_decrypted_flag(priv, - (struct ieee80211_hdr *)rxb_addr(rxb), - le32_to_cpu(rx_end->status), stats); - - skb_add_rx_frag(skb, 0, rxb->page, - (void *)rx_hdr->payload - (void *)pkt, len); - - iwl_update_stats(priv, false, fc, len); - memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - - ieee80211_rx(priv->hw, skb); - priv->alloc_rxb_page--; - rxb->page = NULL; -} - -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) - -static void iwl3945_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - u16 rx_stats_sig_avg __maybe_unused = le16_to_cpu(rx_stats->sig_avg); - u16 rx_stats_noise_diff __maybe_unused = le16_to_cpu(rx_stats->noise_diff); - u8 network_packet; - - rx_status.flag = 0; - rx_status.mactime = le64_to_cpu(rx_end->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel)); - rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - - rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - - rx_status.antenna = (le16_to_cpu(rx_hdr->phy_flags) & - RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; - - /* set the preamble flag if appropriate */ - if (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - rx_status.flag |= RX_FLAG_SHORTPRE; - - if ((unlikely(rx_stats->phy_count > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - rx_stats->phy_count); - return; - } - - if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) - || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", rx_end->status); - return; - } - - - - /* Convert 3945's rssi indicator to dBm */ - rx_status.signal = rx_stats->rssi - IWL39_RSSI_OFFSET; - - IWL_DEBUG_STATS(priv, "Rssi %d sig_avg %d noise_diff %d\n", - rx_status.signal, rx_stats_sig_avg, - rx_stats_noise_diff); - - header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); - - network_packet = iwl3945_is_network_packet(priv, header); - - IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Rate:%u\n", - network_packet ? '*' : ' ', - le16_to_cpu(rx_hdr->channel), - rx_status.signal, rx_status.signal, - rx_status.rate_idx); - - iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header); - - if (network_packet) { - priv->_3945.last_beacon_time = - le32_to_cpu(rx_end->beacon_timestamp); - priv->_3945.last_tsf = le64_to_cpu(rx_end->timestamp); - priv->_3945.last_rx_rssi = rx_status.signal; - } - - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); -} - -int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, u8 reset, u8 pad) -{ - int count; - struct iwl_queue *q; - struct iwl3945_tfd *tfd, *tfd_tmp; - - q = &txq->q; - tfd_tmp = (struct iwl3945_tfd *)txq->tfds; - tfd = &tfd_tmp[q->write_ptr]; - - if (reset) - memset(tfd, 0, sizeof(*tfd)); - - count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); - - if ((count >= NUM_TFD_CHUNKS) || (count < 0)) { - IWL_ERR(priv, "Error can not send more than %d chunks\n", - NUM_TFD_CHUNKS); - return -EINVAL; - } - - tfd->tbs[count].addr = cpu_to_le32(addr); - tfd->tbs[count].len = cpu_to_le32(len); - - count++; - - tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) | - TFD_CTL_PAD_SET(pad)); - - return 0; -} - -/** - * iwl3945_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr] - * - * Does NOT advance any indexes - */ -void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) -{ - struct iwl3945_tfd *tfd_tmp = (struct iwl3945_tfd *)txq->tfds; - int index = txq->q.read_ptr; - struct iwl3945_tfd *tfd = &tfd_tmp[index]; - struct pci_dev *dev = priv->pci_dev; - int i; - int counter; - - /* sanity check */ - counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); - if (counter > NUM_TFD_CHUNKS) { - IWL_ERR(priv, "Too many chunks: %i\n", counter); - /* @todo issue fatal error, it is quite serious situation */ - return; - } - - /* Unmap tx_cmd */ - if (counter) - pci_unmap_single(dev, - dma_unmap_addr(&txq->meta[index], mapping), - dma_unmap_len(&txq->meta[index], len), - PCI_DMA_TODEVICE); - - /* unmap chunks if any */ - - for (i = 1; i < counter; i++) - pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr), - le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE); - - /* free SKB */ - if (txq->txb) { - struct sk_buff *skb; - - skb = txq->txb[txq->q.read_ptr].skb; - - /* can be called from irqs-disabled context */ - if (skb) { - dev_kfree_skb_any(skb); - txq->txb[txq->q.read_ptr].skb = NULL; - } - } -} - -/** - * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: - * -*/ -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id) -{ - u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; - u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT_3945); - u16 rate_mask; - int rate; - u8 rts_retry_limit; - u8 data_retry_limit; - __le32 tx_flags; - __le16 fc = hdr->frame_control; - struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - - rate = iwl3945_rates[rate_index].plcp; - tx_flags = tx_cmd->tx_flags; - - /* We need to figure out how to get the sta->supp_rates while - * in this running context */ - rate_mask = IWL_RATES_MASK; - - - /* Set retry limit on DATA packets and Probe Responses*/ - if (ieee80211_is_probe_resp(fc)) - data_retry_limit = 3; - else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - tx_cmd->data_retry_limit = data_retry_limit; - - if (tx_id >= IWL39_CMD_QUEUE_NUM) - rts_retry_limit = 3; - else - rts_retry_limit = 7; - - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - tx_cmd->rts_retry_limit = rts_retry_limit; - - tx_cmd->rate = rate; - tx_cmd->tx_flags = tx_flags; - - /* OFDM */ - tx_cmd->supp_rates[0] = - ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF; - - /* CCK */ - tx_cmd->supp_rates[1] = (rate_mask & 0xF); - - IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " - "cck/ofdm mask: 0x%x/0x%x\n", sta_id, - tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags), - tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]); -} - -static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate) -{ - unsigned long flags_spin; - struct iwl_station_entry *station; - - if (sta_id == IWL_INVALID_STATION) - return IWL_INVALID_STATION; - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - station = &priv->stations[sta_id]; - - station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; - station->sta.rate_n_flags = cpu_to_le16(tx_rate); - station->sta.mode = STA_CONTROL_MODIFY_MSK; - iwl_send_add_sta(priv, &station->sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", - sta_id, tx_rate); - return sta_id; -} - -static void iwl3945_set_pwr_vmain(struct iwl_priv *priv) -{ -/* - * (for documentation purposes) - * to set power to V_AUX, do - - if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - - iwl_poll_bit(priv, CSR_GPIO_IN, - CSR_GPIO_IN_VAL_VAUX_PWR_SRC, - CSR_GPIO_IN_BIT_AUX_POWER, 5000); - } - */ - - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); - - iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, - CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ -} - -static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->bd_dma); - iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma); - iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0); - iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), - FH39_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE | - FH39_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE | - FH39_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN | - FH39_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 | - (RX_QUEUE_SIZE_LOG << FH39_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) | - FH39_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST | - (1 << FH39_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) | - FH39_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH); - - /* fake read to flush all prev I/O */ - iwl_read_direct32(priv, FH39_RSSR_CTRL); - - return 0; -} - -static int iwl3945_tx_reset(struct iwl_priv *priv) -{ - - /* bypass mode */ - iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2); - - /* RA 0 is active */ - iwl_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01); - - /* all 6 fifo are active */ - iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f); - - iwl_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000); - iwl_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002); - iwl_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004); - iwl_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005); - - iwl_write_direct32(priv, FH39_TSSR_CBB_BASE, - priv->_3945.shared_phys); - - iwl_write_direct32(priv, FH39_TSSR_MSG_CONFIG, - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | - FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); - - - return 0; -} - -/** - * iwl3945_txq_ctx_reset - Reset TX queue context - * - * Destroys all DMA structures and initialize them again - */ -static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) -{ - int rc; - int txq_id, slots_num; - - iwl3945_hw_txq_ctx_free(priv); - - /* allocate tx queue structure */ - rc = iwl_alloc_txq_mem(priv); - if (rc) - return rc; - - /* Tx CMD queue */ - rc = iwl3945_tx_reset(priv); - if (rc) - goto error; - - /* Tx queue(s) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == IWL39_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (rc) { - IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return rc; - - error: - iwl3945_hw_txq_ctx_free(priv); - return rc; -} - - -/* - * Start up 3945's basic functionality after it has been reset - * (e.g. after platform boot, or shutdown via iwl_apm_stop()) - * NOTE: This does not load uCode nor start the embedded processor - */ -static int iwl3945_apm_init(struct iwl_priv *priv) -{ - int ret = iwl_apm_init(priv); - - /* Clear APMG (NIC's internal power management) interrupts */ - iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); - - /* Reset radio chip */ - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - - return ret; -} - -static void iwl3945_nic_config(struct iwl_priv *priv) -{ - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - unsigned long flags; - u8 rev_id = 0; - - spin_lock_irqsave(&priv->lock, flags); - - /* Determine HW type */ - pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); - - if (rev_id & PCI_CFG_REV_ID_BIT_RTP) - IWL_DEBUG_INFO(priv, "RTP type\n"); - else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { - IWL_DEBUG_INFO(priv, "3945 RADIO-MB type\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BIT_3945_MB); - } else { - IWL_DEBUG_INFO(priv, "3945 RADIO-MM type\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BIT_3945_MM); - } - - if (EEPROM_SKU_CAP_OP_MODE_MRC == eeprom->sku_cap) { - IWL_DEBUG_INFO(priv, "SKU OP mode is mrc\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC); - } else - IWL_DEBUG_INFO(priv, "SKU OP mode is basic\n"); - - if ((eeprom->board_revision & 0xF0) == 0xD0) { - IWL_DEBUG_INFO(priv, "3945ABG revision is 0x%X\n", - eeprom->board_revision); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); - } else { - IWL_DEBUG_INFO(priv, "3945ABG revision is 0x%X\n", - eeprom->board_revision); - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); - } - - if (eeprom->almgor_m_version <= 1) { - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); - IWL_DEBUG_INFO(priv, "Card M type A version is 0x%X\n", - eeprom->almgor_m_version); - } else { - IWL_DEBUG_INFO(priv, "Card M type B version is 0x%X\n", - eeprom->almgor_m_version); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); - } - spin_unlock_irqrestore(&priv->lock, flags); - - if (eeprom->sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL(priv, "SW RF KILL supported in EEPROM.\n"); - - if (eeprom->sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL(priv, "HW RF KILL supported in EEPROM.\n"); -} - -int iwl3945_hw_nic_init(struct iwl_priv *priv) -{ - int rc; - unsigned long flags; - struct iwl_rx_queue *rxq = &priv->rxq; - - spin_lock_irqsave(&priv->lock, flags); - priv->cfg->ops->lib->apm_ops.init(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl3945_set_pwr_vmain(priv); - - priv->cfg->ops->lib->apm_ops.config(priv); - - /* Allocate the RX queue, or reset if it is already allocated */ - if (!rxq->bd) { - rc = iwl_rx_queue_alloc(priv); - if (rc) { - IWL_ERR(priv, "Unable to initialize Rx queue\n"); - return -ENOMEM; - } - } else - iwl3945_rx_queue_reset(priv, rxq); - - iwl3945_rx_replenish(priv); - - iwl3945_rx_init(priv, rxq); - - - /* Look at using this instead: - rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(priv, rxq); - */ - - iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7); - - rc = iwl3945_txq_ctx_reset(priv); - if (rc) - return rc; - - set_bit(STATUS_INIT, &priv->status); - - return 0; -} - -/** - * iwl3945_hw_txq_ctx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) -{ - int txq_id; - - /* Tx queues */ - if (priv->txq) - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; - txq_id++) - if (txq_id == IWL39_CMD_QUEUE_NUM) - iwl_cmd_queue_free(priv); - else - iwl_tx_queue_free(priv, txq_id); - - /* free tx queue structure */ - iwl_free_txq_mem(priv); -} - -void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) -{ - int txq_id; - - /* stop SCD */ - iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); - iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0); - - /* reset TFD queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); - iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, - FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), - 1000); - } - - iwl3945_hw_txq_ctx_free(priv); -} - -/** - * iwl3945_hw_reg_adjust_power_by_temp - * return index delta into power gain settings table -*/ -static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) -{ - return (new_reading - old_reading) * (-11) / 100; -} - -/** - * iwl3945_hw_reg_temp_out_of_range - Keep temperature in sane range - */ -static inline int iwl3945_hw_reg_temp_out_of_range(int temperature) -{ - return ((temperature < -260) || (temperature > 25)) ? 1 : 0; -} - -int iwl3945_hw_get_temperature(struct iwl_priv *priv) -{ - return iwl_read32(priv, CSR_UCODE_DRV_GP2); -} - -/** - * iwl3945_hw_reg_txpower_get_temperature - * get the current temperature by reading from NIC -*/ -static int iwl3945_hw_reg_txpower_get_temperature(struct iwl_priv *priv) -{ - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - int temperature; - - temperature = iwl3945_hw_get_temperature(priv); - - /* driver's okay range is -260 to +25. - * human readable okay range is 0 to +285 */ - IWL_DEBUG_INFO(priv, "Temperature: %d\n", temperature + IWL_TEMP_CONVERT); - - /* handle insane temp reading */ - if (iwl3945_hw_reg_temp_out_of_range(temperature)) { - IWL_ERR(priv, "Error bad temperature value %d\n", temperature); - - /* if really really hot(?), - * substitute the 3rd band/group's temp measured at factory */ - if (priv->last_temperature > 100) - temperature = eeprom->groups[2].temperature; - else /* else use most recent "sane" value from driver */ - temperature = priv->last_temperature; - } - - return temperature; /* raw, not "human readable" */ -} - -/* Adjust Txpower only if temperature variance is greater than threshold. - * - * Both are lower than older versions' 9 degrees */ -#define IWL_TEMPERATURE_LIMIT_TIMER 6 - -/** - * is_temp_calib_needed - determines if new calibration is needed - * - * records new temperature in tx_mgr->temperature. - * replaces tx_mgr->last_temperature *only* if calib needed - * (assumes caller will actually do the calibration!). */ -static int is_temp_calib_needed(struct iwl_priv *priv) -{ - int temp_diff; - - priv->temperature = iwl3945_hw_reg_txpower_get_temperature(priv); - temp_diff = priv->temperature - priv->last_temperature; - - /* get absolute value */ - if (temp_diff < 0) { - IWL_DEBUG_POWER(priv, "Getting cooler, delta %d,\n", temp_diff); - temp_diff = -temp_diff; - } else if (temp_diff == 0) - IWL_DEBUG_POWER(priv, "Same temp,\n"); - else - IWL_DEBUG_POWER(priv, "Getting warmer, delta %d,\n", temp_diff); - - /* if we don't need calibration, *don't* update last_temperature */ - if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) { - IWL_DEBUG_POWER(priv, "Timed thermal calib not needed\n"); - return 0; - } - - IWL_DEBUG_POWER(priv, "Timed thermal calib needed\n"); - - /* assume that caller will actually do calib ... - * update the "last temperature" value */ - priv->last_temperature = priv->temperature; - return 1; -} - -#define IWL_MAX_GAIN_ENTRIES 78 -#define IWL_CCK_FROM_OFDM_POWER_DIFF -5 -#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10) - -/* radio and DSP power table, each step is 1/2 dB. - * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */ -static struct iwl3945_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { - { - {251, 127}, /* 2.4 GHz, highest power */ - {251, 127}, - {251, 127}, - {251, 127}, - {251, 125}, - {251, 110}, - {251, 105}, - {251, 98}, - {187, 125}, - {187, 115}, - {187, 108}, - {187, 99}, - {243, 119}, - {243, 111}, - {243, 105}, - {243, 97}, - {243, 92}, - {211, 106}, - {211, 100}, - {179, 120}, - {179, 113}, - {179, 107}, - {147, 125}, - {147, 119}, - {147, 112}, - {147, 106}, - {147, 101}, - {147, 97}, - {147, 91}, - {115, 107}, - {235, 121}, - {235, 115}, - {235, 109}, - {203, 127}, - {203, 121}, - {203, 115}, - {203, 108}, - {203, 102}, - {203, 96}, - {203, 92}, - {171, 110}, - {171, 104}, - {171, 98}, - {139, 116}, - {227, 125}, - {227, 119}, - {227, 113}, - {227, 107}, - {227, 101}, - {227, 96}, - {195, 113}, - {195, 106}, - {195, 102}, - {195, 95}, - {163, 113}, - {163, 106}, - {163, 102}, - {163, 95}, - {131, 113}, - {131, 106}, - {131, 102}, - {131, 95}, - {99, 113}, - {99, 106}, - {99, 102}, - {99, 95}, - {67, 113}, - {67, 106}, - {67, 102}, - {67, 95}, - {35, 113}, - {35, 106}, - {35, 102}, - {35, 95}, - {3, 113}, - {3, 106}, - {3, 102}, - {3, 95} }, /* 2.4 GHz, lowest power */ - { - {251, 127}, /* 5.x GHz, highest power */ - {251, 120}, - {251, 114}, - {219, 119}, - {219, 101}, - {187, 113}, - {187, 102}, - {155, 114}, - {155, 103}, - {123, 117}, - {123, 107}, - {123, 99}, - {123, 92}, - {91, 108}, - {59, 125}, - {59, 118}, - {59, 109}, - {59, 102}, - {59, 96}, - {59, 90}, - {27, 104}, - {27, 98}, - {27, 92}, - {115, 118}, - {115, 111}, - {115, 104}, - {83, 126}, - {83, 121}, - {83, 113}, - {83, 105}, - {83, 99}, - {51, 118}, - {51, 111}, - {51, 104}, - {51, 98}, - {19, 116}, - {19, 109}, - {19, 102}, - {19, 98}, - {19, 93}, - {171, 113}, - {171, 107}, - {171, 99}, - {139, 120}, - {139, 113}, - {139, 107}, - {139, 99}, - {107, 120}, - {107, 113}, - {107, 107}, - {107, 99}, - {75, 120}, - {75, 113}, - {75, 107}, - {75, 99}, - {43, 120}, - {43, 113}, - {43, 107}, - {43, 99}, - {11, 120}, - {11, 113}, - {11, 107}, - {11, 99}, - {131, 107}, - {131, 99}, - {99, 120}, - {99, 113}, - {99, 107}, - {99, 99}, - {67, 120}, - {67, 113}, - {67, 107}, - {67, 99}, - {35, 120}, - {35, 113}, - {35, 107}, - {35, 99}, - {3, 120} } /* 5.x GHz, lowest power */ -}; - -static inline u8 iwl3945_hw_reg_fix_power_index(int index) -{ - if (index < 0) - return 0; - if (index >= IWL_MAX_GAIN_ENTRIES) - return IWL_MAX_GAIN_ENTRIES - 1; - return (u8) index; -} - -/* Kick off thermal recalibration check every 60 seconds */ -#define REG_RECALIB_PERIOD (60) - -/** - * iwl3945_hw_reg_set_scan_power - Set Tx power for scan probe requests - * - * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK) - * or 6 Mbit (OFDM) rates. - */ -static void iwl3945_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, - s32 rate_index, const s8 *clip_pwrs, - struct iwl_channel_info *ch_info, - int band_index) -{ - struct iwl3945_scan_power_info *scan_power_info; - s8 power; - u8 power_index; - - scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index]; - - /* use this channel group's 6Mbit clipping/saturation pwr, - * but cap at regulatory scan power restriction (set during init - * based on eeprom channel data) for this channel. */ - power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX_TABLE]); - - /* further limit to user's max power preference. - * FIXME: Other spectrum management power limitations do not - * seem to apply?? */ - power = min(power, priv->tx_power_user_lmt); - scan_power_info->requested_power = power; - - /* find difference between new scan *power* and current "normal" - * Tx *power* for 6Mb. Use this difference (x2) to adjust the - * current "normal" temperature-compensated Tx power *index* for - * this rate (1Mb or 6Mb) to yield new temp-compensated scan power - * *index*. */ - power_index = ch_info->power_info[rate_index].power_table_index - - (power - ch_info->power_info - [IWL_RATE_6M_INDEX_TABLE].requested_power) * 2; - - /* store reference index that we use when adjusting *all* scan - * powers. So we can accommodate user (all channel) or spectrum - * management (single channel) power changes "between" temperature - * feedback compensation procedures. - * don't force fit this reference index into gain table; it may be a - * negative number. This will help avoid errors when we're at - * the lower bounds (highest gains, for warmest temperatures) - * of the table. */ - - /* don't exceed table bounds for "real" setting */ - power_index = iwl3945_hw_reg_fix_power_index(power_index); - - scan_power_info->power_table_index = power_index; - scan_power_info->tpc.tx_gain = - power_gain_table[band_index][power_index].tx_gain; - scan_power_info->tpc.dsp_atten = - power_gain_table[band_index][power_index].dsp_atten; -} - -/** - * iwl3945_send_tx_power - fill in Tx Power command with gain settings - * - * Configures power settings for all rates for the current channel, - * using values from channel info struct, and send to NIC - */ -static int iwl3945_send_tx_power(struct iwl_priv *priv) -{ - int rate_idx, i; - const struct iwl_channel_info *ch_info = NULL; - struct iwl3945_txpowertable_cmd txpower = { - .channel = priv->contexts[IWL_RXON_CTX_BSS].active.channel, - }; - u16 chan; - - if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), - "TX Power requested while scanning!\n")) - return -EAGAIN; - - chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel); - - txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1; - ch_info = iwl_get_channel_info(priv, priv->band, chan); - if (!ch_info) { - IWL_ERR(priv, - "Failed to get channel info for channel %d [%d]\n", - chan, priv->band); - return -EINVAL; - } - - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_POWER(priv, "Not calling TX_PWR_TABLE_CMD on " - "non-Tx channel.\n"); - return 0; - } - - /* fill cmd with power settings for all rates for current channel */ - /* Fill OFDM rate */ - for (rate_idx = IWL_FIRST_OFDM_RATE, i = 0; - rate_idx <= IWL39_LAST_OFDM_RATE; rate_idx++, i++) { - - txpower.power[i].tpc = ch_info->power_info[i].tpc; - txpower.power[i].rate = iwl3945_rates[rate_idx].plcp; - - IWL_DEBUG_POWER(priv, "ch %d:%d rf %d dsp %3d rate code 0x%02x\n", - le16_to_cpu(txpower.channel), - txpower.band, - txpower.power[i].tpc.tx_gain, - txpower.power[i].tpc.dsp_atten, - txpower.power[i].rate); - } - /* Fill CCK rates */ - for (rate_idx = IWL_FIRST_CCK_RATE; - rate_idx <= IWL_LAST_CCK_RATE; rate_idx++, i++) { - txpower.power[i].tpc = ch_info->power_info[i].tpc; - txpower.power[i].rate = iwl3945_rates[rate_idx].plcp; - - IWL_DEBUG_POWER(priv, "ch %d:%d rf %d dsp %3d rate code 0x%02x\n", - le16_to_cpu(txpower.channel), - txpower.band, - txpower.power[i].tpc.tx_gain, - txpower.power[i].tpc.dsp_atten, - txpower.power[i].rate); - } - - return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, - sizeof(struct iwl3945_txpowertable_cmd), - &txpower); - -} - -/** - * iwl3945_hw_reg_set_new_power - Configures power tables at new levels - * @ch_info: Channel to update. Uses power_info.requested_power. - * - * Replace requested_power and base_power_index ch_info fields for - * one channel. - * - * Called if user or spectrum management changes power preferences. - * Takes into account h/w and modulation limitations (clip power). - * - * This does *not* send anything to NIC, just sets up ch_info for one channel. - * - * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to - * properly fill out the scan powers, and actual h/w gain settings, - * and send changes to NIC - */ -static int iwl3945_hw_reg_set_new_power(struct iwl_priv *priv, - struct iwl_channel_info *ch_info) -{ - struct iwl3945_channel_power_info *power_info; - int power_changed = 0; - int i; - const s8 *clip_pwrs; - int power; - - /* Get this chnlgrp's rate-to-max/clip-powers table */ - clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers; - - /* Get this channel's rate-to-current-power settings table */ - power_info = ch_info->power_info; - - /* update OFDM Txpower settings */ - for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; - i++, ++power_info) { - int delta_idx; - - /* limit new power to be no more than h/w capability */ - power = min(ch_info->curr_txpow, clip_pwrs[i]); - if (power == power_info->requested_power) - continue; - - /* find difference between old and new requested powers, - * update base (non-temp-compensated) power index */ - delta_idx = (power - power_info->requested_power) * 2; - power_info->base_power_index -= delta_idx; - - /* save new requested power value */ - power_info->requested_power = power; - - power_changed = 1; - } - - /* update CCK Txpower settings, based on OFDM 12M setting ... - * ... all CCK power settings for a given channel are the *same*. */ - if (power_changed) { - power = - ch_info->power_info[IWL_RATE_12M_INDEX_TABLE]. - requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF; - - /* do all CCK rates' iwl3945_channel_power_info structures */ - for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) { - power_info->requested_power = power; - power_info->base_power_index = - ch_info->power_info[IWL_RATE_12M_INDEX_TABLE]. - base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF; - ++power_info; - } - } - - return 0; -} - -/** - * iwl3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel - * - * NOTE: Returned power limit may be less (but not more) than requested, - * based strictly on regulatory (eeprom and spectrum mgt) limitations - * (no consideration for h/w clipping limitations). - */ -static int iwl3945_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) -{ - s8 max_power; - -#if 0 - /* if we're using TGd limits, use lower of TGd or EEPROM */ - if (ch_info->tgd_data.max_power != 0) - max_power = min(ch_info->tgd_data.max_power, - ch_info->eeprom.max_power_avg); - - /* else just use EEPROM limits */ - else -#endif - max_power = ch_info->eeprom.max_power_avg; - - return min(max_power, ch_info->max_power_avg); -} - -/** - * iwl3945_hw_reg_comp_txpower_temp - Compensate for temperature - * - * Compensate txpower settings of *all* channels for temperature. - * This only accounts for the difference between current temperature - * and the factory calibration temperatures, and bases the new settings - * on the channel's base_power_index. - * - * If RxOn is "associated", this sends the new Txpower to NIC! - */ -static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv) -{ - struct iwl_channel_info *ch_info = NULL; - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - int delta_index; - const s8 *clip_pwrs; /* array of h/w max power levels for each rate */ - u8 a_band; - u8 rate_index; - u8 scan_tbl_index; - u8 i; - int ref_temp; - int temperature = priv->temperature; - - if (priv->disable_tx_power_cal || - test_bit(STATUS_SCANNING, &priv->status)) { - /* do not perform tx power calibration */ - return 0; - } - /* set up new Tx power info for each and every channel, 2.4 and 5.x */ - for (i = 0; i < priv->channel_count; i++) { - ch_info = &priv->channel_info[i]; - a_band = is_channel_a_band(ch_info); - - /* Get this chnlgrp's factory calibration temperature */ - ref_temp = (s16)eeprom->groups[ch_info->group_index]. - temperature; - - /* get power index adjustment based on current and factory - * temps */ - delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, - ref_temp); - - /* set tx power value for all rates, OFDM and CCK */ - for (rate_index = 0; rate_index < IWL_RATE_COUNT; - rate_index++) { - int power_idx = - ch_info->power_info[rate_index].base_power_index; - - /* temperature compensate */ - power_idx += delta_index; - - /* stay within table range */ - power_idx = iwl3945_hw_reg_fix_power_index(power_idx); - ch_info->power_info[rate_index]. - power_table_index = (u8) power_idx; - ch_info->power_info[rate_index].tpc = - power_gain_table[a_band][power_idx]; - } - - /* Get this chnlgrp's rate-to-max/clip-powers table */ - clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers; - - /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ - for (scan_tbl_index = 0; - scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { - s32 actual_index = (scan_tbl_index == 0) ? - IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE; - iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index, - actual_index, clip_pwrs, - ch_info, a_band); - } - } - - /* send Txpower command for current channel to ucode */ - return priv->cfg->ops->lib->send_tx_power(priv); -} - -int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) -{ - struct iwl_channel_info *ch_info; - s8 max_power; - u8 a_band; - u8 i; - - if (priv->tx_power_user_lmt == power) { - IWL_DEBUG_POWER(priv, "Requested Tx power same as current " - "limit: %ddBm.\n", power); - return 0; - } - - IWL_DEBUG_POWER(priv, "Setting upper limit clamp to %ddBm.\n", power); - priv->tx_power_user_lmt = power; - - /* set up new Tx powers for each and every channel, 2.4 and 5.x */ - - for (i = 0; i < priv->channel_count; i++) { - ch_info = &priv->channel_info[i]; - a_band = is_channel_a_band(ch_info); - - /* find minimum power of all user and regulatory constraints - * (does not consider h/w clipping limitations) */ - max_power = iwl3945_hw_reg_get_ch_txpower_limit(ch_info); - max_power = min(power, max_power); - if (max_power != ch_info->curr_txpow) { - ch_info->curr_txpow = max_power; - - /* this considers the h/w clipping limitations */ - iwl3945_hw_reg_set_new_power(priv, ch_info); - } - } - - /* update txpower settings for all channels, - * send to NIC if associated. */ - is_temp_calib_needed(priv); - iwl3945_hw_reg_comp_txpower_temp(priv); - - return 0; -} - -static int iwl3945_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int rc = 0; - struct iwl_rx_packet *pkt; - struct iwl3945_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { - .id = REPLY_RXON_ASSOC, - .len = sizeof(rxon_assoc), - .flags = CMD_WANT_SKB, - .data = &rxon_assoc, - }; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved = 0; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - pkt = (struct iwl_rx_packet *)cmd.reply_page; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); - rc = -EIO; - } - - iwl_free_pages(priv, cmd.reply_page); - - return rc; -} - -/** - * iwl3945_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is committed 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. - */ -int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - /* cast away the const for active_rxon in this function */ - struct iwl3945_rxon_cmd *active_rxon = (void *)&ctx->active; - struct iwl3945_rxon_cmd *staging_rxon = (void *)&ctx->staging; - int rc = 0; - bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EINVAL; - - if (!iwl_is_alive(priv)) - return -1; - - /* always get timestamp with Rx frame */ - staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK; - - /* select antenna */ - staging_rxon->flags &= - ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); - staging_rxon->flags |= iwl3945_get_antenna_flags(priv); - - rc = iwl_check_rxon_cmd(priv, ctx); - if (rc) { - IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* If we don't need to send a full RXON, we can use - * iwl3945_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv, &priv->contexts[IWL_RXON_CTX_BSS])) { - rc = iwl_send_rxon_assoc(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); - if (rc) { - IWL_ERR(priv, "Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - return 0; - } - - /* 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, IWL_RXON_CTX_BSS) && new_assoc) { - IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - active_rxon->reserved4 = 0; - active_rxon->reserved5 = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - &priv->contexts[IWL_RXON_CTX_BSS].active); - - /* 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_ERR(priv, "Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; - } - iwl_clear_ucode_stations(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); - iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]); - } - - IWL_DEBUG_INFO(priv, "Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %pM\n", - (new_assoc ? "" : "out"), - le16_to_cpu(staging_rxon->channel), - staging_rxon->bssid_addr); - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - staging_rxon->reserved4 = 0; - staging_rxon->reserved5 = 0; - - iwl_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto); - - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - staging_rxon); - if (rc) { - IWL_ERR(priv, "Error setting new configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - if (!new_assoc) { - iwl_clear_ucode_stations(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); - iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]); - } - - /* 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 = priv->cfg->ops->lib->send_tx_power(priv); - if (rc) { - IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); - return rc; - } - - /* Init the hardware's rate fallback order based on the band */ - rc = iwl3945_init_hw_rate_table(priv); - if (rc) { - IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc); - return -EIO; - } - - return 0; -} - -/** - * iwl3945_reg_txpower_periodic - called when time to check our temperature. - * - * -- reset periodic timer - * -- see if temp has changed enough to warrant re-calibration ... if so: - * -- correct coeffs for temp (can reset temp timer) - * -- save this temp as "last", - * -- send new set of gain settings to NIC - * NOTE: This should continue working, even when we're not associated, - * so we can keep our internal table of scan powers current. */ -void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) -{ - /* This will kick in the "brute force" - * iwl3945_hw_reg_comp_txpower_temp() below */ - if (!is_temp_calib_needed(priv)) - goto reschedule; - - /* Set up a new set of temp-adjusted TxPowers, send to NIC. - * This is based *only* on current temperature, - * ignoring any previous power measurements */ - iwl3945_hw_reg_comp_txpower_temp(priv); - - reschedule: - queue_delayed_work(priv->workqueue, - &priv->_3945.thermal_periodic, REG_RECALIB_PERIOD * HZ); -} - -static void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, - _3945.thermal_periodic.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl3945_reg_txpower_periodic(priv); - mutex_unlock(&priv->mutex); -} - -/** - * iwl3945_hw_reg_get_ch_grp_index - find the channel-group index (0-4) - * for the channel. - * - * This function is used when initializing channel-info structs. - * - * NOTE: These channel groups do *NOT* match the bands above! - * These channel groups are based on factory-tested channels; - * on A-band, EEPROM's "group frequency" entries represent the top - * channel in each group 1-4. Group 5 All B/G channels are in group 0. - */ -static u16 iwl3945_hw_reg_get_ch_grp_index(struct iwl_priv *priv, - const struct iwl_channel_info *ch_info) -{ - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - struct iwl3945_eeprom_txpower_group *ch_grp = &eeprom->groups[0]; - u8 group; - u16 group_index = 0; /* based on factory calib frequencies */ - u8 grp_channel; - - /* Find the group index for the channel ... don't use index 1(?) */ - if (is_channel_a_band(ch_info)) { - for (group = 1; group < 5; group++) { - grp_channel = ch_grp[group].group_channel; - if (ch_info->channel <= grp_channel) { - group_index = group; - break; - } - } - /* group 4 has a few channels *above* its factory cal freq */ - if (group == 5) - group_index = 4; - } else - group_index = 0; /* 2.4 GHz, group 0 */ - - IWL_DEBUG_POWER(priv, "Chnl %d mapped to grp %d\n", ch_info->channel, - group_index); - return group_index; -} - -/** - * iwl3945_hw_reg_get_matched_power_index - Interpolate to get nominal index - * - * Interpolate to get nominal (i.e. at factory calibration temperature) index - * into radio/DSP gain settings table for requested power. - */ -static int iwl3945_hw_reg_get_matched_power_index(struct iwl_priv *priv, - s8 requested_power, - s32 setting_index, s32 *new_index) -{ - const struct iwl3945_eeprom_txpower_group *chnl_grp = NULL; - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - s32 index0, index1; - s32 power = 2 * requested_power; - s32 i; - const struct iwl3945_eeprom_txpower_sample *samples; - s32 gains0, gains1; - s32 res; - s32 denominator; - - chnl_grp = &eeprom->groups[setting_index]; - samples = chnl_grp->samples; - for (i = 0; i < 5; i++) { - if (power == samples[i].power) { - *new_index = samples[i].gain_index; - return 0; - } - } - - if (power > samples[1].power) { - index0 = 0; - index1 = 1; - } else if (power > samples[2].power) { - index0 = 1; - index1 = 2; - } else if (power > samples[3].power) { - index0 = 2; - index1 = 3; - } else { - index0 = 3; - index1 = 4; - } - - denominator = (s32) samples[index1].power - (s32) samples[index0].power; - if (denominator == 0) - return -EINVAL; - gains0 = (s32) samples[index0].gain_index * (1 << 19); - gains1 = (s32) samples[index1].gain_index * (1 << 19); - res = gains0 + (gains1 - gains0) * - ((s32) power - (s32) samples[index0].power) / denominator + - (1 << 18); - *new_index = res >> 19; - return 0; -} - -static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv) -{ - u32 i; - s32 rate_index; - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - const struct iwl3945_eeprom_txpower_group *group; - - IWL_DEBUG_POWER(priv, "Initializing factory calib info from EEPROM\n"); - - for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) { - s8 *clip_pwrs; /* table of power levels for each rate */ - s8 satur_pwr; /* saturation power for each chnl group */ - group = &eeprom->groups[i]; - - /* sanity check on factory saturation power value */ - if (group->saturation_power < 40) { - IWL_WARN(priv, "Error: saturation power is %d, " - "less than minimum expected 40\n", - group->saturation_power); - return; - } - - /* - * Derive requested power levels for each rate, based on - * hardware capabilities (saturation power for band). - * Basic value is 3dB down from saturation, with further - * power reductions for highest 3 data rates. These - * backoffs provide headroom for high rate modulation - * power peaks, without too much distortion (clipping). - */ - /* we'll fill in this array with h/w max power levels */ - clip_pwrs = (s8 *) priv->_3945.clip_groups[i].clip_powers; - - /* divide factory saturation power by 2 to find -3dB level */ - satur_pwr = (s8) (group->saturation_power >> 1); - - /* fill in channel group's nominal powers for each rate */ - for (rate_index = 0; - rate_index < IWL_RATE_COUNT_3945; rate_index++, clip_pwrs++) { - switch (rate_index) { - case IWL_RATE_36M_INDEX_TABLE: - if (i == 0) /* B/G */ - *clip_pwrs = satur_pwr; - else /* A */ - *clip_pwrs = satur_pwr - 5; - break; - case IWL_RATE_48M_INDEX_TABLE: - if (i == 0) - *clip_pwrs = satur_pwr - 7; - else - *clip_pwrs = satur_pwr - 10; - break; - case IWL_RATE_54M_INDEX_TABLE: - if (i == 0) - *clip_pwrs = satur_pwr - 9; - else - *clip_pwrs = satur_pwr - 12; - break; - default: - *clip_pwrs = satur_pwr; - break; - } - } - } -} - -/** - * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM - * - * Second pass (during init) to set up priv->channel_info - * - * Set up Tx-power settings in our channel info database for each VALID - * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values - * and current temperature. - * - * Since this is based on current temperature (at init time), these values may - * not be valid for very long, but it gives us a starting/default point, - * and allows us to active (i.e. using Tx) scan. - * - * This does *not* write values to NIC, just sets up our internal table. - */ -int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) -{ - struct iwl_channel_info *ch_info = NULL; - struct iwl3945_channel_power_info *pwr_info; - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - int delta_index; - u8 rate_index; - u8 scan_tbl_index; - const s8 *clip_pwrs; /* array of power levels for each rate */ - u8 gain, dsp_atten; - s8 power; - u8 pwr_index, base_pwr_index, a_band; - u8 i; - int temperature; - - /* save temperature reference, - * so we can determine next time to calibrate */ - temperature = iwl3945_hw_reg_txpower_get_temperature(priv); - priv->last_temperature = temperature; - - iwl3945_hw_reg_init_channel_groups(priv); - - /* initialize Tx power info for each and every channel, 2.4 and 5.x */ - for (i = 0, ch_info = priv->channel_info; i < priv->channel_count; - i++, ch_info++) { - a_band = is_channel_a_band(ch_info); - if (!is_channel_valid(ch_info)) - continue; - - /* find this channel's channel group (*not* "band") index */ - ch_info->group_index = - iwl3945_hw_reg_get_ch_grp_index(priv, ch_info); - - /* Get this chnlgrp's rate->max/clip-powers table */ - clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers; - - /* calculate power index *adjustment* value according to - * diff between current temperature and factory temperature */ - delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, - eeprom->groups[ch_info->group_index]. - temperature); - - IWL_DEBUG_POWER(priv, "Delta index for channel %d: %d [%d]\n", - ch_info->channel, delta_index, temperature + - IWL_TEMP_CONVERT); - - /* set tx power value for all OFDM rates */ - for (rate_index = 0; rate_index < IWL_OFDM_RATES; - rate_index++) { - s32 uninitialized_var(power_idx); - int rc; - - /* use channel group's clip-power table, - * but don't exceed channel's max power */ - s8 pwr = min(ch_info->max_power_avg, - clip_pwrs[rate_index]); - - pwr_info = &ch_info->power_info[rate_index]; - - /* get base (i.e. at factory-measured temperature) - * power table index for this rate's power */ - rc = iwl3945_hw_reg_get_matched_power_index(priv, pwr, - ch_info->group_index, - &power_idx); - if (rc) { - IWL_ERR(priv, "Invalid power index\n"); - return rc; - } - pwr_info->base_power_index = (u8) power_idx; - - /* temperature compensate */ - power_idx += delta_index; - - /* stay within range of gain table */ - power_idx = iwl3945_hw_reg_fix_power_index(power_idx); - - /* fill 1 OFDM rate's iwl3945_channel_power_info struct */ - pwr_info->requested_power = pwr; - pwr_info->power_table_index = (u8) power_idx; - pwr_info->tpc.tx_gain = - power_gain_table[a_band][power_idx].tx_gain; - pwr_info->tpc.dsp_atten = - power_gain_table[a_band][power_idx].dsp_atten; - } - - /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/ - pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX_TABLE]; - power = pwr_info->requested_power + - IWL_CCK_FROM_OFDM_POWER_DIFF; - pwr_index = pwr_info->power_table_index + - IWL_CCK_FROM_OFDM_INDEX_DIFF; - base_pwr_index = pwr_info->base_power_index + - IWL_CCK_FROM_OFDM_INDEX_DIFF; - - /* stay within table range */ - pwr_index = iwl3945_hw_reg_fix_power_index(pwr_index); - gain = power_gain_table[a_band][pwr_index].tx_gain; - dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten; - - /* fill each CCK rate's iwl3945_channel_power_info structure - * NOTE: All CCK-rate Txpwrs are the same for a given chnl! - * NOTE: CCK rates start at end of OFDM rates! */ - for (rate_index = 0; - rate_index < IWL_CCK_RATES; rate_index++) { - pwr_info = &ch_info->power_info[rate_index+IWL_OFDM_RATES]; - pwr_info->requested_power = power; - pwr_info->power_table_index = pwr_index; - pwr_info->base_power_index = base_pwr_index; - pwr_info->tpc.tx_gain = gain; - pwr_info->tpc.dsp_atten = dsp_atten; - } - - /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ - for (scan_tbl_index = 0; - scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { - s32 actual_index = (scan_tbl_index == 0) ? - IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE; - iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index, - actual_index, clip_pwrs, ch_info, a_band); - } - } - - return 0; -} - -int iwl3945_hw_rxq_stop(struct iwl_priv *priv) -{ - int rc; - - iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0); - rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS, - FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); - if (rc < 0) - IWL_ERR(priv, "Can't stop Rx DMA.\n"); - - return 0; -} - -int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) -{ - int txq_id = txq->q.id; - - struct iwl3945_shared *shared_data = priv->_3945.shared_virt; - - shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); - - iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0); - iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0); - - iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), - FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT | - FH39_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF | - FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | - FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | - FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); - - /* fake read to flush all prev. writes */ - iwl_read32(priv, FH39_TSSR_CBB_BASE); - - return 0; -} - -/* - * HCMD utils - */ -static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len) -{ - switch (cmd_id) { - case REPLY_RXON: - return sizeof(struct iwl3945_rxon_cmd); - case POWER_TABLE_CMD: - return sizeof(struct iwl3945_powertable_cmd); - default: - return len; - } -} - - -static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) -{ - struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data; - addsta->mode = cmd->mode; - memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); - memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); - addsta->station_flags = cmd->station_flags; - addsta->station_flags_msk = cmd->station_flags_msk; - addsta->tid_disable_tx = cpu_to_le16(0); - addsta->rate_n_flags = cmd->rate_n_flags; - addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; - addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; - addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; - - return (u16)sizeof(struct iwl3945_addsta_cmd); -} - -static int iwl3945_add_bssid_station(struct iwl_priv *priv, - const u8 *addr, u8 *sta_id_r) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - int ret; - u8 sta_id; - unsigned long flags; - - if (sta_id_r) - *sta_id_r = IWL_INVALID_STATION; - - ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id); - if (ret) { - IWL_ERR(priv, "Unable to add station %pM\n", addr); - return ret; - } - - if (sta_id_r) - *sta_id_r = sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].used |= IWL_STA_LOCAL; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return 0; -} -static int iwl3945_manage_ibss_station(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add) -{ - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - int ret; - - if (add) { - ret = iwl3945_add_bssid_station(priv, vif->bss_conf.bssid, - &vif_priv->ibss_bssid_sta_id); - if (ret) - return ret; - - iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id, - (priv->band == IEEE80211_BAND_5GHZ) ? - IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP); - iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id); - - return 0; - } - - return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id, - vif->bss_conf.bssid); -} - -/** - * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table - */ -int iwl3945_init_hw_rate_table(struct iwl_priv *priv) -{ - int rc, i, index, prev_index; - struct iwl3945_rate_scaling_cmd rate_cmd = { - .reserved = {0, 0, 0}, - }; - struct iwl3945_rate_scaling_info *table = rate_cmd.table; - - for (i = 0; i < ARRAY_SIZE(iwl3945_rates); i++) { - index = iwl3945_rates[i].table_rs_index; - - table[index].rate_n_flags = - iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0); - table[index].try_cnt = priv->retry_rate; - prev_index = iwl3945_get_prev_ieee_rate(i); - table[index].next_rate_index = - iwl3945_rates[prev_index].table_rs_index; - } - - switch (priv->band) { - case IEEE80211_BAND_5GHZ: - IWL_DEBUG_RATE(priv, "Select A mode rate scale\n"); - /* If one of the following CCK rates is used, - * have it fall back to the 6M OFDM rate */ - for (i = IWL_RATE_1M_INDEX_TABLE; - i <= IWL_RATE_11M_INDEX_TABLE; i++) - table[i].next_rate_index = - iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; - - /* Don't fall back to CCK rates */ - table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = - IWL_RATE_9M_INDEX_TABLE; - - /* Don't drop out of OFDM rates */ - table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = - iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; - break; - - case IEEE80211_BAND_2GHZ: - IWL_DEBUG_RATE(priv, "Select B/G mode rate scale\n"); - /* If an OFDM rate is used, have it fall back to the - * 1M CCK rates */ - - if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) && - iwl_is_associated(priv, IWL_RXON_CTX_BSS)) { - - index = IWL_FIRST_CCK_RATE; - for (i = IWL_RATE_6M_INDEX_TABLE; - i <= IWL_RATE_54M_INDEX_TABLE; i++) - table[i].next_rate_index = - iwl3945_rates[index].table_rs_index; - - index = IWL_RATE_11M_INDEX_TABLE; - /* CCK shouldn't fall back to OFDM... */ - table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE; - } - break; - - default: - WARN_ON(1); - break; - } - - /* Update the rate scaling for control frame Tx */ - rate_cmd.table_id = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), - &rate_cmd); - if (rc) - return rc; - - /* Update the rate scaling for data frame Tx */ - rate_cmd.table_id = 1; - return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), - &rate_cmd); -} - -/* Called when initializing driver */ -int iwl3945_hw_set_hw_params(struct iwl_priv *priv) -{ - memset((void *)&priv->hw_params, 0, - sizeof(struct iwl_hw_params)); - - priv->_3945.shared_virt = - dma_alloc_coherent(&priv->pci_dev->dev, - sizeof(struct iwl3945_shared), - &priv->_3945.shared_phys, GFP_KERNEL); - if (!priv->_3945.shared_virt) { - IWL_ERR(priv, "failed to allocate pci memory\n"); - return -ENOMEM; - } - - /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - - priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); - priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K); - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - priv->hw_params.max_stations = IWL3945_STATION_COUNT; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL3945_BROADCAST_ID; - - priv->sta_key_max_num = STA_KEY_MAX_NUM; - - priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR; - priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL; - priv->hw_params.beacon_time_tsf_bits = IWL3945_EXT_BEACON_TIME_POS; - - return 0; -} - -unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl3945_frame *frame, u8 rate) -{ - struct iwl3945_tx_beacon_cmd *tx_beacon_cmd; - unsigned int frame_size; - - tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - - tx_beacon_cmd->tx.sta_id = - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id; - tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - frame_size = iwl3945_fill_beacon_frame(priv, - tx_beacon_cmd->frame, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - - BUG_ON(frame_size > MAX_MPDU_SIZE); - tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); - - tx_beacon_cmd->tx.rate = rate; - tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | - TX_CMD_FLG_TSF_MSK); - - /* supp_rates[0] == OFDM start at IWL_FIRST_OFDM_RATE*/ - tx_beacon_cmd->tx.supp_rates[0] = - (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; - - tx_beacon_cmd->tx.supp_rates[1] = - (IWL_CCK_BASIC_RATES_MASK & 0xF); - - return sizeof(struct iwl3945_tx_beacon_cmd) + frame_size; -} - -void iwl3945_hw_rx_handler_setup(struct iwl_priv *priv) -{ - priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; - priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; -} - -void iwl3945_hw_setup_deferred_work(struct iwl_priv *priv) -{ - INIT_DELAYED_WORK(&priv->_3945.thermal_periodic, - iwl3945_bg_reg_txpower_periodic); -} - -void iwl3945_hw_cancel_deferred_work(struct iwl_priv *priv) -{ - cancel_delayed_work(&priv->_3945.thermal_periodic); -} - -/* check contents of special bootstrap uCode SRAM */ -static int iwl3945_verify_bsm(struct iwl_priv *priv) - { - __le32 *image = priv->ucode_boot.v_addr; - u32 len = priv->ucode_boot.len; - u32 reg; - u32 val; - - IWL_DEBUG_INFO(priv, "Begin verify bsm\n"); - - /* verify BSM SRAM contents */ - val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG); - for (reg = BSM_SRAM_LOWER_BOUND; - reg < BSM_SRAM_LOWER_BOUND + len; - reg += sizeof(u32), image++) { - val = iwl_read_prph(priv, reg); - if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "BSM uCode verification failed at " - "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", - BSM_SRAM_LOWER_BOUND, - reg - BSM_SRAM_LOWER_BOUND, len, - val, le32_to_cpu(*image)); - return -EIO; - } - } - - IWL_DEBUG_INFO(priv, "BSM bootstrap uCode image OK\n"); - - return 0; -} - - -/****************************************************************************** - * - * EEPROM related functions - * - ******************************************************************************/ - -/* - * Clear the OWNER_MSK, to establish driver (instead of uCode running on - * embedded controller) as EEPROM reader; each read is a series of pulses - * to/from the EEPROM chip, not a single event, so even reads could conflict - * if they weren't arbitrated by some ownership mechanism. Here, the driver - * simply claims ownership, which should be safe when this function is called - * (i.e. before loading uCode!). - */ -static int iwl3945_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); - return 0; -} - - -static void iwl3945_eeprom_release_semaphore(struct iwl_priv *priv) -{ - return; -} - - /** - * iwl3945_load_bsm - Load bootstrap instructions - * - * BSM operation: - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down during RFKILL. When powering back - * up after power-saving sleeps (or during initial uCode load), the BSM loads - * the bootstrap program into the on-board processor, and starts it. - * - * The bootstrap program loads (via DMA) instructions and data for a new - * program from host DRAM locations indicated by the host driver in the - * BSM_DRAM_* registers. Once the new program is loaded, it starts - * automatically. - * - * When initializing the NIC, the host driver points the BSM to the - * "initialize" uCode image. This uCode sets up some internal data, then - * notifies host via "initialize alive" that it is complete. - * - * The host then replaces the BSM_DRAM_* pointer values to point to the - * normal runtime uCode instructions and a backup uCode data cache buffer - * (filled initially with starting data values for the on-board processor), - * then triggers the "initialize" uCode to load and launch the runtime uCode, - * which begins normal operation. - * - * When doing a power-save shutdown, runtime uCode saves data SRAM into - * the backup data cache in DRAM before SRAM is powered down. - * - * When powering back up, the BSM loads the bootstrap program. This reloads - * the runtime uCode instructions and the backup data cache into SRAM, - * and re-launches the runtime uCode from where it left off. - */ -static int iwl3945_load_bsm(struct iwl_priv *priv) -{ - __le32 *image = priv->ucode_boot.v_addr; - u32 len = priv->ucode_boot.len; - dma_addr_t pinst; - dma_addr_t pdata; - u32 inst_len; - u32 data_len; - int rc; - int i; - u32 done; - u32 reg_offset; - - IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - - /* make sure bootstrap program is no larger than BSM's SRAM size */ - if (len > IWL39_MAX_BSM_SIZE) - return -EINVAL; - - /* Tell bootstrap uCode where to find the "Initialize" uCode - * in host DRAM ... host DRAM physical address bits 31:0 for 3945. - * NOTE: iwl3945_initialize_alive_start() will replace these values, - * after the "initialize" uCode has run, to point to - * runtime/protocol instructions and backup data cache. */ - pinst = priv->ucode_init.p_addr; - pdata = priv->ucode_init_data.p_addr; - inst_len = priv->ucode_init.len; - data_len = priv->ucode_init_data.len; - - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); - - /* Fill BSM memory with bootstrap instructions */ - for (reg_offset = BSM_SRAM_LOWER_BOUND; - reg_offset < BSM_SRAM_LOWER_BOUND + len; - reg_offset += sizeof(u32), image++) - _iwl_write_prph(priv, reg_offset, - le32_to_cpu(*image)); - - rc = iwl3945_verify_bsm(priv); - if (rc) - return rc; - - /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ - iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); - iwl_write_prph(priv, BSM_WR_MEM_DST_REG, - IWL39_RTC_INST_LOWER_BOUND); - iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); - - /* Load bootstrap code into instruction SRAM now, - * to prepare to load "initialize" uCode */ - iwl_write_prph(priv, BSM_WR_CTRL_REG, - BSM_WR_CTRL_REG_BIT_START); - - /* Wait for load of bootstrap uCode to finish */ - for (i = 0; i < 100; i++) { - done = iwl_read_prph(priv, BSM_WR_CTRL_REG); - if (!(done & BSM_WR_CTRL_REG_BIT_START)) - break; - udelay(10); - } - if (i < 100) - IWL_DEBUG_INFO(priv, "BSM write complete, poll %d iterations\n", i); - else { - IWL_ERR(priv, "BSM write did not complete!\n"); - return -EIO; - } - - /* Enable future boot loads whenever power management unit triggers it - * (e.g. when powering back up after power-save shutdown) */ - iwl_write_prph(priv, BSM_WR_CTRL_REG, - BSM_WR_CTRL_REG_BIT_START_EN); - - return 0; -} - -static struct iwl_hcmd_ops iwl3945_hcmd = { - .rxon_assoc = iwl3945_send_rxon_assoc, - .commit_rxon = iwl3945_commit_rxon, - .send_bt_config = iwl_send_bt_config, -}; - -static struct iwl_lib_ops iwl3945_lib = { - .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, - .txq_free_tfd = iwl3945_hw_txq_free_tfd, - .txq_init = iwl3945_hw_tx_queue_init, - .load_ucode = iwl3945_load_bsm, - .dump_nic_event_log = iwl3945_dump_nic_event_log, - .dump_nic_error_log = iwl3945_dump_nic_error_log, - .apm_ops = { - .init = iwl3945_apm_init, - .config = iwl3945_nic_config, - }, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REGULATORY_BAND_1_CHANNELS, - EEPROM_REGULATORY_BAND_2_CHANNELS, - EEPROM_REGULATORY_BAND_3_CHANNELS, - EEPROM_REGULATORY_BAND_4_CHANNELS, - EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - EEPROM_REGULATORY_BAND_NO_HT40, - }, - .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, - .release_semaphore = iwl3945_eeprom_release_semaphore, - .query_addr = iwlcore_eeprom_query_addr, - }, - .send_tx_power = iwl3945_send_tx_power, - .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, - .isr_ops = { - .isr = iwl_isr_legacy, - }, - - .debugfs_ops = { - .rx_stats_read = iwl3945_ucode_rx_stats_read, - .tx_stats_read = iwl3945_ucode_tx_stats_read, - .general_stats_read = iwl3945_ucode_general_stats_read, - }, -}; - -static const struct iwl_legacy_ops iwl3945_legacy_ops = { - .post_associate = iwl3945_post_associate, - .config_ap = iwl3945_config_ap, - .manage_ibss_station = iwl3945_manage_ibss_station, -}; - -static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { - .get_hcmd_size = iwl3945_get_hcmd_size, - .build_addsta_hcmd = iwl3945_build_addsta_hcmd, - .tx_cmd_protection = iwl_legacy_tx_cmd_protection, - .request_scan = iwl3945_request_scan, - .post_scan = iwl3945_post_scan, -}; - -static const struct iwl_ops iwl3945_ops = { - .lib = &iwl3945_lib, - .hcmd = &iwl3945_hcmd, - .utils = &iwl3945_hcmd_utils, - .led = &iwl3945_led_ops, - .legacy = &iwl3945_legacy_ops, - .ieee80211_ops = &iwl3945_hw_ops, -}; - -static struct iwl_base_params iwl3945_base_params = { - .eeprom_size = IWL3945_EEPROM_IMG_SIZE, - .num_of_queues = IWL39_NUM_QUEUES, - .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL, - .set_l0s = false, - .use_bsm = true, - .use_isr_legacy = true, - .led_compensation = 64, - .broken_powersave = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .wd_timeout = IWL_DEF_WD_TIMEOUT, - .max_event_log_size = 512, - .tx_power_by_driver = true, -}; - -static struct iwl_cfg iwl3945_bg_cfg = { - .name = "3945BG", - .fw_name_pre = IWL3945_FW_PRE, - .ucode_api_max = IWL3945_UCODE_API_MAX, - .ucode_api_min = IWL3945_UCODE_API_MIN, - .sku = IWL_SKU_G, - .eeprom_ver = EEPROM_3945_EEPROM_VERSION, - .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params, - .base_params = &iwl3945_base_params, - .led_mode = IWL_LED_BLINK, -}; - -static struct iwl_cfg iwl3945_abg_cfg = { - .name = "3945ABG", - .fw_name_pre = IWL3945_FW_PRE, - .ucode_api_max = IWL3945_UCODE_API_MAX, - .ucode_api_min = IWL3945_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .eeprom_ver = EEPROM_3945_EEPROM_VERSION, - .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params, - .base_params = &iwl3945_base_params, - .led_mode = IWL_LED_BLINK, -}; - -DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { - {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)}, - {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)}, - {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)}, - {IWL_PCI_DEVICE(0x4227, 0x1014, iwl3945_bg_cfg)}, - {IWL_PCI_DEVICE(0x4222, PCI_ANY_ID, iwl3945_abg_cfg)}, - {IWL_PCI_DEVICE(0x4227, PCI_ANY_ID, iwl3945_abg_cfg)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h deleted file mode 100644 index 3eef1eb74a78..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ /dev/null @@ -1,308 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -/* - * Please use this file (iwl-3945.h) for driver implementation definitions. - * Please use iwl-3945-commands.h for uCode API definitions. - * Please use iwl-3945-hw.h for hardware-related definitions. - */ - -#ifndef __iwl_3945_h__ -#define __iwl_3945_h__ - -#include <linux/pci.h> /* for struct pci_device_id */ -#include <linux/kernel.h> -#include <net/ieee80211_radiotap.h> - -/* Hardware specific file defines the PCI IDs table for that hardware module */ -extern const struct pci_device_id iwl3945_hw_card_ids[]; - -#include "iwl-csr.h" -#include "iwl-prph.h" -#include "iwl-fh.h" -#include "iwl-3945-hw.h" -#include "iwl-debug.h" -#include "iwl-power.h" -#include "iwl-dev.h" -#include "iwl-led.h" - -/* Highest firmware API version supported */ -#define IWL3945_UCODE_API_MAX 2 - -/* Lowest firmware API version supported */ -#define IWL3945_UCODE_API_MIN 1 - -#define IWL3945_FW_PRE "iwlwifi-3945-" -#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode" -#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api) - -/* Default noise level to report when noise measurement is not available. - * This may be because we're: - * 1) Not associated (4965, no beacon statistics being sent to driver) - * 2) Scanning (noise measurement does not apply to associated channel) - * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) - * Use default noise value of -127 ... this is below the range of measurable - * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. - * Also, -127 works better than 0 when averaging frames with/without - * noise info (e.g. averaging might be done in app); measured dBm values are - * always negative ... using a negative value as the default keeps all - * averages within an s8's (used in some apps) range of negative values. */ -#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) - -/* Module parameters accessible from iwl-*.c */ -extern struct iwl_mod_params iwl3945_mod_params; - -struct iwl3945_rate_scale_data { - u64 data; - s32 success_counter; - s32 success_ratio; - s32 counter; - s32 average_tpt; - unsigned long stamp; -}; - -struct iwl3945_rs_sta { - spinlock_t lock; - struct iwl_priv *priv; - s32 *expected_tpt; - unsigned long last_partial_flush; - unsigned long last_flush; - u32 flush_time; - u32 last_tx_packets; - u32 tx_packets; - u8 tgg; - u8 flush_pending; - u8 start_rate; - struct timer_list rate_scale_flush; - struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_stats_table_file; -#endif - - /* used to be in sta_info */ - int last_txrate_idx; -}; - - -/* - * The common struct MUST be first because it is shared between - * 3945 and agn! - */ -struct iwl3945_sta_priv { - struct iwl_station_priv_common common; - struct iwl3945_rs_sta rs_sta; -}; - -enum iwl3945_antenna { - IWL_ANTENNA_DIVERSITY, - IWL_ANTENNA_MAIN, - IWL_ANTENNA_AUX -}; - -/* - * RTS threshold here is total size [2347] minus 4 FCS bytes - * Per spec: - * a value of 0 means RTS on all data/management packets - * a value > max MSDU size means no RTS - * else RTS for data/management frames where MPDU is larger - * than RTS value. - */ -#define DEFAULT_RTS_THRESHOLD 2347U -#define MIN_RTS_THRESHOLD 0U -#define MAX_RTS_THRESHOLD 2347U -#define MAX_MSDU_SIZE 2304U -#define MAX_MPDU_SIZE 2346U -#define DEFAULT_BEACON_INTERVAL 100U -#define DEFAULT_SHORT_RETRY_LIMIT 7U -#define DEFAULT_LONG_RETRY_LIMIT 4U - -#define IWL_TX_FIFO_AC0 0 -#define IWL_TX_FIFO_AC1 1 -#define IWL_TX_FIFO_AC2 2 -#define IWL_TX_FIFO_AC3 3 -#define IWL_TX_FIFO_HCCA_1 5 -#define IWL_TX_FIFO_HCCA_2 6 -#define IWL_TX_FIFO_NONE 7 - -#define IEEE80211_DATA_LEN 2304 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -struct iwl3945_frame { - union { - struct ieee80211_hdr frame; - struct iwl3945_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; - -#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) -#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) -#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) - -#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 -#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 -#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 - -#define IWL_SUPPORTED_RATES_IE_LEN 8 - -#define SCAN_INTERVAL 100 - -#define MAX_TID_COUNT 9 - -#define IWL_INVALID_RATE 0xFF -#define IWL_INVALID_VALUE -1 - -#define STA_PS_STATUS_WAKE 0 -#define STA_PS_STATUS_SLEEP 1 - -struct iwl3945_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - -#define IWL_RX_HDR(x) ((struct iwl3945_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl3945_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - - -/****************************************************************************** - * - * Functions implemented in iwl-base.c which are forward declared here - * for use by iwl-*.c - * - *****************************************************************************/ -extern int iwl3945_calc_db_from_ratio(int sig_ratio); -extern void iwl3945_rx_replenish(void *data); -extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr,int left); -extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display); -extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv); - -/****************************************************************************** - * - * Functions implemented in iwl-[34]*.c which are forward declared here - * for use by iwl-base.c - * - * NOTE: The implementation of these functions are hardware specific - * which is why they are in the hardware specific files (vs. iwl-base.c) - * - * Naming convention -- - * iwl3945_ <-- Its part of iwlwifi (should be changed to iwl3945_) - * iwl3945_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) - * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl3945_bg_ <-- Called from work queue context - * iwl3945_mac_ <-- mac80211 callback - * - ****************************************************************************/ -extern void iwl3945_hw_rx_handler_setup(struct iwl_priv *priv); -extern void iwl3945_hw_setup_deferred_work(struct iwl_priv *priv); -extern void iwl3945_hw_cancel_deferred_work(struct iwl_priv *priv); -extern int iwl3945_hw_rxq_stop(struct iwl_priv *priv); -extern int iwl3945_hw_set_hw_params(struct iwl_priv *priv); -extern int iwl3945_hw_nic_init(struct iwl_priv *priv); -extern int iwl3945_hw_nic_stop_master(struct iwl_priv *priv); -extern void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv); -extern void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv); -extern int iwl3945_hw_nic_reset(struct iwl_priv *priv); -extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, - u8 reset, u8 pad); -extern void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -extern int iwl3945_hw_get_temperature(struct iwl_priv *priv); -extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl3945_frame *frame, u8 rate); -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); -extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv); -extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); -extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl3945_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -extern void iwl3945_disable_events(struct iwl_priv *priv); -extern int iwl4965_get_temperature(const struct iwl_priv *priv); -extern void iwl3945_post_associate(struct iwl_priv *priv); -extern void iwl3945_config_ap(struct iwl_priv *priv); - -extern int iwl3945_commit_rxon(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); - -/** - * iwl3945_hw_find_station - Find station id for a given BSSID - * @bssid: MAC address of station ID to find - * - * NOTE: This should not be hardware specific but the code has - * not yet been merged into a single common layer for managing the - * station tables. - */ -extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); - -extern struct ieee80211_ops iwl3945_hw_ops; - -/* - * Forward declare iwl-3945.c functions for iwl-base.c - */ -extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv); -extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv); -extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv); -extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv); - -extern const struct iwl_channel_info *iwl3945_get_channel_info( - const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - -extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate); - -/* scanning */ -int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); -void iwl3945_post_scan(struct iwl_priv *priv); - -/* rates */ -extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945]; - -/* Requires full declaration of iwl_priv before including */ -#include "iwl-io.h" - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h deleted file mode 100644 index 9166794eda0d..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ /dev/null @@ -1,792 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -/* - * Please use this file (iwl-4965-hw.h) only for hardware-related definitions. - * Use iwl-commands.h for uCode API definitions. - * Use iwl-dev.h for driver implementation definitions. - */ - -#ifndef __iwl_4965_hw_h__ -#define __iwl_4965_hw_h__ - -#include "iwl-fh.h" - -/* EEPROM */ -#define IWL4965_EEPROM_IMG_SIZE 1024 - -/* - * uCode queue management definitions ... - * The first queue used for block-ack aggregation is #7 (4965 only). - * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7. - */ -#define IWL49_FIRST_AMPDU_QUEUE 7 - -/* Sizes and addresses for instruction and data memory (SRAM) in - * 4965's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ -#define IWL49_RTC_INST_LOWER_BOUND (0x000000) -#define IWL49_RTC_INST_UPPER_BOUND (0x018000) - -#define IWL49_RTC_DATA_LOWER_BOUND (0x800000) -#define IWL49_RTC_DATA_UPPER_BOUND (0x80A000) - -#define IWL49_RTC_INST_SIZE (IWL49_RTC_INST_UPPER_BOUND - \ - IWL49_RTC_INST_LOWER_BOUND) -#define IWL49_RTC_DATA_SIZE (IWL49_RTC_DATA_UPPER_BOUND - \ - IWL49_RTC_DATA_LOWER_BOUND) - -#define IWL49_MAX_INST_SIZE IWL49_RTC_INST_SIZE -#define IWL49_MAX_DATA_SIZE IWL49_RTC_DATA_SIZE - -/* Size of uCode instruction memory in bootstrap state machine */ -#define IWL49_MAX_BSM_SIZE BSM_SRAM_SIZE - -static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) -{ - return (addr >= IWL49_RTC_DATA_LOWER_BOUND) && - (addr < IWL49_RTC_DATA_UPPER_BOUND); -} - -/********************* START TEMPERATURE *************************************/ - -/** - * 4965 temperature calculation. - * - * The driver must calculate the device temperature before calculating - * a txpower setting (amplifier gain is temperature dependent). The - * calculation uses 4 measurements, 3 of which (R1, R2, R3) are calibration - * values used for the life of the driver, and one of which (R4) is the - * real-time temperature indicator. - * - * uCode provides all 4 values to the driver via the "initialize alive" - * notification (see struct iwl4965_init_alive_resp). After the runtime uCode - * image loads, uCode updates the R4 value via statistics notifications - * (see STATISTICS_NOTIFICATION), which occur after each received beacon - * when associated, or can be requested via REPLY_STATISTICS_CMD. - * - * NOTE: uCode provides the R4 value as a 23-bit signed value. Driver - * must sign-extend to 32 bits before applying formula below. - * - * Formula: - * - * degrees Kelvin = ((97 * 259 * (R4 - R2) / (R3 - R1)) / 100) + 8 - * - * NOTE: The basic formula is 259 * (R4-R2) / (R3-R1). The 97/100 is - * an additional correction, which should be centered around 0 degrees - * Celsius (273 degrees Kelvin). The 8 (3 percent of 273) compensates for - * centering the 97/100 correction around 0 degrees K. - * - * Add 273 to Kelvin value to find degrees Celsius, for comparing current - * temperature with factory-measured temperatures when calculating txpower - * settings. - */ -#define TEMPERATURE_CALIB_KELVIN_OFFSET 8 -#define TEMPERATURE_CALIB_A_VAL 259 - -/* Limit range of calculated temperature to be between these Kelvin values */ -#define IWL_TX_POWER_TEMPERATURE_MIN (263) -#define IWL_TX_POWER_TEMPERATURE_MAX (410) - -#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \ - (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \ - ((t) > IWL_TX_POWER_TEMPERATURE_MAX)) - -/********************* END TEMPERATURE ***************************************/ - -/********************* START TXPOWER *****************************************/ - -/** - * 4965 txpower calculations rely on information from three sources: - * - * 1) EEPROM - * 2) "initialize" alive notification - * 3) statistics notifications - * - * EEPROM data consists of: - * - * 1) Regulatory information (max txpower and channel usage flags) is provided - * separately for each channel that can possibly supported by 4965. - * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz - * (legacy) channels. - * - * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom - * for locations in EEPROM. - * - * 2) Factory txpower calibration information is provided separately for - * sub-bands of contiguous channels. 2.4GHz has just one sub-band, - * but 5 GHz has several sub-bands. - * - * In addition, per-band (2.4 and 5 Ghz) saturation txpowers are provided. - * - * See struct iwl4965_eeprom_calib_info (and the tree of structures - * contained within it) for format, and struct iwl4965_eeprom for - * locations in EEPROM. - * - * "Initialization alive" notification (see struct iwl4965_init_alive_resp) - * consists of: - * - * 1) Temperature calculation parameters. - * - * 2) Power supply voltage measurement. - * - * 3) Tx gain compensation to balance 2 transmitters for MIMO use. - * - * Statistics notifications deliver: - * - * 1) Current values for temperature param R4. - */ - -/** - * To calculate a txpower setting for a given desired target txpower, channel, - * modulation bit rate, and transmitter chain (4965 has 2 transmitters to - * support MIMO and transmit diversity), driver must do the following: - * - * 1) Compare desired txpower vs. (EEPROM) regulatory limit for this channel. - * Do not exceed regulatory limit; reduce target txpower if necessary. - * - * If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31), - * 2 transmitters will be used simultaneously; driver must reduce the - * regulatory limit by 3 dB (half-power) for each transmitter, so the - * combined total output of the 2 transmitters is within regulatory limits. - * - * - * 2) Compare target txpower vs. (EEPROM) saturation txpower *reduced by - * backoff for this bit rate*. Do not exceed (saturation - backoff[rate]); - * reduce target txpower if necessary. - * - * Backoff values below are in 1/2 dB units (equivalent to steps in - * txpower gain tables): - * - * OFDM 6 - 36 MBit: 10 steps (5 dB) - * OFDM 48 MBit: 15 steps (7.5 dB) - * OFDM 54 MBit: 17 steps (8.5 dB) - * OFDM 60 MBit: 20 steps (10 dB) - * CCK all rates: 10 steps (5 dB) - * - * Backoff values apply to saturation txpower on a per-transmitter basis; - * when using MIMO (2 transmitters), each transmitter uses the same - * saturation level provided in EEPROM, and the same backoff values; - * no reduction (such as with regulatory txpower limits) is required. - * - * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel - * widths and 40 Mhz (.11n HT40) channel widths; there is no separate - * factory measurement for ht40 channels. - * - * The result of this step is the final target txpower. The rest of - * the steps figure out the proper settings for the device to achieve - * that target txpower. - * - * - * 3) Determine (EEPROM) calibration sub band for the target channel, by - * comparing against first and last channels in each sub band - * (see struct iwl4965_eeprom_calib_subband_info). - * - * - * 4) Linearly interpolate (EEPROM) factory calibration measurement sets, - * referencing the 2 factory-measured (sample) channels within the sub band. - * - * Interpolation is based on difference between target channel's frequency - * and the sample channels' frequencies. Since channel numbers are based - * on frequency (5 MHz between each channel number), this is equivalent - * to interpolating based on channel number differences. - * - * Note that the sample channels may or may not be the channels at the - * edges of the sub band. The target channel may be "outside" of the - * span of the sampled channels. - * - * Driver may choose the pair (for 2 Tx chains) of measurements (see - * struct iwl4965_eeprom_calib_ch_info) for which the actual measured - * txpower comes closest to the desired txpower. Usually, though, - * the middle set of measurements is closest to the regulatory limits, - * and is therefore a good choice for all txpower calculations (this - * assumes that high accuracy is needed for maximizing legal txpower, - * while lower txpower configurations do not need as much accuracy). - * - * Driver should interpolate both members of the chosen measurement pair, - * i.e. for both Tx chains (radio transmitters), unless the driver knows - * that only one of the chains will be used (e.g. only one tx antenna - * connected, but this should be unusual). The rate scaling algorithm - * switches antennas to find best performance, so both Tx chains will - * be used (although only one at a time) even for non-MIMO transmissions. - * - * Driver should interpolate factory values for temperature, gain table - * index, and actual power. The power amplifier detector values are - * not used by the driver. - * - * Sanity check: If the target channel happens to be one of the sample - * channels, the results should agree with the sample channel's - * measurements! - * - * - * 5) Find difference between desired txpower and (interpolated) - * factory-measured txpower. Using (interpolated) factory gain table index - * (shown elsewhere) as a starting point, adjust this index lower to - * increase txpower, or higher to decrease txpower, until the target - * txpower is reached. Each step in the gain table is 1/2 dB. - * - * For example, if factory measured txpower is 16 dBm, and target txpower - * is 13 dBm, add 6 steps to the factory gain index to reduce txpower - * by 3 dB. - * - * - * 6) Find difference between current device temperature and (interpolated) - * factory-measured temperature for sub-band. Factory values are in - * degrees Celsius. To calculate current temperature, see comments for - * "4965 temperature calculation". - * - * If current temperature is higher than factory temperature, driver must - * increase gain (lower gain table index), and vice verse. - * - * Temperature affects gain differently for different channels: - * - * 2.4 GHz all channels: 3.5 degrees per half-dB step - * 5 GHz channels 34-43: 4.5 degrees per half-dB step - * 5 GHz channels >= 44: 4.0 degrees per half-dB step - * - * NOTE: Temperature can increase rapidly when transmitting, especially - * with heavy traffic at high txpowers. Driver should update - * temperature calculations often under these conditions to - * maintain strong txpower in the face of rising temperature. - * - * - * 7) Find difference between current power supply voltage indicator - * (from "initialize alive") and factory-measured power supply voltage - * indicator (EEPROM). - * - * If the current voltage is higher (indicator is lower) than factory - * voltage, gain should be reduced (gain table index increased) by: - * - * (eeprom - current) / 7 - * - * If the current voltage is lower (indicator is higher) than factory - * voltage, gain should be increased (gain table index decreased) by: - * - * 2 * (current - eeprom) / 7 - * - * If number of index steps in either direction turns out to be > 2, - * something is wrong ... just use 0. - * - * NOTE: Voltage compensation is independent of band/channel. - * - * NOTE: "Initialize" uCode measures current voltage, which is assumed - * to be constant after this initial measurement. Voltage - * compensation for txpower (number of steps in gain table) - * may be calculated once and used until the next uCode bootload. - * - * - * 8) If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31), - * adjust txpower for each transmitter chain, so txpower is balanced - * between the two chains. There are 5 pairs of tx_atten[group][chain] - * values in "initialize alive", one pair for each of 5 channel ranges: - * - * Group 0: 5 GHz channel 34-43 - * Group 1: 5 GHz channel 44-70 - * Group 2: 5 GHz channel 71-124 - * Group 3: 5 GHz channel 125-200 - * Group 4: 2.4 GHz all channels - * - * Add the tx_atten[group][chain] value to the index for the target chain. - * The values are signed, but are in pairs of 0 and a non-negative number, - * so as to reduce gain (if necessary) of the "hotter" channel. This - * avoids any need to double-check for regulatory compliance after - * this step. - * - * - * 9) If setting up for a CCK rate, lower the gain by adding a CCK compensation - * value to the index: - * - * Hardware rev B: 9 steps (4.5 dB) - * Hardware rev C: 5 steps (2.5 dB) - * - * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG, - * bits [3:2], 1 = B, 2 = C. - * - * NOTE: This compensation is in addition to any saturation backoff that - * might have been applied in an earlier step. - * - * - * 10) Select the gain table, based on band (2.4 vs 5 GHz). - * - * Limit the adjusted index to stay within the table! - * - * - * 11) Read gain table entries for DSP and radio gain, place into appropriate - * location(s) in command (struct iwl4965_txpowertable_cmd). - */ - -/** - * When MIMO is used (2 transmitters operating simultaneously), driver should - * limit each transmitter to deliver a max of 3 dB below the regulatory limit - * for the device. That is, use half power for each transmitter, so total - * txpower is within regulatory limits. - * - * The value "6" represents number of steps in gain table to reduce power 3 dB. - * Each step is 1/2 dB. - */ -#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6) - -/** - * CCK gain compensation. - * - * When calculating txpowers for CCK, after making sure that the target power - * is within regulatory and saturation limits, driver must additionally - * back off gain by adding these values to the gain table index. - * - * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG, - * bits [3:2], 1 = B, 2 = C. - */ -#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) -#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) - -/* - * 4965 power supply voltage compensation for txpower - */ -#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V (7) - -/** - * Gain tables. - * - * The following tables contain pair of values for setting txpower, i.e. - * gain settings for the output of the device's digital signal processor (DSP), - * and for the analog gain structure of the transmitter. - * - * Each entry in the gain tables represents a step of 1/2 dB. Note that these - * are *relative* steps, not indications of absolute output power. Output - * power varies with temperature, voltage, and channel frequency, and also - * requires consideration of average power (to satisfy regulatory constraints), - * and peak power (to avoid distortion of the output signal). - * - * Each entry contains two values: - * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained - * linear value that multiplies the output of the digital signal processor, - * before being sent to the analog radio. - * 2) Radio gain. This sets the analog gain of the radio Tx path. - * It is a coarser setting, and behaves in a logarithmic (dB) fashion. - * - * EEPROM contains factory calibration data for txpower. This maps actual - * measured txpower levels to gain settings in the "well known" tables - * below ("well-known" means here that both factory calibration *and* the - * driver work with the same table). - * - * There are separate tables for 2.4 GHz and 5 GHz bands. The 5 GHz table - * has an extension (into negative indexes), in case the driver needs to - * boost power setting for high device temperatures (higher than would be - * present during factory calibration). A 5 Ghz EEPROM index of "40" - * corresponds to the 49th entry in the table used by the driver. - */ -#define MIN_TX_GAIN_INDEX (0) /* highest gain, lowest idx, 2.4 */ -#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9) /* highest gain, lowest idx, 5 */ - -/** - * 2.4 GHz gain table - * - * Index Dsp gain Radio gain - * 0 110 0x3f (highest gain) - * 1 104 0x3f - * 2 98 0x3f - * 3 110 0x3e - * 4 104 0x3e - * 5 98 0x3e - * 6 110 0x3d - * 7 104 0x3d - * 8 98 0x3d - * 9 110 0x3c - * 10 104 0x3c - * 11 98 0x3c - * 12 110 0x3b - * 13 104 0x3b - * 14 98 0x3b - * 15 110 0x3a - * 16 104 0x3a - * 17 98 0x3a - * 18 110 0x39 - * 19 104 0x39 - * 20 98 0x39 - * 21 110 0x38 - * 22 104 0x38 - * 23 98 0x38 - * 24 110 0x37 - * 25 104 0x37 - * 26 98 0x37 - * 27 110 0x36 - * 28 104 0x36 - * 29 98 0x36 - * 30 110 0x35 - * 31 104 0x35 - * 32 98 0x35 - * 33 110 0x34 - * 34 104 0x34 - * 35 98 0x34 - * 36 110 0x33 - * 37 104 0x33 - * 38 98 0x33 - * 39 110 0x32 - * 40 104 0x32 - * 41 98 0x32 - * 42 110 0x31 - * 43 104 0x31 - * 44 98 0x31 - * 45 110 0x30 - * 46 104 0x30 - * 47 98 0x30 - * 48 110 0x6 - * 49 104 0x6 - * 50 98 0x6 - * 51 110 0x5 - * 52 104 0x5 - * 53 98 0x5 - * 54 110 0x4 - * 55 104 0x4 - * 56 98 0x4 - * 57 110 0x3 - * 58 104 0x3 - * 59 98 0x3 - * 60 110 0x2 - * 61 104 0x2 - * 62 98 0x2 - * 63 110 0x1 - * 64 104 0x1 - * 65 98 0x1 - * 66 110 0x0 - * 67 104 0x0 - * 68 98 0x0 - * 69 97 0 - * 70 96 0 - * 71 95 0 - * 72 94 0 - * 73 93 0 - * 74 92 0 - * 75 91 0 - * 76 90 0 - * 77 89 0 - * 78 88 0 - * 79 87 0 - * 80 86 0 - * 81 85 0 - * 82 84 0 - * 83 83 0 - * 84 82 0 - * 85 81 0 - * 86 80 0 - * 87 79 0 - * 88 78 0 - * 89 77 0 - * 90 76 0 - * 91 75 0 - * 92 74 0 - * 93 73 0 - * 94 72 0 - * 95 71 0 - * 96 70 0 - * 97 69 0 - * 98 68 0 - */ - -/** - * 5 GHz gain table - * - * Index Dsp gain Radio gain - * -9 123 0x3F (highest gain) - * -8 117 0x3F - * -7 110 0x3F - * -6 104 0x3F - * -5 98 0x3F - * -4 110 0x3E - * -3 104 0x3E - * -2 98 0x3E - * -1 110 0x3D - * 0 104 0x3D - * 1 98 0x3D - * 2 110 0x3C - * 3 104 0x3C - * 4 98 0x3C - * 5 110 0x3B - * 6 104 0x3B - * 7 98 0x3B - * 8 110 0x3A - * 9 104 0x3A - * 10 98 0x3A - * 11 110 0x39 - * 12 104 0x39 - * 13 98 0x39 - * 14 110 0x38 - * 15 104 0x38 - * 16 98 0x38 - * 17 110 0x37 - * 18 104 0x37 - * 19 98 0x37 - * 20 110 0x36 - * 21 104 0x36 - * 22 98 0x36 - * 23 110 0x35 - * 24 104 0x35 - * 25 98 0x35 - * 26 110 0x34 - * 27 104 0x34 - * 28 98 0x34 - * 29 110 0x33 - * 30 104 0x33 - * 31 98 0x33 - * 32 110 0x32 - * 33 104 0x32 - * 34 98 0x32 - * 35 110 0x31 - * 36 104 0x31 - * 37 98 0x31 - * 38 110 0x30 - * 39 104 0x30 - * 40 98 0x30 - * 41 110 0x25 - * 42 104 0x25 - * 43 98 0x25 - * 44 110 0x24 - * 45 104 0x24 - * 46 98 0x24 - * 47 110 0x23 - * 48 104 0x23 - * 49 98 0x23 - * 50 110 0x22 - * 51 104 0x18 - * 52 98 0x18 - * 53 110 0x17 - * 54 104 0x17 - * 55 98 0x17 - * 56 110 0x16 - * 57 104 0x16 - * 58 98 0x16 - * 59 110 0x15 - * 60 104 0x15 - * 61 98 0x15 - * 62 110 0x14 - * 63 104 0x14 - * 64 98 0x14 - * 65 110 0x13 - * 66 104 0x13 - * 67 98 0x13 - * 68 110 0x12 - * 69 104 0x08 - * 70 98 0x08 - * 71 110 0x07 - * 72 104 0x07 - * 73 98 0x07 - * 74 110 0x06 - * 75 104 0x06 - * 76 98 0x06 - * 77 110 0x05 - * 78 104 0x05 - * 79 98 0x05 - * 80 110 0x04 - * 81 104 0x04 - * 82 98 0x04 - * 83 110 0x03 - * 84 104 0x03 - * 85 98 0x03 - * 86 110 0x02 - * 87 104 0x02 - * 88 98 0x02 - * 89 110 0x01 - * 90 104 0x01 - * 91 98 0x01 - * 92 110 0x00 - * 93 104 0x00 - * 94 98 0x00 - * 95 93 0x00 - * 96 88 0x00 - * 97 83 0x00 - * 98 78 0x00 - */ - - -/** - * Sanity checks and default values for EEPROM regulatory levels. - * If EEPROM values fall outside MIN/MAX range, use default values. - * - * Regulatory limits refer to the maximum average txpower allowed by - * regulatory agencies in the geographies in which the device is meant - * to be operated. These limits are SKU-specific (i.e. geography-specific), - * and channel-specific; each channel has an individual regulatory limit - * listed in the EEPROM. - * - * Units are in half-dBm (i.e. "34" means 17 dBm). - */ -#define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34) -#define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34) -#define IWL_TX_POWER_REGULATORY_MIN (0) -#define IWL_TX_POWER_REGULATORY_MAX (34) - -/** - * Sanity checks and default values for EEPROM saturation levels. - * If EEPROM values fall outside MIN/MAX range, use default values. - * - * Saturation is the highest level that the output power amplifier can produce - * without significant clipping distortion. This is a "peak" power level. - * Different types of modulation (i.e. various "rates", and OFDM vs. CCK) - * require differing amounts of backoff, relative to their average power output, - * in order to avoid clipping distortion. - * - * Driver must make sure that it is violating neither the saturation limit, - * nor the regulatory limit, when calculating Tx power settings for various - * rates. - * - * Units are in half-dBm (i.e. "38" means 19 dBm). - */ -#define IWL_TX_POWER_DEFAULT_SATURATION_24 (38) -#define IWL_TX_POWER_DEFAULT_SATURATION_52 (38) -#define IWL_TX_POWER_SATURATION_MIN (20) -#define IWL_TX_POWER_SATURATION_MAX (50) - -/** - * Channel groups used for Tx Attenuation calibration (MIMO tx channel balance) - * and thermal Txpower calibration. - * - * When calculating txpower, driver must compensate for current device - * temperature; higher temperature requires higher gain. Driver must calculate - * current temperature (see "4965 temperature calculation"), then compare vs. - * factory calibration temperature in EEPROM; if current temperature is higher - * than factory temperature, driver must *increase* gain by proportions shown - * in table below. If current temperature is lower than factory, driver must - * *decrease* gain. - * - * Different frequency ranges require different compensation, as shown below. - */ -/* Group 0, 5.2 GHz ch 34-43: 4.5 degrees per 1/2 dB. */ -#define CALIB_IWL_TX_ATTEN_GR1_FCH 34 -#define CALIB_IWL_TX_ATTEN_GR1_LCH 43 - -/* Group 1, 5.3 GHz ch 44-70: 4.0 degrees per 1/2 dB. */ -#define CALIB_IWL_TX_ATTEN_GR2_FCH 44 -#define CALIB_IWL_TX_ATTEN_GR2_LCH 70 - -/* Group 2, 5.5 GHz ch 71-124: 4.0 degrees per 1/2 dB. */ -#define CALIB_IWL_TX_ATTEN_GR3_FCH 71 -#define CALIB_IWL_TX_ATTEN_GR3_LCH 124 - -/* Group 3, 5.7 GHz ch 125-200: 4.0 degrees per 1/2 dB. */ -#define CALIB_IWL_TX_ATTEN_GR4_FCH 125 -#define CALIB_IWL_TX_ATTEN_GR4_LCH 200 - -/* Group 4, 2.4 GHz all channels: 3.5 degrees per 1/2 dB. */ -#define CALIB_IWL_TX_ATTEN_GR5_FCH 1 -#define CALIB_IWL_TX_ATTEN_GR5_LCH 20 - -enum { - CALIB_CH_GROUP_1 = 0, - CALIB_CH_GROUP_2 = 1, - CALIB_CH_GROUP_3 = 2, - CALIB_CH_GROUP_4 = 3, - CALIB_CH_GROUP_5 = 4, - CALIB_CH_GROUP_MAX -}; - -/********************* END TXPOWER *****************************************/ - - -/** - * Tx/Rx Queues - * - * Most communication between driver and 4965 is via queues of data buffers. - * For example, all commands that the driver issues to device's embedded - * controller (uCode) are via the command queue (one of the Tx queues). All - * uCode command responses/replies/notifications, including Rx frames, are - * conveyed from uCode to driver via the Rx queue. - * - * Most support for these queues, including handshake support, resides in - * structures in host DRAM, shared between the driver and the device. When - * allocating this memory, the driver must make sure that data written by - * the host CPU updates DRAM immediately (and does not get "stuck" in CPU's - * cache memory), so DRAM and cache are consistent, and the device can - * immediately see changes made by the driver. - * - * 4965 supports up to 16 DRAM-based Tx queues, and services these queues via - * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array - * in DRAM containing 256 Transmit Frame Descriptors (TFDs). - */ -#define IWL49_NUM_FIFOS 7 -#define IWL49_CMD_FIFO_NUM 4 -#define IWL49_NUM_QUEUES 16 -#define IWL49_NUM_AMPDU_QUEUES 8 - - -/** - * struct iwl4965_schedq_bc_tbl - * - * Byte Count table - * - * Each Tx queue uses a byte-count table containing 320 entries: - * one 16-bit entry for each of 256 TFDs, plus an additional 64 entries that - * duplicate the first 64 entries (to avoid wrap-around within a Tx window; - * max Tx window is 64 TFDs). - * - * When driver sets up a new TFD, it must also enter the total byte count - * of the frame to be transmitted into the corresponding entry in the byte - * count table for the chosen Tx queue. If the TFD index is 0-63, the driver - * must duplicate the byte count entry in corresponding index 256-319. - * - * padding puts each byte count table on a 1024-byte boundary; - * 4965 assumes tables are separated by 1024 bytes. - */ -struct iwl4965_scd_bc_tbl { - __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; - u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; -} __packed; - -#endif /* !__iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c deleted file mode 100644 index 91a9f5253469..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ /dev/null @@ -1,2645 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/mac80211.h> -#include <linux/etherdevice.h> -#include <asm/unaligned.h> - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-agn-calib.h" -#include "iwl-sta.h" -#include "iwl-agn-led.h" -#include "iwl-agn.h" -#include "iwl-agn-debugfs.h" -#include "iwl-legacy.h" - -static int iwl4965_send_tx_power(struct iwl_priv *priv); -static int iwl4965_hw_get_temperature(struct iwl_priv *priv); - -/* Highest firmware API version supported */ -#define IWL4965_UCODE_API_MAX 2 - -/* Lowest firmware API version supported */ -#define IWL4965_UCODE_API_MIN 2 - -#define IWL4965_FW_PRE "iwlwifi-4965-" -#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode" -#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api) - -/* check contents of special bootstrap uCode SRAM */ -static int iwl4965_verify_bsm(struct iwl_priv *priv) -{ - __le32 *image = priv->ucode_boot.v_addr; - u32 len = priv->ucode_boot.len; - u32 reg; - u32 val; - - IWL_DEBUG_INFO(priv, "Begin verify bsm\n"); - - /* verify BSM SRAM contents */ - val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG); - for (reg = BSM_SRAM_LOWER_BOUND; - reg < BSM_SRAM_LOWER_BOUND + len; - reg += sizeof(u32), image++) { - val = iwl_read_prph(priv, reg); - if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "BSM uCode verification failed at " - "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", - BSM_SRAM_LOWER_BOUND, - reg - BSM_SRAM_LOWER_BOUND, len, - val, le32_to_cpu(*image)); - return -EIO; - } - } - - IWL_DEBUG_INFO(priv, "BSM bootstrap uCode image OK\n"); - - return 0; -} - -/** - * iwl4965_load_bsm - Load bootstrap instructions - * - * BSM operation: - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down during RFKILL. When powering back - * up after power-saving sleeps (or during initial uCode load), the BSM loads - * the bootstrap program into the on-board processor, and starts it. - * - * The bootstrap program loads (via DMA) instructions and data for a new - * program from host DRAM locations indicated by the host driver in the - * BSM_DRAM_* registers. Once the new program is loaded, it starts - * automatically. - * - * When initializing the NIC, the host driver points the BSM to the - * "initialize" uCode image. This uCode sets up some internal data, then - * notifies host via "initialize alive" that it is complete. - * - * The host then replaces the BSM_DRAM_* pointer values to point to the - * normal runtime uCode instructions and a backup uCode data cache buffer - * (filled initially with starting data values for the on-board processor), - * then triggers the "initialize" uCode to load and launch the runtime uCode, - * which begins normal operation. - * - * When doing a power-save shutdown, runtime uCode saves data SRAM into - * the backup data cache in DRAM before SRAM is powered down. - * - * When powering back up, the BSM loads the bootstrap program. This reloads - * the runtime uCode instructions and the backup data cache into SRAM, - * and re-launches the runtime uCode from where it left off. - */ -static int iwl4965_load_bsm(struct iwl_priv *priv) -{ - __le32 *image = priv->ucode_boot.v_addr; - u32 len = priv->ucode_boot.len; - dma_addr_t pinst; - dma_addr_t pdata; - u32 inst_len; - u32 data_len; - int i; - u32 done; - u32 reg_offset; - int ret; - - IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - - priv->ucode_type = UCODE_RT; - - /* make sure bootstrap program is no larger than BSM's SRAM size */ - if (len > IWL49_MAX_BSM_SIZE) - return -EINVAL; - - /* Tell bootstrap uCode where to find the "Initialize" uCode - * in host DRAM ... host DRAM physical address bits 35:4 for 4965. - * NOTE: iwl_init_alive_start() will replace these values, - * after the "initialize" uCode has run, to point to - * runtime/protocol instructions and backup data cache. - */ - pinst = priv->ucode_init.p_addr >> 4; - pdata = priv->ucode_init_data.p_addr >> 4; - inst_len = priv->ucode_init.len; - data_len = priv->ucode_init_data.len; - - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); - - /* Fill BSM memory with bootstrap instructions */ - for (reg_offset = BSM_SRAM_LOWER_BOUND; - reg_offset < BSM_SRAM_LOWER_BOUND + len; - reg_offset += sizeof(u32), image++) - _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); - - ret = iwl4965_verify_bsm(priv); - if (ret) - return ret; - - /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ - iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); - iwl_write_prph(priv, BSM_WR_MEM_DST_REG, IWL49_RTC_INST_LOWER_BOUND); - iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); - - /* Load bootstrap code into instruction SRAM now, - * to prepare to load "initialize" uCode */ - iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START); - - /* Wait for load of bootstrap uCode to finish */ - for (i = 0; i < 100; i++) { - done = iwl_read_prph(priv, BSM_WR_CTRL_REG); - if (!(done & BSM_WR_CTRL_REG_BIT_START)) - break; - udelay(10); - } - if (i < 100) - IWL_DEBUG_INFO(priv, "BSM write complete, poll %d iterations\n", i); - else { - IWL_ERR(priv, "BSM write did not complete!\n"); - return -EIO; - } - - /* Enable future boot loads whenever power management unit triggers it - * (e.g. when powering back up after power-save shutdown) */ - iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - - - return 0; -} - -/** - * iwl4965_set_ucode_ptrs - Set uCode address location - * - * Tell initialization uCode where to find runtime uCode. - * - * BSM registers initially contain pointers to initialization uCode. - * We need to replace them to load runtime uCode inst and data, - * and to save runtime data when powering down. - */ -static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) -{ - dma_addr_t pinst; - dma_addr_t pdata; - int ret = 0; - - /* bits 35:4 for 4965 */ - pinst = priv->ucode_code.p_addr >> 4; - pdata = priv->ucode_data_backup.p_addr >> 4; - - /* Tell bootstrap uCode where to find image to load */ - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, - priv->ucode_data.len); - - /* Inst byte count must be last to set up, bit 31 signals uCode - * that all new ptr/size info is in place */ - iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, - priv->ucode_code.len | BSM_DRAM_INST_LOAD); - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); - - return ret; -} - -/** - * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received - * - * Called after REPLY_ALIVE notification received from "initialize" uCode. - * - * The 4965 "initialize" ALIVE reply contains calibration data for: - * Voltage, temperature, and MIMO tx gain correction, now stored in priv - * (3945 does not contain this data). - * - * Tell "initialize" uCode to go ahead and load the runtime uCode. -*/ -static void iwl4965_init_alive_start(struct iwl_priv *priv) -{ - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); - goto restart; - } - - /* Bootstrap uCode has loaded initialize uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - /* Calculate temperature */ - priv->temperature = iwl4965_hw_get_temperature(priv); - - /* Send pointers to protocol/runtime uCode image ... init code will - * load and launch runtime uCode, which will send us another "Alive" - * notification. */ - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - if (iwl4965_set_ucode_ptrs(priv)) { - /* Runtime instruction load won't happen; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); - goto restart; - } - return; - -restart: - queue_work(priv->workqueue, &priv->restart); -} - -static bool is_ht40_channel(__le32 rxon_flags) -{ - int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) - >> RXON_FLG_CHANNEL_MODE_POS; - return ((chan_mod == CHANNEL_MODE_PURE_40) || - (chan_mod == CHANNEL_MODE_MIXED)); -} - -/* - * EEPROM handlers - */ -static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv) -{ - return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); -} - -/* - * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - * must be called under priv->lock and mac access - */ -static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) -{ - iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); -} - -static void iwl4965_nic_config(struct iwl_priv *priv) -{ - unsigned long flags; - u16 radio_cfg; - - spin_lock_irqsave(&priv->lock, flags); - - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); - - /* write radio config values to register */ - if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX) - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | - EEPROM_RF_CFG_STEP_MSK(radio_cfg) | - EEPROM_RF_CFG_DASH_MSK(radio_cfg)); - - /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); - - priv->calib_info = (struct iwl_eeprom_calib_info *) - iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -/* Reset differential Rx gains in NIC to prepare for chain noise calibration. - * Called after every association, but this runs only once! - * ... once chain noise is calibrated the first time, it's good forever. */ -static void iwl4965_chain_noise_reset(struct iwl_priv *priv) -{ - struct iwl_chain_noise_data *data = &(priv->chain_noise_data); - - if ((data->state == IWL_CHAIN_NOISE_ALIVE) && - iwl_is_any_associated(priv)) { - struct iwl_calib_diff_gain_cmd cmd; - - /* clear data for chain noise calibration algorithm */ - data->chain_noise_a = 0; - data->chain_noise_b = 0; - data->chain_noise_c = 0; - data->chain_signal_a = 0; - data->chain_signal_b = 0; - data->chain_signal_c = 0; - data->beacon_count = 0; - - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; - cmd.diff_gain_a = 0; - cmd.diff_gain_b = 0; - cmd.diff_gain_c = 0; - if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd)) - IWL_ERR(priv, - "Could not send REPLY_PHY_CALIBRATION_CMD\n"); - data->state = IWL_CHAIN_NOISE_ACCUMULATE; - IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n"); - } -} - -static void iwl4965_gain_computation(struct iwl_priv *priv, - u32 *average_noise, - u16 min_average_noise_antenna_i, - u32 min_average_noise, - u8 default_chain) -{ - int i, ret; - struct iwl_chain_noise_data *data = &priv->chain_noise_data; - - data->delta_gain_code[min_average_noise_antenna_i] = 0; - - for (i = default_chain; i < NUM_RX_CHAINS; i++) { - s32 delta_g = 0; - - if (!(data->disconn_array[i]) && - (data->delta_gain_code[i] == - CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) { - delta_g = average_noise[i] - min_average_noise; - data->delta_gain_code[i] = (u8)((delta_g * 10) / 15); - data->delta_gain_code[i] = - min(data->delta_gain_code[i], - (u8) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); - - data->delta_gain_code[i] = - (data->delta_gain_code[i] | (1 << 2)); - } else { - data->delta_gain_code[i] = 0; - } - } - IWL_DEBUG_CALIB(priv, "delta_gain_codes: a %d b %d c %d\n", - data->delta_gain_code[0], - data->delta_gain_code[1], - data->delta_gain_code[2]); - - /* Differential gain gets sent to uCode only once */ - if (!data->radio_write) { - struct iwl_calib_diff_gain_cmd cmd; - data->radio_write = 1; - - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; - cmd.diff_gain_a = data->delta_gain_code[0]; - cmd.diff_gain_b = data->delta_gain_code[1]; - cmd.diff_gain_c = data->delta_gain_code[2]; - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_DEBUG_CALIB(priv, "fail sending cmd " - "REPLY_PHY_CALIBRATION_CMD\n"); - - /* TODO we might want recalculate - * rx_chain in rxon cmd */ - - /* Mark so we run this algo only once! */ - data->state = IWL_CHAIN_NOISE_CALIBRATED; - } -} - -static void iwl4965_bg_txpower_work(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, - txpower_work); - - /* If a scan happened to start before we got here - * then just return; the statistics notification will - * kick off another scheduled work to compensate for - * any temperature delta we missed here. */ - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - /* Regardless of if we are associated, we must reconfigure the - * TX power since frames can be sent on non-radar channels while - * not associated */ - iwl4965_send_tx_power(priv); - - /* Update last_temperature to keep is_calib_needed from running - * when it isn't needed... */ - priv->last_temperature = priv->temperature; - - mutex_unlock(&priv->mutex); -} - -/* - * Acquire priv->lock before calling this function ! - */ -static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) -{ - iwl_write_direct32(priv, HBUS_TARG_WRPTR, - (index & 0xff) | (txq_id << 8)); - iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(txq_id), index); -} - -/** - * iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue - * @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed - * @scd_retry: (1) Indicates queue will be used in aggregation mode - * - * NOTE: Acquire priv->lock before calling this function ! - */ -static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - int tx_fifo_id, int scd_retry) -{ - int txq_id = txq->q.id; - - /* Find out whether to activate Tx queue */ - int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; - - /* Set up and activate */ - iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (active << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (tx_fifo_id << IWL49_SCD_QUEUE_STTS_REG_POS_TXF) | - (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_WSL) | - (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK) | - IWL49_SCD_QUEUE_STTS_REG_MSK); - - txq->sched_retry = scd_retry; - - IWL_DEBUG_INFO(priv, "%s %s Queue %d on AC %d\n", - active ? "Activate" : "Deactivate", - scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); -} - -static const s8 default_queue_to_tx_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, - IWL49_CMD_FIFO_NUM, - IWL_TX_FIFO_UNUSED, - IWL_TX_FIFO_UNUSED, -}; - -static int iwl4965_alive_notify(struct iwl_priv *priv) -{ - u32 a; - unsigned long flags; - int i, chan; - u32 reg_val; - - spin_lock_irqsave(&priv->lock, flags); - - /* Clear 4965's internal Tx Scheduler data base */ - priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); - a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; - for (; a < priv->scd_base_addr + IWL49_SCD_TX_STTS_BITMAP_OFFSET; a += 4) - iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4) - iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + - IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) - iwl_write_targ_mem(priv, a, 0); - - /* Tel 4965 where to find Tx byte count tables */ - iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, - priv->scd_bc_tbls.dma >> 10); - - /* Enable DMA channel */ - for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++) - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); - - /* Update FH chicken bits */ - reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); - iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, - reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); - - /* Disable chain mode for all queues */ - iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); - - /* Initialize each Tx queue (including the command queue) */ - for (i = 0; i < priv->hw_params.max_txq_num; i++) { - - /* TFD circular buffer read/write indexes */ - iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(i), 0); - iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); - - /* Max Tx Window size for Scheduler-ACK mode */ - iwl_write_targ_mem(priv, priv->scd_base_addr + - IWL49_SCD_CONTEXT_QUEUE_OFFSET(i), - (SCD_WIN_SIZE << - IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); - - /* Frame limit */ - iwl_write_targ_mem(priv, priv->scd_base_addr + - IWL49_SCD_CONTEXT_QUEUE_OFFSET(i) + - sizeof(u32), - (SCD_FRAME_LIMIT << - IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); - - } - iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK, - (1 << priv->hw_params.max_txq_num) - 1); - - /* Activate all Tx DMA/FIFO channels */ - priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6)); - - iwl4965_set_wr_ptrs(priv, IWL_DEFAULT_CMD_QUEUE_NUM, 0); - - /* make sure all queue are not stopped */ - memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); - for (i = 0; i < 4; i++) - atomic_set(&priv->queue_stop_count[i], 0); - - /* reset to 0 to enable all the queue first */ - priv->txq_ctx_active_msk = 0; - /* Map each Tx/cmd queue to its corresponding fifo */ - BUILD_BUG_ON(ARRAY_SIZE(default_queue_to_tx_fifo) != 7); - - for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { - int ac = default_queue_to_tx_fifo[i]; - - iwl_txq_ctx_activate(priv, i); - - if (ac == IWL_TX_FIFO_UNUSED) - continue; - - iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static struct iwl_sensitivity_ranges iwl4965_sensitivity = { - .min_nrg_cck = 97, - .max_nrg_cck = 0, /* not used, set to 0 */ - - .auto_corr_min_ofdm = 85, - .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 105, - .auto_corr_min_ofdm_mrc_x1 = 220, - - .auto_corr_max_ofdm = 120, - .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 140, - .auto_corr_max_ofdm_mrc_x1 = 270, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 200, - .auto_corr_max_cck_mrc = 400, - - .nrg_th_cck = 100, - .nrg_th_ofdm = 100, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -static void iwl4965_set_ct_threshold(struct iwl_priv *priv) -{ - /* want Kelvin */ - priv->hw_params.ct_kill_threshold = - CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY); -} - -/** - * iwl4965_hw_set_hw_params - * - * Called when initializing driver - */ -static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) -{ - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; - - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwl4965_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWL4965_STATION_COUNT; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL4965_BROADCAST_ID; - priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ); - - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - - iwl4965_set_ct_threshold(priv); - - priv->hw_params.sens = &iwl4965_sensitivity; - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; - - return 0; -} - -static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) -{ - s32 sign = 1; - - if (num < 0) { - sign = -sign; - num = -num; - } - if (denom < 0) { - sign = -sign; - denom = -denom; - } - *res = 1; - *res = ((num * 2 + denom) / (denom * 2)) * sign; - - return 1; -} - -/** - * iwl4965_get_voltage_compensation - Power supply voltage comp for txpower - * - * Determines power supply voltage compensation for txpower calculations. - * Returns number of 1/2-dB steps to subtract from gain table index, - * to compensate for difference between power supply voltage during - * factory measurements, vs. current power supply voltage. - * - * Voltage indication is higher for lower voltage. - * Lower voltage requires more gain (lower gain table index). - */ -static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, - s32 current_voltage) -{ - s32 comp = 0; - - if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) || - (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage)) - return 0; - - iwl4965_math_div_round(current_voltage - eeprom_voltage, - TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp); - - if (current_voltage > eeprom_voltage) - comp *= 2; - if ((comp < -2) || (comp > 2)) - comp = 0; - - return comp; -} - -static s32 iwl4965_get_tx_atten_grp(u16 channel) -{ - if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH && - channel <= CALIB_IWL_TX_ATTEN_GR5_LCH) - return CALIB_CH_GROUP_5; - - if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH && - channel <= CALIB_IWL_TX_ATTEN_GR1_LCH) - return CALIB_CH_GROUP_1; - - if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH && - channel <= CALIB_IWL_TX_ATTEN_GR2_LCH) - return CALIB_CH_GROUP_2; - - if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH && - channel <= CALIB_IWL_TX_ATTEN_GR3_LCH) - return CALIB_CH_GROUP_3; - - if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH && - channel <= CALIB_IWL_TX_ATTEN_GR4_LCH) - return CALIB_CH_GROUP_4; - - return -1; -} - -static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) -{ - s32 b = -1; - - for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) { - if (priv->calib_info->band_info[b].ch_from == 0) - continue; - - if ((channel >= priv->calib_info->band_info[b].ch_from) - && (channel <= priv->calib_info->band_info[b].ch_to)) - break; - } - - return b; -} - -static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) -{ - s32 val; - - if (x2 == x1) - return y1; - else { - iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val); - return val + y2; - } -} - -/** - * iwl4965_interpolate_chan - Interpolate factory measurements for one channel - * - * Interpolates factory measurements from the two sample channels within a - * sub-band, to apply to channel of interest. Interpolation is proportional to - * differences in channel frequencies, which is proportional to differences - * in channel number. - */ -static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, - struct iwl_eeprom_calib_ch_info *chan_info) -{ - s32 s = -1; - u32 c; - u32 m; - const struct iwl_eeprom_calib_measure *m1; - const struct iwl_eeprom_calib_measure *m2; - struct iwl_eeprom_calib_measure *omeas; - u32 ch_i1; - u32 ch_i2; - - s = iwl4965_get_sub_band(priv, channel); - if (s >= EEPROM_TX_POWER_BANDS) { - IWL_ERR(priv, "Tx Power can not find channel %d\n", channel); - return -1; - } - - ch_i1 = priv->calib_info->band_info[s].ch1.ch_num; - ch_i2 = priv->calib_info->band_info[s].ch2.ch_num; - chan_info->ch_num = (u8) channel; - - IWL_DEBUG_TXPOWER(priv, "channel %d subband %d factory cal ch %d & %d\n", - channel, s, ch_i1, ch_i2); - - for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) { - for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) { - m1 = &(priv->calib_info->band_info[s].ch1. - measurements[c][m]); - m2 = &(priv->calib_info->band_info[s].ch2. - measurements[c][m]); - omeas = &(chan_info->measurements[c][m]); - - omeas->actual_pow = - (u8) iwl4965_interpolate_value(channel, ch_i1, - m1->actual_pow, - ch_i2, - m2->actual_pow); - omeas->gain_idx = - (u8) iwl4965_interpolate_value(channel, ch_i1, - m1->gain_idx, ch_i2, - m2->gain_idx); - omeas->temperature = - (u8) iwl4965_interpolate_value(channel, ch_i1, - m1->temperature, - ch_i2, - m2->temperature); - omeas->pa_det = - (s8) iwl4965_interpolate_value(channel, ch_i1, - m1->pa_det, ch_i2, - m2->pa_det); - - IWL_DEBUG_TXPOWER(priv, - "chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m, - m1->actual_pow, m2->actual_pow, omeas->actual_pow); - IWL_DEBUG_TXPOWER(priv, - "chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m, - m1->gain_idx, m2->gain_idx, omeas->gain_idx); - IWL_DEBUG_TXPOWER(priv, - "chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m, - m1->pa_det, m2->pa_det, omeas->pa_det); - IWL_DEBUG_TXPOWER(priv, - "chain %d meas %d T1=%d T2=%d T=%d\n", c, m, - m1->temperature, m2->temperature, - omeas->temperature); - } - } - - return 0; -} - -/* bit-rate-dependent table to prevent Tx distortion, in half-dB units, - * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */ -static s32 back_off_table[] = { - 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */ - 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */ - 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */ - 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */ - 10 /* CCK */ -}; - -/* Thermal compensation values for txpower for various frequency ranges ... - * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */ -static struct iwl4965_txpower_comp_entry { - s32 degrees_per_05db_a; - s32 degrees_per_05db_a_denom; -} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = { - {9, 2}, /* group 0 5.2, ch 34-43 */ - {4, 1}, /* group 1 5.2, ch 44-70 */ - {4, 1}, /* group 2 5.2, ch 71-124 */ - {4, 1}, /* group 3 5.2, ch 125-200 */ - {3, 1} /* group 4 2.4, ch all */ -}; - -static s32 get_min_power_index(s32 rate_power_index, u32 band) -{ - if (!band) { - if ((rate_power_index & 7) <= 4) - return MIN_TX_GAIN_INDEX_52GHZ_EXT; - } - return MIN_TX_GAIN_INDEX; -} - -struct gain_entry { - u8 dsp; - u8 radio; -}; - -static const struct gain_entry gain_table[2][108] = { - /* 5.2GHz power gain index table */ - { - {123, 0x3F}, /* highest txpower */ - {117, 0x3F}, - {110, 0x3F}, - {104, 0x3F}, - {98, 0x3F}, - {110, 0x3E}, - {104, 0x3E}, - {98, 0x3E}, - {110, 0x3D}, - {104, 0x3D}, - {98, 0x3D}, - {110, 0x3C}, - {104, 0x3C}, - {98, 0x3C}, - {110, 0x3B}, - {104, 0x3B}, - {98, 0x3B}, - {110, 0x3A}, - {104, 0x3A}, - {98, 0x3A}, - {110, 0x39}, - {104, 0x39}, - {98, 0x39}, - {110, 0x38}, - {104, 0x38}, - {98, 0x38}, - {110, 0x37}, - {104, 0x37}, - {98, 0x37}, - {110, 0x36}, - {104, 0x36}, - {98, 0x36}, - {110, 0x35}, - {104, 0x35}, - {98, 0x35}, - {110, 0x34}, - {104, 0x34}, - {98, 0x34}, - {110, 0x33}, - {104, 0x33}, - {98, 0x33}, - {110, 0x32}, - {104, 0x32}, - {98, 0x32}, - {110, 0x31}, - {104, 0x31}, - {98, 0x31}, - {110, 0x30}, - {104, 0x30}, - {98, 0x30}, - {110, 0x25}, - {104, 0x25}, - {98, 0x25}, - {110, 0x24}, - {104, 0x24}, - {98, 0x24}, - {110, 0x23}, - {104, 0x23}, - {98, 0x23}, - {110, 0x22}, - {104, 0x18}, - {98, 0x18}, - {110, 0x17}, - {104, 0x17}, - {98, 0x17}, - {110, 0x16}, - {104, 0x16}, - {98, 0x16}, - {110, 0x15}, - {104, 0x15}, - {98, 0x15}, - {110, 0x14}, - {104, 0x14}, - {98, 0x14}, - {110, 0x13}, - {104, 0x13}, - {98, 0x13}, - {110, 0x12}, - {104, 0x08}, - {98, 0x08}, - {110, 0x07}, - {104, 0x07}, - {98, 0x07}, - {110, 0x06}, - {104, 0x06}, - {98, 0x06}, - {110, 0x05}, - {104, 0x05}, - {98, 0x05}, - {110, 0x04}, - {104, 0x04}, - {98, 0x04}, - {110, 0x03}, - {104, 0x03}, - {98, 0x03}, - {110, 0x02}, - {104, 0x02}, - {98, 0x02}, - {110, 0x01}, - {104, 0x01}, - {98, 0x01}, - {110, 0x00}, - {104, 0x00}, - {98, 0x00}, - {93, 0x00}, - {88, 0x00}, - {83, 0x00}, - {78, 0x00}, - }, - /* 2.4GHz power gain index table */ - { - {110, 0x3f}, /* highest txpower */ - {104, 0x3f}, - {98, 0x3f}, - {110, 0x3e}, - {104, 0x3e}, - {98, 0x3e}, - {110, 0x3d}, - {104, 0x3d}, - {98, 0x3d}, - {110, 0x3c}, - {104, 0x3c}, - {98, 0x3c}, - {110, 0x3b}, - {104, 0x3b}, - {98, 0x3b}, - {110, 0x3a}, - {104, 0x3a}, - {98, 0x3a}, - {110, 0x39}, - {104, 0x39}, - {98, 0x39}, - {110, 0x38}, - {104, 0x38}, - {98, 0x38}, - {110, 0x37}, - {104, 0x37}, - {98, 0x37}, - {110, 0x36}, - {104, 0x36}, - {98, 0x36}, - {110, 0x35}, - {104, 0x35}, - {98, 0x35}, - {110, 0x34}, - {104, 0x34}, - {98, 0x34}, - {110, 0x33}, - {104, 0x33}, - {98, 0x33}, - {110, 0x32}, - {104, 0x32}, - {98, 0x32}, - {110, 0x31}, - {104, 0x31}, - {98, 0x31}, - {110, 0x30}, - {104, 0x30}, - {98, 0x30}, - {110, 0x6}, - {104, 0x6}, - {98, 0x6}, - {110, 0x5}, - {104, 0x5}, - {98, 0x5}, - {110, 0x4}, - {104, 0x4}, - {98, 0x4}, - {110, 0x3}, - {104, 0x3}, - {98, 0x3}, - {110, 0x2}, - {104, 0x2}, - {98, 0x2}, - {110, 0x1}, - {104, 0x1}, - {98, 0x1}, - {110, 0x0}, - {104, 0x0}, - {98, 0x0}, - {97, 0}, - {96, 0}, - {95, 0}, - {94, 0}, - {93, 0}, - {92, 0}, - {91, 0}, - {90, 0}, - {89, 0}, - {88, 0}, - {87, 0}, - {86, 0}, - {85, 0}, - {84, 0}, - {83, 0}, - {82, 0}, - {81, 0}, - {80, 0}, - {79, 0}, - {78, 0}, - {77, 0}, - {76, 0}, - {75, 0}, - {74, 0}, - {73, 0}, - {72, 0}, - {71, 0}, - {70, 0}, - {69, 0}, - {68, 0}, - {67, 0}, - {66, 0}, - {65, 0}, - {64, 0}, - {63, 0}, - {62, 0}, - {61, 0}, - {60, 0}, - {59, 0}, - } -}; - -static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, - u8 is_ht40, u8 ctrl_chan_high, - struct iwl4965_tx_power_db *tx_power_tbl) -{ - u8 saturation_power; - s32 target_power; - s32 user_target_power; - s32 power_limit; - s32 current_temp; - s32 reg_limit; - s32 current_regulatory; - s32 txatten_grp = CALIB_CH_GROUP_MAX; - int i; - int c; - const struct iwl_channel_info *ch_info = NULL; - struct iwl_eeprom_calib_ch_info ch_eeprom_info; - const struct iwl_eeprom_calib_measure *measurement; - s16 voltage; - s32 init_voltage; - s32 voltage_compensation; - s32 degrees_per_05db_num; - s32 degrees_per_05db_denom; - s32 factory_temp; - s32 temperature_comp[2]; - s32 factory_gain_index[2]; - s32 factory_actual_pwr[2]; - s32 power_index; - - /* tx_power_user_lmt is in dBm, convert to half-dBm (half-dB units - * are used for indexing into txpower table) */ - user_target_power = 2 * priv->tx_power_user_lmt; - - /* Get current (RXON) channel, band, width */ - IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band, - is_ht40); - - ch_info = iwl_get_channel_info(priv, priv->band, channel); - - if (!is_channel_valid(ch_info)) - return -EINVAL; - - /* get txatten group, used to select 1) thermal txpower adjustment - * and 2) mimo txpower balance between Tx chains. */ - txatten_grp = iwl4965_get_tx_atten_grp(channel); - if (txatten_grp < 0) { - IWL_ERR(priv, "Can't find txatten group for channel %d.\n", - channel); - return -EINVAL; - } - - IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", - channel, txatten_grp); - - if (is_ht40) { - if (ctrl_chan_high) - channel -= 2; - else - channel += 2; - } - - /* hardware txpower limits ... - * saturation (clipping distortion) txpowers are in half-dBm */ - if (band) - saturation_power = priv->calib_info->saturation_power24; - else - saturation_power = priv->calib_info->saturation_power52; - - if (saturation_power < IWL_TX_POWER_SATURATION_MIN || - saturation_power > IWL_TX_POWER_SATURATION_MAX) { - if (band) - saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24; - else - saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52; - } - - /* regulatory txpower limits ... reg_limit values are in half-dBm, - * max_power_avg values are in dBm, convert * 2 */ - if (is_ht40) - reg_limit = ch_info->ht40_max_power_avg * 2; - else - reg_limit = ch_info->max_power_avg * 2; - - if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) || - (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) { - if (band) - reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24; - else - reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52; - } - - /* Interpolate txpower calibration values for this channel, - * based on factory calibration tests on spaced channels. */ - iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); - - /* calculate tx gain adjustment based on power supply voltage */ - voltage = le16_to_cpu(priv->calib_info->voltage); - init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); - voltage_compensation = - iwl4965_get_voltage_compensation(voltage, init_voltage); - - IWL_DEBUG_TXPOWER(priv, "curr volt %d eeprom volt %d volt comp %d\n", - init_voltage, - voltage, voltage_compensation); - - /* get current temperature (Celsius) */ - current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN); - current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX); - current_temp = KELVIN_TO_CELSIUS(current_temp); - - /* select thermal txpower adjustment params, based on channel group - * (same frequency group used for mimo txatten adjustment) */ - degrees_per_05db_num = - tx_power_cmp_tble[txatten_grp].degrees_per_05db_a; - degrees_per_05db_denom = - tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom; - - /* get per-chain txpower values from factory measurements */ - for (c = 0; c < 2; c++) { - measurement = &ch_eeprom_info.measurements[c][1]; - - /* txgain adjustment (in half-dB steps) based on difference - * between factory and current temperature */ - factory_temp = measurement->temperature; - iwl4965_math_div_round((current_temp - factory_temp) * - degrees_per_05db_denom, - degrees_per_05db_num, - &temperature_comp[c]); - - factory_gain_index[c] = measurement->gain_idx; - factory_actual_pwr[c] = measurement->actual_pow; - - IWL_DEBUG_TXPOWER(priv, "chain = %d\n", c); - IWL_DEBUG_TXPOWER(priv, "fctry tmp %d, " - "curr tmp %d, comp %d steps\n", - factory_temp, current_temp, - temperature_comp[c]); - - IWL_DEBUG_TXPOWER(priv, "fctry idx %d, fctry pwr %d\n", - factory_gain_index[c], - factory_actual_pwr[c]); - } - - /* for each of 33 bit-rates (including 1 for CCK) */ - for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) { - u8 is_mimo_rate; - union iwl4965_tx_power_dual_stream tx_power; - - /* for mimo, reduce each chain's txpower by half - * (3dB, 6 steps), so total output power is regulatory - * compliant. */ - if (i & 0x8) { - current_regulatory = reg_limit - - IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION; - is_mimo_rate = 1; - } else { - current_regulatory = reg_limit; - is_mimo_rate = 0; - } - - /* find txpower limit, either hardware or regulatory */ - power_limit = saturation_power - back_off_table[i]; - if (power_limit > current_regulatory) - power_limit = current_regulatory; - - /* reduce user's txpower request if necessary - * for this rate on this channel */ - target_power = user_target_power; - if (target_power > power_limit) - target_power = power_limit; - - IWL_DEBUG_TXPOWER(priv, "rate %d sat %d reg %d usr %d tgt %d\n", - i, saturation_power - back_off_table[i], - current_regulatory, user_target_power, - target_power); - - /* for each of 2 Tx chains (radio transmitters) */ - for (c = 0; c < 2; c++) { - s32 atten_value; - - if (is_mimo_rate) - atten_value = - (s32)le32_to_cpu(priv->card_alive_init. - tx_atten[txatten_grp][c]); - else - atten_value = 0; - - /* calculate index; higher index means lower txpower */ - power_index = (u8) (factory_gain_index[c] - - (target_power - - factory_actual_pwr[c]) - - temperature_comp[c] - - voltage_compensation + - atten_value); - -/* IWL_DEBUG_TXPOWER(priv, "calculated txpower index %d\n", - power_index); */ - - if (power_index < get_min_power_index(i, band)) - power_index = get_min_power_index(i, band); - - /* adjust 5 GHz index to support negative indexes */ - if (!band) - power_index += 9; - - /* CCK, rate 32, reduce txpower for CCK */ - if (i == POWER_TABLE_CCK_ENTRY) - power_index += - IWL_TX_POWER_CCK_COMPENSATION_C_STEP; - - /* stay within the table! */ - if (power_index > 107) { - IWL_WARN(priv, "txpower index %d > 107\n", - power_index); - power_index = 107; - } - if (power_index < 0) { - IWL_WARN(priv, "txpower index %d < 0\n", - power_index); - power_index = 0; - } - - /* fill txpower command for this rate/chain */ - tx_power.s.radio_tx_gain[c] = - gain_table[band][power_index].radio; - tx_power.s.dsp_predis_atten[c] = - gain_table[band][power_index].dsp; - - IWL_DEBUG_TXPOWER(priv, "chain %d mimo %d index %d " - "gain 0x%02x dsp %d\n", - c, atten_value, power_index, - tx_power.s.radio_tx_gain[c], - tx_power.s.dsp_predis_atten[c]); - } /* for each chain */ - - tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw); - - } /* for each rate */ - - return 0; -} - -/** - * iwl4965_send_tx_power - Configure the TXPOWER level user limit - * - * Uses the active RXON for channel, band, and characteristics (ht40, high) - * The power limit is taken from priv->tx_power_user_lmt. - */ -static int iwl4965_send_tx_power(struct iwl_priv *priv) -{ - struct iwl4965_txpowertable_cmd cmd = { 0 }; - int ret; - u8 band = 0; - bool is_ht40 = false; - u8 ctrl_chan_high = 0; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), - "TX Power requested while scanning!\n")) - return -EAGAIN; - - band = priv->band == IEEE80211_BAND_2GHZ; - - is_ht40 = is_ht40_channel(ctx->active.flags); - - if (is_ht40 && (ctx->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) - ctrl_chan_high = 1; - - cmd.band = band; - cmd.channel = ctx->active.channel; - - ret = iwl4965_fill_txpower_tbl(priv, band, - le16_to_cpu(ctx->active.channel), - is_ht40, ctrl_chan_high, &cmd.tx_power); - if (ret) - goto out; - - ret = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); - -out: - return ret; -} - -static int iwl4965_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret = 0; - struct iwl4965_rxon_assoc_cmd rxon_assoc; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (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) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved = 0; - rxon_assoc.ofdm_ht_single_stream_basic_rates = - ctx->staging.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - ctx->staging.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; - - ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC, - sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - - return ret; -} - -static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active; - int ret; - bool new_assoc = - !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); - - if (!iwl_is_alive(priv)) - return -EBUSY; - - if (!ctx->is_active) - return 0; - - /* always get timestamp with Rx frame */ - ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; - - ret = iwl_check_rxon_cmd(priv, ctx); - if (ret) { - IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* - * receive commit_rxon request - * abort any previous channel switch if still in process - */ - if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { - IWL_DEBUG_11H(priv, "abort channel switch on %d\n", - le16_to_cpu(priv->switch_rxon.channel)); - iwl_chswitch_done(priv, false); - } - - /* 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, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); - if (ret) { - IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); - return ret; - } - - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - iwl_print_rx_config_cmd(priv, ctx); - return 0; - } - - /* 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_ctx(ctx) && new_assoc) { - IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), - active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (ret) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); - return ret; - } - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - - IWL_DEBUG_INFO(priv, "Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %pM\n", - (new_assoc ? "" : "out"), - le16_to_cpu(ctx->staging.channel), - ctx->staging.bssid_addr); - - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); - - /* Apply the new configuration - * RXON unassoc clears the station table in uCode so restoration of - * stations is needed after it (the RXON command) completes - */ - if (!new_assoc) { - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n"); - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - if (new_assoc) { - priv->start_calib = 0; - /* Apply the new configuration - * RXON assoc doesn't clear the station table in uCode, - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - } - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(priv); - - /* 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 */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (ret) { - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } - - return 0; -} - -static int iwl4965_hw_channel_switch(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - int rc; - u8 band = 0; - bool is_ht40 = false; - u8 ctrl_chan_high = 0; - struct iwl4965_channel_switch_cmd cmd; - const struct iwl_channel_info *ch_info; - u32 switch_time_in_usec, ucode_switch_time; - u16 ch; - u32 tsf_low; - u8 switch_count; - u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); - struct ieee80211_vif *vif = ctx->vif; - band = priv->band == IEEE80211_BAND_2GHZ; - - is_ht40 = is_ht40_channel(ctx->staging.flags); - - if (is_ht40 && - (ctx->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) - ctrl_chan_high = 1; - - cmd.band = band; - cmd.expect_beacon = 0; - ch = ch_switch->channel->hw_value; - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp & 0x0ffffffff; - /* - * calculate the ucode channel switch time - * adding TSF as one of the factor for when to switch - */ - if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { - if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - } else - switch_count = 0; - } - if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); - else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count * TIME_UNIT; - ucode_switch_time = iwl_usecs_to_beacons(priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } - IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - ch_info = iwl_get_channel_info(priv, priv->band, ch); - if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); - else { - IWL_ERR(priv, "invalid channel switch from %u to %u\n", - ctx->active.channel, ch); - return -EFAULT; - } - - rc = iwl4965_fill_txpower_tbl(priv, band, ch, is_ht40, - ctrl_chan_high, &cmd.tx_power); - if (rc) { - IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); - return rc; - } - - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; - - return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); -} - -/** - * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array - */ -static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt) -{ - struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; - int txq_id = txq->q.id; - int write_ptr = txq->q.write_ptr; - int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; - __le16 bc_ent; - - WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - - bc_ent = cpu_to_le16(len & 0xFFF); - /* Set up byte count within first 256 entries */ - scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; - - /* If within first 64 entries, duplicate at end */ - if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) - scd_bc_tbl[txq_id]. - tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; -} - -/** - * iwl4965_hw_get_temperature - return the calibrated temperature (in Kelvin) - * @statistics: Provides the temperature reading from the uCode - * - * A return of <0 indicates bogus data in the statistics - */ -static int iwl4965_hw_get_temperature(struct iwl_priv *priv) -{ - s32 temperature; - s32 vt; - s32 R1, R2, R3; - u32 R4; - - if (test_bit(STATUS_TEMPERATURE, &priv->status) && - (priv->_agn.statistics.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { - IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); - R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]); - } else { - IWL_DEBUG_TEMP(priv, "Running temperature calibration\n"); - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); - R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]); - } - - /* - * Temperature is only 23 bits, so sign extend out to 32. - * - * NOTE If we haven't received a statistics notification yet - * with an updated temperature, use R4 provided to us in the - * "initialize" ALIVE response. - */ - if (!test_bit(STATUS_TEMPERATURE, &priv->status)) - vt = sign_extend32(R4, 23); - else - vt = sign_extend32(le32_to_cpu(priv->_agn.statistics. - general.common.temperature), 23); - - IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt); - - if (R3 == R1) { - IWL_ERR(priv, "Calibration conflict R1 == R3\n"); - return -1; - } - - /* Calculate temperature in degrees Kelvin, adjust by 97%. - * Add offset to center the adjustment around 0 degrees Centigrade. */ - temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2); - temperature /= (R3 - R1); - temperature = (temperature * 97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET; - - IWL_DEBUG_TEMP(priv, "Calibrated temperature: %dK, %dC\n", - temperature, KELVIN_TO_CELSIUS(temperature)); - - return temperature; -} - -/* Adjust Txpower only if temperature variance is greater than threshold. */ -#define IWL_TEMPERATURE_THRESHOLD 3 - -/** - * iwl4965_is_temp_calib_needed - determines if new calibration is needed - * - * If the temperature changed has changed sufficiently, then a recalibration - * is needed. - * - * Assumes caller will replace priv->last_temperature once calibration - * executed. - */ -static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) -{ - int temp_diff; - - if (!test_bit(STATUS_STATISTICS, &priv->status)) { - IWL_DEBUG_TEMP(priv, "Temperature not updated -- no statistics.\n"); - return 0; - } - - temp_diff = priv->temperature - priv->last_temperature; - - /* get absolute value */ - if (temp_diff < 0) { - IWL_DEBUG_POWER(priv, "Getting cooler, delta %d\n", temp_diff); - temp_diff = -temp_diff; - } else if (temp_diff == 0) - IWL_DEBUG_POWER(priv, "Temperature unchanged\n"); - else - IWL_DEBUG_POWER(priv, "Getting warmer, delta %d\n", temp_diff); - - if (temp_diff < IWL_TEMPERATURE_THRESHOLD) { - IWL_DEBUG_POWER(priv, " => thermal txpower calib not needed\n"); - return 0; - } - - IWL_DEBUG_POWER(priv, " => thermal txpower calib needed\n"); - - return 1; -} - -static void iwl4965_temperature_calib(struct iwl_priv *priv) -{ - s32 temp; - - temp = iwl4965_hw_get_temperature(priv); - if (temp < 0) - return; - - if (priv->temperature != temp) { - if (priv->temperature) - IWL_DEBUG_TEMP(priv, "Temperature changed " - "from %dC to %dC\n", - KELVIN_TO_CELSIUS(priv->temperature), - KELVIN_TO_CELSIUS(temp)); - else - IWL_DEBUG_TEMP(priv, "Temperature " - "initialized to %dC\n", - KELVIN_TO_CELSIUS(temp)); - } - - priv->temperature = temp; - iwl_tt_handler(priv); - set_bit(STATUS_TEMPERATURE, &priv->status); - - if (!priv->disable_tx_power_cal && - unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - iwl4965_is_temp_calib_needed(priv)) - queue_work(priv->workqueue, &priv->txpower_work); -} - -/** - * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration - */ -static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, - u16 txq_id) -{ - /* Simply stop the queue, but don't change any configuration; - * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ - iwl_write_prph(priv, - IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); -} - -/** - * txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE - * priv->lock must be held by the caller - */ -static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) -{ - if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { - IWL_WARN(priv, - "queue number out of range: %d, must be %d to %d\n", - txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues - 1); - return -EINVAL; - } - - iwl4965_tx_queue_stop_scheduler(priv, txq_id); - - iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); - - priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - /* supposes that ssn_idx is valid (!= 0xFFF) */ - iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); - - iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl_txq_ctx_deactivate(priv, txq_id); - iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - - return 0; -} - -/** - * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue - */ -static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, - u16 txq_id) -{ - u32 tbl_dw_addr; - u32 tbl_dw; - u16 scd_q2ratid; - - scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; - - tbl_dw_addr = priv->scd_base_addr + - IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); - - tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); - - if (txq_id & 0x1) - tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); - else - tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); - - iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw); - - return 0; -} - - -/** - * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue - * - * NOTE: txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE, - * i.e. it must be one of the higher queues used for aggregation - */ -static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) -{ - unsigned long flags; - u16 ra_tid; - int ret; - - if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { - IWL_WARN(priv, - "queue number out of range: %d, must be %d to %d\n", - txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues - 1); - return -EINVAL; - } - - ra_tid = BUILD_RAxTID(sta_id, tid); - - /* Modify device's station table to Tx this TID */ - ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); - if (ret) - return ret; - - spin_lock_irqsave(&priv->lock, flags); - - /* Stop this Tx queue before configuring it */ - iwl4965_tx_queue_stop_scheduler(priv, txq_id); - - /* Map receiver-address / traffic-ID to this queue */ - iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); - - /* Set this queue as a chain-building queue */ - iwl_set_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); - - /* Place first TFD at index corresponding to start sequence number. - * Assumes that ssn_idx is valid (!= 0xFFF) */ - priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); - - /* Set up Tx window size and frame limit for this queue */ - iwl_write_targ_mem(priv, - priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id), - (SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); - - iwl_write_targ_mem(priv, priv->scd_base_addr + - IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - (SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) - & IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); - - iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); - - /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ - iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - - -static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len) -{ - switch (cmd_id) { - case REPLY_RXON: - return (u16) sizeof(struct iwl4965_rxon_cmd); - default: - return len; - } -} - -static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) -{ - struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data; - addsta->mode = cmd->mode; - memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); - memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); - addsta->station_flags = cmd->station_flags; - addsta->station_flags_msk = cmd->station_flags_msk; - addsta->tid_disable_tx = cmd->tid_disable_tx; - addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; - addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; - addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; - addsta->sleep_tx_count = cmd->sleep_tx_count; - addsta->reserved1 = cpu_to_le16(0); - addsta->reserved2 = cpu_to_le16(0); - - return (u16)sizeof(struct iwl4965_addsta_cmd); -} - -static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) -{ - return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN; -} - -/** - * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue - */ -static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl4965_tx_resp *tx_resp, - int txq_id, u16 start_idx) -{ - u16 status; - struct agg_tx_status *frame_status = tx_resp->u.agg_status; - struct ieee80211_tx_info *info = NULL; - struct ieee80211_hdr *hdr = NULL; - u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - int i, sh, idx; - u16 seq; - if (agg->wait_for_ba) - IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n"); - - agg->frame_count = tx_resp->frame_count; - agg->start_idx = start_idx; - agg->rate_n_flags = rate_n_flags; - agg->bitmap = 0; - - /* num frames attempted by Tx command */ - if (agg->frame_count == 1) { - /* Only one frame was attempted; no block-ack will arrive */ - status = le16_to_cpu(frame_status[0].status); - idx = start_idx; - - /* FIXME: code repetition */ - IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", - agg->frame_count, agg->start_idx, idx); - - info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb); - info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_tx_status_to_mac80211(status); - iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info); - /* FIXME: code repetition end */ - - IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n", - status & 0xff, tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags); - - agg->wait_for_ba = 0; - } else { - /* Two or more frames were attempted; expect block-ack */ - u64 bitmap = 0; - int start = agg->start_idx; - - /* Construct bit-map of pending frames within Tx window */ - for (i = 0; i < agg->frame_count; i++) { - u16 sc; - status = le16_to_cpu(frame_status[i].status); - seq = le16_to_cpu(frame_status[i].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - if (status & (AGG_TX_STATE_FEW_BYTES_MSK | - AGG_TX_STATE_ABORT_MSK)) - continue; - - IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n", - agg->frame_count, txq_id, idx); - - hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); - if (!hdr) { - IWL_ERR(priv, - "BUG_ON idx doesn't point to valid skb" - " idx=%d, txq_id=%d\n", idx, txq_id); - return -1; - } - - sc = le16_to_cpu(hdr->seq_ctrl); - if (idx != (SEQ_TO_SN(sc) & 0xff)) { - IWL_ERR(priv, - "BUG_ON idx doesn't match seq control" - " idx=%d, seq_idx=%d, seq=%d\n", - idx, SEQ_TO_SN(sc), hdr->seq_ctrl); - return -1; - } - - IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n", - i, idx, SEQ_TO_SN(sc)); - - sh = idx - start; - if (sh > 64) { - sh = (start - idx) + 0xff; - bitmap = bitmap << sh; - sh = 0; - start = idx; - } else if (sh < -64) - sh = 0xff - (start - idx); - else if (sh < 0) { - sh = start - idx; - start = idx; - bitmap = bitmap << sh; - sh = 0; - } - bitmap |= 1ULL << sh; - IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n", - start, (unsigned long long)bitmap); - } - - agg->bitmap = bitmap; - agg->start_idx = start; - IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n", - agg->frame_count, agg->start_idx, - (unsigned long long)agg->bitmap); - - if (bitmap) - agg->wait_for_ba = 1; - } - return 0; -} - -static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i; - int start = 0; - int ret = IWL_INVALID_STATION; - unsigned long flags; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || - (priv->iw_mode == NL80211_IFTYPE_AP)) - start = IWL_STA_ID; - - if (is_broadcast_ether_addr(addr)) - return priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = start; i < priv->hw_params.max_stations; i++) - if (priv->stations[i].used && - (!compare_ether_addr(priv->stations[i].sta.sta.addr, - addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n", - addr, priv->num_stations); - - out: - /* - * It may be possible that more commands interacting with stations - * arrive before we completed processing the adding of - * station - */ - if (ret != IWL_INVALID_STATION && - (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) || - ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) && - (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) { - IWL_ERR(priv, "Requested station info for sta %d before ready.\n", - ret); - ret = IWL_INVALID_STATION; - } - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; -} - -static int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) -{ - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - return IWL_AP_ID; - } else { - u8 *da = ieee80211_get_DA(hdr); - return iwl_find_station(priv, da); - } -} - -/** - * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response - */ -static void iwl4965_rx_reply_tx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *info; - struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->u.status); - int uninitialized_var(tid); - int sta_id; - int freed; - u8 *qc = NULL; - unsigned long flags; - - if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { - IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - txq->time_stamp = jiffies; - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); - memset(&info->status, 0, sizeof(info->status)); - - hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - sta_id = iwl_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERR(priv, "Station not known\n"); - return; - } - - spin_lock_irqsave(&priv->sta_lock, flags); - if (txq->sched_retry) { - const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); - struct iwl_ht_agg *agg = NULL; - WARN_ON(!qc); - - agg = &priv->stations[sta_id].tid[tid].agg; - - iwl4965_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); - - /* check if BAR is needed */ - if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) - info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - - if (txq->q.read_ptr != (scd_ssn & 0xff)) { - index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn " - "%d index %d\n", scd_ssn , index); - freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - if (qc) - iwl_free_tfds_in_queue(priv, sta_id, - tid, freed); - - if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark) && - (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq); - } - } else { - info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= iwl_tx_status_to_mac80211(status); - iwlagn_hwrate_to_tx_control(priv, - le32_to_cpu(tx_resp->rate_n_flags), - info); - - IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) " - "rate_n_flags 0x%x retries %d\n", - txq_id, - iwl_get_tx_fail_reason(status), status, - le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); - - freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - if (qc && likely(sta_id != IWL_INVALID_STATION)) - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); - else if (sta_id == IWL_INVALID_STATION) - IWL_DEBUG_TX_REPLY(priv, "Station not known\n"); - - if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark)) - iwl_wake_queue(priv, txq); - } - if (qc && likely(sta_id != IWL_INVALID_STATION)) - iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); - - iwl_check_abort_status(priv, tx_resp->frame_count, status); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -static int iwl4965_calc_rssi(struct iwl_priv *priv, - struct iwl_rx_phy_res *rx_resp) -{ - /* data from PHY/DSP regarding signal strength, etc., - * contents are always there, not configurable by host. */ - struct iwl4965_rx_non_cfg_phy *ncphy = - (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy_buf; - u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL49_AGC_DB_MASK) - >> IWL49_AGC_DB_POS; - - u32 valid_antennae = - (le16_to_cpu(rx_resp->phy_flags) & IWL49_RX_PHY_FLAGS_ANTENNAE_MASK) - >> IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET; - u8 max_rssi = 0; - u32 i; - - /* Find max rssi among 3 possible receivers. - * These values are measured by the digital signal processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's automatic gain control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. */ - for (i = 0; i < 3; i++) - if (valid_antennae & (1 << i)) - max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); - - IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", - ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], - max_rssi, agc); - - /* dBm = max_rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. */ - return max_rssi - agc - IWLAGN_RSSI_OFFSET; -} - - -/* Set up 4965-specific Rx frame reply handlers */ -static void iwl4965_rx_handler_setup(struct iwl_priv *priv) -{ - /* Legacy Rx frames */ - priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx; - /* Tx response */ - priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; -} - -static void iwl4965_setup_deferred_work(struct iwl_priv *priv) -{ - INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); -} - -static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) -{ - cancel_work_sync(&priv->txpower_work); -} - -static struct iwl_hcmd_ops iwl4965_hcmd = { - .rxon_assoc = iwl4965_send_rxon_assoc, - .commit_rxon = iwl4965_commit_rxon, - .set_rxon_chain = iwlagn_set_rxon_chain, - .send_bt_config = iwl_send_bt_config, -}; - -static void iwl4965_post_scan(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - /* - * Since setting the RXON may have been deferred while - * performing the scan, fire one off if needed - */ - if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) - iwlcore_commit_rxon(priv, ctx); -} - -static void iwl4965_post_associate(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct ieee80211_vif *vif = ctx->vif; - struct ieee80211_conf *conf = NULL; - int ret = 0; - - if (!vif || !priv->is_open) - return; - - if (vif->type == NL80211_IFTYPE_AP) { - IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__); - return; - } - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl_scan_cancel_timeout(priv, 200); - - conf = ieee80211_get_hw_conf(priv->hw); - - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) - IWL_WARN(priv, "RXON timing - " - "Attempting to continue.\n"); - - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - - iwl_set_rxon_ht(priv, &priv->current_ht_config); - - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - - ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); - - IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", - vif->bss_conf.aid, vif->bss_conf.beacon_int); - - if (vif->bss_conf.use_short_preamble) - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) - ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - } - - iwlcore_commit_rxon(priv, ctx); - - IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", - vif->bss_conf.aid, ctx->active.bssid_addr); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - iwlagn_send_beacon_cmd(priv); - break; - default: - IWL_ERR(priv, "%s Should not be called in %d mode\n", - __func__, vif->type); - break; - } - - /* the chain noise calibration will enabled PM upon completion - * If chain noise has already been run, then we need to enable - * power management here */ - if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_update_mode(priv, false); - - /* Enable Rx differential gain and sensitivity calibrations */ - iwl_chain_noise_reset(priv); - priv->start_calib = 1; -} - -static void iwl4965_config_ap(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct ieee80211_vif *vif = ctx->vif; - int ret = 0; - - lockdep_assert_held(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* The following should be done only at AP bring up */ - if (!iwl_is_associated_ctx(ctx)) { - - /* RXON - unassoc (to set timing command) */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - /* RXON Timing */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) - IWL_WARN(priv, "RXON timing failed - " - "Attempting to continue.\n"); - - /* AP has all antennas */ - priv->chain_noise_data.active_chains = - priv->hw_params.valid_rx_ant; - iwl_set_rxon_ht(priv, &priv->current_ht_config); - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - - ctx->staging.assoc_id = 0; - - if (vif->bss_conf.use_short_preamble) - ctx->staging.flags |= - RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) - ctx->staging.flags |= - RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_SLOT_MSK; - } - /* need to send beacon cmd before committing assoc RXON! */ - iwlagn_send_beacon_cmd(priv); - /* restore RXON assoc */ - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - } - iwlagn_send_beacon_cmd(priv); - - /* FIXME - we need to add code here to detect a totally new - * configuration, reset the AP, unassoc, rxon timing, assoc, - * clear sta table, add BCAST sta... */ -} - -static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { - .get_hcmd_size = iwl4965_get_hcmd_size, - .build_addsta_hcmd = iwl4965_build_addsta_hcmd, - .chain_noise_reset = iwl4965_chain_noise_reset, - .gain_computation = iwl4965_gain_computation, - .tx_cmd_protection = iwl_legacy_tx_cmd_protection, - .calc_rssi = iwl4965_calc_rssi, - .request_scan = iwlagn_request_scan, - .post_scan = iwl4965_post_scan, -}; - -static struct iwl_lib_ops iwl4965_lib = { - .set_hw_params = iwl4965_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, - .txq_set_sched = iwl4965_txq_set_sched, - .txq_agg_enable = iwl4965_txq_agg_enable, - .txq_agg_disable = iwl4965_txq_agg_disable, - .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, - .txq_free_tfd = iwl_hw_txq_free_tfd, - .txq_init = iwl_hw_tx_queue_init, - .rx_handler_setup = iwl4965_rx_handler_setup, - .setup_deferred_work = iwl4965_setup_deferred_work, - .cancel_deferred_work = iwl4965_cancel_deferred_work, - .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, - .alive_notify = iwl4965_alive_notify, - .init_alive_start = iwl4965_init_alive_start, - .load_ucode = iwl4965_load_bsm, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_fh = iwl_dump_fh, - .set_channel_switch = iwl4965_hw_channel_switch, - .apm_ops = { - .init = iwl_apm_init, - .config = iwl4965_nic_config, - }, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REGULATORY_BAND_1_CHANNELS, - EEPROM_REGULATORY_BAND_2_CHANNELS, - EEPROM_REGULATORY_BAND_3_CHANNELS, - EEPROM_REGULATORY_BAND_4_CHANNELS, - EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, - EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS - }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwl4965_eeprom_calib_version, - .query_addr = iwlcore_eeprom_query_addr, - }, - .send_tx_power = iwl4965_send_tx_power, - .update_chain_flags = iwl_update_chain_flags, - .isr_ops = { - .isr = iwl_isr_legacy, - }, - .temp_ops = { - .temperature = iwl4965_temperature_calib, - }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, -}; - -static const struct iwl_legacy_ops iwl4965_legacy_ops = { - .post_associate = iwl4965_post_associate, - .config_ap = iwl4965_config_ap, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, -}; - -struct ieee80211_ops iwl4965_hw_ops = { - .tx = iwlagn_mac_tx, - .start = iwlagn_mac_start, - .stop = iwlagn_mac_stop, - .add_interface = iwl_mac_add_interface, - .remove_interface = iwl_mac_remove_interface, - .change_interface = iwl_mac_change_interface, - .config = iwl_legacy_mac_config, - .configure_filter = iwlagn_configure_filter, - .set_key = iwlagn_mac_set_key, - .update_tkip_key = iwlagn_mac_update_tkip_key, - .conf_tx = iwl_mac_conf_tx, - .reset_tsf = iwl_legacy_mac_reset_tsf, - .bss_info_changed = iwl_legacy_mac_bss_info_changed, - .ampdu_action = iwlagn_mac_ampdu_action, - .hw_scan = iwl_mac_hw_scan, - .sta_add = iwlagn_mac_sta_add, - .sta_remove = iwl_mac_sta_remove, - .channel_switch = iwlagn_mac_channel_switch, - .flush = iwlagn_mac_flush, - .tx_last_beacon = iwl_mac_tx_last_beacon, -}; - -static const struct iwl_ops iwl4965_ops = { - .lib = &iwl4965_lib, - .hcmd = &iwl4965_hcmd, - .utils = &iwl4965_hcmd_utils, - .led = &iwlagn_led_ops, - .legacy = &iwl4965_legacy_ops, - .ieee80211_ops = &iwl4965_hw_ops, -}; - -static struct iwl_base_params iwl4965_base_params = { - .eeprom_size = IWL4965_EEPROM_IMG_SIZE, - .num_of_queues = IWL49_NUM_QUEUES, - .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = true, - .use_isr_legacy = true, - .broken_powersave = true, - .led_compensation = 61, - .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .wd_timeout = IWL_DEF_WD_TIMEOUT, - .temperature_kelvin = true, - .max_event_log_size = 512, - .tx_power_by_driver = true, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, - .no_agg_framecnt_info = true, -}; - -struct iwl_cfg iwl4965_agn_cfg = { - .name = "Intel(R) Wireless WiFi Link 4965AGN", - .fw_name_pre = IWL4965_FW_PRE, - .ucode_api_max = IWL4965_UCODE_API_MAX, - .ucode_api_min = IWL4965_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_ABC, - .eeprom_ver = EEPROM_4965_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, - .ops = &iwl4965_ops, - .mod_params = &iwlagn_mod_params, - .base_params = &iwl4965_base_params, - .led_mode = IWL_LED_BLINK, - /* - * Force use of chains B and C for scan RX on 5 GHz band - * because the device has off-channel reception on chain A. - */ - .scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC, -}; - -/* Module firmware */ -MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); - diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 3975e45e7500..05ad47628b63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 79ab0a6b1386..98f81df166e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -45,13 +45,11 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-agn.h" -#include "iwl-agn-led.h" #include "iwl-agn-hw.h" #include "iwl-5000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ -#define IWL5000_UCODE_API_MAX 2 +#define IWL5000_UCODE_API_MAX 5 #define IWL5150_UCODE_API_MAX 2 /* Lowest firmware API version supported */ @@ -59,12 +57,10 @@ #define IWL5150_UCODE_API_MIN 1 #define IWL5000_FW_PRE "iwlwifi-5000-" -#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" -#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" -#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" -#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" /* NIC configuration for 5000 series */ static void iwl5000_nic_config(struct iwl_priv *priv) @@ -168,10 +164,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -185,7 +181,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -214,10 +209,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -231,7 +226,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -263,7 +257,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) u32 vt = 0; s32 offset = iwl_temp_calib_to_offset(priv); - vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature); + vt = le32_to_cpu(priv->statistics.common.temperature); vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); @@ -345,24 +339,13 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -380,58 +363,24 @@ static struct iwl_lib_ops iwl5000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, - .check_ack_health = iwl_good_ack_health, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_lib_ops iwl5150_lib = { .set_hw_params = iwl5150_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -449,53 +398,25 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwl5150_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, - .check_ack_health = iwl_good_ack_health, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl5000_base_params = { @@ -503,17 +424,12 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, @@ -527,13 +443,15 @@ static struct iwl_ht_params iwl5000_ht_params = { .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .ops = &iwl5000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .led_mode = IWL_LED_BLINK struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", IWL_DEVICE_5000, + /* at least EEPROM 0x11A has wrong info */ + .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ + .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ .ht_params = &iwl5000_ht_params, }; @@ -568,7 +486,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .ops = &iwl5000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, @@ -582,7 +499,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .ops = &iwl5150_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 47891e16a758..b27986e57c92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ef36aff1bb43..a7921f9a03c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -46,8 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-led.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -60,20 +58,16 @@ #define IWL6000G2_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" -#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" -#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api) +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" #define IWL6050_FW_PRE "iwlwifi-6050-" -#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" -#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" -#define IWL6000G2A_FW_PRE "iwlwifi-6000g2a-" -#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode" -#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api) +#define IWL6005_FW_PRE "iwlwifi-6000g2a-" +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" -#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-" -#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode" -#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api) +#define IWL6030_FW_PRE "iwlwifi-6000g2b-" +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { @@ -85,15 +79,15 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } -static void iwl6050g2_additional_nic_config(struct iwl_priv *priv) +static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); iwl_set_bit(priv, CSR_GP_DRIVER_REG, @@ -159,10 +153,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -176,7 +170,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -285,24 +278,13 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -320,47 +302,19 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, - .check_ack_health = iwl_good_ack_health, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; -static struct iwl_lib_ops iwl6000g2b_lib = { +static struct iwl_lib_ops iwl6030_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -368,13 +322,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -392,80 +339,48 @@ static struct iwl_lib_ops iwl6000g2b_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, - .check_plcp_health = iwl_good_plcp_health, - .check_ack_health = iwl_good_ack_health, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_nic_ops iwl6050_nic_ops = { .additional_nic_config = &iwl6050_additional_nic_config, }; -static struct iwl_nic_ops iwl6050g2_nic_ops = { - .additional_nic_config = &iwl6050g2_additional_nic_config, +static struct iwl_nic_ops iwl6150_nic_ops = { + .additional_nic_config = &iwl6150_additional_nic_config, }; static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6050_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .nic = &iwl6050_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; -static const struct iwl_ops iwl6050g2_ops = { +static const struct iwl_ops iwl6150_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .nic = &iwl6050g2_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, + .nic = &iwl6150_nic_ops, }; -static const struct iwl_ops iwl6000g2b_ops = { - .lib = &iwl6000g2b_lib, +static const struct iwl_ops iwl6030_ops = { + .lib = &iwl6030_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl6000_base_params = { @@ -473,22 +388,16 @@ static struct iwl_base_params iwl6000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -497,22 +406,16 @@ static struct iwl_base_params iwl6050_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; static struct iwl_base_params iwl6000_g2_base_params = { @@ -520,22 +423,16 @@ static struct iwl_base_params iwl6000_g2_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -545,7 +442,6 @@ static struct iwl_ht_params iwl6000_ht_params = { }; static struct iwl_bt_params iwl6000_bt_params = { - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, @@ -555,13 +451,12 @@ static struct iwl_bt_params iwl6000_bt_params = { }; #define IWL_DEVICE_6005 \ - .fw_name_pre = IWL6000G2A_FW_PRE, \ + .fw_name_pre = IWL6005_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \ + .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -584,13 +479,12 @@ struct iwl_cfg iwl6005_2bg_cfg = { }; #define IWL_DEVICE_6030 \ - .fw_name_pre = IWL6000G2B_FW_PRE, \ + .fw_name_pre = IWL6030_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \ - .ops = &iwl6000g2b_ops, \ - .mod_params = &iwlagn_mod_params, \ + .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .ops = &iwl6030_ops, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ .need_dc_calib = true, \ @@ -620,6 +514,22 @@ struct iwl_cfg iwl6030_2bg_cfg = { IWL_DEVICE_6030, }; +struct iwl_cfg iwl6035_2agn_cfg = { + .name = "6035 Series 2x2 AGN/BT", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +struct iwl_cfg iwl6035_2abg_cfg = { + .name = "6035 Series 2x2 ABG/BT", + IWL_DEVICE_6030, +}; + +struct iwl_cfg iwl6035_2bg_cfg = { + .name = "6035 Series 2x2 BG/BT", + IWL_DEVICE_6030, +}; + struct iwl_cfg iwl1030_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", IWL_DEVICE_6030, @@ -656,7 +566,6 @@ struct iwl_cfg iwl130_bg_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_base_params, \ .pa_type = IWL_PA_INTERNAL, \ .led_mode = IWL_LED_BLINK @@ -686,7 +595,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ops = &iwl6050_ops, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6050_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ @@ -708,10 +616,9 @@ struct iwl_cfg iwl6150_bgn_cfg = { .fw_name_pre = IWL6050_FW_PRE, .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, - .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION, - .ops = &iwl6050g2_ops, - .mod_params = &iwlagn_mod_params, + .eeprom_ver = EEPROM_6150_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, + .ops = &iwl6150_ops, .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -727,7 +634,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .ops = &iwl6000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -736,5 +642,5 @@ struct iwl_cfg iwl6000_3agn_cfg = { MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index d16bb5ede014..0f6bb9b2e642 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret); } -void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) +void iwl_sensitivity_calibration(struct iwl_priv *priv) { u32 rx_enable_time; u32 fa_cck; @@ -631,17 +631,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> - rx.general.common); - ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck); - } else { - rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general); - ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_notif_statistics *)resp)->rx.cck); - } + rx_info = &priv->statistics.rx_non_phy; + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -852,7 +844,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. */ -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) +void iwl_chain_noise_calibration(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = NULL; @@ -897,14 +889,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> - rx.general.common); - } else { - rx_info = &(((struct iwl_notif_statistics *)stat_resp)-> - rx.general); - } + + rx_info = &priv->statistics.rx_non_phy; + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -913,20 +900,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_chnum = le16_to_cpu(ctx->staging.channel); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - stat_band24 = !!(((struct iwl_bt_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *) - stat_resp)->flag) >> 16; - } else { - stat_band24 = !!(((struct iwl_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *) - stat_resp)->flag) >> 16; - } + stat_band24 = + !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); + stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16; /* Make sure we accumulate data for just the associated channel * (even if scanning). */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index e37ae7261630..4ef4dd934254 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,8 +66,8 @@ #include "iwl-core.h" #include "iwl-commands.h" -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); -void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); +void iwl_chain_noise_calibration(struct iwl_priv *priv); +void iwl_sensitivity_calibration(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c deleted file mode 100644 index a6dbd8983dac..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ /dev/null @@ -1,1077 +0,0 @@ -/****************************************************************************** -* -* GPL LICENSE SUMMARY -* -* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of version 2 of the GNU General Public License as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, -* USA -* -* The full GNU General Public License is included in this distribution -* in the file called LICENSE.GPL. -* -* Contact Information: -* Intel Linux Wireless <ilw@linux.intel.com> -* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*****************************************************************************/ -#include "iwl-agn.h" -#include "iwl-agn-debugfs.h" - -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; - -static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) -{ - int p = 0; - u32 flag; - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) - flag = le32_to_cpu(priv->_agn.statistics_bt.flag); - else - flag = le32_to_cpu(priv->_agn.statistics.flag); - - p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); - if (flag & UCODE_STATISTICS_CLEAR_MSK) - p += scnprintf(buf + p, bufsz - p, - "\tStatistics have been cleared\n"); - p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", - (flag & UCODE_STATISTICS_FREQUENCY_MSK) - ? "2.4 GHz" : "5.2 GHz"); - p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", - (flag & UCODE_STATISTICS_NARROW_BAND_MSK) - ? "enabled" : "disabled"); - - return p; -} - -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) - { - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 40 + - sizeof(struct statistics_rx_non_phy) * 40 + - sizeof(struct statistics_rx_ht_phy) * 40 + 400; - ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; - struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_non_phy *delta_general, *max_general; - struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - ofdm = &priv->_agn.statistics_bt.rx.ofdm; - cck = &priv->_agn.statistics_bt.rx.cck; - general = &priv->_agn.statistics_bt.rx.general.common; - ht = &priv->_agn.statistics_bt.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics_bt.rx.cck; - accum_general = - &priv->_agn.accum_statistics_bt.rx.general.common; - accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics_bt.rx.cck; - delta_general = - &priv->_agn.delta_statistics_bt.rx.general.common; - delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm; - max_cck = &priv->_agn.max_delta_bt.rx.cck; - max_general = &priv->_agn.max_delta_bt.rx.general.common; - max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht; - } else { - ofdm = &priv->_agn.statistics.rx.ofdm; - cck = &priv->_agn.statistics.rx.cck; - general = &priv->_agn.statistics.rx.general; - ht = &priv->_agn.statistics.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics.rx.cck; - accum_general = &priv->_agn.accum_statistics.rx.general; - accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics.rx.cck; - delta_general = &priv->_agn.delta_statistics.rx.general; - delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta.rx.ofdm; - max_cck = &priv->_agn.max_delta.rx.cck; - max_general = &priv->_agn.max_delta.rx.general; - max_ht = &priv->_agn.max_delta.rx.ofdm_ht; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, delta_ofdm->overrun_err, - max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, delta_ofdm->crc32_good, - max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, - max_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt, - delta_ofdm->sent_ba_rsp_cnt, - max_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill, - delta_ofdm->dsp_self_kill, - max_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err, - delta_ofdm->mh_format_err, - max_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum, - delta_ofdm->re_acq_main_rssi_sum, - max_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, delta_cck->overrun_err, - max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, delta_cck->sfd_timeout, - max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, delta_cck->fina_timeout, - max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt, - delta_cck->sent_ba_rsp_cnt, - max_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, - max_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err, delta_cck->mh_format_err, - max_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum, - delta_cck->re_acq_main_rssi_sum, - max_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_cts:", - le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, delta_general->bogus_cts, - max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_ack:", - le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, delta_general->bogus_ack, - max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_bssid_frames:", - le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "filtered_frames:", - le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_channel_beacons:", - le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_beacons:", - le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons, - delta_general->channel_beacons, - max_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_missed_bcon:", - le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon, - delta_general->num_missed_bcon, - max_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "adc_rx_saturation_time:", - le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time, - delta_general->adc_rx_saturation_time, - max_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_detect_search_tm:", - le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time, - delta_general->ina_detection_search_time, - max_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_a:", - le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a, - delta_general->beacon_silence_rssi_a, - max_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_b:", - le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b, - delta_general->beacon_silence_rssi_b, - max_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_c:", - le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c, - delta_general->beacon_silence_rssi_c, - max_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "interference_data_flag:", - le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag, - delta_general->interference_data_flag, - max_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_load:", - le32_to_cpu(general->channel_load), - accum_general->channel_load, - delta_general->channel_load, - max_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_false_alarms:", - le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms, - delta_general->dsp_false_alarms, - max_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_a:", - le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a, - delta_general->beacon_rssi_a, - max_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_b:", - le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b, - delta_general->beacon_rssi_b, - max_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_c:", - le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c, - delta_general->beacon_rssi_c, - max_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_a:", - le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a, - delta_general->beacon_energy_a, - max_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_b:", - le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b, - delta_general->beacon_energy_b, - max_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_c:", - le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c, - delta_general->beacon_energy_c, - max_general->beacon_energy_c); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM_HT:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, - delta_ht->plcp_err, max_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, - delta_ht->overrun_err, max_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err, - delta_ht->early_overrun_err, - max_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, - delta_ht->crc32_good, max_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, - delta_ht->crc32_err, max_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err, - delta_ht->mh_format_err, max_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_crc32_good:", - le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good, - delta_ht->agg_crc32_good, max_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_mpdu_cnt:", - le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt, - delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_cnt:", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, - delta_ht->agg_cnt, max_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unsupport_mcs:", - le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs, - delta_ht->unsupport_mcs, max_ht->unsupport_mcs); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_tx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_tx) * 48) + 250; - ssize_t ret; - struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta_tx = &priv->_agn.delta_statistics_bt.tx; - max_tx = &priv->_agn.max_delta_bt.tx; - } else { - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta_tx = &priv->_agn.delta_statistics.tx; - max_tx = &priv->_agn.max_delta.tx; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "preamble:", - le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_detected_cnt:", - le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_defer_cnt:", - le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_kill_cnt:", - le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "few_bytes_cnt:", - le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_timeout:", - le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "expected_ack_cnt:", - le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "actual_ack_cnt:", - le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dump_msdu_cnt:", - le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt, - delta_tx->dump_msdu_cnt, - max_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_nxt_frame_mismatch:", - le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt, - delta_tx->burst_abort_next_frame_mismatch_cnt, - max_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_missing_nxt_frame:", - le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt, - delta_tx->burst_abort_missing_next_frame_cnt, - max_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout_collision:", - le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision, - delta_tx->cts_timeout_collision, - max_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_ba_timeout_collision:", - le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision, - delta_tx->ack_or_ba_timeout_collision, - max_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_timeout:", - le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout, - delta_tx->agg.ba_timeout, - max_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_resched_frames:", - le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames, - delta_tx->agg.ba_reschedule_frames, - max_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg_frame:", - le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt, - delta_tx->agg.scd_query_agg_frame_cnt, - max_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_no_agg:", - le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg, - delta_tx->agg.scd_query_no_agg, - max_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg:", - le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg, - delta_tx->agg.scd_query_agg, - max_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_mismatch:", - le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch, - delta_tx->agg.scd_query_mismatch, - max_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg frame_not_ready:", - le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready, - delta_tx->agg.frame_not_ready, - max_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg underrun:", - le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun, - delta_tx->agg.underrun, max_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg bt_prio_kill:", - le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill, - delta_tx->agg.bt_prio_kill, - max_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg rx_ba_rsp_cnt:", - le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt, - delta_tx->agg.rx_ba_rsp_cnt, - max_tx->agg.rx_ba_rsp_cnt); - - if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { - pos += scnprintf(buf + pos, bufsz - pos, - "tx power: (1/2 dB step)\n"); - if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna A:", - tx->tx_power.ant_a); - if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna B:", - tx->tx_power.ant_b); - if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna C:", - tx->tx_power.ant_c); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_general) * 10 + 300; - ssize_t ret; - struct statistics_general_common *general, *accum_general; - struct statistics_general_common *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct statistics_div *div, *accum_div, *delta_div, *max_div; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - general = &priv->_agn.statistics_bt.general.common; - dbg = &priv->_agn.statistics_bt.general.common.dbg; - div = &priv->_agn.statistics_bt.general.common.div; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg; - accum_div = &priv->_agn.accum_statistics_bt.general.common.div; - delta_general = &priv->_agn.delta_statistics_bt.general.common; - max_general = &priv->_agn.max_delta_bt.general.common; - delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg; - max_dbg = &priv->_agn.max_delta_bt.general.common.dbg; - delta_div = &priv->_agn.delta_statistics_bt.general.common.div; - max_div = &priv->_agn.max_delta_bt.general.common.div; - } else { - general = &priv->_agn.statistics.general.common; - dbg = &priv->_agn.statistics.general.common.dbg; - div = &priv->_agn.statistics.general.common.div; - accum_general = &priv->_agn.accum_statistics.general.common; - accum_dbg = &priv->_agn.accum_statistics.general.common.dbg; - accum_div = &priv->_agn.accum_statistics.general.common.div; - delta_general = &priv->_agn.delta_statistics.general.common; - max_general = &priv->_agn.max_delta.general.common; - delta_dbg = &priv->_agn.delta_statistics.general.common.dbg; - max_dbg = &priv->_agn.max_delta.general.common.dbg; - delta_div = &priv->_agn.delta_statistics.general.common.div; - max_div = &priv->_agn.max_delta.general.common.div; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature:", - le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature_m:", - le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "ttl_timestamp:", - le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_check:", - le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_count:", - le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "wait_for_silence_timeout_count:", - le32_to_cpu(dbg->wait_for_silence_timeout_cnt), - accum_dbg->wait_for_silence_timeout_cnt, - delta_dbg->wait_for_silence_timeout_cnt, - max_dbg->wait_for_silence_timeout_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sleep_time:", - le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_out:", - le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_idle:", - le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_enable_counter:", - le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter, - delta_general->rx_enable_counter, - max_general->rx_enable_counter); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_of_sos_states:", - le32_to_cpu(general->num_of_sos_states), - accum_general->num_of_sos_states, - delta_general->num_of_sos_states, - max_general->num_of_sos_states); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; - ssize_t ret; - struct statistics_bt_activity *bt, *accum_bt; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - if (!priv->bt_enable_flag) - return -EINVAL; - - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - bt = &priv->_agn.statistics_bt.general.activity; - accum_bt = &priv->_agn.accum_statistics_bt.general.activity; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_req_cnt), - accum_bt->hi_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_denied_cnt), - accum_bt->hi_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_req_cnt), - accum_bt->lo_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_denied_cnt), - accum_bt->lo_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_req_cnt), - accum_bt->hi_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_denied_cnt), - accum_bt->hi_priority_rx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_req_cnt), - accum_bt->lo_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_denied_cnt), - accum_bt->lo_priority_rx_denied_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, - "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", - le32_to_cpu(priv->_agn.statistics_bt.rx. - general.num_bt_kills), - priv->_agn.accum_statistics_bt.rx. - general.num_bt_kills); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + - (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; - ssize_t ret; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), - priv->_agn.reply_tx_stats.pp_few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), - priv->_agn.reply_tx_stats.pp_bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), - priv->_agn.reply_tx_stats.pp_quiet_period); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), - priv->_agn.reply_tx_stats.pp_calc_ttak); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), - priv->_agn.reply_tx_stats.int_crossed_retry); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), - priv->_agn.reply_tx_stats.short_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), - priv->_agn.reply_tx_stats.long_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), - priv->_agn.reply_tx_stats.fifo_underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), - priv->_agn.reply_tx_stats.drain_flow); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), - priv->_agn.reply_tx_stats.rfkill_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), - priv->_agn.reply_tx_stats.life_expire); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), - priv->_agn.reply_tx_stats.dest_ps); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), - priv->_agn.reply_tx_stats.host_abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), - priv->_agn.reply_tx_stats.sta_invalid); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), - priv->_agn.reply_tx_stats.frag_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), - priv->_agn.reply_tx_stats.tid_disable); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), - priv->_agn.reply_tx_stats.fifo_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), - priv->_agn.reply_tx_stats.insuff_cf_poll); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), - priv->_agn.reply_tx_stats.fail_hw_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_NO_BEACON_ON_RADAR), - priv->_agn.reply_tx_stats.sta_color_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_tx_stats.unknown); - - pos += scnprintf(buf + pos, bufsz - pos, - "\nStatistics_Agg_TX_Error:\n"); - - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), - priv->_agn.reply_agg_tx_stats.underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), - priv->_agn.reply_agg_tx_stats.bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), - priv->_agn.reply_agg_tx_stats.few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), - priv->_agn.reply_agg_tx_stats.abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TTL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_ttl); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_try); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), - priv->_agn.reply_agg_tx_stats.scd_query); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_TEST_BAD_CRC32_MSK), - priv->_agn.reply_agg_tx_stats.bad_crc32); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), - priv->_agn.reply_agg_tx_stats.response); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), - priv->_agn.reply_agg_tx_stats.dump_tx); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), - priv->_agn.reply_agg_tx_stats.delay_tx); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_agg_tx_stats.unknown); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h deleted file mode 100644 index f2573b5486cd..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" - -#ifdef CONFIG_IWLWIFI_DEBUGFS -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -#else -static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 27b5a3eec9dc..2ef9448b1c20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -81,52 +81,13 @@ * ******************************************************************************/ -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - u16 count; - int ret; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_IO(priv, - "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} - -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) -{ - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - -} - int iwl_eeprom_check_version(struct iwl_priv *priv) { u16 eeprom_ver; u16 calib_ver; eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + calib_ver = iwlagn_eeprom_calib_version(priv); if (eeprom_ver < priv->cfg->eeprom_ver || calib_ver < priv->cfg->eeprom_calib_ver) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 366340f3fb0f..b12c72d63ccb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -37,54 +37,6 @@ #include "iwl-io.h" #include "iwl-agn.h" -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret = 0; - struct iwl5000_rxon_assoc_cmd rxon_assoc; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (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->ofdm_ht_triple_stream_basic_rates == - rxon2->ofdm_ht_triple_stream_basic_rates) && - (rxon1->acquisition_data == rxon2->acquisition_data) && - (rxon1->rx_chain == rxon2->rx_chain) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved1 = 0; - rxon_assoc.reserved2 = 0; - rxon_assoc.reserved3 = 0; - rxon_assoc.ofdm_ht_single_stream_basic_rates = - ctx->staging.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - ctx->staging.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; - rxon_assoc.ofdm_ht_triple_stream_basic_rates = - ctx->staging.ofdm_ht_triple_stream_basic_rates; - rxon_assoc.acquisition_data = ctx->staging.acquisition_data; - - ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, - sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - - return ret; -} - int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) { struct iwl_tx_ant_config_cmd tx_ant_cmd = { @@ -102,12 +54,6 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) } } -/* Currently this is the superset of everything */ -static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len) -{ - return len; -} - static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); @@ -305,7 +251,11 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) cmd.slots[0].type = 0; /* BSS */ cmd.slots[1].type = 1; /* PAN */ - if (ctx_bss->vif && ctx_pan->vif) { + if (priv->_agn.hw_roc_channel) { + /* both contexts must be used for this to happen */ + slot1 = priv->_agn.hw_roc_duration; + slot0 = IWL_MIN_SLOT_TIME; + } else if (ctx_bss->vif && ctx_pan->vif) { int bcnint = ctx_pan->vif->bss_conf.beacon_int; int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; @@ -330,12 +280,12 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) if (test_bit(STATUS_SCAN_HW, &priv->status) || (!ctx_bss->vif->bss_conf.idle && !ctx_bss->vif->bss_conf.assoc)) { - slot0 = dtim * bcnint * 3 - 20; - slot1 = 20; + slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; + slot1 = IWL_MIN_SLOT_TIME; } else if (!ctx_pan->vif->bss_conf.idle && !ctx_pan->vif->bss_conf.assoc) { - slot1 = bcnint * 3 - 20; - slot0 = 20; + slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME; + slot0 = IWL_MIN_SLOT_TIME; } } else if (ctx_pan->vif) { slot0 = 0; @@ -344,8 +294,8 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1); if (test_bit(STATUS_SCAN_HW, &priv->status)) { - slot0 = slot1 * 3 - 20; - slot1 = 20; + slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME; + slot1 = IWL_MIN_SLOT_TIME; } } @@ -360,7 +310,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) } struct iwl_hcmd_ops iwlagn_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -369,7 +318,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = { }; struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -378,7 +326,6 @@ struct iwl_hcmd_ops iwlagn_bt_hcmd = { }; struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { - .get_hcmd_size = iwlagn_get_hcmd_size, .build_addsta_hcmd = iwlagn_build_addsta_hcmd, .gain_computation = iwlagn_gain_computation, .chain_noise_reset = iwlagn_chain_noise_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index a52b82c8e7a6..7bd19f4e66de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index b5cb3be0eb4b..0d5fda44c3a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv) int iwl_alloc_isr_ict(struct iwl_priv *priv) { - if (priv->cfg->base_params->use_isr_legacy) - return 0; /* allocate shrared data table */ priv->_agn.ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, @@ -69,7 +67,7 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv) if (!priv->_agn.ict_tbl_vir) return -ENOMEM; - /* align table to PAGE_SIZE boundry */ + /* align table to PAGE_SIZE boundary */ priv->_agn.aligned_ict_tbl_dma = ALIGN(priv->_agn.ict_tbl_dma, PAGE_SIZE); IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c deleted file mode 100644 index 1a24946bc203..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ /dev/null @@ -1,85 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/mac80211.h> -#include <linux/etherdevice.h> -#include <asm/unaligned.h> - -#include "iwl-commands.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn-led.h" - -/* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - u32 reg; - - reg = iwl_read32(priv, CSR_LED_REG); - if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - - return iwl_send_cmd(priv, &cmd); -} - -/* Set led register off */ -static int iwl_led_on_reg(struct iwl_priv *priv) -{ - IWL_DEBUG_LED(priv, "led on\n"); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); - return 0; -} - -/* Set led register off */ -static int iwl_led_off_reg(struct iwl_priv *priv) -{ - IWL_DEBUG_LED(priv, "LED Reg off\n"); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); - return 0; -} - -const struct iwl_led_ops iwlagn_led_ops = { - .cmd = iwl_send_led_cmd, - .on = iwl_led_on_reg, - .off = iwl_led_off_reg, -}; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h deleted file mode 100644 index a594e4fdc6b8..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_agn_led_h__ -#define __iwl_agn_led_h__ - -extern const struct iwl_led_ops iwlagn_led_ops; - -#endif /* __iwl_agn_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3dee87e8f55d..8e79653aed9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) static void iwlagn_set_tx_status(struct iwl_priv *priv, struct ieee80211_tx_info *info, + struct iwl_rxon_context *ctx, struct iwlagn_tx_resp *tx_resp, int txq_id, bool is_agg) { @@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv, if (!iwl_is_tx_success(status)) iwlagn_count_tx_err_status(priv, status); + if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && + iwl_is_associated_ctx(ctx) && ctx->vif && + ctx->vif->type == NL80211_IFTYPE_STATION) { + ctx->last_tx_rejected = true; + iwl_stop_queue(priv, &priv->txq[txq_id]); + } + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " "0x%x retries %d\n", txq_id, @@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, /* # frames attempted by Tx command */ if (agg->frame_count == 1) { + struct iwl_tx_info *txb; + /* Only one frame was attempted; no block-ack will arrive */ idx = start_idx; IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", agg->frame_count, agg->start_idx, idx); - iwlagn_set_tx_status(priv, - IEEE80211_SKB_CB( - priv->txq[txq_id].txb[idx].skb), - tx_resp, txq_id, true); + txb = &priv->txq[txq_id].txb[idx]; + iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), + txb->ctx, tx_resp, txq_id, true); agg->wait_for_ba = 0; } else { /* Two or more frames were attempted; expect block-ack */ @@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_info *info; struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le16_to_cpu(tx_resp->status.status); + struct iwl_tx_info *txb; + u32 status = le16_to_cpu(tx_resp->status.status); int tid; int sta_id; int freed; @@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, } txq->time_stamp = jiffies; - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); + txb = &txq->txb[txq->q.read_ptr]; + info = IEEE80211_SKB_CB(txb->skb); memset(&info->status, 0, sizeof(info->status)); tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> @@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, iwl_wake_queue(priv, txq); } } else { - iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); + iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, + txq_id, false); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); iwl_free_tfds_in_queue(priv, sta_id, tid, freed); if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark)) + iwl_queue_space(&txq->q) > txq->q.low_mark && + status != TX_STATUS_FAIL_PASSIVE_NO_RX) iwl_wake_queue(priv, txq); } @@ -470,15 +483,20 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = iwlagn_rx_calib_result; - priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = - iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; + + /* set up notification wait support */ + spin_lock_init(&priv->_agn.notif_wait_lock); + INIT_LIST_HEAD(&priv->_agn.notif_waits); + init_waitqueue_head(&priv->_agn.notif_waitq); } void iwlagn_setup_deferred_work(struct iwl_priv *priv) { - /* in agn, the tx power calibration is done in uCode */ - priv->disable_tx_power_cal = 1; + /* + * nothing need to be done here anymore + * still keep for future use if needed + */ } int iwlagn_hw_valid_rtc_data_addr(u32 addr) @@ -528,9 +546,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) void iwlagn_temperature(struct iwl_priv *priv) { - /* store temperature from statistics (in Celsius) */ - priv->temperature = - le32_to_cpu(priv->_agn.statistics.general.common.temperature); + /* store temperature from correct statistics (in Celsius) */ + priv->temperature = le32_to_cpu(priv->statistics.common.temperature); iwl_tt_handler(priv); } @@ -604,6 +621,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv, struct iwl_mod_params iwlagn_mod_params = { .amsdu_size_8K = 1, .restart_fw = 1, + .plcp_check = true, /* the rest are 0 by default */ }; @@ -645,10 +663,9 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (!priv->cfg->base_params->use_isr_legacy) - rb_timeout = RX_RB_TIMEOUT; + rb_timeout = RX_RB_TIMEOUT; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; @@ -906,7 +923,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -988,240 +1004,6 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) return -1; } -/* Calc max signal level (dBm) among 3 possible receivers */ -static inline int iwlagn_calc_rssi(struct iwl_priv *priv, - struct iwl_rx_phy_res *rx_resp) -{ - return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); -} - -static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) -{ - u32 decrypt_out = 0; - - if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == - RX_RES_STATUS_STATION_FOUND) - decrypt_out |= (RX_RES_STATUS_STATION_FOUND | - RX_RES_STATUS_NO_STATION_INFO_MISMATCH); - - decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); - - /* packet was not encrypted */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_NONE) - return decrypt_out; - - /* packet was encrypted with unknown alg */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_ERR) - return decrypt_out; - - /* decryption was not done in HW */ - if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != - RX_MPDU_RES_STATUS_DEC_DONE_MSK) - return decrypt_out; - - switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { - - case RX_RES_STATUS_SEC_TYPE_CCMP: - /* alg is CCM: check MIC only */ - if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) - /* Bad MIC */ - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - - break; - - case RX_RES_STATUS_SEC_TYPE_TKIP: - if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { - /* Bad TTAK */ - decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; - break; - } - /* fall through if TTAK OK */ - default: - if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - break; - } - - IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", - decrypt_in, decrypt_out); - - return decrypt_out; -} - -static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - u16 len, - u32 ampdu_status, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct sk_buff *skb; - __le16 fc = hdr->frame_control; - - /* We only process data packets if the interface is open */ - if (unlikely(!priv->is_open)) { - IWL_DEBUG_DROP_LIMIT(priv, - "Dropping packet while interface is not open.\n"); - return; - } - - /* In case of HW accelerated crypto and bad decryption, drop */ - if (!priv->cfg->mod_params->sw_crypto && - iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) - return; - - skb = dev_alloc_skb(128); - if (!skb) { - IWL_ERR(priv, "dev_alloc_skb failed\n"); - return; - } - - skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); - - iwl_update_stats(priv, false, fc, len); - memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - - ieee80211_rx(priv->hw, skb); - priv->alloc_rxb_page--; - rxb->page = NULL; -} - -/* Called for REPLY_RX (legacy ABG frames), or - * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -void iwlagn_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_rx_phy_res *phy_res; - __le32 rx_pkt_status; - struct iwl_rx_mpdu_res_start *amsdu; - u32 len; - u32 ampdu_status; - u32 rate_n_flags; - - /** - * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. - * REPLY_RX: physical layer info is in this buffer - * REPLY_RX_MPDU_CMD: physical layer info was sent in separate - * command and cached in priv->last_phy_res - * - * Here we set up local variables depending on which command is - * received. - */ - if (pkt->hdr.cmd == REPLY_RX) { - phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; - header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) - + phy_res->cfg_phy_cnt); - - len = le16_to_cpu(phy_res->byte_count); - rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + - phy_res->cfg_phy_cnt + len); - ampdu_status = le32_to_cpu(rx_pkt_status); - } else { - if (!priv->_agn.last_phy_res_valid) { - IWL_ERR(priv, "MPDU frame without cached PHY data\n"); - return; - } - phy_res = &priv->_agn.last_phy_res; - amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; - header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); - len = le16_to_cpu(amsdu->byte_count); - rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); - ampdu_status = iwlagn_translate_rx_status(priv, - le32_to_cpu(rx_pkt_status)); - } - - if ((unlikely(phy_res->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - phy_res->cfg_phy_cnt); - return; - } - - if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || - !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(rx_pkt_status)); - return; - } - - /* This will be used in several places later */ - rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); - - /* rx_status carries information about the packet to mac80211 */ - rx_status.mactime = le64_to_cpu(phy_res->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); - rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - rx_status.rate_idx = - iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); - rx_status.flag = 0; - - /* TSF isn't reliable. In order to allow smooth user experience, - * this W/A doesn't propagate it to the mac80211 */ - /*rx_status.flag |= RX_FLAG_TSFT;*/ - - priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); - - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwlagn_calc_rssi(priv, phy_res); - - iwl_dbg_log_rx_data_frame(priv, len, header); - IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n", - rx_status.signal, (unsigned long long)rx_status.mactime); - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bit field. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favor of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - rx_status.antenna = - (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) - >> RX_RES_PHY_FLAGS_ANTENNA_POS; - - /* set the preamble flag if appropriate */ - if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - rx_status.flag |= RX_FLAG_SHORTPRE; - - /* Set up the HT phy flags */ - if (rate_n_flags & RATE_MCS_HT_MSK) - rx_status.flag |= RX_FLAG_HT; - if (rate_n_flags & RATE_MCS_HT40_MSK) - rx_status.flag |= RX_FLAG_40MHZ; - if (rate_n_flags & RATE_MCS_SGI_MSK) - rx_status.flag |= RX_FLAG_SHORT_GI; - - iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, - rxb, &rx_status); -} - -/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). - * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - priv->_agn.last_phy_res_valid = true; - memcpy(&priv->_agn.last_phy_res, pkt->u.raw, - sizeof(struct iwl_rx_phy_res)); -} - static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, struct ieee80211_vif *vif, enum ieee80211_band band, @@ -1342,6 +1124,18 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, return added; } +static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen) +{ + struct sk_buff *skb = priv->_agn.offchan_tx_skb; + + if (skb->len < maxlen) + maxlen = skb->len; + + memcpy(data, skb->data, maxlen); + + return maxlen; +} + int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) { struct iwl_host_cmd cmd = { @@ -1384,20 +1178,25 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - if (iwl_is_any_associated(priv)) { + if (priv->scan_type != IWL_SCAN_OFFCH_TX && + iwl_is_any_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; u32 scan_suspend_time = 100; - unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - spin_lock_irqsave(&priv->lock, flags); - if (priv->is_internal_short_scan) + switch (priv->scan_type) { + case IWL_SCAN_OFFCH_TX: + WARN_ON(1); + break; + case IWL_SCAN_RADIO_RESET: interval = 0; - else + break; + case IWL_SCAN_NORMAL: interval = vif->bss_conf.beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); + break; + } scan->suspend_time = 0; scan->max_out_time = cpu_to_le32(200 * 1024); @@ -1410,29 +1209,41 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) scan->suspend_time = cpu_to_le32(scan_suspend_time); IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", scan_suspend_time, interval); + } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) { + scan->suspend_time = 0; + scan->max_out_time = + cpu_to_le32(1024 * priv->_agn.offchan_tx_timeout); } - if (priv->is_internal_short_scan) { + switch (priv->scan_type) { + case IWL_SCAN_RADIO_RESET: IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); - } else if (priv->scan_request->n_ssids) { - int i, p = 0; - IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - for (i = 0; i < priv->scan_request->n_ssids; i++) { - /* always does wildcard anyway */ - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } - is_active = true; - } else - IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); + break; + case IWL_SCAN_NORMAL: + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; + } else + IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); + break; + case IWL_SCAN_OFFCH_TX: + IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n"); + break; + } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = ctx->bcast_sta_id; @@ -1483,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; band = priv->scan_band; @@ -1530,38 +1349,77 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; scan->rx_chain = cpu_to_le16(rx_chain); - if (!priv->is_internal_short_scan) { + switch (priv->scan_type) { + case IWL_SCAN_NORMAL: cmd_len = iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, vif->addr, priv->scan_request->ie, priv->scan_request->ie_len, IWL_MAX_SCAN_SIZE - sizeof(*scan)); - } else { + break; + case IWL_SCAN_RADIO_RESET: /* use bcast addr, will not be transmitted but must be valid */ cmd_len = iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, iwl_bcast_addr, NULL, 0, IWL_MAX_SCAN_SIZE - sizeof(*scan)); - + break; + case IWL_SCAN_OFFCH_TX: + cmd_len = iwl_fill_offch_tx(priv, scan->data, + IWL_MAX_SCAN_SIZE + - sizeof(*scan) + - sizeof(struct iwl_scan_channel)); + scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX; + break; + default: + BUG(); } scan->tx_cmd.len = cpu_to_le16(cmd_len); scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); - if (priv->is_internal_short_scan) { + switch (priv->scan_type) { + case IWL_SCAN_RADIO_RESET: scan->channel_count = iwl_get_single_channel_for_scan(priv, vif, band, - (void *)&scan->data[le16_to_cpu( - scan->tx_cmd.len)]); - } else { + (void *)&scan->data[cmd_len]); + break; + case IWL_SCAN_NORMAL: scan->channel_count = iwl_get_channels_for_scan(priv, vif, band, is_active, n_probes, - (void *)&scan->data[le16_to_cpu( - scan->tx_cmd.len)]); + (void *)&scan->data[cmd_len]); + break; + case IWL_SCAN_OFFCH_TX: { + struct iwl_scan_channel *scan_ch; + + scan->channel_count = 1; + + scan_ch = (void *)&scan->data[cmd_len]; + scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; + scan_ch->channel = + cpu_to_le16(priv->_agn.offchan_tx_chan->hw_value); + scan_ch->active_dwell = + cpu_to_le16(priv->_agn.offchan_tx_timeout); + scan_ch->passive_dwell = 0; + + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level: + * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; + */ + if (priv->_agn.offchan_tx_chan->band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + } + break; } + if (scan->channel_count == 0) { IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); return -EIO; @@ -1801,26 +1659,39 @@ static const __le32 iwlagn_concurrent_lookup[12] = { void iwlagn_send_advance_bt_config(struct iwl_priv *priv) { - struct iwlagn_bt_cmd bt_cmd = { + struct iwl_basic_bt_cmd basic = { .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT, .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT, .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT, .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT, }; + struct iwl6000_bt_cmd bt_cmd_6000; + struct iwl2000_bt_cmd bt_cmd_2000; + int ret; BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != - sizeof(bt_cmd.bt3_lookup_table)); - - if (priv->cfg->bt_params) - bt_cmd.prio_boost = priv->cfg->bt_params->bt_prio_boost; - else - bt_cmd.prio_boost = 0; - bt_cmd.kill_ack_mask = priv->kill_ack_mask; - bt_cmd.kill_cts_mask = priv->kill_cts_mask; + sizeof(basic.bt3_lookup_table)); + + if (priv->cfg->bt_params) { + if (priv->cfg->bt_params->bt_session_2) { + bt_cmd_2000.prio_boost = cpu_to_le32( + priv->cfg->bt_params->bt_prio_boost); + bt_cmd_2000.tx_prio_boost = 0; + bt_cmd_2000.rx_prio_boost = 0; + } else { + bt_cmd_6000.prio_boost = + priv->cfg->bt_params->bt_prio_boost; + bt_cmd_6000.tx_prio_boost = 0; + bt_cmd_6000.rx_prio_boost = 0; + } + } else { + IWL_ERR(priv, "failed to construct BT Coex Config\n"); + return; + } - bt_cmd.valid = priv->bt_valid; - bt_cmd.tx_prio_boost = 0; - bt_cmd.rx_prio_boost = 0; + basic.kill_ack_mask = priv->kill_ack_mask; + basic.kill_cts_mask = priv->kill_cts_mask; + basic.valid = priv->bt_valid; /* * Configure BT coex mode to "no coexistence" when the @@ -1829,49 +1700,45 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) * IBSS mode (no proper uCode support for coex then). */ if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) { - bt_cmd.flags = 0; + basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED; } else { - bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << + basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << IWLAGN_BT_FLAG_COEX_MODE_SHIFT; if (priv->cfg->bt_params && priv->cfg->bt_params->bt_sco_disable) - bt_cmd.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; + basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; if (priv->bt_ch_announce) - bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; - IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags); + basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; + IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", basic.flags); } - priv->bt_enable_flag = bt_cmd.flags; + priv->bt_enable_flag = basic.flags; if (priv->bt_full_concurrent) - memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup, + memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup, sizeof(iwlagn_concurrent_lookup)); else - memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup, + memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup, sizeof(iwlagn_def_3w_lookup)); IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n", - bt_cmd.flags ? "active" : "disabled", + basic.flags ? "active" : "disabled", priv->bt_full_concurrent ? "full concurrency" : "3-wire"); - if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd)) + if (priv->cfg->bt_params->bt_session_2) { + memcpy(&bt_cmd_2000.basic, &basic, + sizeof(basic)); + ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(bt_cmd_2000), &bt_cmd_2000); + } else { + memcpy(&bt_cmd_6000.basic, &basic, + sizeof(basic)); + ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(bt_cmd_6000), &bt_cmd_6000); + } + if (ret) IWL_ERR(priv, "failed to send BT Coex Config\n"); - /* - * When we are doing a restart, need to also reconfigure BT - * SCO to the device. If not doing a restart, bt_sco_active - * will always be false, so there's no need to have an extra - * variable to check for it. - */ - if (priv->bt_sco_active) { - struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; - - if (priv->bt_sco_active) - sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO, - sizeof(sco_cmd), &sco_cmd)) - IWL_ERR(priv, "failed to send BT SCO command\n"); - } } static void iwlagn_bt_traffic_change_work(struct work_struct *work) @@ -1881,6 +1748,11 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) struct iwl_rxon_context *ctx; int smps_request = -1; + if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { + /* bt coex disabled */ + return; + } + /* * Note: bt_traffic_load can be overridden by scan complete and * coex profile notifications. Ignore that since only bad consequence @@ -1991,12 +1863,14 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >> BT_UART_MSG_FRAME6DISCOVERABLE_POS); - IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = " - "0x%X, Connectable = 0x%X", + IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Page = " + "0x%X, Inquiry = 0x%X, Connectable = 0x%X", (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >> BT_UART_MSG_FRAME7SNIFFACTIVITY_POS, - (BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >> - BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS, + (BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >> + BT_UART_MSG_FRAME7PAGE_POS, + (BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >> + BT_UART_MSG_FRAME7INQUIRY_POS, (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >> BT_UART_MSG_FRAME7CONNECTABLE_POS); } @@ -2032,9 +1906,13 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, unsigned long flags; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; - struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg; + if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { + /* bt coex disabled */ + return; + } + IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n"); IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status); IWL_DEBUG_NOTIF(priv, " traffic load: %d\n", coex->bt_traffic_load); @@ -2063,15 +1941,6 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->bt_traffic_change_work); } - if (priv->bt_sco_active != - (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) { - priv->bt_sco_active = uart_msg->frame3 & - BT_UART_MSG_FRAME3SCOESCO_MSK; - if (priv->bt_sco_active) - sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; - iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO, - sizeof(sco_cmd), &sco_cmd, NULL); - } } iwlagn_set_kill_msk(priv, uart_msg); @@ -2389,3 +2258,138 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) } return 0; } + +/* notification wait support */ +void iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + u8 cmd, + void (*fn)(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) +{ + wait_entry->fn = fn; + wait_entry->fn_data = fn_data; + wait_entry->cmd = cmd; + wait_entry->triggered = false; + wait_entry->aborted = false; + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_add(&wait_entry->list, &priv->_agn.notif_waits); + spin_unlock_bh(&priv->_agn.notif_wait_lock); +} + +int iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) +{ + int ret; + + ret = wait_event_timeout(priv->_agn.notif_waitq, + wait_entry->triggered || wait_entry->aborted, + timeout); + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); + + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; +} + +void iwlagn_remove_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry) +{ + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); +} + +int iwlagn_start_device(struct iwl_priv *priv) +{ + int ret; + + if (iwl_prepare_card_hw(priv)) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); + return -ERFKILL; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = iwlagn_hw_nic_init(priv); + if (ret) { + IWL_ERR(priv, "Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + return 0; +} + +void iwlagn_stop_device(struct iwl_priv *priv) +{ + unsigned long flags; + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { + iwlagn_txq_ctx_stop(priv); + iwlagn_rxq_stop(priv); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + } + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 75fcd30a7c13..91f26556ac23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { /* FIXME:RS: ^^ should be INV (legacy) */ }; +static inline u8 rs_extract_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); +} + static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; /* HT rate format */ if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); + idx = rs_extract_rate(rate_n_flags); if (idx >= IWL_RATE_MIMO3_6M_PLCP) idx = idx - IWL_RATE_MIMO3_6M_PLCP; @@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) /* legacy rate format, search for match in table */ } else { for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + if (iwl_rates[idx].plcp == + rs_extract_rate(rate_n_flags)) return idx; } @@ -179,31 +185,31 @@ static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { }; static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */ - {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */ - {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */ - {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */ + {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ + {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ + {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ + {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ }; static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ - {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */ - {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */ + {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ + {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ }; static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */ - {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */ - {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */ - {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/ + {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ + {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ + {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ + {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ }; static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ - {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */ - {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */ + {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ + {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ }; static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { @@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - return (u8)(rate_n_flags & 0xFF); -} - static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; @@ -2770,16 +2771,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = &sta_priv->lq_sta; - - return lq_sta; + return &sta_priv->lq_sta; } /* @@ -2890,6 +2888,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; u8 valid_tx_ant = 0; + struct iwl_station_priv *sta_priv = + container_of(lq_sta, struct iwl_station_priv, lq_sta); struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; /* Override starting rate (index 0) if needed for debug purposes */ @@ -2910,7 +2910,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; } else { - repeat_rate = IWL_HT_NUMBER_TRY; + repeat_rate = min(IWL_HT_NUMBER_TRY, + LINK_QUAL_AGG_DISABLE_START_DEF - 1); } lq_cmd->general_params.mimo_delimiter = @@ -3008,7 +3009,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + lq_cmd->agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize ?: LINK_QUAL_AGG_FRAME_LIMIT_DEF; lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; lq_cmd->agg_params.agg_time_limit = @@ -3084,7 +3086,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; char buf[64]; - int buf_size; + size_t buf_size; u32 parsed_rate; struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); @@ -3254,7 +3256,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, { char buff[120]; int desc = 0; - ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; @@ -3271,8 +3272,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, "Bit Rate= %d Mb/s\n", iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); } static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 75e50d33ecb3..bdae82e7fa90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -41,20 +41,6 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; -struct iwl3945_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ - u8 table_rs_index; /* index in rate scale table cmd */ - u8 prev_table_rs; /* prev in rate table cmd */ -}; - - /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -75,7 +61,6 @@ enum { IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ - IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, }; @@ -98,7 +83,6 @@ enum { enum { IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, - IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, @@ -452,19 +436,9 @@ static inline u8 first_antenna(u8 mask) } -/** - * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - /* Initialize station's rate scaling information after adding station */ extern void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id); -extern void iwl3945_rs_rate_init(struct iwl_priv *priv, - struct ieee80211_sta *sta, u8 sta_id); /** * iwl_rate_control_register - Register the rate control algorithm callbacks @@ -477,7 +451,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv, * */ extern int iwlagn_rate_control_register(void); -extern int iwl3945_rate_control_register(void); /** * iwl_rate_control_unregister - Unregister the rate control callbacks @@ -486,6 +459,5 @@ extern int iwl3945_rate_control_register(void); * the driver is unloaded. */ extern void iwlagn_rate_control_unregister(void); -extern void iwl3945_rate_control_unregister(void); #endif /* __iwl_agn__rs__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c deleted file mode 100644 index bbd40b7dd597..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ /dev/null @@ -1,356 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/sched.h> - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-agn-calib.h" -#include "iwl-sta.h" -#include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-agn-hw.h" -#include "iwl-agn.h" - -void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) - -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_missed_beacon_notif *missed_beacon; - - missed_beacon = &pkt->u.missed_beacon; - if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > - priv->missed_beacon_threshold) { - IWL_DEBUG_CALIB(priv, - "missed bcn cnsq %d totl %d rcd %d expctd %d\n", - le32_to_cpu(missed_beacon->consecutive_missed_beacons), - le32_to_cpu(missed_beacon->total_missed_becons), - le32_to_cpu(missed_beacon->num_recvd_beacons), - le32_to_cpu(missed_beacon->num_expected_beacons)); - if (!test_bit(STATUS_SCANNING, &priv->status)) - iwl_init_sensitivity(priv); - } -} - -/* Calculate noise level, based on measurements during network silence just - * before arriving beacon. This measurement can be done only if we know - * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl_rx_calc_noise(struct iwl_priv *priv) -{ - struct statistics_rx_non_phy *rx_info; - int num_active_rx = 0; - int total_silence = 0; - int bcn_silence_a, bcn_silence_b, bcn_silence_c; - int last_rx_noise; - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) - rx_info = &(priv->_agn.statistics_bt.rx.general.common); - else - rx_info = &(priv->_agn.statistics.rx.general); - bcn_silence_a = - le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; - bcn_silence_b = - le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; - bcn_silence_c = - le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; - - if (bcn_silence_a) { - total_silence += bcn_silence_a; - num_active_rx++; - } - if (bcn_silence_b) { - total_silence += bcn_silence_b; - num_active_rx++; - } - if (bcn_silence_c) { - total_silence += bcn_silence_c; - num_active_rx++; - } - - /* Average among active antennas */ - if (num_active_rx) - last_rx_noise = (total_silence / num_active_rx) - 107; - else - last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", - bcn_silence_a, bcn_silence_b, bcn_silence_c, - last_rx_noise); -} - -#ifdef CONFIG_IWLWIFI_DEBUGFS -/* - * based on the assumption of all statistics counter are in DWORD - * FIXME: This function is for debugging, do not deal with - * the case of counters roll-over. - */ -static void iwl_accumulative_statistics(struct iwl_priv *priv, - __le32 *stats) -{ - int i, size; - __le32 *prev_stats; - u32 *accum_stats; - u32 *delta, *max_delta; - struct statistics_general_common *general, *accum_general; - struct statistics_tx *tx, *accum_tx; - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - prev_stats = (__le32 *)&priv->_agn.statistics_bt; - accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; - size = sizeof(struct iwl_bt_notif_statistics); - general = &priv->_agn.statistics_bt.general.common; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta = (u32 *)&priv->_agn.delta_statistics_bt; - max_delta = (u32 *)&priv->_agn.max_delta_bt; - } else { - prev_stats = (__le32 *)&priv->_agn.statistics; - accum_stats = (u32 *)&priv->_agn.accum_statistics; - size = sizeof(struct iwl_notif_statistics); - general = &priv->_agn.statistics.general.common; - accum_general = &priv->_agn.accum_statistics.general.common; - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta = (u32 *)&priv->_agn.delta_statistics; - max_delta = (u32 *)&priv->_agn.max_delta; - } - for (i = sizeof(__le32); i < size; - i += sizeof(__le32), stats++, prev_stats++, delta++, - max_delta++, accum_stats++) { - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { - *delta = (le32_to_cpu(*stats) - - le32_to_cpu(*prev_stats)); - *accum_stats += *delta; - if (*delta > *max_delta) - *max_delta = *delta; - } - } - - /* reset accumulative statistics for "no-counter" type statistics */ - accum_general->temperature = general->temperature; - accum_general->temperature_m = general->temperature_m; - accum_general->ttl_timestamp = general->ttl_timestamp; - accum_tx->tx_power.ant_a = tx->tx_power.ant_a; - accum_tx->tx_power.ant_b = tx->tx_power.ant_b; - accum_tx->tx_power.ant_c = tx->tx_power.ant_c; -} -#endif - -#define REG_RECALIB_PERIOD (60) - -/** - * iwl_good_plcp_health - checks for plcp error. - * - * When the plcp error is exceeding the thresholds, reset the radio - * to improve the throughput. - */ -bool iwl_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) -{ - bool rc = true; - int combined_plcp_delta; - unsigned int plcp_msec; - unsigned long plcp_received_jiffies; - - if (priv->cfg->base_params->plcp_delta_threshold == - IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { - IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); - return rc; - } - - /* - * check for plcp_err and trigger radio reset if it exceeds - * the plcp error threshold plcp_delta. - */ - plcp_received_jiffies = jiffies; - plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - - (long) priv->plcp_jiffies); - priv->plcp_jiffies = plcp_received_jiffies; - /* - * check to make sure plcp_msec is not 0 to prevent division - * by zero. - */ - if (plcp_msec) { - struct statistics_rx_phy *ofdm; - struct statistics_rx_ht_phy *ofdm_ht; - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - ofdm = &pkt->u.stats_bt.rx.ofdm; - ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht; - combined_plcp_delta = - (le32_to_cpu(ofdm->plcp_err) - - le32_to_cpu(priv->_agn.statistics_bt. - rx.ofdm.plcp_err)) + - (le32_to_cpu(ofdm_ht->plcp_err) - - le32_to_cpu(priv->_agn.statistics_bt. - rx.ofdm_ht.plcp_err)); - } else { - ofdm = &pkt->u.stats.rx.ofdm; - ofdm_ht = &pkt->u.stats.rx.ofdm_ht; - combined_plcp_delta = - (le32_to_cpu(ofdm->plcp_err) - - le32_to_cpu(priv->_agn.statistics. - rx.ofdm.plcp_err)) + - (le32_to_cpu(ofdm_ht->plcp_err) - - le32_to_cpu(priv->_agn.statistics. - rx.ofdm_ht.plcp_err)); - } - - if ((combined_plcp_delta > 0) && - ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->base_params->plcp_delta_threshold) { - /* - * if plcp_err exceed the threshold, - * the following data is printed in csv format: - * Text: plcp_err exceeded %d, - * Received ofdm.plcp_err, - * Current ofdm.plcp_err, - * Received ofdm_ht.plcp_err, - * Current ofdm_ht.plcp_err, - * combined_plcp_delta, - * plcp_msec - */ - IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " - "%u, %u, %u, %u, %d, %u mSecs\n", - priv->cfg->base_params->plcp_delta_threshold, - le32_to_cpu(ofdm->plcp_err), - le32_to_cpu(ofdm->plcp_err), - le32_to_cpu(ofdm_ht->plcp_err), - le32_to_cpu(ofdm_ht->plcp_err), - combined_plcp_delta, plcp_msec); - - rc = false; - } - } - return rc; -} - -void iwl_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - int change; - struct iwl_rx_packet *pkt = rxb_addr(rxb); - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_bt_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); - - change = ((priv->_agn.statistics_bt.general.common.temperature != - pkt->u.stats_bt.general.common.temperature) || - ((priv->_agn.statistics_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); -#ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); -#endif - - } else { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); - - change = ((priv->_agn.statistics.general.common.temperature != - pkt->u.stats.general.common.temperature) || - ((priv->_agn.statistics.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); -#ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); -#endif - - } - - iwl_recover_from_statistics(priv, pkt); - - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) - memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, - sizeof(priv->_agn.statistics_bt)); - else - memcpy(&priv->_agn.statistics, &pkt->u.stats, - sizeof(priv->_agn.statistics)); - - set_bit(STATUS_STATISTICS, &priv->status); - - /* Reschedule the statistics timer to occur in - * REG_RECALIB_PERIOD seconds to ensure we get a - * thermal update even if the uCode doesn't give - * us one */ - mod_timer(&priv->statistics_periodic, jiffies + - msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); - - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { - iwl_rx_calc_noise(priv); - queue_work(priv->workqueue, &priv->run_time_calib_work); - } - if (priv->cfg->ops->lib->temp_ops.temperature && change) - priv->cfg->ops->lib->temp_ops.temperature(priv); -} - -void iwl_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - - if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - memset(&priv->_agn.accum_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.delta_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.max_delta, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.accum_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.delta_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.max_delta_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); -#endif - IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); - } - iwl_rx_statistics(priv, rxb); -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 6d140bd53291..02387430f7fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -29,6 +29,7 @@ #include "iwl-sta.h" #include "iwl-core.h" #include "iwl-agn-calib.h" +#include "iwl-helpers.h" static int iwlagn_disable_bss(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -52,10 +53,15 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_rxon_cmd *send) { + struct iwl_notification_wait disable_wait; __le32 old_filter = send->filter_flags; u8 old_dev_type = send->dev_type; int ret; + iwlagn_init_notification_wait(priv, &disable_wait, + REPLY_WIPAN_DEACTIVATION_COMPLETE, + NULL, NULL); + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send); @@ -63,11 +69,14 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, send->filter_flags = old_filter; send->dev_type = old_dev_type; - if (ret) + if (ret) { IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); - - /* FIXME: WAIT FOR PAN DISABLE */ - msleep(300); + iwlagn_remove_notification(priv, &disable_wait); + } else { + ret = iwlagn_wait_notification(priv, &disable_wait, HZ); + if (ret) + IWL_ERR(priv, "Timed out waiting for PAN disable\n"); + } return ret; } @@ -112,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, return iwlagn_send_beacon_cmd(priv); } +static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret = 0; + struct iwl_rxon_assoc_cmd rxon_assoc; + const struct iwl_rxon_cmd *rxon1 = &ctx->staging; + const struct iwl_rxon_cmd *rxon2 = &ctx->active; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (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->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = ctx->staging.flags; + rxon_assoc.filter_flags = ctx->staging.filter_flags; + rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; + rxon_assoc.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + ctx->staging.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + ctx->staging.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + ctx->staging.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = ctx->staging.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} + +static int iwlagn_rxon_disconn(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; + + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); + return 0; +} + +static int iwlagn_rxon_connect(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + /* RXON timing must be before associated RXON */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + /* QoS info may be cleared by previous un-assoc RXON */ + iwlagn_update_qos(priv, ctx); + + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { + ret = iwlagn_update_beacon(priv, ctx->vif); + if (ret) { + IWL_ERR(priv, + "Error sending required beacon (%d)!\n", + ret); + return ret; + } + } + + priv->start_calib = 0; + /* + * Apply the new configuration. + * + * Associated RXON doesn't clear the station table in uCode, + * so we don't need to restore stations etc. after this. + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active, &ctx->staging, sizeof(*active)); + + iwl_reprogram_ap_sta(priv, ctx); + + /* IBSS beacon needs to be sent after setting assoc */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) + if (iwlagn_update_beacon(priv, ctx->vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); + iwl_init_sensitivity(priv); + + /* + * 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. + * + * It's expected we set power here if channel is changing. + */ + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + return 0; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -119,6 +273,16 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, * 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. + * + * The connect/disconnect flow should be as the following: + * + * 1. make sure send RXON command with association bit unset if not connect + * this should include the channel and the band for the candidate + * to be connected to + * 2. Add Station before RXON association with the AP + * 3. RXON_timing has to send before RXON for connection + * 4. full RXON command - associated bit set + * 5. use RXON_ASSOC command to update any flags changes */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -145,12 +309,30 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) /* always get timestamp with Rx frame */ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; + if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->_agn.hw_roc_channel) { + struct ieee80211_channel *chan = priv->_agn.hw_roc_channel; + + iwl_set_rxon_channel(priv, chan, ctx); + iwl_set_flags_for_band(priv, ctx, chan->band, NULL); + ctx->staging.filter_flags |= + RXON_FILTER_ASSOC_MSK | + RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK; + ctx->staging.dev_type = RXON_DEV_TYPE_P2P; + new_assoc = true; + + if (memcmp(&ctx->staging, &ctx->active, + sizeof(ctx->staging)) == 0) + return 0; + } + if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + iwl_print_rx_config_cmd(priv, ctx); ret = iwl_check_rxon_cmd(priv, ctx); if (ret) { IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); @@ -174,14 +356,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); + ret = iwlagn_send_rxon_assoc(priv, ctx); if (ret) { IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); return ret; } memcpy(active, &ctx->staging, sizeof(*active)); - iwl_print_rx_config_cmd(priv, ctx); return 0; } @@ -191,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return ret; } - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" @@ -209,93 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * set up filters in the device. */ if ((old_assoc && new_assoc) || !new_assoc) { - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else - ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + ret = iwlagn_rxon_disconn(priv, ctx); if (ret) return ret; - - memcpy(active, &ctx->staging, sizeof(*active)); - - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - - /* RXON timing must be before associated RXON */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); - return ret; } - if (new_assoc) { - /* QoS info may be cleared by previous un-assoc RXON */ - iwlagn_update_qos(priv, ctx); - - /* - * We'll run into this code path when beaconing is - * enabled, but then we also need to send the beacon - * to the device. - */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { - ret = iwlagn_update_beacon(priv, ctx->vif); - if (ret) { - IWL_ERR(priv, - "Error sending required beacon (%d)!\n", - ret); - return ret; - } - } - - priv->start_calib = 0; - /* - * Apply the new configuration. - * - * Associated RXON doesn't clear the station table in uCode, - * so we don't need to restore stations etc. after this. - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active, &ctx->staging, sizeof(*active)); - - iwl_reprogram_ap_sta(priv, ctx); - - /* IBSS beacon needs to be sent after setting assoc */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) - if (iwlagn_update_beacon(priv, ctx->vif)) - IWL_ERR(priv, "Error sending IBSS beacon\n"); - } - - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(priv); - - /* - * 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. - * - * FIXME: which RXON requires a tune? Can we optimise this out in - * some cases? - */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (ret) { - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } + if (new_assoc) + return iwlagn_rxon_connect(priv, ctx); return 0; } @@ -308,7 +409,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -356,10 +456,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { + if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { @@ -428,8 +526,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); - if (ht_changed[ctx->ctxid]) - iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); @@ -444,6 +540,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, struct iwl_rxon_context *tmp; struct ieee80211_sta *sta; struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct ieee80211_sta_ht_cap *ht_cap; bool need_multiple; lockdep_assert_held(&priv->mutex); @@ -452,23 +549,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, case NL80211_IFTYPE_STATION: rcu_read_lock(); sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int maxstreams; - - maxstreams = (ht_cap->mcs.tx_params & - IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) - >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - maxstreams += 1; - - need_multiple = true; - - if ((ht_cap->mcs.rx_mask[1] == 0) && - (ht_cap->mcs.rx_mask[2] == 0)) - need_multiple = false; - if (maxstreams <= 1) - need_multiple = false; - } else { + if (!sta) { /* * If at all, this can only happen through a race * when the AP disconnects us while we're still @@ -476,7 +557,46 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, * will soon tell us about that. */ need_multiple = false; + rcu_read_unlock(); + break; } + + ht_cap = &sta->ht_cap; + + need_multiple = true; + + /* + * If the peer advertises no support for receiving 2 and 3 + * stream MCS rates, it can't be transmitting them either. + */ + if (ht_cap->mcs.rx_mask[1] == 0 && + ht_cap->mcs.rx_mask[2] == 0) { + need_multiple = false; + } else if (!(ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_DEFINED)) { + /* If it can't TX MCS at all ... */ + need_multiple = false; + } else if (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_RX_DIFF) { + int maxstreams; + + /* + * But if it can receive them, it might still not + * be able to transmit them, which is what we need + * to check here -- so check the number of streams + * it advertises for TX (if different from RX). + */ + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK); + maxstreams >>= + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if (maxstreams <= 1) + need_multiple = false; + } + rcu_read_unlock(); break; case NL80211_IFTYPE_ADHOC: @@ -546,12 +666,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - iwl_led_associate(priv); priv->timestamp = bss_conf->timestamp; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { + /* + * If we disassociate while there are pending + * frames, just wake up the queues and let the + * frames "escape" ... This shouldn't really + * be happening to start with, but we should + * not get stuck in this case either since it + * can happen if userspace gets confused. + */ + if (ctx->last_tx_rejected) { + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_led_disassociate(priv); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35f085ac336b..079275f2c64d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, - sizeof(struct iwl4965_keyinfo)); + sizeof(struct iwl_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index e3a8216a033c..348f74f1c8e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d55060427cac..d118ed29bf3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 24a11b8f73bc..342de780a366 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -98,9 +98,9 @@ static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) /** * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt) +static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int write_ptr = txq->q.write_ptr; @@ -112,21 +112,19 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - if (txq_id != priv->cmd_queue) { - sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; - sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; - - switch (sec_ctl & TX_CMD_SEC_MSK) { - case TX_CMD_SEC_CCM: - len += CCMP_MIC_LEN; - break; - case TX_CMD_SEC_TKIP: - len += TKIP_ICV_LEN; - break; - case TX_CMD_SEC_WEP: - len += WEP_IV_LEN + WEP_ICV_LEN; - break; - } + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; + + switch (sec_ctl & TX_CMD_SEC_MSK) { + case TX_CMD_SEC_CCM: + len += CCMP_MIC_LEN; + break; + case TX_CMD_SEC_TKIP: + len += TKIP_ICV_LEN; + break; + case TX_CMD_SEC_WEP: + len += WEP_IV_LEN + WEP_ICV_LEN; + break; } bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); @@ -138,8 +136,8 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq) +static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; @@ -222,13 +220,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) { - unsigned long flags; - u16 ra_tid; - int ret; - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { @@ -240,12 +233,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, return -EINVAL; } - ra_tid = BUILD_RAxTID(sta_id, tid); - /* Modify device's station table to Tx this TID */ - ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); - if (ret) - return ret; + return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); +} + +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit) +{ + int sta_id, tx_fifo, txq_id, ssn_idx; + u16 ra_tid; + unsigned long flags; + struct iwl_tid_data *tid_data; + + sta_id = iwl_sta_id(sta); + if (WARN_ON(sta_id == IWL_INVALID_STATION)) + return; + if (WARN_ON(tid >= MAX_TID_COUNT)) + return; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn_idx = SEQ_TO_SN(tid_data->seq_number); + txq_id = tid_data->agg.txq_id; + tx_fifo = tid_data->agg.tx_fifo; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ra_tid = BUILD_RAxTID(sta_id, tid); spin_lock_irqsave(&priv->lock, flags); @@ -271,10 +285,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_write_targ_mem(priv, priv->scd_base_addr + IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((SCD_WIN_SIZE << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((SCD_FRAME_LIMIT << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); @@ -284,12 +298,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); spin_unlock_irqrestore(&priv->lock, flags); - - return 0; } -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + @@ -525,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl_tx_cmd *tx_cmd; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; int txq_id; - dma_addr_t phys_addr; + dma_addr_t phys_addr = 0; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; u16 len, firstlen, secondlen; @@ -539,13 +551,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) unsigned long flags; bool is_agg = false; - if (info->control.vif) + /* + * If the frame needs to go out off-channel, then + * we'll have put the PAN context to that channel, + * so make the frame go out there. + */ + if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + else if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); - goto drop_unlock; + goto drop_unlock_priv; } fc = hdr->frame_control; @@ -561,12 +580,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock_priv; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -609,10 +633,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } + + if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) + goto drop_unlock_sta; + seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -630,18 +654,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq = &priv->txq[txq_id]; q = &txq->q; - if (unlikely(iwl_queue_space(q) < q->high_mark)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } - - if (ieee80211_is_data_qos(fc)) { - priv->stations[sta_id].tid[tid].tfds_in_queue++; - if (!ieee80211_has_morefrags(fc)) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } - - spin_unlock(&priv->sta_lock); + if (unlikely(iwl_queue_space(q) < q->high_mark)) + goto drop_unlock_sta; /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); @@ -705,12 +719,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, firstlen, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys))) + goto drop_unlock_sta; dma_unmap_addr_set(out_meta, mapping, txcmd_phys); dma_unmap_len_set(out_meta, len, firstlen); - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - txcmd_phys, firstlen, 1, 0); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -725,10 +737,30 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (secondlen > 0) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, secondlen, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(out_meta, mapping), + dma_unmap_len(out_meta, len), + PCI_DMA_BIDIRECTIONAL); + goto drop_unlock_sta; + } + } + + if (ieee80211_is_data_qos(fc)) { + priv->stations[sta_id].tid[tid].tfds_in_queue++; + if (!ieee80211_has_morefrags(fc)) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + + spin_unlock(&priv->sta_lock); + + /* Attach buffers to TFD */ + priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, + txcmd_phys, firstlen, 1, 0); + if (secondlen > 0) priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, secondlen, 0, 0); - } scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); @@ -747,8 +779,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, - le16_to_cpu(tx_cmd->len)); + iwlagn_txq_update_byte_cnt_tbl(priv, txq, + le16_to_cpu(tx_cmd->len)); pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, firstlen, PCI_DMA_BIDIRECTIONAL); @@ -794,7 +826,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return 0; -drop_unlock: +drop_unlock_sta: + spin_unlock(&priv->sta_lock); +drop_unlock_priv: spin_unlock_irqrestore(&priv->lock, flags); return -1; } @@ -940,7 +974,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv) */ void iwlagn_txq_ctx_stop(struct iwl_priv *priv) { - int ch; + int ch, txq_id; unsigned long flags; /* Turn off all Tx DMA fifos */ @@ -959,6 +993,16 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv) iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG)); } spin_unlock_irqrestore(&priv->lock, flags); + + if (!priv->txq) + return; + + /* Unmap DMA from host system and free skb's */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + if (txq_id == priv->cmd_queue) + iwl_cmd_queue_unmap(priv); + else + iwl_tx_queue_unmap(priv, txq_id); } /* @@ -1017,11 +1061,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + tid_data->agg.tx_fifo = tx_fifo; iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); - ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, *ssn); + ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); if (ret) return ret; @@ -1108,8 +1152,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, * to deactivate the uCode queue, just return "success" to allow * mac80211 to clean up it own data. */ - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, - tx_fifo_id); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -1138,8 +1181,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = get_fifo_from_tid(ctx, tid); IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, - ssn, tx_fifo); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); } @@ -1207,16 +1249,19 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwlagn_tx_status(priv, tx_info, + txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; - if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) - priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); + iwlagn_txq_inval_byte_cnt_tbl(priv, txq); priv->cfg->ops->lib->txq_free_tfd(priv, txq); } @@ -1234,11 +1279,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, struct iwl_compressed_ba_resp *ba_resp) { - int i, sh, ack; + int sh; u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - int successes = 0; struct ieee80211_tx_info *info; + u64 bitmap, sent_bitmap; if (unlikely(!agg->wait_for_ba)) { if (unlikely(ba_resp->bitmap)) @@ -1252,70 +1297,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, /* Calculate shift to align block-ack bits with our Tx window bits */ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); - if (sh < 0) /* tbw something is wrong with indices */ + if (sh < 0) sh += 0x100; - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); - return -1; - } - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + /* + * Check for success or failure according to the + * transmitted bitmap and block-ack bitmap + */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + sent_bitmap = bitmap & agg->bitmap; + + /* Sanity check values reported by uCode */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); /* - * sent and ack information provided by uCode - * use it instead of figure out ourself + * set txed_2_done = txed, + * so it won't impact rate scale */ - if (ba_resp->txed_2_done > ba_resp->txed) { - IWL_DEBUG_TX_REPLY(priv, - "bogus sent(%d) and ack(%d) count\n", - ba_resp->txed, ba_resp->txed_2_done); - /* - * set txed_2_done = txed, - * so it won't impact rate scale - */ - ba_resp->txed = ba_resp->txed_2_done; - } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); - } else { - u64 bitmap, sent_bitmap; - - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - sent_bitmap = bitmap & agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - i = 0; - while (sent_bitmap) { - ack = sent_bitmap & 1ULL; - successes += ack; - IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", - ack ? "ACK" : "NACK", i, - (agg->start_idx + i) & 0xff, - agg->start_idx + i); - sent_bitmap >>= 1; - ++i; - } + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); - IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", - (unsigned long long)bitmap); + /* Find the first ACKed frame to store the TX status */ + while (sent_bitmap && !(sent_bitmap & 1)) { + agg->start_idx = (agg->start_idx + 1) & 0xff; + sent_bitmap >>= 1; } info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); memset(&info->status, 0, sizeof(info->status)); info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { - info->status.ampdu_ack_len = ba_resp->txed_2_done; - info->status.ampdu_len = ba_resp->txed; - - } else { - info->status.ampdu_ack_len = successes; - info->status.ampdu_len = agg->frame_count; - } + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 24dabcd2a36c..8bda0e8d6661 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, } static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) + struct fw_img *image) { int ret = 0; - ret = iwlagn_load_section(priv, "INST", inst_image, + ret = iwlagn_load_section(priv, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(priv, "DATA", data_image, + return iwlagn_load_section(priv, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } -int iwlagn_load_ucode(struct iwl_priv *priv) -{ - int ret = 0; - - /* check whether init ucode should be loaded, or rather runtime ucode */ - if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { - IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_init, &priv->ucode_init_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); - priv->ucode_type = UCODE_INIT; - } - } else { - IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " - "Loading runtime ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_code, &priv->ucode_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); - priv->ucode_type = UCODE_RT; - } - } - - return ret; -} - /* * Calibration */ @@ -297,41 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +int iwlagn_init_alive_start(struct iwl_priv *priv) { - IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); - queue_work(priv->workqueue, &priv->restart); -} - -void iwlagn_init_alive_start(struct iwl_priv *priv) -{ - int ret = 0; - - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); - goto restart; - } - - /* initialize uCode was loaded... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - ret = priv->cfg->ops->lib->alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition: %d\n", ret); - goto restart; - } + int ret; if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { @@ -341,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) * no need to close the envlope since we are going * to load the runtime uCode later. */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } - iwlagn_send_calib_cfg(priv); + + ret = iwlagn_send_calib_cfg(priv); + if (ret) + return ret; /** * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ if (priv->cfg->need_temp_offset_calib) - iwlagn_set_temperature_offset_calib(priv); - - return; + return iwlagn_set_temperature_offset_calib(priv); -restart: - /* real restart (first load init_ucode) */ - queue_work(priv->workqueue, &priv->restart); + return 0; } static int iwlagn_send_wimax_coex(struct iwl_priv *priv) @@ -421,25 +362,30 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) IWL_ERR(priv, "failed to send BT prio tbl command\n"); } -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; + int ret; env_cmd.action = action; env_cmd.type = type; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, - sizeof(env_cmd), &env_cmd)) + ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, + sizeof(env_cmd), &env_cmd); + if (ret) IWL_ERR(priv, "failed to send BT env command\n"); + return ret; } -int iwlagn_alive_notify(struct iwl_priv *priv) +static int iwlagn_alive_notify(struct iwl_priv *priv) { const struct queue_to_fifo_ac *queue_to_fifo; + struct iwl_rxon_context *ctx; u32 a; unsigned long flags; int i, chan; u32 reg_val; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -508,6 +454,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv) memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); for (i = 0; i < 4; i++) atomic_set(&priv->queue_stop_count[i], 0); + for_each_context(priv, ctx) + ctx->last_tx_rejected = false; /* reset to 0 to enable all the queue first */ priv->txq_ctx_active_msk = 0; @@ -535,12 +483,15 @@ int iwlagn_alive_notify(struct iwl_priv *priv) iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwlagn_send_wimax_coex(priv); + ret = iwlagn_send_wimax_coex(priv); + if (ret) + return ret; - iwlagn_set_Xtal_calib(priv); - iwl_send_calib_results(priv); + ret = iwlagn_set_Xtal_calib(priv); + if (ret) + return ret; - return 0; + return iwl_send_calib_results(priv); } @@ -549,11 +500,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - int ret = 0; - u32 errcnt = 0; u32 i; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); @@ -564,104 +516,204 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - ret = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) + return -EIO; } - return ret; + return 0; } -/** - * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) +static void iwl_print_mismatch_inst(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - u32 save_len = len; - int ret = 0; - u32 errcnt; + u32 offs; + int errors = 0; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { + for (offs = 0; + offs < len && errors < 20; + offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - ret = -EIO; - errcnt++; - if (errcnt >= 20) - break; + IWL_ERR(priv, "uCode INST section at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + offs, val, le32_to_cpu(*image)); + errors++; } } - - if (!errcnt) - IWL_DEBUG_INFO(priv, - "ucode image in INSTRUCTION memory is good\n"); - - return ret; } /** * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv) +static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) +{ + if (!iwlcore_verify_inst_sparse(priv, &img->code)) { + IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + + iwl_print_mismatch_inst(priv, &img->code); + return -EIO; +} + +struct iwlagn_alive_data { + bool valid; + u8 subtype; +}; + +static void iwlagn_alive_fn(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data) { - __le32 *image; - u32 len; + struct iwlagn_alive_data *alive_data = data; + struct iwl_alive_resp *palive; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + priv->device_pointers.log_event_table = + le32_to_cpu(palive->log_event_table_ptr); + + alive_data->subtype = palive->ver_subtype; + alive_data->valid = palive->is_valid == UCODE_VALID_OK; +} + +#define UCODE_ALIVE_TIMEOUT HZ +#define UCODE_CALIB_TIMEOUT (2*HZ) + +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype) +{ + struct iwl_notification_wait alive_wait; + struct iwlagn_alive_data alive_data; int ret; + enum iwlagn_ucode_subtype old_type; - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); - return 0; + ret = iwlagn_start_device(priv); + if (ret) + return ret; + + iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, + iwlagn_alive_fn, &alive_data); + + old_type = priv->ucode_type; + priv->ucode_type = subtype; + + ret = iwlagn_load_given_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + iwlagn_remove_notification(priv, &alive_wait); + return ret; } - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); - return 0; + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); + + /* + * Some things may run in the background now, but we + * just wait for the ALIVE notification here. + */ + ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); + if (ret) { + priv->ucode_type = old_type; + return ret; } - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); - return 0; + if (!alive_data.valid) { + IWL_ERR(priv, "Loaded ucode is not valid!\n"); + priv->ucode_type = old_type; + return -EIO; + } + + if (alive_data.subtype != subtype && + alive_data.subtype != alternate_subtype) { + IWL_ERR(priv, + "Loaded ucode is not expected type (got %d, expected %d)!\n", + alive_data.subtype, subtype); + priv->ucode_type = old_type; + return -EIO; + } + + ret = iwl_verify_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + return ret; } - IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + /* delay a bit to give rfkill time to run */ + msleep(5); + + ret = iwlagn_alive_notify(priv); + if (ret) { + IWL_WARN(priv, + "Could not complete ALIVE transition: %d\n", ret); + priv->ucode_type = old_type; + return ret; + } + + return 0; +} + +int iwlagn_run_init_ucode(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + lockdep_assert_held(&priv->mutex); + + /* No init ucode required? Curious, but maybe ok */ + if (!priv->ucode_init.code.len) + return 0; + + if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) + return 0; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + + /* Will also start the device */ + ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (ret) + goto error; + + ret = iwlagn_init_alive_start(priv); + if (ret) + goto error; + + /* + * Some things may run in the background now, but we + * just wait for the calibration complete notification. + */ + ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwl_verify_inst_full(priv, image, len); + goto out; + error: + iwlagn_remove_notification(priv, &calib_wait); + out: + /* Whatever happened, stop the device */ + iwlagn_stop_device(priv); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1cfd9952e52..3ecc3198d9bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -85,7 +85,6 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); -MODULE_ALIAS("iwl4965"); static int iwlagn_ant_coupling; static bool iwlagn_bt_ch_announce = 1; @@ -103,70 +102,6 @@ void iwl_update_chain_flags(struct iwl_priv *priv) } } -static void iwl_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO(priv, "%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_WARN(priv, "%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_ERR(priv, "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); -} - -static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - int left) -{ - lockdep_assert_held(&priv->mutex); - - if (!priv->beacon_skb) - return 0; - - if (priv->beacon_skb->len > left) - return 0; - - memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - - return priv->beacon_skb->len; -} - /* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ static void iwl_set_beacon_tim(struct iwl_priv *priv, struct iwl_tx_beacon_cmd *tx_beacon_cmd, @@ -194,13 +129,18 @@ static void iwl_set_beacon_tim(struct iwl_priv *priv, IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); } -static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame) +int iwlagn_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; + struct iwl_host_cmd cmd = { + .id = REPLY_TX_BEACON, + .flags = CMD_SIZE_HUGE, + }; u32 frame_size; u32 rate_flags; u32 rate; + int err; + /* * We have to set up the TX command, the TX Beacon command, and the * beacon contents. @@ -213,17 +153,19 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, return 0; } - /* Initialize memory */ - tx_beacon_cmd = &frame->u.beacon; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + if (WARN_ON(!priv->beacon_skb)) + return -EINVAL; + + /* Allocate beacon memory */ + tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len, + GFP_KERNEL); + if (!tx_beacon_cmd) + return -ENOMEM; + + frame_size = priv->beacon_skb->len; /* Set up TX beacon contents */ - frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) - return 0; - if (!frame_size) - return 0; + memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size); /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); @@ -246,35 +188,16 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); - return sizeof(*tx_beacon_cmd) + frame_size; -} - -int iwlagn_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - unsigned int frame_size; - int rc; - - frame = iwl_get_free_frame(priv); - if (!frame) { - IWL_ERR(priv, "Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } - - frame_size = iwl_hw_get_beacon_cmd(priv, frame); - if (!frame_size) { - IWL_ERR(priv, "Error configuring the beacon command\n"); - iwl_free_frame(priv, frame); - return -EINVAL; - } + /* Submit command */ + cmd.len = sizeof(*tx_beacon_cmd) + frame_size; + cmd.data = tx_beacon_cmd; - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); + err = iwl_send_cmd_sync(priv, &cmd); - iwl_free_frame(priv, frame); + /* Free temporary storage */ + kfree(tx_beacon_cmd); - return rc; + return err; } static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) @@ -395,7 +318,9 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, return -EINVAL; } - BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (WARN_ON(addr & ~DMA_BIT_MASK(36))) + return -EINVAL; + if (unlikely(addr & ~IWL_TX_DMA_MASK)) IWL_ERR(priv, "Unaligned address = %llx\n", (unsigned long long)addr); @@ -409,7 +334,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA * channels supported in hardware. */ int iwl_hw_tx_queue_init(struct iwl_priv *priv, @@ -424,47 +349,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, return 0; } -/****************************************************************************** - * - * Generic RX handler implementations - * - ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else - IWL_WARN(priv, "uCode did not respond OK.\n"); -} - static void iwl_bg_beacon_update(struct work_struct *work) { struct iwl_priv *priv = @@ -524,12 +408,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) container_of(work, struct iwl_priv, bt_full_concurrency); struct iwl_rxon_context *ctx; + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) - return; + goto out; IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", priv->bt_full_concurrent ? @@ -539,15 +425,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) * LQ & RXON updated cmds must be sent before BT Config cmd * to avoid 3-wire collisions */ - mutex_lock(&priv->mutex); for_each_context(priv, ctx) { if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); iwlcore_commit_rxon(priv, ctx); } - mutex_unlock(&priv->mutex); priv->cfg->ops->hcmd->send_bt_config(priv); +out: + mutex_unlock(&priv->mutex); } /** @@ -597,7 +483,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* @@ -605,13 +491,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event(priv, time, data, ev); } @@ -629,10 +515,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + base = priv->device_pointers.error_event_table; if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { capacity = iwl_read_targ_mem(priv, base); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); @@ -699,83 +582,6 @@ static void iwl_bg_ucode_trace(unsigned long data) } } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl4965_beacon_notif *beacon = - (struct iwl4965_beacon_notif *)pkt->u.raw; -#ifdef CONFIG_IWLWIFI_DEBUG - u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); - - IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d " - "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, - beacon->beacon_notify_hdr.failure_frame, - le32_to_cpu(beacon->ibss_mgr_status), - le32_to_cpu(beacon->high_tsf), - le32_to_cpu(beacon->low_tsf), rate); -#endif - - priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - queue_work(priv->workqueue, &priv->beacon_update); -} - -/* Handle notification from uCode that card's power state is changing - * due to software, hardware, or critical temperature RFKILL */ -static void iwl_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); - unsigned long status = priv->status; - - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", - (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On", - (flags & CT_CARD_DISABLED) ? - "Reached" : "Not reached"); - - if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | - CT_CARD_DISABLED)) { - - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - iwl_write_direct32(priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - } - if (flags & CT_CARD_DISABLED) - iwl_tt_enter_ct_kill(priv); - } - if (!(flags & CT_CARD_DISABLED)) - iwl_tt_exit_ct_kill(priv); - - if (flags & HW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - - if (!(flags & RXON_CARD_DISABLED)) - iwl_scan_cancel(priv); - - if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status))) - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); - else - wake_up_interruptible(&priv->wait_command_queue); -} - static void iwl_bg_tx_flush(struct work_struct *work) { struct iwl_priv *priv = @@ -795,58 +601,13 @@ static void iwl_bg_tx_flush(struct work_struct *work) } /** - * iwl_setup_rx_handlers - Initialize Rx handler callbacks - * - * Setup the RX handlers for each of the reply types sent from the uCode - * to the host. - * - * This function chains into the hardware specific files for them to setup - * any hardware specific handlers as well. - */ -static void iwl_setup_rx_handlers(struct iwl_priv *priv) -{ - priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; - priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; - - /* - * The same handler is used for both the REPLY to a discrete - * statistics request from the host as well as for the periodic - * statistics notifications (after received beacons) from the uCode. - */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; - - iwl_setup_rx_scan_handlers(priv); - - /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; - - priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = - iwl_rx_missed_beacon_notif; - /* Rx handlers */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx; - /* block ack */ - priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; - /* Set up hardware specific Rx handlers */ - priv->cfg->ops->lib->rx_handler_setup(priv); -} - -/** * iwl_rx_handle - Main entry function for receiving responses from uCode * * Uses the priv->rx_handlers callback function array to invoke * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -void iwl_rx_handle(struct iwl_priv *priv) +static void iwl_rx_handle(struct iwl_priv *priv) { struct iwl_rx_mem_buffer *rxb; struct iwl_rx_packet *pkt; @@ -883,7 +644,10 @@ void iwl_rx_handle(struct iwl_priv *priv) /* If an RXB doesn't have a Rx queue slot associated with it, * then a bug has been introduced in the queue refilling * routines -- catch it here */ - BUG_ON(rxb == NULL); + if (WARN_ON(rxb == NULL)) { + i = (i + 1) & RX_QUEUE_MASK; + continue; + } rxq->queue[i] = NULL; @@ -910,6 +674,29 @@ void iwl_rx_handle(struct iwl_priv *priv) (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); + /* + * Do the notification wait before RX handlers so + * even if the RX handler consumes the RXB we have + * access to it in the notification wait entry. + */ + if (!list_empty(&priv->_agn.notif_waits)) { + struct iwl_notification_wait *w; + + spin_lock(&priv->_agn.notif_wait_lock); + list_for_each_entry(w, &priv->_agn.notif_waits, list) { + if (w->cmd == pkt->hdr.cmd) { + w->triggered = true; + if (w->fn) + w->fn(priv, pkt, w->fn_data); + } + } + spin_unlock(&priv->_agn.notif_wait_lock); + + wake_up_all(&priv->_agn.notif_waitq); + } + if (priv->pre_rx_handler) + priv->pre_rx_handler(priv, rxb); + /* Based on type of command response or notification, * handle those that need handling via function in * rx_handlers table. See iwl_setup_rx_handlers() */ @@ -979,199 +766,6 @@ void iwl_rx_handle(struct iwl_priv *priv) iwlagn_rx_queue_restock(priv); } -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - -static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; - u32 i; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR49_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR49_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - priv->isr_stats.rfkill++; - - /* driver only loads ucode once setting the interface up. - * the driver allows loading the ucode even if the radio - * is killed. Hence update the killswitch state here. The - * rfkill handler will care about restarting if needed. - */ - if (!test_bit(STATUS_ALIVE, &priv->status)) { - if (hw_rf_kill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERR(priv, "Microcode CT kill error detected.\n"); - priv->isr_stats.ctkill++; - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - " Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* - * uCode wakes up after power-down sleep. - * Tell device about any new tx or host commands enqueued, - * and about any Rx buffers made available while asleep. - */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - for (i = 0; i < priv->hw_params.max_txq_num; i++) - iwl_txq_update_write_ptr(priv, &priv->txq[i]); - priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl_rx_handle(priv); - priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - /* This "Tx" DMA channel is used only for loading uCode */ - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); - priv->isr_stats.tx++; - handled |= CSR_INT_BIT_FH_TX; - /* Wake up uCode load routine, now that load is complete */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~(priv->inta_mask)) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -1313,7 +907,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); iwl_write32(priv, CSR_FH_INT_STATUS, - CSR49_FH_INT_RX_MASK); + CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; @@ -1351,7 +945,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; @@ -1379,66 +973,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_enable_rfkill_int(priv); } -/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ -#define ACK_CNT_RATIO (50) -#define BA_TIMEOUT_CNT (5) -#define BA_TIMEOUT_MAX (16) - -/** - * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. - * - * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding - * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal - * operation state. - */ -bool iwl_good_ack_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) -{ - bool rc = true; - int actual_ack_cnt_delta, expected_ack_cnt_delta; - int ba_timeout_delta; - - actual_ack_cnt_delta = - le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - - le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt); - expected_ack_cnt_delta = - le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) - - le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt); - ba_timeout_delta = - le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) - - le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout); - if ((priv->_agn.agg_tids_count > 0) && - (expected_ack_cnt_delta > 0) && - (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) - < ACK_CNT_RATIO) && - (ba_timeout_delta > BA_TIMEOUT_CNT)) { - IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d," - " expected_ack_cnt = %d\n", - actual_ack_cnt_delta, expected_ack_cnt_delta); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - /* - * This is ifdef'ed on DEBUGFS because otherwise the - * statistics aren't available. If DEBUGFS is set but - * DEBUG is not, these will just compile out. - */ - IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", - priv->_agn.delta_statistics.tx.rx_detected_cnt); - IWL_DEBUG_RADIO(priv, - "ack_or_ba_timeout_collision delta = %d\n", - priv->_agn.delta_statistics.tx. - ack_or_ba_timeout_collision); -#endif - IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", - ba_timeout_delta); - if (!actual_ack_cnt_delta && - (ba_timeout_delta >= BA_TIMEOUT_MAX)) - rc = false; - } - return rc; -} - - /***************************************************************************** * * sysfs attributes @@ -1559,26 +1093,48 @@ static struct attribute_group iwl_attribute_group = { * ******************************************************************************/ -static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); + if (desc->v_addr) + dma_free_coherent(&pci_dev->dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; } -static void iwl_nic_start(struct iwl_priv *priv) +static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img) { - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl_free_fw_desc(pci_dev, &img->code); + iwl_free_fw_desc(pci_dev, &img->data); +} + +static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc, + const void *data, size_t len) +{ + if (!len) { + desc->v_addr = NULL; + return -EINVAL; + } + + desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len, + &desc->p_addr, GFP_KERNEL); + if (!desc->v_addr) + return -ENOMEM; + desc->len = len; + memcpy(desc->v_addr, data, len); + return 0; +} + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt); + iwl_free_fw_img(priv->pci_dev, &priv->ucode_init); } struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; - bool pan; + u32 flags; }; static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); @@ -1624,8 +1180,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) } struct iwlagn_firmware_pieces { - const void *inst, *data, *init, *init_data, *boot; - size_t inst_size, data_size, init_size, init_data_size, boot_size; + const void *inst, *data, *init, *init_data; + size_t inst_size, data_size, init_size, init_data_size; u32 build; @@ -1646,28 +1202,18 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, switch (api_ver) { default: - /* - * 4965 doesn't revision the firmware file format - * along with the API version, it always uses v1 - * file format. - */ - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != - CSR_HW_REV_TYPE_4965) { - hdr_size = 28; - if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); - return -EINVAL; - } - pieces->build = le32_to_cpu(ucode->u.v2.build); - pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); - pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); - pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); - pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); - src = ucode->u.v2.data; - break; + hdr_size = 28; + if (ucode_raw->size < hdr_size) { + IWL_ERR(priv, "File size too small!\n"); + return -EINVAL; } - /* fall through for 4965 */ + pieces->build = le32_to_cpu(ucode->u.v2.build); + pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); + pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); + src = ucode->u.v2.data; + break; case 0: case 1: case 2: @@ -1681,7 +1227,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); src = ucode->u.v1.data; break; } @@ -1689,7 +1234,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != hdr_size + pieces->inst_size + pieces->data_size + pieces->init_size + - pieces->init_data_size + pieces->boot_size) { + pieces->init_data_size) { IWL_ERR(priv, "uCode file size %d does not match expected size\n", @@ -1705,8 +1250,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, src += pieces->init_size; pieces->init_data = src; src += pieces->init_data_size; - pieces->boot = src; - src += pieces->boot_size; return 0; } @@ -1807,8 +1350,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - pieces->boot = tlv_data; - pieces->boot_size = tlv_len; + IWL_ERR(priv, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -1819,7 +1361,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_PAN: if (tlv_len) goto invalid_tlv_len; - capa->pan = true; + capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; + break; + case IWL_UCODE_TLV_FLAGS: + /* must be at least one u32 */ + if (tlv_len < sizeof(u32)) + goto invalid_tlv_len; + /* and a proper number of u32s */ + if (tlv_len % sizeof(u32)) + goto invalid_tlv_len; + /* + * This driver only reads the first u32 as + * right now no more features are defined, + * if that changes then either the driver + * will not work with the new firmware, or + * it'll not take advantage of new features. + */ + capa->flags = le32_to_cpup((__le32 *)tlv_data); break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) @@ -1869,7 +1427,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, le32_to_cpup((__le32 *)tlv_data); break; default: - IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); + IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); break; } } @@ -2008,8 +1566,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_size); IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", - pieces.boot_size); /* Verify that uCode images will fit in card's SRAM */ if (pieces.inst_size > priv->hw_params.max_inst_size) { @@ -2036,48 +1592,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto try_again; } - if (pieces.boot_size > priv->hw_params.max_bsm_size) { - IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", - pieces.boot_size); - goto try_again; - } - /* Allocate ucode buffers for card's bus-master loading ... */ /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = pieces.inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - priv->ucode_data_backup.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_data_backup.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code, + pieces.inst, pieces.inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data, + pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - priv->ucode_init.len = pieces.init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = pieces.init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code, + pieces.init, pieces.init_size)) goto err_pci_alloc; - } - - /* Bootstrap (instructions only, no data) */ - if (pieces.boot_size) { - priv->ucode_boot.len = pieces.boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data, + pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } @@ -2103,50 +1636,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; - if (ucode_capa.pan) { + priv->new_scan_threshold_behaviour = + !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; } else priv->sta_key_max_num = STA_KEY_MAX_NUM; - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", - pieces.inst_size); - memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size); - - IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* - * Runtime data - * NOTE: Copy into backup buffer will be done in iwl_up() - */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", - pieces.data_size); - memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); - - /* Initialization instructions */ - if (pieces.init_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", - pieces.init_size); - memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size); - } - - /* Initialization data */ - if (pieces.init_data_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", - pieces.init_data_size); - memcpy(priv->ucode_init_data.v_addr, pieces.init_data, - pieces.init_data_size); - } - - /* Bootstrap instructions */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", - pieces.boot_size); - memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); + if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) + priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + else + priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; /* * figure out the offset of chain noise reset and gain commands @@ -2278,13 +1780,13 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + struct iwl_error_event_table table; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + base = priv->device_pointers.error_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_errlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!base) base = priv->_agn.inst_errlog_ptr; } @@ -2292,11 +1794,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return; } - count = iwl_read_targ_mem(priv, base); + iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); + + count = table.valid; if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERR(priv, "Start IWL Error Log Dump:\n"); @@ -2304,18 +1810,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, count); } - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + desc = table.error_id; priv->isr_stats.err_code = desc; - pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); + pc = table.pc; + blink1 = table.blink1; + blink2 = table.blink2; + ilink1 = table.ilink1; + ilink2 = table.ilink2; + data1 = table.data1; + data2 = table.data2; + line = table.line; + time = table.tsf_low; + hcmd = table.hcmd; trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, blink1, blink2, ilink1, ilink2); @@ -2349,12 +1855,11 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return pos; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!base) base = priv->_agn.inst_evtlog_ptr; } @@ -2371,14 +1876,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, iwl_grab_nic_access(priv); /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -2392,7 +1897,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time, ev); } } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -2463,13 +1968,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, int pos = 0; size_t bufsz = 0; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); logsize = priv->_agn.inst_evtlog_size; if (!base) base = priv->_agn.inst_evtlog_ptr; @@ -2478,7 +1982,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return -EINVAL; } @@ -2625,37 +2131,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +int iwl_alive_start(struct iwl_priv *priv) { int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - - if (priv->card_alive.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Alive failed.\n"); - goto restart; - } - - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); - goto restart; - } - - ret = priv->cfg->ops->lib->alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition [ntf]: %d\n", ret); - goto restart; - } + iwl_reset_ict(priv); + IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); @@ -2664,7 +2147,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_setup_watchdog(priv); if (iwl_is_rfkill(priv)) - return; + return -ERFKILL; /* download priority table before any calibration request */ if (priv->cfg->bt_params && @@ -2678,10 +2161,14 @@ static void iwl_alive_start(struct iwl_priv *priv) iwlagn_send_prio_tbl(priv); /* FIXME: w/a to force change uCode BT state machine */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } if (priv->hw_params.calib_rt_cfg) iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); @@ -2710,9 +2197,11 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); } - if (priv->cfg->bt_params && - !priv->cfg->bt_params->advanced_bt_coexist) { - /* Configure Bluetooth device coexistence support */ + if (!priv->cfg->bt_params || (priv->cfg->bt_params && + !priv->cfg->bt_params->advanced_bt_coexist)) { + /* + * default is 2-wire BT coexexistence support + */ priv->cfg->ops->hcmd->send_bt_config(priv); } @@ -2721,32 +2210,23 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); /* Configure the adapter for unassociated operation */ - iwlcore_commit_rxon(priv, ctx); + ret = iwlcore_commit_rxon(priv, ctx); + if (ret) + return ret; /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); - iwl_leds_init(priv); - IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); - - iwl_power_update_mode(priv, true); - IWL_DEBUG_INFO(priv, "Updated power mode\n"); - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); + return iwl_power_update_mode(priv, true); } static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { - unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2769,44 +2249,18 @@ static void __iwl_down(struct iwl_priv *priv) priv->cfg->bt_params->bt_init_traffic_load; else priv->bt_traffic_load = 0; - priv->bt_sco_active = false; priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ if (!exit_pending) clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bit and return */ - if (!iwl_is_init(priv)) { - priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill - * bit and continue taking the NIC down. */ + /* Clear out all status bits but a few that are stable across reset */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << @@ -2816,31 +2270,10 @@ static void __iwl_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - /* device going down, Stop using ICT table */ - if (priv->cfg->ops->lib->isr_ops.disable) - priv->cfg->ops->lib->isr_ops.disable(priv); - - iwlagn_txq_ctx_stop(priv); - iwlagn_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - - /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); - - exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + iwlagn_stop_device(priv); dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; - - /* clear out any free frames */ - iwl_clear_free_frames(priv); } static void iwl_down(struct iwl_priv *priv) @@ -2854,9 +2287,10 @@ static void iwl_down(struct iwl_priv *priv) #define HW_READY_TIMEOUT (50) +/* Note: returns poll_bit return value, which is >= 0 if success */ static int iwl_set_hw_ready(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); @@ -2866,25 +2300,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); - if (ret != -ETIMEDOUT) - priv->hw_ready = true; - else - priv->hw_ready = false; - IWL_DEBUG_INFO(priv, "hardware %s\n", - (priv->hw_ready == 1) ? "ready" : "not ready"); + IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); return ret; } -static int iwl_prepare_card_hw(struct iwl_priv *priv) +/* Note: returns standard 0/-ERROR code */ +int iwl_prepare_card_hw(struct iwl_priv *priv) { - int ret = 0; + int ret; IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n"); ret = iwl_set_hw_ready(priv); - if (priv->hw_ready) - return ret; + if (ret >= 0) + return 0; /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, @@ -2894,10 +2324,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); - /* HW should be ready by now, check again. */ - if (ret != -ETIMEDOUT) - iwl_set_hw_ready(priv); + if (ret < 0) + return ret; + /* HW should be ready by now, check again. */ + ret = iwl_set_hw_ready(priv); + if (ret >= 0) + return 0; return ret; } @@ -2906,19 +2339,15 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; - int i; int ret; + lockdep_assert_held(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); return -EIO; } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERR(priv, "ucode not available for device bringup\n"); - return -EIO; - } - for_each_context(priv, ctx) { ret = iwlagn_alloc_bcast_station(priv, ctx); if (ret) { @@ -2927,89 +2356,33 @@ static int __iwl_up(struct iwl_priv *priv) } } - iwl_prepare_card_hw(priv); - - if (!priv->hw_ready) { - IWL_WARN(priv, "Exit HW not ready\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (iwl_is_rfkill(priv)) { - wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); - - iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return 0; + ret = iwlagn_run_init_ucode(priv); + if (ret) { + IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); + goto error; } - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - /* must be initialised before iwl_hw_nic_init */ - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - else - priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - - ret = iwlagn_hw_nic_init(priv); + ret = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); if (ret) { - IWL_ERR(priv, "Unable to init nic\n"); - return ret; + IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); + goto error; } - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - ret = priv->cfg->ops->lib->load_ucode(priv); - - if (ret) { - IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", - ret); - continue; - } - - /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); - - return 0; - } + ret = iwl_alive_start(priv); + if (ret) + goto error; + return 0; + error: set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); - return -EIO; + IWL_ERR(priv, "Unable to initialize device.\n"); + return ret; } @@ -3019,36 +2392,6 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - priv->cfg->ops->lib->init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* enable dram interrupt */ - if (priv->cfg->ops->lib->isr_ops.reset) - priv->cfg->ops->lib->isr_ops.reset(priv); - - mutex_lock(&priv->mutex); - iwl_alive_start(priv); - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -3063,23 +2406,49 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics_bt); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics_bt); - } else { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics); - } + iwl_chain_noise_calibration(priv); + iwl_sensitivity_calibration(priv); } mutex_unlock(&priv->mutex); } +static void iwlagn_prepare_restart(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + bool bt_full_concurrent; + u8 bt_ci_compliance; + u8 bt_load; + u8 bt_status; + + lockdep_assert_held(&priv->mutex); + + for_each_context(priv, ctx) + ctx->vif = NULL; + priv->is_open = 0; + + /* + * __iwl_down() will clear the BT status variables, + * which is correct, but when we restart we really + * want to keep them so restore them afterwards. + * + * The restart process will later pick them up and + * re-configure the hw when we reconfigure the BT + * command. + */ + bt_full_concurrent = priv->bt_full_concurrent; + bt_ci_compliance = priv->bt_ci_compliance; + bt_load = priv->bt_traffic_load; + bt_status = priv->bt_status; + + __iwl_down(priv); + + priv->bt_full_concurrent = bt_full_concurrent; + priv->bt_ci_compliance = bt_ci_compliance; + priv->bt_traffic_load = bt_load; + priv->bt_status = bt_status; +} + static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -3088,52 +2457,13 @@ static void iwl_bg_restart(struct work_struct *data) return; if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - struct iwl_rxon_context *ctx; - bool bt_sco, bt_full_concurrent; - u8 bt_ci_compliance; - u8 bt_load; - u8 bt_status; - mutex_lock(&priv->mutex); - for_each_context(priv, ctx) - ctx->vif = NULL; - priv->is_open = 0; - - /* - * __iwl_down() will clear the BT status variables, - * which is correct, but when we restart we really - * want to keep them so restore them afterwards. - * - * The restart process will later pick them up and - * re-configure the hw when we reconfigure the BT - * command. - */ - bt_sco = priv->bt_sco_active; - bt_full_concurrent = priv->bt_full_concurrent; - bt_ci_compliance = priv->bt_ci_compliance; - bt_load = priv->bt_traffic_load; - bt_status = priv->bt_status; - - __iwl_down(priv); - - priv->bt_sco_active = bt_sco; - priv->bt_full_concurrent = bt_full_concurrent; - priv->bt_ci_compliance = bt_ci_compliance; - priv->bt_traffic_load = bt_load; - priv->bt_status = bt_status; - + iwlagn_prepare_restart(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); } else { - iwl_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); + WARN_ON(1); } } @@ -3150,14 +2480,100 @@ static void iwl_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } +static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int wait) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + /* Not supported if we don't have PAN */ + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) { + ret = -EOPNOTSUPP; + goto free; + } + + /* Not supported on pre-P2P firmware */ + if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & + BIT(NL80211_IFTYPE_P2P_CLIENT))) { + ret = -EOPNOTSUPP; + goto free; + } + + mutex_lock(&priv->mutex); + + if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) { + /* + * If the PAN context is free, use the normal + * way of doing remain-on-channel offload + TX. + */ + ret = 1; + goto out; + } + + /* TODO: queue up if scanning? */ + if (test_bit(STATUS_SCANNING, &priv->status) || + priv->_agn.offchan_tx_skb) { + ret = -EBUSY; + goto out; + } + + /* + * max_scan_ie_len doesn't include the blank SSID or the header, + * so need to add that again here. + */ + if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) { + ret = -ENOBUFS; + goto out; + } + + priv->_agn.offchan_tx_skb = skb; + priv->_agn.offchan_tx_timeout = wait; + priv->_agn.offchan_tx_chan = chan; + + ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif, + IWL_SCAN_OFFCH_TX, chan->band); + if (ret) + priv->_agn.offchan_tx_skb = NULL; + out: + mutex_unlock(&priv->mutex); + free: + if (ret < 0) + kfree_skb(skb); + + return ret; +} + +static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + mutex_lock(&priv->mutex); + + if (!priv->_agn.offchan_tx_skb) { + ret = -EINVAL; + goto unlock; + } + + priv->_agn.offchan_tx_skb = NULL; + + ret = iwl_scan_cancel_timeout(priv, 200); + if (ret) + ret = -EIO; +unlock: + mutex_unlock(&priv->mutex); + + return ret; +} + /***************************************************************************** * * mac80211 entry point functions * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (4 * HZ) - /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -3178,14 +2594,18 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS; - if (!priv->cfg->base_params->broken_powersave) - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (priv->cfg->sku & IWL_SKU_N) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; + if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->vif_data_size = sizeof(struct iwl_vif_priv); @@ -3194,8 +2614,11 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; } + hw->wiphy->max_remain_on_channel_duration = 1000; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS; + WIPHY_FLAG_DISABLE_BEACON_HINTS | + WIPHY_FLAG_IBSS_RSN; /* * For now, disable PS by default because it affects @@ -3219,6 +2642,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; + iwl_leds_init(priv); + ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); @@ -3230,7 +2655,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, } -int iwlagn_mac_start(struct ieee80211_hw *hw) +static int iwlagn_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -3241,37 +2666,23 @@ int iwlagn_mac_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); ret = __iwl_up(priv); mutex_unlock(&priv->mutex); - if (ret) return ret; - if (iwl_is_rfkill(priv)) - goto out; - IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - return -ETIMEDOUT; - } - } + /* Now we should be done, and the READY bit should be set. */ + if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) + ret = -EIO; - iwl_led_start(priv); + iwlagn_led_enable(priv); -out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } -void iwlagn_mac_stop(struct ieee80211_hw *hw) +static void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3294,7 +2705,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3307,14 +2718,13 @@ int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb_any(skb); IWL_DEBUG_MACDUMP(priv, "leave\n"); - return NETDEV_TX_OK; } -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3327,9 +2737,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3340,11 +2751,19 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (iwlagn_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } + /* + * To support IBSS RSN, don't program group keys in IBSS, the + * hardware will then not attempt to decrypt the frames. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta); if (sta_id == IWL_INVALID_STATION) return -EINVAL; @@ -3396,13 +2815,15 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) +static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); @@ -3457,11 +2878,32 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + + iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); + + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the + * minimum below, and we don't want to go above our + * default due to hardware restrictions. + */ + if (sta_priv->max_agg_bufsize == 0) + sta_priv->max_agg_bufsize = + LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + /* + * Even though in theory the peer could have different + * aggregation reorder buffer sizes for different sessions, + * our ucode doesn't allow for that and has a global limit + * for each station. Therefore, use the minimum of all the + * aggregation sessions and our default value. + */ + sta_priv->max_agg_bufsize = + min(sta_priv->max_agg_bufsize, buf_size); + if (priv->cfg->ht_params && priv->cfg->ht_params->use_rts_for_aggregation) { - struct iwl_station_priv *sta_priv = - (void *) sta->drv_priv; - /* * switch to RTS/CTS if it is the prefer protection * method for HT traffic @@ -3469,9 +2911,13 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, sta_priv->lq_sta.lq.general_params.flags |= LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); } + + sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize; + + iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), + &sta_priv->lq_sta.lq, CMD_ASYNC, false); ret = 0; break; } @@ -3480,9 +2926,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3523,8 +2969,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -3545,21 +2991,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -3615,16 +3062,15 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 filter_or = 0, filter_nand = 0; @@ -3671,7 +3117,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -3709,6 +3155,95 @@ done: IWL_DEBUG_MAC80211(priv, "leave\n"); } +static void iwlagn_disable_roc(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel); + + lockdep_assert_held(&priv->mutex); + + if (!ctx->is_active) + return; + + ctx->staging.dev_type = RXON_DEV_TYPE_2STA; + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_set_rxon_channel(priv, chan, ctx); + iwl_set_flags_for_band(priv, ctx, chan->band, NULL); + + priv->_agn.hw_roc_channel = NULL; + + iwlcore_commit_rxon(priv, ctx); + + ctx->is_active = false; +} + +static void iwlagn_bg_roc_done(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + _agn.hw_roc_work.work); + + mutex_lock(&priv->mutex); + ieee80211_remain_on_channel_expired(priv->hw); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); +} + +static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + int duration) +{ + struct iwl_priv *priv = hw->priv; + int err = 0; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & + BIT(NL80211_IFTYPE_P2P_CLIENT))) + return -EOPNOTSUPP; + + mutex_lock(&priv->mutex); + + if (priv->contexts[IWL_RXON_CTX_PAN].is_active || + test_bit(STATUS_SCAN_HW, &priv->status)) { + err = -EBUSY; + goto out; + } + + priv->contexts[IWL_RXON_CTX_PAN].is_active = true; + priv->_agn.hw_roc_channel = channel; + priv->_agn.hw_roc_chantype = channel_type; + priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); + iwlcore_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); + queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work, + msecs_to_jiffies(duration + 20)); + + msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ + ieee80211_ready_on_channel(priv->hw); + + out: + mutex_unlock(&priv->mutex); + + return err; +} + +static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + cancel_delayed_work_sync(&priv->_agn.hw_roc_work); + + mutex_lock(&priv->mutex); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + /***************************************************************************** * * driver setup and teardown @@ -3728,8 +3263,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3748,12 +3282,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.data = (unsigned long)priv; priv->watchdog.function = iwl_bg_watchdog; - if (!priv->cfg->base_params->use_isr_legacy) - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); - else - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet_legacy, (unsigned long)priv); + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -3761,8 +3291,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) if (priv->cfg->ops->lib->cancel_deferred_work) priv->cfg->ops->lib->cancel_deferred_work(priv); - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->run_time_calib_work); cancel_work_sync(&priv->beacon_update); @@ -3803,10 +3331,7 @@ static int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - INIT_LIST_HEAD(&priv->free_frames); - mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3823,6 +3348,8 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->force_reset[IWL_FW_RESET].reset_duration = IWL_DELAY_NEXT_FORCE_FW_RELOAD; + priv->rx_statistics_jiffies = jiffies; + /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, @@ -3841,12 +3368,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; } - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; - ret = iwl_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); @@ -3876,7 +3397,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kfree(priv->scan_cmd); } -#ifdef CONFIG_IWL5000 struct ieee80211_ops iwlagn_hw_ops = { .tx = iwlagn_mac_tx, .start = iwlagn_mac_start, @@ -3898,29 +3418,34 @@ struct ieee80211_ops iwlagn_hw_ops = { .channel_switch = iwlagn_mac_channel_switch, .flush = iwlagn_mac_flush, .tx_last_beacon = iwl_mac_tx_last_beacon, + .remain_on_channel = iwl_mac_remain_on_channel, + .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, + .offchannel_tx = iwl_mac_offchannel_tx, + .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, + CFG80211_TESTMODE_CMD(iwl_testmode_cmd) }; -#endif -static void iwl_hw_detect(struct iwl_priv *priv) +static u32 iwl_hw_detect(struct iwl_priv *priv) { - priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); - priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); - pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + u8 rev_id; + + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); + return iwl_read32(priv, CSR_HW_REV); } static int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; - if (priv->cfg->mod_params->disable_11n) + if (iwlagn_mod_params.disable_11n) priv->cfg->sku &= ~IWL_SKU_N; /* Device-specific setup */ @@ -3949,6 +3474,28 @@ static const u8 iwlagn_pan_ac_to_queue[] = { 7, 6, 5, 4, }; +/* This function both allocates and initializes hw and priv. */ +static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) +{ + struct iwl_priv *priv; + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); + if (hw == NULL) { + pr_err("%s: Can not allocate network device\n", + cfg->name); + goto out; + } + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} + static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0, i; @@ -3957,24 +3504,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; u16 pci_cmd, num_mac; + u32 hw_rev; /************************ * 1. Allocating HW data ************************/ - /* Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. */ - if (cfg->mod_params->disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); -#ifdef CONFIG_IWL5000 - iwlagn_hw_ops.hw_scan = NULL; -#endif -#ifdef CONFIG_IWL4965 - iwl4965_hw_ops.hw_scan = NULL; -#endif - } - hw = iwl_alloc_all(cfg); if (!hw) { err = -ENOMEM; @@ -3983,6 +3518,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv = hw->priv; /* At this point both hw and priv are allocated. */ + priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED; + /* * The default context is always valid, * more may be discovered when firmware @@ -4025,6 +3562,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; priv->contexts[IWL_RXON_CTX_PAN].interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_IWL_P2P + priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); +#endif priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; @@ -4111,16 +3652,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - iwl_hw_detect(priv); + hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - priv->cfg->name, priv->hw_rev); + priv->cfg->name, hw_rev); /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - iwl_prepare_card_hw(priv); - if (!priv->hw_ready) { + if (iwl_prepare_card_hw(priv)) { IWL_WARN(priv, "Failed, HW not ready\n"); goto out_iounmap; } @@ -4129,7 +3669,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv); + err = iwl_eeprom_init(priv, hw_rev); if (err) { IWL_ERR(priv, "Unable to init EEPROM\n"); goto out_iounmap; @@ -4181,10 +3721,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - if (priv->cfg->ops->lib->isr_ops.alloc) - priv->cfg->ops->lib->isr_ops.alloc(priv); + iwl_alloc_isr_ict(priv); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, + err = request_irq(priv->pci_dev->irq, iwl_isr_ict, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -4193,6 +3732,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); + iwl_testmode_init(priv); /********************************************* * 8. Enable interrupts and read RFKILL state @@ -4231,8 +3771,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -4272,20 +3811,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_leds_exit(priv); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; - } else { - iwl_down(priv); } - /* - * Make sure device is reset to low power before unloading driver. - * This may be redundant with iwl_down(), but there are paths to - * run iwl_down() without calling apm_ops.stop(), and there are - * paths to avoid running iwl_down() at all before leaving driver. - * This (inexpensive) call *makes sure* device is reset. - */ + /* Reset to low power before unloading driver. */ iwl_apm_stop(priv); iwl_tt_exit(priv); @@ -4327,8 +3861,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); dev_kfree_skb(priv->beacon_skb); @@ -4344,12 +3877,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) /* Hardware specific file defines the PCI IDs table for that hardware module */ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { -#ifdef CONFIG_IWL4965 - {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, - {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, -#endif /* CONFIG_IWL4965 */ -#ifdef CONFIG_IWL5000 -/* 5100 Series WiFi */ {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */ @@ -4492,7 +4019,48 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)}, {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)}, -#endif /* CONFIG_IWL5000 */ +/* 2x00 Series */ + {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)}, + +/* 2x30 Series */ + {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)}, + +/* 6x35 Series */ + {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, + +/* 105 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, + +/* 135 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, {0} }; @@ -4542,43 +4110,21 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); -MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); -MODULE_PARM_DESC(swcrypto50, - "using crypto in software (default 0 [hardware]) (deprecated)"); module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(queues_num50, - iwlagn_mod_params.num_of_queues, int, S_IRUGO); -MODULE_PARM_DESC(queues_num50, - "number of hw queues in 50xx series (deprecated)"); module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); -MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, - int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K50, - "enable 8K amsdu size in 50XX series (deprecated)"); module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart50, - "restart firmware in case of error (deprecated)"); module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); -module_param_named( - disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, S_IRUGO); @@ -4592,3 +4138,9 @@ MODULE_PARM_DESC(antenna_coupling, module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO); MODULE_PARM_DESC(bt_ch_inhibition, "Disable BT channel inhibition (default: enable)"); + +module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO); +MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); + +module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); +MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index da303585f801..fe33fe8aa418 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ #include "iwl-dev.h" /* configuration for the _agn devices */ -extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; @@ -96,6 +95,17 @@ extern struct iwl_cfg iwl100_bgn_cfg; extern struct iwl_cfg iwl100_bg_cfg; extern struct iwl_cfg iwl130_bgn_cfg; extern struct iwl_cfg iwl130_bg_cfg; +extern struct iwl_cfg iwl2000_2bgn_cfg; +extern struct iwl_cfg iwl2000_2bg_cfg; +extern struct iwl_cfg iwl2030_2bgn_cfg; +extern struct iwl_cfg iwl2030_2bg_cfg; +extern struct iwl_cfg iwl6035_2agn_cfg; +extern struct iwl_cfg iwl6035_2abg_cfg; +extern struct iwl_cfg iwl6035_2bg_cfg; +extern struct iwl_cfg iwl105_bg_cfg; +extern struct iwl_cfg iwl105_bgn_cfg; +extern struct iwl_cfg iwl135_bg_cfg; +extern struct iwl_cfg iwl135_bgn_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; @@ -103,15 +113,25 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; extern struct ieee80211_ops iwlagn_hw_ops; -extern struct ieee80211_ops iwl4965_hw_ops; int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); int iwl_alloc_isr_ict(struct iwl_priv *priv); void iwl_free_isr_ict(struct iwl_priv *priv); irqreturn_t iwl_isr_ict(int irq, void *data); -bool iwl_good_ack_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt); + +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + +int iwl_prepare_card_hw(struct iwl_priv *priv); + +int iwlagn_start_device(struct iwl_priv *priv); +void iwlagn_stop_device(struct iwl_priv *priv); /* tx queue */ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, @@ -119,15 +139,6 @@ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, void iwlagn_tx_queue_set_status(struct iwl_priv *priv, struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry); -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx); -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); @@ -142,16 +153,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); /* uCode */ -int iwlagn_load_ucode(struct iwl_priv *priv); void iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_init_alive_start(struct iwl_priv *priv); -int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv); -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); +int iwlagn_run_init_ucode(struct iwl_priv *priv); +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype); /* lib */ void iwl_check_abort_status(struct iwl_priv *priv, @@ -170,8 +179,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); -void iwl_dump_csr(struct iwl_priv *priv); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); /* rx */ void iwlagn_rx_queue_restock(struct iwl_priv *priv); @@ -181,11 +188,7 @@ void iwlagn_rx_replenish_now(struct iwl_priv *priv); void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwlagn_rxq_stop(struct iwl_priv *priv); int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); -void iwlagn_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl_rx_handle(struct iwl_priv *priv); +void iwl_setup_rx_handlers(struct iwl_priv *priv); /* tx */ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); @@ -201,6 +204,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit); int iwlagn_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, @@ -220,6 +226,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status) case TX_STATUS_DIRECT_DONE: return IEEE80211_TX_STAT_ACK; case TX_STATUS_FAIL_DEST_PS: + case TX_STATUS_FAIL_PASSIVE_NO_RX: return IEEE80211_TX_STAT_TX_FILTERED; default: return 0; @@ -235,16 +242,6 @@ static inline bool iwl_is_tx_success(u32 status) u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); -/* rx */ -void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -bool iwl_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt); -void iwl_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); - /* scan */ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwlagn_post_scan(struct iwl_priv *priv); @@ -254,8 +251,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add); /* hcmd */ -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); @@ -316,7 +311,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { - return le32_to_cpu(rate_n_flags) & 0xFF; + return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; } static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) @@ -327,34 +322,39 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) /* eeprom */ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); -/* mac80211 handlers (for 4965) */ -int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int iwlagn_mac_start(struct ieee80211_hw *hw); -void iwlagn_mac_stop(struct ieee80211_hw *hw); -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast); -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key); -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn); -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch); -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); +/* notification wait support */ +void __acquires(wait_entry) +iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + u8 cmd, + void (*fn)(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data), + void *fn_data); +int __must_check __releases(wait_entry) +iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout); +void __releases(wait_entry) +iwlagn_remove_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry); +extern int iwlagn_init_alive_start(struct iwl_priv *priv); +extern int iwl_alive_start(struct iwl_priv *priv); +/* svtool */ +#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); +extern void iwl_testmode_init(struct iwl_priv *priv); +#else +static inline +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + return -ENOSYS; +} +static inline +void iwl_testmode_init(struct iwl_priv *priv) +{ +} +#endif #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f893d4a6aa87..5fdad6532118 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,9 +103,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ - REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, - REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ @@ -178,7 +176,6 @@ enum { REPLY_BT_COEX_PRIO_TABLE = 0xcc, REPLY_BT_COEX_PROT_ENV = 0xcd, REPLY_BT_COEX_PROFILE_NOTIF = 0xce, - REPLY_BT_COEX_SCO = 0xcf, /* PAN commands */ REPLY_WIPAN_PARAMS = 0xb2, @@ -189,6 +186,7 @@ enum { REPLY_WIPAN_WEPKEY = 0xb8, /* use REPLY_WEPKEY structure */ REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9, REPLY_WIPAN_NOA_NOTIFICATION = 0xbc, + REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd, REPLY_MAX = 0xff }; @@ -229,7 +227,7 @@ struct iwl_cmd_header { * There is one exception: uCode sets bit 15 when it originates * the response/notification, i.e. when the response/notification * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_3945_RX when it sends a received frame + * example, uCode issues REPLY_RX when it sends a received frame * to the driver; it is not a direct response to any driver command. * * The Linux driver uses the following format: @@ -249,36 +247,6 @@ struct iwl_cmd_header { /** - * struct iwl3945_tx_power - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH - * - * Each entry contains two values: - * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained - * linear value that multiplies the output of the digital signal processor, - * before being sent to the analog radio. - * 2) Radio gain. This sets the analog gain of the radio Tx path. - * It is a coarser setting, and behaves in a logarithmic (dB) fashion. - * - * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. - */ -struct iwl3945_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __packed; - -/** - * struct iwl3945_power_per_rate - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl3945_power_per_rate { - u8 rate; /* plcp */ - struct iwl3945_tx_power tpc; - u8 reserved; -} __packed; - -/** * iwlagn rate_n_flags bit fields * * rate_n_flags format is used in following iwlagn commands: @@ -324,6 +292,8 @@ struct iwl3945_power_per_rate { #define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 +/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ +#define RATE_MCS_RATE_MSK 0xff /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ #define RATE_MCS_FLAGS_POS 8 @@ -375,30 +345,6 @@ struct iwl3945_power_per_rate { #define IWL_PWR_CCK_ENTRIES 2 /** - * union iwl4965_tx_power_dual_stream - * - * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * Use __le32 version (struct tx_power_dual_stream) when building command. - * - * Driver provides radio gain and DSP attenuation settings to device in pairs, - * one value for each transmitter chain. The first value is for transmitter A, - * second for transmitter B. - * - * For SISO bit rates, both values in a pair should be identical. - * For MIMO rates, one value may be different from the other, - * in order to balance the Tx output between the two transmitters. - * - * See more details in doc for TXPOWER in iwl-4965-hw.h. - */ -union iwl4965_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; -}; - -/** * struct tx_power_dual_stream * * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH @@ -410,15 +356,6 @@ struct tx_power_dual_stream { } __packed; /** - * struct iwl4965_tx_power_db - * - * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl4965_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __packed; - -/** * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwlagn_tx_power_dbm_cmd */ @@ -449,55 +386,18 @@ struct iwl_tx_ant_config_cmd { *****************************************************************************/ #define UCODE_VALID_OK cpu_to_le32(0x1) -#define INITIALIZE_SUBTYPE (9) - -/* - * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "initialize alive" notification once the initialization - * uCode image has completed its work, and is ready to load the runtime image. - * This is the *first* "alive" notification that the driver will receive after - * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * For 4965, this notification contains important calibration data for - * calculating txpower settings: - * - * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice verse. - * - * 2) Temperature measurement parameters, for each of two channel widths - * (20 MHz and 40 MHz) supported by the radios. Temperature sensing - * is done via one of the receiver chains, and channel width influences - * the results. - * - * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, - * for each of 5 frequency ranges. - */ -struct iwl_init_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* "9" for initialize alive */ - __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; - __le32 timestamp; - __le32 is_valid; - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -} __packed; +enum iwlagn_ucode_subtype { + UCODE_SUBTYPE_REGULAR = 0, + UCODE_SUBTYPE_REGULAR_NEW = 1, + UCODE_SUBTYPE_INIT = 9, + /* + * Not a valid subtype, the ucode has just a u8, so + * we can use something > 0xff for this value. + */ + UCODE_SUBTYPE_NONE_LOADED = 0x100, +}; /** * REPLY_ALIVE = 0x1 (response only, not a command) @@ -533,49 +433,61 @@ struct iwl_init_alive_resp { * * 2) error_event_table_ptr indicates base of the error log. This contains * information about any uCode error that occurs. For agn, the format - * of the error log is: - * - * __le32 valid; (nonzero) valid, (0) log is empty - * __le32 error_id; type of error - * __le32 pc; program counter - * __le32 blink1; branch link - * __le32 blink2; branch link - * __le32 ilink1; interrupt link - * __le32 ilink2; interrupt link - * __le32 data1; error-specific data - * __le32 data2; error-specific data - * __le32 line; source code line of error - * __le32 bcon_time; beacon timer - * __le32 tsf_low; network timestamp function timer - * __le32 tsf_hi; network timestamp function timer - * __le32 gp1; GP1 timer register - * __le32 gp2; GP2 timer register - * __le32 gp3; GP3 timer register - * __le32 ucode_ver; uCode version - * __le32 hw_ver; HW Silicon version - * __le32 brd_ver; HW board version - * __le32 log_pc; log program counter - * __le32 frame_ptr; frame pointer - * __le32 stack_ptr; stack pointer - * __le32 hcmd; last host command - * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag - * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag - * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag - * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag - * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt - * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT - * __le32 wait_event; wait event() caller address - * __le32 l2p_control; L2pControlField - * __le32 l2p_duration; L2pDurationField - * __le32 l2p_mhvalid; L2pMhValidBits - * __le32 l2p_addr_match; L2pAddrMatchStat - * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL) - * __le32 u_timestamp; indicate when the date and time of the compilation - * __le32 reserved; + * of the error log is defined by struct iwl_error_event_table. * * The Linux driver can print both logs to the system log when a uCode error * occurs. */ + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ +#if 0 + /* no need to read the remainder, we don't use the values */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +#endif +} __packed; + struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; @@ -722,46 +634,6 @@ enum { * regardless of whether RXON_FILTER_ASSOC_MSK is set. */ -struct iwl3945_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 reserved4; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - __le16 reserved5; -} __packed; - -struct iwl4965_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 rx_chain; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -} __packed; - -/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -789,26 +661,7 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl3945_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 reserved; -} __packed; - -struct iwl4965_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; - __le16 reserved; -} __packed; - -struct iwl5000_rxon_assoc_cmd { +struct iwl_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; u8 ofdm_basic_rates; @@ -843,26 +696,6 @@ struct iwl_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl3945_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl4965_tx_power_db tx_power; -} __packed; - /** * struct iwl5000_channel_switch_cmd * @band: 0- 5.2GHz, 1- 2.4GHz @@ -976,15 +809,10 @@ struct iwl_qosparam_cmd { #define IWL_AP_ID 0 #define IWL_AP_ID_PAN 1 #define IWL_STA_ID 2 -#define IWL3945_BROADCAST_ID 24 -#define IWL3945_STATION_COUNT 25 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 #define IWLAGN_PAN_BCAST_ID 14 #define IWLAGN_BROADCAST_ID 15 #define IWLAGN_STATION_COUNT 16 -#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) @@ -1032,16 +860,6 @@ struct iwl_qosparam_cmd { * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -struct iwl4965_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ - u8 reserved1; - __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - u8 key_offset; - u8 reserved2; - u8 key[16]; /* 16-byte unicast decryption key */ -} __packed; - /* agn */ struct iwl_keyinfo { __le16 key_flags; @@ -1083,7 +901,6 @@ struct sta_id_modify { * with info on security keys, aggregation parameters, and Tx rates for * initial Tx attempt and any retries (agn devices uses * REPLY_TX_LINK_QUALITY_CMD, - * 3945 uses REPLY_RATE_SCALE to set up rate tables). * * REPLY_ADD_STA sets up the table entry for one station, either creating * a new entry, or modifying a pre-existing one. @@ -1103,72 +920,6 @@ struct sta_id_modify { * entries for all STAs in network, starting with index IWL_STA_ID. */ -struct iwl3945_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 rate_n_flags; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; -} __packed; - -struct iwl4965_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 reserved1; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; - - /* - * Number of packets OK to transmit to station even though - * it is asleep -- used to synchronise PS-poll and u-APSD - * responses while ucode keeps track of STA sleep state. - */ - __le16 sleep_tx_count; - - __le16 reserved2; -} __packed; - -/* agn */ struct iwl_addsta_cmd { u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; @@ -1337,62 +1088,6 @@ struct iwl_wep_cmd { #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl3945_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __packed; - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl3945_rx_frame { - struct iwl3945_rx_frame_stats stats; - struct iwl3945_rx_frame_hdr hdr; - struct iwl3945_rx_frame_end end; -} __packed; - -#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) - -/* Fixed (non-configurable) rx data from phy */ - -#define IWL49_RX_RES_PHY_CNT 14 -#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL49_AGC_DB_POS (7) -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]; -} __packed; - - #define IWLAGN_RX_RES_PHY_CNT 8 #define IWLAGN_RX_RES_AGC_IDX 1 #define IWLAGN_RX_RES_RSSI_AB_IDX 2 @@ -1576,80 +1271,6 @@ struct iwl_rx_mpdu_res_start { * REPLY_TX = 0x1c (command) */ -struct iwl3945_tx_cmd { - /* - * MPDU byte count: - * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * NOTE: Does not include Tx command bytes, post-MAC pad bytes, - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i - * Range: 14-2342 bytes. - */ - __le16 len; - - /* - * MPDU or MSDU byte count for next frame. - * Used for fragmentation and bursting, but not 11n aggregation. - * Same as "len", but for next frame. Set to 0 if not applicable. - */ - __le16 next_frame_len; - - __le32 tx_flags; /* TX_CMD_FLG_* */ - - u8 rate; - - /* Index of recipient station in uCode's station table */ - u8 sta_id; - u8 tid_tspec; - u8 sec_ctl; - u8 key[16]; - union { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; - } tkip_mic; - __le32 next_frame_info; - union { - __le32 life_time; - __le32 attempt; - } stop_time; - u8 supp_rates[2]; - u8 rts_retry_limit; /*byte 50 */ - u8 data_retry_limit; /*byte 51 */ - union { - __le16 pm_frame_timeout; - __le16 attempt_duration; - } timeout; - - /* - * Duration of EDCA burst Tx Opportunity, in 32-usec units. - * Set this if txop time is not specified by HCCA protocol (e.g. by AP). - */ - __le16 driver_txop; - - /* - * MAC header goes here, followed by 2 bytes padding if MAC header - * length is 26 or 30 bytes, followed by payload data - */ - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __packed; - -/* - * REPLY_TX = 0x1c (response) - */ -struct iwl3945_tx_resp { - u8 failure_rts; - u8 failure_frame; - u8 bt_kill_count; - u8 rate; - __le32 wireless_media_time; - __le32 status; /* TX status */ -} __packed; - - /* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. @@ -1740,54 +1361,6 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; -/* TX command response is sent after *3945* transmission attempts. - * - * NOTES: - * - * TX_STATUS_FAIL_NEXT_FRAG - * - * If the fragment flag in the MAC header for the frame being transmitted - * is set and there is insufficient time to transmit the next frame, the - * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. - * - * TX_STATUS_FIFO_UNDERRUN - * - * Indicates the host did not provide bytes to the FIFO fast enough while - * a TX was in progress. - * - * TX_STATUS_FAIL_MGMNT_ABORT - * - * This status is only possible if the ABORT ON MGMT RX parameter was - * set to true with the TX command. - * - * If the MSB of the status parameter is set then an abort sequence is - * required. This sequence consists of the host activating the TX Abort - * control line, and then waiting for the TX Abort command response. This - * indicates that a the device is no longer in a transmit state, and that the - * command FIFO has been cleared. The host must then deactivate the TX Abort - * control line. Receiving is still allowed in this case. - */ -enum { - TX_3945_STATUS_SUCCESS = 0x01, - TX_3945_STATUS_DIRECT_DONE = 0x02, - TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, - TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, - TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, - TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_3945_STATUS_FAIL_DEST_PS = 0x88, - TX_3945_STATUS_FAIL_ABORTED = 0x89, - TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, - TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, - TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, - TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, - TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, - TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, -}; - /* * TX command response is sent after *agn* transmission attempts. * @@ -1905,43 +1478,6 @@ struct agg_tx_status { __le16 sequence; } __packed; -struct iwl4965_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ - u8 failure_rts; /* # failures due to unsuccessful RTS */ - u8 failure_frame; /* # failures due to no ACK (unused for agg) */ - - /* For non-agg: Rate at which frame was successful. - * For agg: Rate at which all frames were transmitted. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* For non-agg: RTS + CTS + frame tx attempts time + ACK. - * For agg: RTS + CTS + aggregation tx time + block-ack time. */ - __le16 wireless_media_time; /* uSecs */ - - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; - - /* - * For non-agg: frame status TX_STATUS_* - * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status - * fields follow this one, up to frame_count. - * Bit fields: - * 11- 0: AGG_TX_STATE_* status code - * 15-12: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a - * member of a previous aggregation block). If rate - * scaling is used, retry count indicates the rate - * table entry used for all frames in the new agg. - * 31-16: Sequence # for this frame's Tx cmd (not SSN!) - */ - union { - __le32 status; - struct agg_tx_status agg_status[0]; /* for each agg frame */ - } u; -} __packed; - /* * definitions for initial rate index field * bits [3:0] initial rate index @@ -2030,51 +1566,7 @@ struct iwl_compressed_ba_resp { /* * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) * - * See details under "TXPOWER" in iwl-4965-hw.h. - */ - -struct iwl3945_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl4965_tx_power_db tx_power; -} __packed; - - -/** - * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response - * - * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) - * - * NOTE: The table of rates passed to the uCode via the - * RATE_SCALE command sets up the corresponding order of - * rates used for all related commands, including rate - * masks, etc. - * - * For example, if you set 9MB (PLCP 0x0f) as the first - * rate in the rate table, the bit mask for that rate - * when passed through ofdm_basic_rates on the REPLY_RXON - * command would be bit 0 (1 << 0) */ -struct iwl3945_rate_scaling_info { - __le16 rate_n_flags; - u8 try_cnt; - u8 next_rate_index; -} __packed; - -struct iwl3945_rate_scaling_cmd { - u8 table_id; - u8 reserved[3]; - struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; -} __packed; - /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) @@ -2130,7 +1622,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MAX (255) #define LINK_QUAL_AGG_DISABLE_START_MIN (0) -#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) @@ -2477,7 +1969,7 @@ struct iwl_bt_cmd { IWLAGN_BT_VALID_BT4_TIMES | \ IWLAGN_BT_VALID_3W_LUT) -struct iwlagn_bt_cmd { +struct iwl_basic_bt_cmd { u8 flags; u8 ledtime; /* unused */ u8 max_kill; @@ -2490,6 +1982,10 @@ struct iwlagn_bt_cmd { __le32 bt3_lookup_table[12]; __le16 bt4_decision_time; /* unused */ __le16 valid; +}; + +struct iwl6000_bt_cmd { + struct iwl_basic_bt_cmd basic; u8 prio_boost; /* * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask @@ -2499,6 +1995,18 @@ struct iwlagn_bt_cmd { __le16 rx_prio_boost; /* SW boost of WiFi rx priority */ }; +struct iwl2000_bt_cmd { + struct iwl_basic_bt_cmd basic; + __le32 prio_boost; + /* + * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask + * if configure the following patterns + */ + u8 reserved; + u8 tx_prio_boost; /* SW boost of WiFi tx priority */ + __le16 rx_prio_boost; /* SW boost of WiFi rx priority */ +}; + #define IWLAGN_BT_SCO_ACTIVE cpu_to_le32(BIT(0)) struct iwlagn_bt_sco_cmd { @@ -2680,14 +2188,6 @@ struct iwl_spectrum_notification { #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) -struct iwl3945_powertable_cmd { - __le16 flags; - u8 reserved[2]; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; -} __packed; - struct iwl_powertable_cmd { __le16 flags; u8 keep_alive_seconds; /* 3945 reserved */ @@ -2790,25 +2290,6 @@ struct iwl_ct_kill_throttling_config { * active_dwell < max_out_time */ -/* FIXME: rename to AP1, remove tpc */ -struct iwl3945_scan_channel { - /* - * type is defined as: - * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding - * SSID IE is transmitted in probe request. - * 5:7 reserved - */ - u8 type; - u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ - struct iwl3945_tx_power tpc; - __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ - __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ -} __packed; - -/* set number of direct probes u8 type */ -#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) - struct iwl_scan_channel { /* * type is defined as: @@ -2904,53 +2385,15 @@ struct iwl_ssid_ie { * struct iwl_scan_channel. */ -struct iwl3945_scan_cmd { - __le16 len; - u8 reserved0; - u8 channel_count; /* # channels in channel list */ - __le16 quiet_time; /* dwell only this # millisecs on quiet channel - * (only for active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ - __le16 reserved1; - __le32 max_out_time; /* max usec to be away from associated (service) - * channel */ - __le32 suspend_time; /* pause scan this long (in "extended beacon - * format") when returning to service channel: - * 3945; 31:24 # beacons, 19:0 additional usec, - * 4965; 31:22 # beacons, 21:0 additional usec. - */ - __le32 flags; /* RXON_FLG_* */ - __le32 filter_flags; /* RXON_FILTER_* */ - - /* For active scans (set to all-0s for passive scans). - * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl3945_tx_cmd tx_cmd; - - /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl3945_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __packed; +enum iwl_scan_flags { + /* BIT(0) currently unused */ + IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), + /* bits 2-7 reserved */ +}; struct iwl_scan_cmd { __le16 len; - u8 reserved0; + u8 scan_flags; /* scan flags: see enum iwl_scan_flags */ u8 channel_count; /* # channels in channel list */ __le16 quiet_time; /* dwell only this # millisecs on quiet channel * (only for active scan) */ @@ -3068,15 +2511,8 @@ enum iwl_ibss_manager { * BEACON_NOTIFICATION = 0x90 (notification only, not a command) */ -struct iwl3945_beacon_notif { - struct iwl3945_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - -struct iwl4965_beacon_notif { - struct iwl4965_tx_resp beacon_notify_hdr; +struct iwlagn_beacon_notif { + struct iwlagn_tx_resp beacon_notify_hdr; __le32 low_tsf; __le32 high_tsf; __le32 ibss_mgr_status; @@ -3086,14 +2522,6 @@ struct iwl4965_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl3945_tx_beacon_cmd { - struct iwl3945_tx_cmd tx; - __le16 tim_idx; - u8 tim_size; - u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ -} __packed; - struct iwl_tx_beacon_cmd { struct iwl_tx_cmd tx; __le16 tim_idx; @@ -3130,53 +2558,6 @@ struct rate_histogram { /* statistics command response */ -struct iwl39_statistics_rx_phy { - __le32 ina_cnt; - __le32 fina_cnt; - __le32 plcp_err; - __le32 crc32_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 false_alarm_cnt; - __le32 fina_sync_err_cnt; - __le32 sfd_timeout; - __le32 fina_timeout; - __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; - __le32 sent_ack_cnt; - __le32 sent_cts_cnt; -} __packed; - -struct iwl39_statistics_rx_non_phy { - __le32 bogus_cts; /* CTS received when not expecting CTS */ - __le32 bogus_ack; /* ACK received when not expecting ACK */ - __le32 non_bssid_frames; /* number of frames with BSSID that - * doesn't belong to the STA BSSID */ - __le32 filtered_frames; /* count frames that were dumped in the - * filtering process */ - __le32 non_channel_beacons; /* beacons with our bss id but not on - * our serving channel */ -} __packed; - -struct iwl39_statistics_rx { - struct iwl39_statistics_rx_phy ofdm; - struct iwl39_statistics_rx_phy cck; - struct iwl39_statistics_rx_non_phy general; -} __packed; - -struct iwl39_statistics_tx { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; -} __packed; - struct statistics_dbg { __le32 burst_check; __le32 burst_count; @@ -3184,23 +2565,6 @@ struct statistics_dbg { __le32 reserved[3]; } __packed; -struct iwl39_statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; -} __packed; - -struct iwl39_statistics_general { - __le32 temperature; - struct statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct iwl39_statistics_div div; -} __packed; - struct statistics_rx_phy { __le32 ina_cnt; __le32 fina_cnt; @@ -3442,13 +2806,6 @@ struct iwl_statistics_cmd { #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) -struct iwl3945_notif_statistics { - __le32 flag; - struct iwl39_statistics_rx rx; - struct iwl39_statistics_tx tx; - struct iwl39_statistics_general general; -} __packed; - struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -4143,6 +3500,10 @@ enum iwl_bt_coex_profile_traffic_load { */ }; +#define BT_SESSION_ACTIVITY_1_UART_MSG 0x1 +#define BT_SESSION_ACTIVITY_2_UART_MSG 0x2 + +/* BT UART message - Share Part (BT -> WiFi) */ #define BT_UART_MSG_FRAME1MSGTYPE_POS (0) #define BT_UART_MSG_FRAME1MSGTYPE_MSK \ (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS) @@ -4227,9 +3588,12 @@ enum iwl_bt_coex_profile_traffic_load { #define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS (0) #define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK \ (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS) -#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS (3) -#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK \ - (0x3 << BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS) +#define BT_UART_MSG_FRAME7PAGE_POS (3) +#define BT_UART_MSG_FRAME7PAGE_MSK \ + (0x1 << BT_UART_MSG_FRAME7PAGE_POS) +#define BT_UART_MSG_FRAME7INQUIRY_POS (4) +#define BT_UART_MSG_FRAME7INQUIRY_MSK \ + (0x1 << BT_UART_MSG_FRAME7INQUIRY_POS) #define BT_UART_MSG_FRAME7CONNECTABLE_POS (5) #define BT_UART_MSG_FRAME7CONNECTABLE_MSK \ (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS) @@ -4237,6 +3601,83 @@ enum iwl_bt_coex_profile_traffic_load { #define BT_UART_MSG_FRAME7RESERVED_MSK \ (0x3 << BT_UART_MSG_FRAME7RESERVED_POS) +/* BT Session Activity 2 UART message (BT -> WiFi) */ +#define BT_UART_MSG_2_FRAME1RESERVED1_POS (5) +#define BT_UART_MSG_2_FRAME1RESERVED1_MSK \ + (0x1<<BT_UART_MSG_2_FRAME1RESERVED1_POS) +#define BT_UART_MSG_2_FRAME1RESERVED2_POS (6) +#define BT_UART_MSG_2_FRAME1RESERVED2_MSK \ + (0x3<<BT_UART_MSG_2_FRAME1RESERVED2_POS) + +#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS (0) +#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_MSK \ + (0x3F<<BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS) +#define BT_UART_MSG_2_FRAME2RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME2RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME2RESERVED_POS) + +#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS (0) +#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_MSK \ + (0xF<<BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS) +#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS (4) +#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_MSK \ + (0x1<<BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS) +#define BT_UART_MSG_2_FRAME3LEMASTER_POS (5) +#define BT_UART_MSG_2_FRAME3LEMASTER_MSK \ + (0x1<<BT_UART_MSG_2_FRAME3LEMASTER_POS) +#define BT_UART_MSG_2_FRAME3RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME3RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME3RESERVED_POS) + +#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS (0) +#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_MSK \ + (0xF<<BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS) +#define BT_UART_MSG_2_FRAME4NUMLECONN_POS (4) +#define BT_UART_MSG_2_FRAME4NUMLECONN_MSK \ + (0x3<<BT_UART_MSG_2_FRAME4NUMLECONN_POS) +#define BT_UART_MSG_2_FRAME4RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME4RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME4RESERVED_POS) + +#define BT_UART_MSG_2_FRAME5BTMINRSSI_POS (0) +#define BT_UART_MSG_2_FRAME5BTMINRSSI_MSK \ + (0xF<<BT_UART_MSG_2_FRAME5BTMINRSSI_POS) +#define BT_UART_MSG_2_FRAME5LESCANINITMODE_POS (4) +#define BT_UART_MSG_2_FRAME5LESCANINITMODE_MSK \ + (0x1<<BT_UART_MSG_2_FRAME5LESCANINITMODE_POS) +#define BT_UART_MSG_2_FRAME5LEADVERMODE_POS (5) +#define BT_UART_MSG_2_FRAME5LEADVERMODE_MSK \ + (0x1<<BT_UART_MSG_2_FRAME5LEADVERMODE_POS) +#define BT_UART_MSG_2_FRAME5RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME5RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME5RESERVED_POS) + +#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS (0) +#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_MSK \ + (0x1F<<BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS) +#define BT_UART_MSG_2_FRAME6RFU_POS (5) +#define BT_UART_MSG_2_FRAME6RFU_MSK \ + (0x1<<BT_UART_MSG_2_FRAME6RFU_POS) +#define BT_UART_MSG_2_FRAME6RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME6RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME6RESERVED_POS) + +#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS (0) +#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_MSK \ + (0x7<<BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS) +#define BT_UART_MSG_2_FRAME7LEPROFILE1_POS (3) +#define BT_UART_MSG_2_FRAME7LEPROFILE1_MSK \ + (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE1_POS) +#define BT_UART_MSG_2_FRAME7LEPROFILE2_POS (4) +#define BT_UART_MSG_2_FRAME7LEPROFILE2_MSK \ + (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE2_POS) +#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS (5) +#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_MSK \ + (0x1<<BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS) +#define BT_UART_MSG_2_FRAME7RESERVED_POS (6) +#define BT_UART_MSG_2_FRAME7RESERVED_MSK \ + (0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS) + struct iwl_bt_uart_msg { u8 header; @@ -4338,10 +3779,6 @@ struct iwl_rx_packet { __le32 len_n_flags; struct iwl_cmd_header hdr; union { - struct iwl3945_rx_frame rx_frame; - struct iwl3945_tx_resp tx_resp; - struct iwl3945_beacon_notif beacon_status; - struct iwl_alive_resp alive_frame; struct iwl_spectrum_notification spectrum_notif; struct iwl_csa_notification csa_notif; @@ -4369,6 +3806,11 @@ int iwl_agn_check_rxon_cmd(struct iwl_priv *priv); * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) */ +/* + * Minimum slot time in TU + */ +#define IWL_MIN_SLOT_TIME 20 + /** * struct iwl_wipan_slot * @width: Time in TU diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index efbde1f1a8bf..4653deada05b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -41,13 +41,9 @@ #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn.h" -MODULE_DESCRIPTION("iwl core"); -MODULE_VERSION(IWLWIFI_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); -MODULE_LICENSE("GPL"); - /* * set bt_coex_active to true, uCode will do kill/defer * every time the priority line is asserted (BT is sending signals on the @@ -65,40 +61,12 @@ MODULE_LICENSE("GPL"); * default: bt_coex_active = true (BT_COEX_ENABLE) */ bool bt_coex_active = true; -EXPORT_SYMBOL_GPL(bt_coex_active); module_param(bt_coex_active, bool, S_IRUGO); MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); u32 iwl_debug_level; -EXPORT_SYMBOL(iwl_debug_level); const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -EXPORT_SYMBOL(iwl_bcast_addr); - - -/* This function both allocates and initializes hw and priv. */ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) -{ - struct iwl_priv *priv; - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - struct ieee80211_hw *hw; - - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), - cfg->ops->ieee80211_ops); - if (hw == NULL) { - pr_err("%s: Can not allocate network device\n", - cfg->name); - goto out; - } - - priv = hw->priv; - priv->hw = hw; - -out: - return hw; -} -EXPORT_SYMBOL(iwl_alloc_all); #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ @@ -127,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, max_bit_rate = MAX_BIT_RATE_40_MHZ; } - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; @@ -168,6 +136,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -219,15 +188,12 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (!is_channel_valid(ch)) continue; - if (is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; geo_ch->center_freq = - ieee80211_channel_to_frequency(ch->channel); + ieee80211_channel_to_frequency(ch->channel, ch->band); geo_ch->max_power = ch->max_power_avg; geo_ch->max_antenna_gain = 0xff; geo_ch->hw_value = ch->channel; @@ -244,8 +210,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -258,6 +224,10 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags); } + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -275,7 +245,6 @@ int iwlcore_init_geos(struct iwl_priv *priv) return 0; } -EXPORT_SYMBOL(iwlcore_init_geos); /* * iwlcore_free_geos - undo allocations in iwlcore_init_geos @@ -286,7 +255,6 @@ void iwlcore_free_geos(struct iwl_priv *priv) kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); } -EXPORT_SYMBOL(iwlcore_free_geos); static bool iwl_is_channel_extension(struct iwl_priv *priv, enum ieee80211_band band, @@ -331,7 +299,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, le16_to_cpu(ctx->staging.channel), ctx->ht.extension_chan_offset); } -EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) { @@ -432,7 +399,6 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return iwl_send_cmd_pdu(priv, ctx->rxon_timing_cmd, sizeof(ctx->timing), &ctx->timing); } -EXPORT_SYMBOL(iwl_send_rxon_timing); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt) @@ -445,80 +411,78 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; } -EXPORT_SYMBOL(iwl_set_rxon_hwcrypto); /* validate RXON structure is valid */ int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct iwl_rxon_cmd *rxon = &ctx->staging; - bool error = false; + u32 errors = 0; if (rxon->flags & RXON_FLG_BAND_24G_MSK) { if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { IWL_WARN(priv, "check 2.4G: wrong narrow\n"); - error = true; + errors |= BIT(0); } if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { IWL_WARN(priv, "check 2.4G: wrong radar\n"); - error = true; + errors |= BIT(1); } } else { if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "check 5.2G: not short slot!\n"); - error = true; + errors |= BIT(2); } if (rxon->flags & RXON_FLG_CCK_MSK) { IWL_WARN(priv, "check 5.2G: CCK!\n"); - error = true; + errors |= BIT(3); } } if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { IWL_WARN(priv, "mac/bssid mcast!\n"); - error = true; + errors |= BIT(4); } /* make sure basic rates 6Mbps and 1Mbps are supported */ if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { IWL_WARN(priv, "neither 1 nor 6 are basic\n"); - error = true; + errors |= BIT(5); } if (le16_to_cpu(rxon->assoc_id) > 2007) { IWL_WARN(priv, "aid > 2007\n"); - error = true; + errors |= BIT(6); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "CCK and short slot\n"); - error = true; + errors |= BIT(7); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { IWL_WARN(priv, "CCK and auto detect"); - error = true; + errors |= BIT(8); } if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK) { IWL_WARN(priv, "TGg but no auto-detect\n"); - error = true; + errors |= BIT(9); } - if (error) - IWL_WARN(priv, "Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERR(priv, "Invalid RXON\n"); - return -EINVAL; + if (rxon->channel == 0) { + IWL_WARN(priv, "zero channel is invalid\n"); + errors |= BIT(10); } - return 0; + + WARN(errors, "Invalid RXON (%#x), channel %d", + errors, le16_to_cpu(rxon->channel)); + + return errors ? -EINVAL : 0; } -EXPORT_SYMBOL(iwl_check_rxon_cmd); /** * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed @@ -582,7 +546,6 @@ int iwl_full_rxon_required(struct iwl_priv *priv, return 0; } -EXPORT_SYMBOL(iwl_full_rxon_required); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, struct iwl_rxon_context *ctx) @@ -596,7 +559,6 @@ u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, else return IWL_RATE_6M_PLCP; } -EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); static void _iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf, @@ -673,7 +635,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) for_each_context(priv, ctx) _iwl_set_rxon_ht(priv, ht_conf, ctx); } -EXPORT_SYMBOL(iwl_set_rxon_ht); /* Return valid, unused, channel for a passive scan to reset the RF */ u8 iwl_get_single_channel_number(struct iwl_priv *priv, @@ -714,7 +675,6 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv, return channel; } -EXPORT_SYMBOL(iwl_get_single_channel_number); /** * iwl_set_rxon_channel - Set the band and channel values in staging RXON @@ -745,7 +705,6 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, return 0; } -EXPORT_SYMBOL(iwl_set_rxon_channel); void iwl_set_flags_for_band(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -769,7 +728,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv, ctx->staging.flags &= ~RXON_FLG_CCK_MSK; } } -EXPORT_SYMBOL(iwl_set_flags_for_band); /* * initialize rxon structure with default values from eeprom @@ -841,7 +799,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff; ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff; } -EXPORT_SYMBOL(iwl_connection_init_rx_config); void iwl_set_rate(struct iwl_priv *priv) { @@ -874,7 +831,6 @@ void iwl_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } } -EXPORT_SYMBOL(iwl_set_rate); void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) { @@ -894,35 +850,6 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) mutex_unlock(&priv->mutex); } } -EXPORT_SYMBOL(iwl_chswitch_done); - -void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_csa_notification *csa = &(pkt->u.csa_notif); - /* - * MULTI-FIXME - * See iwl_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl_rxon_cmd *rxon = (void *)&ctx->active; - - if (priv->switch_rxon.switch_in_progress) { - if (!le32_to_cpu(csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, true); - } else { - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", - le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, false); - } - } -} -EXPORT_SYMBOL(iwl_rx_csa); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, @@ -944,31 +871,90 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } -EXPORT_SYMBOL(iwl_print_rx_config_cmd); #endif -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card - */ -void iwl_irq_handle_error(struct iwl_priv *priv) + +static void iwlagn_abort_notification_waits(struct iwl_priv *priv) { + unsigned long flags; + struct iwl_notification_wait *wait_entry; + + spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags); + list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list) + wait_entry->aborted = true; + spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags); + + wake_up_all(&priv->_agn.notif_waitq); +} + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) +{ + unsigned int reload_msec; + unsigned long reload_jiffies; + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->status); /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + iwlagn_abort_notification_waits(priv); + + /* Keep the restart process from trying to send host + * commands by clearing the ready bit */ + clear_bit(STATUS_READY, &priv->status); + + wake_up_interruptible(&priv->wait_command_queue); + + if (!ondemand) { + /* + * If firmware keep reloading, then it indicate something + * serious wrong and firmware having problem to recover + * from it. Instead of keep trying which will fill the syslog + * and hang the system, let's just stop it + */ + reload_jiffies = jiffies; + reload_msec = jiffies_to_msecs((long) reload_jiffies - + (long) priv->reload_jiffies); + priv->reload_jiffies = reload_jiffies; + if (reload_msec <= IWL_MIN_RELOAD_DURATION) { + priv->reload_count++; + if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { + IWL_ERR(priv, "BUG_ON, Stop restarting\n"); + return; + } + } else + priv->reload_count = 0; + } + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (iwlagn_mod_params.restart_fw) { + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + queue_work(priv->workqueue, &priv->restart); + } else + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Detected FW error, but not restarting\n"); + } +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +void iwl_irq_handle_error(struct iwl_priv *priv) +{ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (priv->cfg->internal_wimax_coex && (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(priv, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - wake_up_interruptible(&priv->wait_command_queue); /* - *Keep the restart process from trying to send host - * commands by clearing the INIT status bit + * Keep the restart process from trying to send host + * commands by clearing the ready bit. */ clear_bit(STATUS_READY, &priv->status); + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); IWL_ERR(priv, "RF is used by WiMAX\n"); return; } @@ -976,33 +962,18 @@ void iwl_irq_handle_error(struct iwl_priv *priv) IWL_ERR(priv, "Loaded firmware version: %s\n", priv->hw->wiphy->fw_version); - priv->cfg->ops->lib->dump_nic_error_log(priv); - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); - if (priv->cfg->ops->lib->dump_fh) - priv->cfg->ops->lib->dump_fh(priv, NULL, false); - priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); + iwl_dump_nic_error_log(priv); + iwl_dump_csr(priv); + iwl_dump_fh(priv, NULL, false); + iwl_dump_nic_event_log(priv, false, NULL, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv, &priv->contexts[IWL_RXON_CTX_BSS]); #endif - wake_up_interruptible(&priv->wait_command_queue); - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - clear_bit(STATUS_READY, &priv->status); - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, - "Restarting adapter due to uCode error.\n"); - - if (priv->cfg->mod_params->restart_fw) - queue_work(priv->workqueue, &priv->restart); - } + iwlagn_fw_error(priv, false); } -EXPORT_SYMBOL(iwl_irq_handle_error); static int iwl_apm_stop_master(struct iwl_priv *priv) { @@ -1025,6 +996,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + clear_bit(STATUS_DEVICE_ENABLED, &priv->status); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); @@ -1039,7 +1012,6 @@ void iwl_apm_stop(struct iwl_priv *priv) */ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } -EXPORT_SYMBOL(iwl_apm_stop); /* @@ -1076,7 +1048,6 @@ int iwl_apm_init(struct iwl_priv *priv) /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s - * NOTE: This is no-op for 3945 (non-existant bit) */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); @@ -1089,20 +1060,18 @@ int iwl_apm_init(struct iwl_priv *priv) * If not (unlikely), enable L0S, so there is at least some * power savings, even without L1. */ - if (priv->cfg->base_params->set_l0s) { - lctl = iwl_pcie_link_ctl(priv); - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == - PCI_CFG_LINK_CTRL_VAL_L1_EN) { - /* L1-ASPM enabled; disable(!) L0S */ - iwl_set_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); - } + lctl = iwl_pcie_link_ctl(priv); + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); } /* Configure analog phase-lock-loop before activating to D0A */ @@ -1130,37 +1099,32 @@ int iwl_apm_init(struct iwl_priv *priv) } /* - * Enable DMA and BSM (if used) clocks, wait for them to stabilize. - * BSM (Boostrap State Machine) is only in 3945 and 4965; - * later devices (i.e. 5000 and later) have non-volatile SRAM, - * and don't need BSM to restore data after power-saving sleep. + * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (priv->cfg->base_params->use_bsm) - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - else - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + set_bit(STATUS_DEVICE_ENABLED, &priv->status); + out: return ret; } -EXPORT_SYMBOL(iwl_apm_init); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret; s8 prev_tx_power; + bool defer; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; lockdep_assert_held(&priv->mutex); @@ -1188,10 +1152,15 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (!iwl_is_ready_rf(priv)) return -EIO; - /* scan complete use tx_power_next, need to be updated */ + /* scan complete and commit_rxon use tx_power_next value, + * it always need to be updated for newest request */ priv->tx_power_next = tx_power; - if (test_bit(STATUS_SCANNING, &priv->status) && !force) { - IWL_DEBUG_INFO(priv, "Deferring tx power set while scanning\n"); + + /* do not set tx power when scanning or channel changing */ + defer = test_bit(STATUS_SCANNING, &priv->status) || + memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); + if (defer && !force) { + IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); return 0; } @@ -1207,7 +1176,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } return ret; } -EXPORT_SYMBOL(iwl_set_tx_power); void iwl_send_bt_config(struct iwl_priv *priv) { @@ -1231,7 +1199,6 @@ void iwl_send_bt_config(struct iwl_priv *priv) sizeof(struct iwl_bt_cmd), &bt_cmd)) IWL_ERR(priv, "failed to send BT Coex Config\n"); } -EXPORT_SYMBOL(iwl_send_bt_config); int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) { @@ -1249,46 +1216,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) sizeof(struct iwl_statistics_cmd), &statistics_cmd); } -EXPORT_SYMBOL(iwl_send_statistics_request); - -void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); - IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", - sleep->pm_sleep_mode, sleep->pm_wakeup_src); -#endif -} -EXPORT_SYMBOL(iwl_rx_pm_sleep_notif); - -void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", len, - get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); -} -EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); - -void iwl_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - - IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " - "seq 0x%04X ser 0x%08X\n", - le32_to_cpu(pkt->u.err_resp.error_type), - get_cmd_string(pkt->u.err_resp.cmd_id), - pkt->u.err_resp.cmd_id, - le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), - le32_to_cpu(pkt->u.err_resp.error_info)); -} -EXPORT_SYMBOL(iwl_rx_reply_error); void iwl_clear_isr_stats(struct iwl_priv *priv) { @@ -1340,7 +1267,6 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } -EXPORT_SYMBOL(iwl_mac_conf_tx); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw) { @@ -1348,7 +1274,6 @@ int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw) return priv->ibss_manager == IWL_IBSS_MANAGER; } -EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -1403,9 +1328,10 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *tmp, *ctx = NULL; int err; + enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", - vif->type, vif->addr); + viftype, vif->addr); mutex_lock(&priv->mutex); @@ -1429,7 +1355,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) continue; } - if (!(possible_modes & BIT(vif->type))) + if (!(possible_modes & BIT(viftype))) continue; /* have maybe usable context w/o interface */ @@ -1457,7 +1383,6 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) IWL_DEBUG_MAC80211(priv, "leave\n"); return err; } -EXPORT_SYMBOL(iwl_mac_add_interface); static void iwl_teardown_interface(struct iwl_priv *priv, struct ieee80211_vif *vif, @@ -1504,13 +1429,11 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, iwl_teardown_interface(priv, vif, false); - memset(priv->bssid, 0, ETH_ALEN); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); } -EXPORT_SYMBOL(iwl_mac_remove_interface); int iwl_alloc_txq_mem(struct iwl_priv *priv) { @@ -1525,14 +1448,12 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv) } return 0; } -EXPORT_SYMBOL(iwl_alloc_txq_mem); void iwl_free_txq_mem(struct iwl_priv *priv) { kfree(priv->txq); priv->txq = NULL; } -EXPORT_SYMBOL(iwl_free_txq_mem); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1571,7 +1492,6 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv) iwl_reset_traffic_log(priv); return 0; } -EXPORT_SYMBOL(iwl_alloc_traffic_mem); void iwl_free_traffic_mem(struct iwl_priv *priv) { @@ -1581,7 +1501,6 @@ void iwl_free_traffic_mem(struct iwl_priv *priv) kfree(priv->rx_traffic); priv->rx_traffic = NULL; } -EXPORT_SYMBOL(iwl_free_traffic_mem); void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header) @@ -1606,7 +1525,6 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; } } -EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame); void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header) @@ -1631,7 +1549,6 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; } } -EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); const char *get_mgmt_string(int cmd) { @@ -1675,7 +1592,6 @@ void iwl_clear_traffic_stats(struct iwl_priv *priv) { memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); - priv->led_tpt = 0; } /* @@ -1768,9 +1684,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) stats->data_cnt++; stats->data_bytes += len; } - iwl_leds_background(priv); } -EXPORT_SYMBOL(iwl_update_stats); #endif static void iwl_force_rf_reset(struct iwl_priv *priv) @@ -1834,21 +1748,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) * detect failure), then fw_restart module parameter * need to be check before performing firmware reload */ - if (!external && !priv->cfg->mod_params->restart_fw) { + if (!external && !iwlagn_mod_params.restart_fw) { IWL_DEBUG_INFO(priv, "Cancel firmware reload based on " "module parameter setting\n"); break; } IWL_ERR(priv, "On demand firmware reload\n"); - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - /* - * Keep the restart process from trying to send host - * commands by clearing the INIT status bit - */ - clear_bit(STATUS_READY, &priv->status); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, true); break; } return 0; @@ -1859,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; u32 interface_modes; int err; @@ -1867,6 +1774,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&priv->mutex); + if (!ctx->vif || !iwl_is_ready_rf(priv)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) { @@ -1874,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } + /* + * Refuse a change that should be done by moving from the PAN + * context to the BSS context instead, if the BSS context is + * available and can support the new interface type. + */ + if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && + (bss_ctx->interface_modes & BIT(newtype) || + bss_ctx->exclusive_interface_modes & BIT(newtype))) { + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + err = -EBUSY; + goto out; + } + if (ctx->exclusive_interface_modes & BIT(newtype)) { for_each_context(priv, tmp) { if (ctx == tmp) @@ -1894,6 +1823,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* success */ iwl_teardown_interface(priv, vif, true); vif->type = newtype; + vif->p2p = newp2p; err = iwl_setup_interface(priv, ctx); WARN_ON(err); /* @@ -1909,7 +1839,6 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&priv->mutex); return err; } -EXPORT_SYMBOL(iwl_mac_change_interface); /* * On every watchdog tick we check (latest) time stamp. If it does not @@ -1981,7 +1910,6 @@ void iwl_bg_watchdog(unsigned long data) mod_timer(&priv->watchdog, jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); } -EXPORT_SYMBOL(iwl_bg_watchdog); void iwl_setup_watchdog(struct iwl_priv *priv) { @@ -1993,7 +1921,6 @@ void iwl_setup_watchdog(struct iwl_priv *priv) else del_timer(&priv->watchdog); } -EXPORT_SYMBOL(iwl_setup_watchdog); /* * extended beacon time format @@ -2019,7 +1946,6 @@ u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval) return (quot << priv->hw_params.beacon_time_tsf_bits) + rem; } -EXPORT_SYMBOL(iwl_usecs_to_beacons); /* base is usually what we get from ucode with each received frame, * the same as HW timer counter counting down @@ -2047,7 +1973,6 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, return cpu_to_le32(res); } -EXPORT_SYMBOL(iwl_add_beacon_time); #ifdef CONFIG_PM @@ -2067,7 +1992,6 @@ int iwl_pci_suspend(struct device *device) return 0; } -EXPORT_SYMBOL(iwl_pci_suspend); int iwl_pci_resume(struct device *device) { @@ -2096,7 +2020,6 @@ int iwl_pci_resume(struct device *device) return 0; } -EXPORT_SYMBOL(iwl_pci_resume); const struct dev_pm_ops iwl_pm_ops = { .suspend = iwl_pci_suspend, @@ -2106,6 +2029,5 @@ const struct dev_pm_ops iwl_pm_ops = { .poweroff = iwl_pci_suspend, .restore = iwl_pci_resume, }; -EXPORT_SYMBOL(iwl_pm_ops); #endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a3474376fdbc..5b5b0cce4a54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,8 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ +#include "iwl-dev.h" + /************************ * forward declarations * ************************/ @@ -71,7 +73,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" #define DRV_AUTHOR "<ilw@linux.intel.com>" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ @@ -88,7 +90,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x struct iwl_hcmd_ops { - int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void (*set_rxon_chain)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -98,7 +99,6 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { - u16 (*get_hcmd_size)(u8 cmd_id, u16 len); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, @@ -120,46 +120,14 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_isr_ops { - irqreturn_t (*isr) (int irq, void *data); - void (*free)(struct iwl_priv *priv); - int (*alloc)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*disable)(struct iwl_priv *priv); -}; - -struct iwl_debugfs_ops { - ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*general_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -}; - struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); }; -struct iwl_tt_ops { - bool (*lower_power_detection)(struct iwl_priv *priv); - u8 (*tt_power_mode)(struct iwl_priv *priv); - bool (*ct_kill_check)(struct iwl_priv *priv); -}; - struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); /* Handling TX */ - void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); - void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq); void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv, struct iwl_tx_queue *txq, @@ -169,30 +137,14 @@ struct iwl_lib_ops { struct iwl_tx_queue *txq); int (*txq_init)(struct iwl_priv *priv, struct iwl_tx_queue *txq); - /* aggregations */ - int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, - int sta_id, int tid, u16 ssn_idx); - int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, - u8 tx_fifo); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* setup deferred work */ void (*setup_deferred_work)(struct iwl_priv *priv); /* cancel deferred work */ void (*cancel_deferred_work)(struct iwl_priv *priv); - /* alive notification after init uCode load */ - void (*init_alive_start)(struct iwl_priv *priv); - /* alive notification */ - int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); - /* 1st ucode load */ - int (*load_ucode)(struct iwl_priv *priv); - int (*dump_nic_event_log)(struct iwl_priv *priv, - bool full_log, char **buf, bool display); - void (*dump_nic_error_log)(struct iwl_priv *priv); - void (*dump_csr)(struct iwl_priv *priv); - int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); int (*set_channel_switch)(struct iwl_priv *priv, struct ieee80211_channel_switch *ch_switch); /* power management */ @@ -202,33 +154,15 @@ struct iwl_lib_ops { int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - /* isr */ - struct iwl_isr_ops isr_ops; - /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; /* temperature */ struct iwl_temp_ops temp_ops; - /* check for plcp health */ - bool (*check_plcp_health)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt); - /* check for ack health */ - bool (*check_ack_health)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt); + int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); - struct iwl_debugfs_ops debugfs_ops; - - /* thermal throttling */ - struct iwl_tt_ops tt_ops; -}; - -struct iwl_led_ops { - int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); - int (*on)(struct iwl_priv *priv); - int (*off)(struct iwl_priv *priv); }; /* NIC specific ops */ @@ -236,33 +170,22 @@ struct iwl_nic_ops { void (*additional_nic_config)(struct iwl_priv *priv); }; -struct iwl_legacy_ops { - void (*post_associate)(struct iwl_priv *priv); - void (*config_ap)(struct iwl_priv *priv); - /* station management */ - int (*update_bcast_stations)(struct iwl_priv *priv); - int (*manage_ibss_station)(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add); -}; - struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; - const struct iwl_led_ops *led; const struct iwl_nic_ops *nic; - const struct iwl_legacy_ops *legacy; - const struct ieee80211_ops *ieee80211_ops; }; struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ + bool plcp_check; /* def: true = enable plcp health check */ + bool ack_check; /* def: false = disable ack health check */ }; /* @@ -281,16 +204,7 @@ struct iwl_mod_params { * @wd_timeout: TX queues watchdog timeout * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging - * @tx_power_by_driver: tx power calibration performed by driver - * instead of uCode - * @ucode_tracing: support ucode continuous tracing - * @sensitivity_calib_by_driver: driver has the capability to perform - * sensitivity calibration operation - * @chain_noise_calib_by_driver: driver has the capability to perform - * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit - * @no_agg_framecnt_info: uCode do not provide aggregation frame count - * information */ struct iwl_base_params { int eeprom_size; @@ -298,16 +212,11 @@ struct iwl_base_params { int num_of_ampdu_queues;/* def: HW dependent */ /* for iwl_apm_init() */ u32 pll_cfg_val; - bool set_l0s; - bool use_bsm; - bool use_isr_legacy; const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; - const bool broken_powersave; int chain_noise_num_beacons; - const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; const bool support_wimax_coexist; @@ -316,18 +225,12 @@ struct iwl_base_params { unsigned int wd_timeout; bool temperature_kelvin; u32 max_event_log_size; - const bool tx_power_by_driver; - const bool ucode_tracing; - const bool sensitivity_calib_by_driver; - const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; - const bool no_agg_framecnt_info; }; /* * @advanced_bt_coexist: support advanced bt coexist * @bt_init_traffic_load: specify initial bt traffic load * @bt_prio_boost: default bt priority boost value - * @bt_statistics: use BT version of statistics notification * @agg_time_limit: maximum number of uSec in aggregation * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing @@ -337,11 +240,11 @@ struct iwl_bt_params { bool advanced_bt_coexist; u8 bt_init_traffic_load; u8 bt_prio_boost; - const bool bt_statistics; u16 agg_time_limit; u8 ampdu_factor; u8 ampdu_density; bool bt_sco_disable; + bool bt_session_2; }; /* * @use_rts_for_aggregation: use rts/cts protection for HT traffic @@ -366,6 +269,8 @@ struct iwl_ht_params { * @adv_pm: advance power management * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device + * @iq_invert: I/Q inversion + * @disable_otp_refresh: disable OTP refresh current limit * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -400,8 +305,6 @@ struct iwl_cfg { u16 eeprom_ver; u16 eeprom_calib_ver; const struct iwl_ops *ops; - /* module based parameters which can be set from modprobe cmd */ - const struct iwl_mod_params *mod_params; /* params not likely to change within a device family */ struct iwl_base_params *base_params; /* params likely to change within a device family */ @@ -415,13 +318,14 @@ struct iwl_cfg { const bool adv_pm; const bool rx_with_siso_diversity; const bool internal_wimax_coex; + const bool iq_invert; + const bool disable_otp_refresh; }; /*************************** * L i b * ***************************/ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); @@ -444,10 +348,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, void iwl_connection_init_rx_config(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwl_set_rate(struct iwl_priv *priv); -int iwl_set_decrypted_flag(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - u32 decrypt_res, - struct ieee80211_rx_status *stats); void iwl_irq_handle_error(struct iwl_priv *priv); int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -494,46 +394,21 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) { - struct traffic_stats *stats; - - if (is_tx) - stats = &priv->tx_stats; - else - stats = &priv->rx_stats; - - if (ieee80211_is_data(fc)) { - /* data */ - stats->data_bytes += len; - } - iwl_leds_background(priv); } #endif -/***************************************************** - * RX handlers. - * **************************************************/ -void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); /***************************************************** * RX ******************************************************/ void iwl_cmd_queue_free(struct iwl_priv *priv); +void iwl_cmd_queue_unmap(struct iwl_priv *priv); int iwl_rx_queue_alloc(struct iwl_priv *priv); void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -/* Handlers */ -void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwl_recover_from_statistics(struct iwl_priv *priv, - struct iwl_rx_packet *pkt); + void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); -void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); /* TX helpers */ @@ -546,6 +421,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id); void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); +void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id); void iwl_setup_watchdog(struct iwl_priv *priv); /***************************************************** * TX power @@ -582,6 +458,10 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); +int __must_check iwl_scan_initiate(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum iwl_scan_type scan_type, + enum ieee80211_band band); /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within @@ -650,6 +530,8 @@ extern const struct dev_pm_ops iwl_pm_ops; void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); +void iwl_dump_csr(struct iwl_priv *priv); +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -687,6 +569,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 +#define STATUS_DEVICE_ENABLED 18 static inline int iwl_is_ready(struct iwl_priv *priv) @@ -739,11 +622,6 @@ void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline int iwl_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx); -} static inline int iwlcore_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -755,7 +633,16 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( return priv->hw->wiphy->bands[band]; } +static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) +{ + return priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist; +} + extern bool bt_coex_active; extern bool bt_siso_mode; + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b80bf7dff55b..5ab90ba7a024 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -155,18 +155,10 @@ #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) - #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ @@ -186,7 +178,7 @@ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ @@ -202,29 +194,17 @@ /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ -#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR39_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - - -#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) -#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) @@ -268,7 +248,7 @@ * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. - * NOTE: This does not indicate that 4965 or 3945 has completed + * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. @@ -290,9 +270,7 @@ /* HW REV */ -#define CSR_HW_REV_TYPE_MSK (0x00000F0) -#define CSR_HW_REV_TYPE_3945 (0x00000D0) -#define CSR_HW_REV_TYPE_4965 (0x0000000) +#define CSR_HW_REV_TYPE_MSK (0x00001F0) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) #define CSR_HW_REV_TYPE_5100 (0x0000050) @@ -300,9 +278,15 @@ #define CSR_HW_REV_TYPE_1000 (0x0000060) #define CSR_HW_REV_TYPE_6x00 (0x0000070) #define CSR_HW_REV_TYPE_6x50 (0x0000080) -#define CSR_HW_REV_TYPE_6x50g2 (0x0000084) -#define CSR_HW_REV_TYPE_6x00g2 (0x00000B0) -#define CSR_HW_REV_TYPE_NONE (0x00000F0) +#define CSR_HW_REV_TYPE_6150 (0x0000084) +#define CSR_HW_REV_TYPE_6x05 (0x00000B0) +#define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 +#define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 +#define CSR_HW_REV_TYPE_2x30 (0x00000C0) +#define CSR_HW_REV_TYPE_2x00 (0x0000100) +#define CSR_HW_REV_TYPE_200 (0x0000110) +#define CSR_HW_REV_TYPE_230 (0x0000120) +#define CSR_HW_REV_TYPE_NONE (0x00001F0) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) @@ -357,7 +341,7 @@ * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. - * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and @@ -376,6 +360,8 @@ #define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) #define CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008) +#define CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER (0x00000080) + /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) @@ -386,7 +372,6 @@ #define CSR_LED_REG_TRUN_OFF (0x38) /* ANA_PLL */ -#define CSR39_ANA_PLL_CFG_VAL (0x01000000) #define CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index ebdea3be3ef9..2824ccbcc1fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DL_RX (1 << 24) #define IWL_DL_ISR (1 << 25) #define IWL_DL_HT (1 << 26) -#define IWL_DL_IO (1 << 27) /* 0xF0000000 - 0x10000000 */ #define IWL_DL_11H (1 << 28) #define IWL_DL_STATS (1 << 29) @@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) -#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6fe80b5e7a15..0e6a04b739ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -39,6 +39,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" +#include "iwl-agn.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -207,58 +208,86 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, return ret; } -#define BYTE1_MASK 0x000000ff; -#define BYTE2_MASK 0x0000ffff; -#define BYTE3_MASK 0x00ffffff; static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - u32 val; + u32 val = 0; char *buf; ssize_t ret; - int i; + int i = 0; + bool device_format = false; + int offset = 0; + int len = 0; int pos = 0; + int sram; struct iwl_priv *priv = file->private_data; size_t bufsz; /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; - if (priv->ucode_type == UCODE_INIT) - priv->dbgfs_sram_len = priv->ucode_init_data.len; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) + priv->dbgfs_sram_len = priv->ucode_init.data.len; else - priv->dbgfs_sram_len = priv->ucode_data.len; + priv->dbgfs_sram_len = priv->ucode_rt.data.len; + } + len = priv->dbgfs_sram_len; + + if (len == -4) { + device_format = true; + len = 4; } - bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10; + + bufsz = 50 + len * 4; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", - priv->dbgfs_sram_len); + len); pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", priv->dbgfs_sram_offset); - for (i = priv->dbgfs_sram_len; i > 0; i -= 4) { - val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \ - priv->dbgfs_sram_len - i); - if (i < 4) { - switch (i) { - case 1: - val &= BYTE1_MASK; - break; - case 2: - val &= BYTE2_MASK; - break; - case 3: - val &= BYTE3_MASK; - break; - } + + /* adjust sram address since reads are only on even u32 boundaries */ + offset = priv->dbgfs_sram_offset & 0x3; + sram = priv->dbgfs_sram_offset & ~0x3; + + /* read the first u32 from sram */ + val = iwl_read_targ_mem(priv, sram); + + for (; len; len--) { + /* put the address at the start of every line */ + if (i == 0) + pos += scnprintf(buf + pos, bufsz - pos, + "%08X: ", sram + offset); + + if (device_format) + pos += scnprintf(buf + pos, bufsz - pos, + "%02x", (val >> (8 * (3 - offset))) & 0xff); + else + pos += scnprintf(buf + pos, bufsz - pos, + "%02x ", (val >> (8 * offset)) & 0xff); + + /* if all bytes processed, read the next u32 from sram */ + if (++offset == 4) { + sram += 4; + offset = 0; + val = iwl_read_targ_mem(priv, sram); } - if (!(i % 16)) + + /* put in extra spaces and split lines for human readability */ + if (++i == 16) { + i = 0; pos += scnprintf(buf + pos, bufsz - pos, "\n"); - pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); + } else if (!(i & 7)) { + pos += scnprintf(buf + pos, bufsz - pos, " "); + } else if (!(i & 3)) { + pos += scnprintf(buf + pos, bufsz - pos, " "); + } } - pos += scnprintf(buf + pos, bufsz - pos, "\n"); + if (i) + pos += scnprintf(buf + pos, bufsz - pos, "\n"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -282,6 +311,9 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, if (sscanf(buf, "%x,%x", &offset, &len) == 2) { priv->dbgfs_sram_offset = offset; priv->dbgfs_sram_len = len; + } else if (sscanf(buf, "%x", &offset) == 1) { + priv->dbgfs_sram_offset = offset; + priv->dbgfs_sram_len = -4; } else { priv->dbgfs_sram_offset = 0; priv->dbgfs_sram_len = 0; @@ -406,8 +438,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, int pos = 0; ssize_t ret = -ENOMEM; - ret = pos = priv->cfg->ops->lib->dump_nic_event_log( - priv, true, &buf, true); + ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -431,8 +462,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv, true, - NULL, false); + iwl_dump_nic_event_log(priv, true, NULL, false); return count; } @@ -668,29 +698,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char buf[256]; - const size_t bufsz = sizeof(buf); - - pos += scnprintf(buf + pos, bufsz - pos, - "allow blinking: %s\n", - (priv->allow_blinking) ? "True" : "False"); - if (priv->allow_blinking) { - pos += scnprintf(buf + pos, bufsz - pos, - "Led blinking rate: %u\n", - priv->last_blink_rate); - pos += scnprintf(buf + pos, bufsz - pos, - "Last blink time: %lu\n", - priv->last_blink_time); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -856,7 +863,6 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); -DEBUGFS_READ_FILE_OPS(led); DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); @@ -1032,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static const char *fmt_value = " %-30s %10u\n"; +static const char *fmt_hex = " %-30s 0x%02X\n"; +static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; +static const char *fmt_header = + "%-32s current cumulative delta max\n"; + +static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) +{ + int p = 0; + u32 flag; + + flag = le32_to_cpu(priv->statistics.flag); + + p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); + if (flag & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", + (flag & UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", + (flag & UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + + return p; +} + static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 40 + + sizeof(struct statistics_rx_non_phy) * 40 + + sizeof(struct statistics_rx_ht_phy) * 40 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; + struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_non_phy *delta_general, *max_general; + struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; + general = &priv->statistics.rx_non_phy; + ht = &priv->statistics.rx_ofdm_ht; + accum_ofdm = &priv->accum_stats.rx_ofdm; + accum_cck = &priv->accum_stats.rx_cck; + accum_general = &priv->accum_stats.rx_non_phy; + accum_ht = &priv->accum_stats.rx_ofdm_ht; + delta_ofdm = &priv->delta_stats.rx_ofdm; + delta_cck = &priv->delta_stats.rx_cck; + delta_general = &priv->delta_stats.rx_non_phy; + delta_ht = &priv->delta_stats.rx_ofdm_ht; + max_ofdm = &priv->max_delta_stats.rx_ofdm; + max_cck = &priv->max_delta_stats.rx_cck; + max_general = &priv->max_delta_stats.rx_non_phy; + max_ht = &priv->max_delta_stats.rx_ofdm_ht; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(ofdm->ina_cnt), + accum_ofdm->ina_cnt, + delta_ofdm->ina_cnt, max_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, + delta_ofdm->fina_cnt, max_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, + delta_ofdm->plcp_err, max_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, + delta_ofdm->crc32_err, max_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err, delta_ofdm->overrun_err, + max_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err, + delta_ofdm->early_overrun_err, + max_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good, delta_ofdm->crc32_good, + max_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt, + delta_ofdm->false_alarm_cnt, + max_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt, + delta_ofdm->fina_sync_err_cnt, + max_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, + max_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, + max_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts, + delta_ofdm->unresponded_rts, + max_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun, + delta_ofdm->rxe_frame_limit_overrun, + max_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, + max_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, + max_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt, + delta_ofdm->sent_ba_rsp_cnt, + max_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill, + delta_ofdm->dsp_self_kill, + max_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err, + delta_ofdm->mh_format_err, + max_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_ofdm->re_acq_main_rssi_sum, + delta_ofdm->re_acq_main_rssi_sum, + max_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - CCK:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, + delta_cck->ina_cnt, max_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, + delta_cck->fina_cnt, max_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, + delta_cck->plcp_err, max_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, + delta_cck->crc32_err, max_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err, delta_cck->overrun_err, + max_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err, + delta_cck->early_overrun_err, + max_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, + delta_cck->crc32_good, max_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt, + delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt, + delta_cck->fina_sync_err_cnt, + max_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout, delta_cck->sfd_timeout, + max_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout, delta_cck->fina_timeout, + max_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts, delta_cck->unresponded_rts, + max_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun, + delta_cck->rxe_frame_limit_overrun, + max_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, + max_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, + max_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt, + delta_cck->sent_ba_rsp_cnt, + max_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, + max_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err, delta_cck->mh_format_err, + max_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_cck->re_acq_main_rssi_sum, + delta_cck->re_acq_main_rssi_sum, + max_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - GENERAL:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_cts:", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts, delta_general->bogus_cts, + max_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_ack:", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack, delta_general->bogus_ack, + max_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_bssid_frames:", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames, + delta_general->non_bssid_frames, + max_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "filtered_frames:", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames, + delta_general->filtered_frames, + max_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_channel_beacons:", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons, + delta_general->non_channel_beacons, + max_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_beacons:", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons, + delta_general->channel_beacons, + max_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_missed_bcon:", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon, + delta_general->num_missed_bcon, + max_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "adc_rx_saturation_time:", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time, + delta_general->adc_rx_saturation_time, + max_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_detect_search_tm:", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time, + delta_general->ina_detection_search_time, + max_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_a:", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a, + delta_general->beacon_silence_rssi_a, + max_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_b:", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b, + delta_general->beacon_silence_rssi_b, + max_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_c:", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c, + delta_general->beacon_silence_rssi_c, + max_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "interference_data_flag:", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag, + delta_general->interference_data_flag, + max_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_load:", + le32_to_cpu(general->channel_load), + accum_general->channel_load, + delta_general->channel_load, + max_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_false_alarms:", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms, + delta_general->dsp_false_alarms, + max_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_a:", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a, + delta_general->beacon_rssi_a, + max_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_b:", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b, + delta_general->beacon_rssi_b, + max_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_c:", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c, + delta_general->beacon_rssi_c, + max_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_a:", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a, + delta_general->beacon_energy_a, + max_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_b:", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b, + delta_general->beacon_energy_b, + max_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_c:", + le32_to_cpu(general->beacon_energy_c), + accum_general->beacon_energy_c, + delta_general->beacon_energy_c, + max_general->beacon_energy_c); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM_HT:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, + delta_ht->plcp_err, max_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, + delta_ht->overrun_err, max_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err, + delta_ht->early_overrun_err, + max_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, + delta_ht->crc32_good, max_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, + delta_ht->crc32_err, max_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err, + delta_ht->mh_format_err, max_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_crc32_good:", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good, + delta_ht->agg_crc32_good, max_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_mpdu_cnt:", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt, + delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_cnt:", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, + delta_ht->agg_cnt, max_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unsupport_mcs:", + le32_to_cpu(ht->unsupport_mcs), + accum_ht->unsupport_mcs, + delta_ht->unsupport_mcs, max_ht->unsupport_mcs); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, @@ -1046,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 48) + 250; + ssize_t ret; + struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + accum_tx = &priv->accum_stats.tx; + delta_tx = &priv->delta_stats.tx; + max_tx = &priv->max_delta_stats.tx; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Tx:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "preamble:", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt, + delta_tx->preamble_cnt, max_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_detected_cnt:", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt, + delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_defer_cnt:", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt, + delta_tx->bt_prio_defer_cnt, + max_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_kill_cnt:", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt, + delta_tx->bt_prio_kill_cnt, + max_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "few_bytes_cnt:", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt, + delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout:", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, + delta_tx->cts_timeout, max_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_timeout:", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout, + delta_tx->ack_timeout, max_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "expected_ack_cnt:", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt, + delta_tx->expected_ack_cnt, + max_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "actual_ack_cnt:", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt, + delta_tx->actual_ack_cnt, + max_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dump_msdu_cnt:", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt, + delta_tx->dump_msdu_cnt, + max_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_nxt_frame_mismatch:", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt, + delta_tx->burst_abort_next_frame_mismatch_cnt, + max_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_missing_nxt_frame:", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt, + delta_tx->burst_abort_missing_next_frame_cnt, + max_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout_collision:", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision, + delta_tx->cts_timeout_collision, + max_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_ba_timeout_collision:", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision, + delta_tx->ack_or_ba_timeout_collision, + max_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_timeout:", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout, + delta_tx->agg.ba_timeout, + max_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_resched_frames:", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames, + delta_tx->agg.ba_reschedule_frames, + max_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg_frame:", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt, + delta_tx->agg.scd_query_agg_frame_cnt, + max_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_no_agg:", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg, + delta_tx->agg.scd_query_no_agg, + max_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg:", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg, + delta_tx->agg.scd_query_agg, + max_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_mismatch:", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch, + delta_tx->agg.scd_query_mismatch, + max_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg frame_not_ready:", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready, + delta_tx->agg.frame_not_ready, + max_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg underrun:", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun, + delta_tx->agg.underrun, max_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg bt_prio_kill:", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill, + delta_tx->agg.bt_prio_kill, + max_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg rx_ba_rsp_cnt:", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt, + delta_tx->agg.rx_ba_rsp_cnt, + max_tx->agg.rx_ba_rsp_cnt); + + if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna A:", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna B:", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna C:", + tx->tx_power.ant_c); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, @@ -1055,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 10 + 300; + ssize_t ret; + struct statistics_general_common *general, *accum_general; + struct statistics_general_common *delta_general, *max_general; + struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; + struct statistics_div *div, *accum_div, *delta_div, *max_div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.common; + dbg = &priv->statistics.common.dbg; + div = &priv->statistics.common.div; + accum_general = &priv->accum_stats.common; + accum_dbg = &priv->accum_stats.common.dbg; + accum_div = &priv->accum_stats.common.div; + delta_general = &priv->delta_stats.common; + max_general = &priv->max_delta_stats.common; + delta_dbg = &priv->delta_stats.common.dbg; + max_dbg = &priv->max_delta_stats.common.dbg; + delta_div = &priv->delta_stats.common.div; + max_div = &priv->max_delta_stats.common.div; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_General:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature:", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature_m:", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "ttl_timestamp:", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_check:", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check, + delta_dbg->burst_check, max_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_count:", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count, + delta_dbg->burst_count, max_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "wait_for_silence_timeout_count:", + le32_to_cpu(dbg->wait_for_silence_timeout_cnt), + accum_dbg->wait_for_silence_timeout_cnt, + delta_dbg->wait_for_silence_timeout_cnt, + max_dbg->wait_for_silence_timeout_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sleep_time:", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time, + delta_general->sleep_time, max_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_out:", + le32_to_cpu(general->slots_out), + accum_general->slots_out, + delta_general->slots_out, max_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_idle:", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle, + delta_general->slots_idle, max_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_a:", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, + delta_div->tx_on_a, max_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_b:", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, + delta_div->tx_on_b, max_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "exec_time:", + le32_to_cpu(div->exec_time), accum_div->exec_time, + delta_div->exec_time, max_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "probe_time:", + le32_to_cpu(div->probe_time), accum_div->probe_time, + delta_div->probe_time, max_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_enable_counter:", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter, + delta_general->rx_enable_counter, + max_general->rx_enable_counter); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_of_sos_states:", + le32_to_cpu(general->num_of_sos_states), + accum_general->num_of_sos_states, + delta_general->num_of_sos_states, + max_general->num_of_sos_states); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; + ssize_t ret; + struct statistics_bt_activity *bt, *accum_bt; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + if (!priv->bt_enable_flag) + return -EINVAL; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + bt = &priv->statistics.bt_activity; + accum_bt = &priv->accum_stats.bt_activity; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_req_cnt), + accum_bt->hi_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_denied_cnt), + accum_bt->hi_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_req_cnt), + accum_bt->lo_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_denied_cnt), + accum_bt->lo_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_req_cnt), + accum_bt->hi_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_denied_cnt), + accum_bt->hi_priority_rx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_req_cnt), + accum_bt->lo_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_denied_cnt), + accum_bt->lo_priority_rx_denied_cnt); + + pos += scnprintf(buf + pos, bufsz - pos, + "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", + le32_to_cpu(priv->statistics.num_bt_kills), + priv->statistics.accum_num_bt_kills); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + + (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; + ssize_t ret; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), + priv->_agn.reply_tx_stats.pp_few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), + priv->_agn.reply_tx_stats.pp_bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), + priv->_agn.reply_tx_stats.pp_quiet_period); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), + priv->_agn.reply_tx_stats.pp_calc_ttak); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), + priv->_agn.reply_tx_stats.int_crossed_retry); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), + priv->_agn.reply_tx_stats.short_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), + priv->_agn.reply_tx_stats.long_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), + priv->_agn.reply_tx_stats.fifo_underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), + priv->_agn.reply_tx_stats.drain_flow); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), + priv->_agn.reply_tx_stats.rfkill_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), + priv->_agn.reply_tx_stats.life_expire); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), + priv->_agn.reply_tx_stats.dest_ps); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), + priv->_agn.reply_tx_stats.host_abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), + priv->_agn.reply_tx_stats.sta_invalid); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), + priv->_agn.reply_tx_stats.frag_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), + priv->_agn.reply_tx_stats.tid_disable); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), + priv->_agn.reply_tx_stats.fifo_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), + priv->_agn.reply_tx_stats.insuff_cf_poll); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), + priv->_agn.reply_tx_stats.fail_hw_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_NO_BEACON_ON_RADAR), + priv->_agn.reply_tx_stats.sta_color_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_tx_stats.unknown); + + pos += scnprintf(buf + pos, bufsz - pos, + "\nStatistics_Agg_TX_Error:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), + priv->_agn.reply_agg_tx_stats.underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), + priv->_agn.reply_agg_tx_stats.bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), + priv->_agn.reply_agg_tx_stats.few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), + priv->_agn.reply_agg_tx_stats.abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TTL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_ttl); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_try); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), + priv->_agn.reply_agg_tx_stats.scd_query); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_TEST_BAD_CRC32_MSK), + priv->_agn.reply_agg_tx_stats.bad_crc32); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), + priv->_agn.reply_agg_tx_stats.response); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), + priv->_agn.reply_agg_tx_stats.dump_tx); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), + priv->_agn.reply_agg_tx_stats.delay_tx); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_agg_tx_stats.unknown); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, @@ -1261,8 +2238,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, if (sscanf(buf, "%d", &csr) != 1) return -EFAULT; - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); + iwl_dump_csr(priv); return count; } @@ -1352,13 +2328,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, int pos = 0; ssize_t ret = -EFAULT; - if (priv->cfg->ops->lib->dump_fh) { - ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } + ret = pos = iwl_dump_fh(priv, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, + count, ppos, buf, pos); + kfree(buf); } return ret; @@ -1524,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - - return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file, - user_buf, count, ppos); -} - static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1565,12 +2529,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, int pos = 0; char buf[200]; const size_t bufsz = sizeof(buf); - ssize_t ret; if (!priv->bt_enable_flag) { pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", priv->bt_enable_flag); @@ -1580,10 +2542,9 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, "last traffic notif: %d\n", priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load); pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, " - "sco_active: %d, kill_ack_mask: %x, " - "kill_cts_mask: %x\n", - priv->bt_ch_announce, priv->bt_sco_active, - priv->kill_ack_mask, priv->kill_cts_mask); + "kill_ack_mask: %x, kill_cts_mask: %x\n", + priv->bt_ch_announce, priv->kill_ack_mask, + priv->kill_cts_mask); pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: "); switch (priv->bt_traffic_load) { @@ -1602,8 +2563,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, break; } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, @@ -1652,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - - if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error) - return priv->cfg->ops->lib->debugfs_ops.reply_tx_error( - file, user_buf, count, ppos); - else - return -ENODATA; -} DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1725,12 +2673,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR); - if (!priv->cfg->base_params->broken_powersave) { - DEBUGFS_ADD_FILE(sleep_level_override, dir_data, - S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); - } + DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); @@ -1753,29 +2697,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - if (priv->cfg->base_params->ucode_tracing) - DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics) - DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); - if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) + if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, - &priv->disable_sens_cal); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, - &priv->disable_chain_noise_cal); - if (priv->cfg->base_params->tx_power_by_driver) - DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, - &priv->disable_tx_power_cal); + DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, + &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, + &priv->disable_chain_noise_cal); return 0; err: @@ -1783,7 +2718,6 @@ err: iwl_dbgfs_unregister(priv); return -ENOMEM; } -EXPORT_SYMBOL(iwl_dbgfs_register); /** * Remove the debugfs files and directories @@ -1797,7 +2731,6 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) debugfs_remove_recursive(priv->debugfs_dir); priv->debugfs_dir = NULL; } -EXPORT_SYMBOL(iwl_dbgfs_unregister); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8dda67850af4..214e4658c495 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -26,7 +26,6 @@ /* * Please use this file (iwl-dev.h) for driver implementation definitions. * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. */ #ifndef __iwl_dev_h__ @@ -34,6 +33,8 @@ #include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> +#include <linux/wait.h> +#include <linux/leds.h> #include <net/ieee80211_radiotap.h> #include "iwl-eeprom.h" @@ -41,14 +42,14 @@ #include "iwl-prph.h" #include "iwl-fh.h" #include "iwl-debug.h" -#include "iwl-4965-hw.h" -#include "iwl-3945-hw.h" #include "iwl-agn-hw.h" #include "iwl-led.h" #include "iwl-power.h" #include "iwl-agn-rs.h" #include "iwl-agn-tt.h" +#define U32_PAD(n) ((4-(n))&0x3) + struct iwl_tx_queue; /* CT-KILL constants */ @@ -136,7 +137,7 @@ struct iwl_queue { * space more than this */ int high_mark; /* high watermark, stop queue if free * space less than this */ -} __packed; +}; /* One for each TFD */ struct iwl_tx_info { @@ -177,53 +178,12 @@ struct iwl_tx_queue { #define IWL_NUM_SCAN_RATES (2) -struct iwl4965_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl4965_channel_tgh_info { - s64 last_radar_time; -}; - -#define IWL4965_MAX_RATE (33) - -struct iwl3945_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl3945_channel_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl3945_scan_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - /* * One for each channel, holds all channel setup data * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant * with one another! */ struct iwl_channel_info { - struct iwl4965_channel_tgd_info tgd; - struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for * HT40 channel */ @@ -243,14 +203,6 @@ struct iwl_channel_info { s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ u8 ht40_flags; /* flags copied from EEPROM */ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; }; #define IWL_TX_FIFO_BK 0 /* shared */ @@ -286,15 +238,6 @@ struct iwl_channel_info { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl_frame { - union { - struct ieee80211_hdr frame; - struct iwl_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) @@ -307,6 +250,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -414,6 +358,7 @@ struct iwl_ht_agg { #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 #define IWL_EMPTYING_HW_QUEUE_DELBA 3 u8 state; + u8 tx_fifo; }; @@ -497,9 +442,6 @@ struct iwl_station_priv_common { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * The common struct MUST be first because it is shared between - * 3945 and agn! */ struct iwl_station_priv { struct iwl_station_priv_common common; @@ -507,6 +449,7 @@ struct iwl_station_priv { atomic_t pending_frames; bool client; bool asleep; + u8 max_agg_bufsize; }; /** @@ -527,6 +470,10 @@ struct fw_desc { u32 len; /* bytes */ }; +struct fw_img { + struct fw_desc code, data; +}; + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -583,6 +530,22 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + /* 16 and 17 reserved for future use */ + IWL_UCODE_TLV_FLAGS = 18, +}; + +/** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean + * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + */ +enum iwl_ucode_tlv_flag { + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; struct iwl_ucode_tlv { @@ -616,14 +579,6 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; -struct iwl4965_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - struct iwl_sensitivity_ranges { u16 min_nrg_cck; u16 max_nrg_cck; @@ -697,7 +652,6 @@ struct iwl_hw_params { u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; - u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ u32 ct_kill_exit_threshold; /* value in hw-dependent units */ /* for 1000, 6000 series and up */ @@ -719,8 +673,6 @@ struct iwl_hw_params { * Naming convention -- * iwl_ <-- Is part of iwlwifi * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl4965_bg_ <-- Called from work queue context - * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); @@ -769,7 +721,6 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define IWL4965_CAL_NUM_BEACONS 20 #define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -803,24 +754,19 @@ struct iwl_dma_ptr { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS 3 -enum iwl4965_false_alarm_state { +enum iwlagn_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, IWL_FA_GOOD_RANGE = 2, }; -enum iwl4965_chain_noise_state { +enum iwlagn_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ IWL_CHAIN_NOISE_ACCUMULATE, IWL_CHAIN_NOISE_CALIBRATED, IWL_CHAIN_NOISE_DONE, }; -enum iwl4965_calib_enabled_state { - IWL_CALIB_DISABLED = 0, /* must be 0 */ - IWL_CALIB_ENABLED = 1, -}; - /* * enum iwl_calib @@ -844,12 +790,6 @@ struct iwl_calib_result { size_t buf_len; }; -enum ucode_type { - UCODE_NONE = 0, - UCODE_INIT, - UCODE_RT -}; - /* Sensitivity calib data */ struct iwl_sensitivity_data { u32 auto_corr_ofdm; @@ -995,7 +935,6 @@ struct reply_agg_tx_error_statistics { u32 unknown; }; -#ifdef CONFIG_IWLWIFI_DEBUGFS /* management statistics */ enum iwl_mgmt_stats { MANAGEMENT_ASSOC_REQ = 0, @@ -1026,16 +965,13 @@ enum iwl_ctrl_stats { }; struct traffic_stats { +#ifdef CONFIG_IWLWIFI_DEBUGFS u32 mgmt[MANAGEMENT_MAX]; u32 ctrl[CONTROL_MAX]; u32 data_cnt; u64 data_bytes; -}; -#else -struct traffic_stats { - u64 data_bytes; -}; #endif +}; /* * iwl_switch_rxon: "channel switch" structure @@ -1111,6 +1047,11 @@ struct iwl_event_log { /* BT Antenna Coupling Threshold (dB) */ #define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35) +/* Firmware reload counter and Timestamp */ +#define IWL_MIN_RELOAD_DURATION 1000 /* 1000 ms */ +#define IWL_MAX_CONTINUE_RELOAD_CNT 4 + + enum iwl_reset { IWL_RF_RESET = 0, IWL_FW_RESET, @@ -1127,18 +1068,41 @@ struct iwl_force_reset { /* extend beacon time format bit shifting */ /* - * for _3945 devices - * bits 31:24 - extended - * bits 23:0 - interval - */ -#define IWL3945_EXT_BEACON_TIME_POS 24 -/* * for _agn devices * bits 31:22 - extended * bits 21:0 - interval */ #define IWLAGN_EXT_BEACON_TIME_POS 22 +/** + * struct iwl_notification_wait - notification wait entry + * @list: list head for global list + * @fn: function called with the notification + * @cmd: command ID + * + * This structure is not used directly, to wait for a + * notification declare it on the stack, and call + * iwlagn_init_notification_wait() with appropriate + * parameters. Then do whatever will cause the ucode + * to notify the driver, and to wait for that then + * call iwlagn_wait_notification(). + * + * Each notification is one-shot. If at some point we + * need to support multi-shot notifications (which + * can't be allocated on the stack) we need to modify + * the code for them. + */ +struct iwl_notification_wait { + struct list_head list; + + void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, + void *data); + void *fn_data; + + u8 cmd; + bool triggered, aborted; +}; + enum iwl_rxon_context_id { IWL_RXON_CTX_BSS, IWL_RXON_CTX_PAN, @@ -1197,6 +1161,14 @@ struct iwl_rxon_context { bool enabled, is_40mhz; u8 extension_chan_offset; } ht; + + bool last_tx_rejected; +}; + +enum iwl_scan_type { + IWL_SCAN_NORMAL, + IWL_SCAN_RADIO_RESET, + IWL_SCAN_OFFCH_TX, }; struct iwl_priv { @@ -1207,13 +1179,10 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct iwl_cfg *cfg; - /* temporary frame storage list */ - struct list_head free_frames; - int frames_count; - enum ieee80211_band band; - int alloc_rxb_page; + void (*pre_rx_handler)(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -1230,12 +1199,16 @@ struct iwl_priv { /* track IBSS manager (last beacon) status */ u32 ibss_manager; - /* storing the jiffies when the plcp error rate is received */ - unsigned long plcp_jiffies; + /* jiffies when last recovery from statistics was performed */ + unsigned long rx_statistics_jiffies; /* force reset */ struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET]; + /* firmware reload counter and timestamp */ + unsigned long reload_jiffies; + int reload_count; + /* we allocate array of iwl_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ struct iwl_channel_info *channel_info; /* channel info array */ @@ -1255,7 +1228,7 @@ struct iwl_priv { enum ieee80211_band scan_band; struct cfg80211_scan_request *scan_request; struct ieee80211_vif *scan_vif; - bool is_internal_short_scan; + enum iwl_scan_type scan_type; u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; @@ -1264,16 +1237,12 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; /* pci hardware address support */ void __iomem *hw_base; - u32 hw_rev; - u32 hw_wa_rev; - u8 rev_id; /* microcode/device supports multiple contexts */ u8 valid_contexts; @@ -1284,6 +1253,8 @@ struct iwl_priv { /* max number of station keys */ u8 sta_key_max_num; + bool new_scan_threshold_behaviour; + /* EEPROM MAC addresses */ struct mac_address addresses[2]; @@ -1291,13 +1262,10 @@ struct iwl_priv { int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - struct fw_desc ucode_code; /* runtime inst */ - struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_data_backup; /* runtime data save/restore */ - struct fw_desc ucode_init; /* initialization inst */ - struct fw_desc ucode_init_data; /* initialization data */ - struct fw_desc ucode_boot; /* bootstrap inst */ - enum ucode_type ucode_type; + struct fw_img ucode_rt; + struct fw_img ucode_init; + + enum iwlagn_ucode_subtype ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; @@ -1305,15 +1273,10 @@ struct iwl_priv { struct iwl_switch_rxon switch_rxon; - /* 1st responses from initialize and runtime uCode images. - * _agn's initialize alive response contains some calibration data. */ - struct iwl_init_alive_resp card_alive_init; - struct iwl_alive_resp card_alive; - - unsigned long last_blink_time; - u8 last_blink_rate; - u8 allow_blinking; - u64 led_tpt; + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; u16 active_rate; @@ -1354,15 +1317,12 @@ struct iwl_priv { struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; - /* context information */ - u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ - /* station table variables */ /* Note: if lock and sta_lock are needed, lock must be acquired first */ spinlock_t sta_lock; int num_stations; - struct iwl_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; /* queue refcounts */ @@ -1386,93 +1346,87 @@ struct iwl_priv { /* Last Rx'd beacon timestamp */ u64 timestamp; - union { -#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) - struct { - void *shared_virt; - dma_addr_t shared_phys; - - struct delayed_work thermal_periodic; - struct delayed_work rfkill_poll; - - struct iwl3945_notif_statistics statistics; + struct { + __le32 flag; + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl3945_notif_statistics accum_statistics; - struct iwl3945_notif_statistics delta_statistics; - struct iwl3945_notif_statistics max_delta; + struct statistics_bt_activity bt_activity; + __le32 num_bt_kills, accum_num_bt_kills; #endif - - u32 sta_supp_rates; - int last_rx_rssi; /* From Rx packet statistics */ - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* - * each calibration channel group in the - * EEPROM has a derived clip setting for - * each rate. - */ - const struct iwl3945_clip_group clip_groups[5]; - - } _3945; -#endif -#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) - struct { - /* INT ICT Table */ - __le32 *ict_tbl; - void *ict_tbl_vir; - dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; - int ict_index; - u32 inta; - bool use_ict; - /* - * reporting the number of tids has AGG on. 0 means - * no AGGREGATION - */ - u8 agg_tids_count; - - struct iwl_rx_phy_res last_phy_res; - bool last_phy_res_valid; - - struct completion firmware_loading_complete; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - - /* - * chain noise reset and gain commands are the - * two extra calibration commands follows the standard - * phy calibration commands - */ - u8 phy_calib_chain_noise_reset_cmd; - u8 phy_calib_chain_noise_gain_cmd; - - struct iwl_notif_statistics statistics; - struct iwl_bt_notif_statistics statistics_bt; - /* counts reply_tx error */ - struct reply_tx_error_statistics reply_tx_stats; - struct reply_agg_tx_error_statistics reply_agg_tx_stats; + } statistics; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; - struct iwl_bt_notif_statistics accum_statistics_bt; - struct iwl_bt_notif_statistics delta_statistics_bt; - struct iwl_bt_notif_statistics max_delta_bt; -#endif - } _agn; + struct { + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; + struct statistics_bt_activity bt_activity; + } accum_stats, delta_stats, max_delta_stats; #endif - }; + + struct { + /* INT ICT Table */ + __le32 *ict_tbl; + void *ict_tbl_vir; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + u32 inta; + bool use_ict; + /* + * reporting the number of tids has AGG on. 0 means + * no AGGREGATION + */ + u8 agg_tids_count; + + struct iwl_rx_phy_res last_phy_res; + bool last_phy_res_valid; + + struct completion firmware_loading_complete; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + /* + * chain noise reset and gain commands are the + * two extra calibration commands follows the standard + * phy calibration commands + */ + u8 phy_calib_chain_noise_reset_cmd; + u8 phy_calib_chain_noise_gain_cmd; + + /* counts reply_tx error */ + struct reply_tx_error_statistics reply_tx_stats; + struct reply_agg_tx_error_statistics reply_agg_tx_stats; + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + /* remain-on-channel offload support */ + struct ieee80211_channel *hw_roc_channel; + struct delayed_work hw_roc_work; + enum nl80211_channel_type hw_roc_chantype; + int hw_roc_duration; + bool hw_roc_setup; + + struct sk_buff *offchan_tx_skb; + int offchan_tx_timeout; + struct ieee80211_channel *offchan_tx_chan; + } _agn; /* bt coex */ u8 bt_enable_flag; u8 bt_status; u8 bt_traffic_load, last_bt_traffic_load; bool bt_ch_announce; - bool bt_sco_active; bool bt_full_concurrent; bool bt_ant_couple_ok; __le32 kill_ack_mask; @@ -1509,8 +1463,6 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; - struct delayed_work init_alive_start; - struct delayed_work alive_start; struct delayed_work scan_check; /* TX Power */ @@ -1539,14 +1491,16 @@ struct iwl_priv { struct work_struct txpower_work; u32 disable_sens_cal; u32 disable_chain_noise_cal; - u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; struct timer_list ucode_trace; struct timer_list watchdog; - bool hw_ready; struct iwl_event_log event_log; + + struct led_classdev led; + unsigned long blink_on, blink_off; + bool led_registered; }; /*iwl_priv */ static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) @@ -1604,21 +1558,24 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \ if (priv->valid_contexts & BIT(ctx->ctxid)) -static inline int iwl_is_associated(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid) +static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) { - return (priv->contexts[ctxid].active.filter_flags & - RXON_FILTER_ASSOC_MSK) ? 1 : 0; + return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; } -static inline int iwl_is_any_associated(struct iwl_priv *priv) +static inline int iwl_is_associated(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) { - return iwl_is_associated(priv, IWL_RXON_CTX_BSS); + return iwl_is_associated_ctx(&priv->contexts[ctxid]); } -static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) +static inline int iwl_is_any_associated(struct iwl_priv *priv) { - return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; + struct iwl_rxon_context *ctx; + for_each_context(priv, ctx) + if (iwl_is_associated_ctx(ctx)) + return true; + return false; } static inline int is_channel_valid(const struct iwl_channel_info *ch_info) @@ -1656,12 +1613,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) { __free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) { free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4a487639d932..a635a7e75447 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4cf864c664ee..f00172cb8a6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 358cfd7e5af1..c8397962632c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * ******************************************************************************/ +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_EEPROM(priv, + "Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} + +static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} + static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; @@ -188,18 +227,16 @@ static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwlcore_get_nvm_type(struct iwl_priv *priv) +static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) { u32 otpgp; int nvm_type; /* OTP only valid for CP/PP and after */ - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: IWL_ERR(priv, "Unknown hardware type\n"); return -ENOENT; - case CSR_HW_REV_TYPE_3945: - case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: case CSR_HW_REV_TYPE_5100: @@ -217,27 +254,20 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) return nvm_type; } -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) -{ - BUG_ON(offset >= priv->cfg->base_params->eeprom_size); - return &priv->eeprom[offset]; -} -EXPORT_SYMBOL(iwlcore_eeprom_query_addr); - static int iwl_init_otp_access(struct iwl_priv *priv) { int ret; /* Enable 40MHz radio clock */ - _iwl_write32(priv, CSR_GP_CNTRL, - _iwl_read32(priv, CSR_GP_CNTRL) | - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_write32(priv, CSR_GP_CNTRL, + iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { @@ -264,17 +294,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat u32 r; u32 otpgp; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + CSR_EEPROM_REG_READ_VALID_MSK, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); return ret; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); /* check for ECC errors: */ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { @@ -382,7 +412,6 @@ const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset); } -EXPORT_SYMBOL(iwl_eeprom_query_addr); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) { @@ -390,7 +419,6 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) return 0; return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); } -EXPORT_SYMBOL(iwl_eeprom_query16); /** * iwl_eeprom_init - read EEPROM contents @@ -399,7 +427,7 @@ EXPORT_SYMBOL(iwl_eeprom_query16); * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); @@ -409,7 +437,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwlcore_get_nvm_type(priv); + priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ @@ -432,7 +460,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); + ret = iwl_eeprom_acquire_semaphore(priv); if (ret < 0) { IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; @@ -447,9 +475,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto done; } - _iwl_write32(priv, CSR_EEPROM_GP, - iwl_read32(priv, CSR_EEPROM_GP) & - ~CSR_EEPROM_GP_IF_OWNER_MSK); + iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | @@ -476,8 +504,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, @@ -487,7 +515,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } @@ -499,7 +527,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = 0; done: - priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); + iwl_eeprom_release_semaphore(priv); err: if (ret) @@ -509,14 +537,12 @@ err: alloc_err: return ret; } -EXPORT_SYMBOL(iwl_eeprom_init); void iwl_eeprom_free(struct iwl_priv *priv) { kfree(priv->eeprom); priv->eeprom = NULL; } -EXPORT_SYMBOL(iwl_eeprom_free); static void iwl_init_band_reference(const struct iwl_priv *priv, int eep_band, int *eeprom_ch_count, @@ -724,13 +750,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } @@ -779,7 +798,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) return 0; } -EXPORT_SYMBOL(iwl_init_channel_map); /* * iwl_free_channel_map - undo allocations in iwl_init_channel_map @@ -789,7 +807,6 @@ void iwl_free_channel_map(struct iwl_priv *priv) kfree(priv->channel_info); priv->channel_count = 0; } -EXPORT_SYMBOL(iwl_free_channel_map); /** * iwl_get_channel_info - Find driver's private channel info @@ -818,4 +835,3 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, return NULL; } -EXPORT_SYMBOL(iwl_get_channel_info); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 9e6f31355eee..c960c6fa009b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -110,10 +110,6 @@ enum { }; /* SKU Capabilities */ -/* 3945 only */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - /* 5000 and up */ #define EEPROM_SKU_CAP_BAND_POS (4) #define EEPROM_SKU_CAP_BAND_SELECTION \ @@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr { s8 mimo3_max; } __packed; -/* 3945 Specific */ -#define EEPROM_3945_EEPROM_VERSION (0x2f) - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 Specific */ -/* 4965 driver does not work with txpower calibration version < 5 */ -#define EEPROM_4965_TX_POWER_VERSION (5) -#define EEPROM_4965_EEPROM_VERSION (0x2f) -#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ -#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - /* 5000 Specific */ #define EEPROM_5000_TX_POWER_VERSION (4) #define EEPROM_5000_EEPROM_VERSION (0x11A) @@ -241,19 +215,32 @@ struct iwl_eeprom_enhanced_txpwr { /* 6x00 Specific */ #define EEPROM_6000_TX_POWER_VERSION (4) -#define EEPROM_6000_EEPROM_VERSION (0x434) +#define EEPROM_6000_EEPROM_VERSION (0x423) /* 6x50 Specific */ #define EEPROM_6050_TX_POWER_VERSION (4) #define EEPROM_6050_EEPROM_VERSION (0x532) -/* 6x50g2 Specific */ -#define EEPROM_6050G2_TX_POWER_VERSION (6) -#define EEPROM_6050G2_EEPROM_VERSION (0x553) +/* 6150 Specific */ +#define EEPROM_6150_TX_POWER_VERSION (6) +#define EEPROM_6150_EEPROM_VERSION (0x553) + +/* 6x05 Specific */ +#define EEPROM_6005_TX_POWER_VERSION (6) +#define EEPROM_6005_EEPROM_VERSION (0x709) + +/* 6x30 Specific */ +#define EEPROM_6030_TX_POWER_VERSION (6) +#define EEPROM_6030_EEPROM_VERSION (0x709) + +/* 2x00 Specific */ +#define EEPROM_2000_TX_POWER_VERSION (6) +#define EEPROM_2000_EEPROM_VERSION (0x805) + +/* 6x35 Specific */ +#define EEPROM_6035_TX_POWER_VERSION (6) +#define EEPROM_6035_EEPROM_VERSION (0x753) -/* 6x00g2 Specific */ -#define EEPROM_6000G2_TX_POWER_VERSION (6) -#define EEPROM_6000G2_EEPROM_VERSION (0x709) /* OTP */ /* lower blocks contain EEPROM image and calibration data */ @@ -264,94 +251,11 @@ struct iwl_eeprom_enhanced_txpwr { #define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ #define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ #define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ +#define OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -/* - * factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __packed; - - -/* - * measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl_eeprom_calib_ch_info { - u8 ch_num; - struct iwl_eeprom_calib_measure - measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __packed; - -/* - * txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl_eeprom_calib_ch_info ch1; - struct iwl_eeprom_calib_ch_info ch2; -} __packed; - - -/* - * txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - __le16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info - band_info[EEPROM_TX_POWER_BANDS]; -} __packed; - - #define ADDRESS_MSK 0x0000FFFF #define INDIRECT_TYPE_MSK 0x000F0000 #define INDIRECT_HOST 0x00010000 @@ -384,103 +288,24 @@ struct iwl_eeprom_calib_info { #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 -#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 - -/* Radio Config for 5000 and up */ -#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 -#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 -#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by iwl has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - -/* - * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, - * and the overall HT40 channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a HT40 channel. - * - * NOTE: 4965 does not support HT40 channels on 2.4 GHz. - */ -#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ - -/* - * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ - #define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { const u32 regulatory_bands[7]; - int (*acquire_semaphore) (struct iwl_priv *priv); - void (*release_semaphore) (struct iwl_priv *priv); - u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); void (*update_enhanced_txpower) (struct iwl_priv *priv); }; -int iwl_eeprom_init(struct iwl_priv *priv); +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); void iwl_eeprom_free(struct iwl_priv *priv); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 55b8370bc6d4..6dfa806aefec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,14 +77,14 @@ /** * Keep-Warm (KW) buffer base address. * - * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * Driver must allocate a 4KByte buffer that is for keeping the * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency - * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * DRAM access when doing Txing or Rxing. The dummy accesses prevent host * from going into a power-savings mode that would cause higher DRAM latency, * and possible data over/under-runs, before all Tx/Rx is complete. * * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) - * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * of the buffer, which must be 4K aligned. Once this is set up, the device * automatically invokes keep-warm accesses when normal accesses might not * be sufficient to maintain fast DRAM response. * @@ -97,7 +97,7 @@ /** * TFD Circular Buffers Base (CBBC) addresses * - * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte @@ -116,16 +116,16 @@ /** * Rx SRAM Control and Status Registers (RSCSR) * - * These registers provide handshake between driver and 4965 for the Rx queue + * These registers provide handshake between driver and device for the Rx queue * (this queue handles *all* command responses, notifications, Rx data, etc. - * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * sent from uCode to host driver). Unlike Tx, there is only one Rx * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * mapping between RBDs and RBs. * * Driver must allocate host DRAM memory for the following, and set the - * physical address of each into 4965 registers: + * physical address of each into device registers: * * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * entries (although any power of 2, up to 4096, is selectable by driver). @@ -140,20 +140,20 @@ * Driver sets physical address [35:8] of base of RBD circular buffer * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * - * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers * (RBs) have been filled, via a "write pointer", actually the index of * the RB's corresponding RBD within the circular buffer. Driver sets * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * * Bit fields in lower dword of Rx status buffer (upper dword not used - * by driver; see struct iwl4965_shared, val0): + * by driver: * 31-12: Not used by driver * 11- 0: Index of last filled Rx buffer descriptor - * (4965 writes, driver reads this value) + * (device writes, driver reads this value) * - * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * As the driver prepares Receive Buffers (RBs) for device to fill, driver must * enter pointers to these RBs into contiguous RBD circular buffer entries, - * and update the 4965's "write" index register, + * and update the device's "write" index register, * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * * This "write" index corresponds to the *next* RBD that the driver will make @@ -162,12 +162,12 @@ * RBs), should be 8 after preparing the first 8 RBs (for example), and must * wrap back to 0 at the end of the circular buffer (but don't wrap before * "read" index has advanced past 1! See below). - * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * - * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * As the device fills RBs (referenced from contiguous RBDs within the circular * buffer), it updates the Rx status buffer in host DRAM, 2) described above, * to tell the driver the index of the latest filled RBD. The driver must - * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * read this "read" index from DRAM after receiving an Rx interrupt from device * * The driver must also internally keep track of a third index, which is the * next RBD to process. When receiving an Rx interrupt, driver should process @@ -176,7 +176,7 @@ * driver may process the RB pointed to by RBD 0. Depending on volume of * traffic, there may be many RBs to process. * - * If read index == write index, 4965 thinks there is no room to put new data. + * If read index == write index, device thinks there is no room to put new data. * Due to this, the maximum number of filled RBs is 255, instead of 256. To * be safe, make sure that there is a gap of at least 2 RBDs between "write" * and "read" indexes; that is, make sure that there are no more than 254 @@ -303,7 +303,7 @@ /** * Transmit DMA Channel Control/Status Registers (TCSR) * - * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * Device has one configuration register for each of 8 Tx DMA/FIFO channels * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * @@ -326,7 +326,6 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH49_TCSR_CHNL_NUM (7) #define FH50_TCSR_CHNL_NUM (8) /* TCSR: tx_config register values */ @@ -424,7 +423,6 @@ #define RX_LOW_WATERMARK 8 /* Size of one Rx buffer in host DRAM */ -#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */ #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) @@ -436,14 +434,14 @@ * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame - * which was transfered + * which was transferred */ struct iwl_rb_status { __le16 closed_rb_num; __le16 closed_fr_num; __le16 finished_rb_num; __le16 finished_fr_nam; - __le32 __unused; /* 3945 only */ + __le32 __unused; } __packed; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index c373b53babea..8f0beb992ccf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_REMOVE_ALL_STA); IWL_CMD(REPLY_TXFIFO_FLUSH); IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_3945_RX); IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); @@ -108,12 +106,12 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_WIPAN_WEPKEY); IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); + IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); default: return "UNKNOWN"; } } -EXPORT_SYMBOL(get_cmd_string); #define HOST_COMPLETE_TIMEOUT (HZ / 2) @@ -145,10 +143,12 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int ret; - BUG_ON(!(cmd->flags & CMD_ASYNC)); + if (WARN_ON(!(cmd->flags & CMD_ASYNC))) + return -EINVAL; /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->flags & CMD_WANT_SKB); + if (WARN_ON(cmd->flags & CMD_WANT_SKB)) + return -EINVAL; /* Assign a generic callback if one is not provided */ if (!cmd->callback) @@ -171,14 +171,15 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->flags & CMD_ASYNC); + if (WARN_ON(cmd->flags & CMD_ASYNC)) + return -EINVAL; /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->callback); + if (WARN_ON(cmd->callback)) + return -EINVAL; IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -189,7 +190,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = cmd_idx; IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); - goto out; + return ret; } ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -229,8 +230,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto cancel; } - ret = 0; - goto out; + return 0; cancel: if (cmd->flags & CMD_WANT_SKB) { @@ -248,11 +248,9 @@ fail: iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } -out: - mutex_unlock(&priv->sync_cmd_mutex); + return ret; } -EXPORT_SYMBOL(iwl_send_cmd_sync); int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { @@ -261,7 +259,6 @@ int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return iwl_send_cmd_sync(priv, cmd); } -EXPORT_SYMBOL(iwl_send_cmd); int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) { @@ -273,7 +270,6 @@ int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) return iwl_send_cmd_sync(priv, &cmd); } -EXPORT_SYMBOL(iwl_send_cmd_pdu); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, @@ -292,4 +288,3 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, return iwl_send_cmd_async(priv, &cmd); } -EXPORT_SYMBOL(iwl_send_cmd_pdu_async); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8821f088ba7f..41207a3645b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) return --index & (n_bd - 1); } -/* TODO: Move fw_desc functions to iwl-pci.ko */ -static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (desc->v_addr) - dma_free_coherent(&pci_dev->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; - desc->len = 0; -} - -static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (!desc->len) { - desc->v_addr = NULL; - return -EINVAL; - } - - desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, - &desc->p_addr, GFP_KERNEL); - return (desc->v_addr != NULL) ? 0 : -ENOMEM; -} - /* * we have 8 bits used like this: * @@ -131,6 +107,19 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, ieee80211_stop_queue(priv->hw, ac); } +static inline void iwl_wake_any_queue(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + u8 ac; + + for (ac = 0; ac < AC_NUM; ac++) { + IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n", + ac, (atomic_read(&priv->queue_stop_count[ac]) > 0) + ? "stopped" : "awake"); + iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]); + } +} + #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c new file mode 100644 index 000000000000..aa4a90674452 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include "iwl-io.h" + +#define IWL_POLL_INTERVAL 10 /* microseconds */ + +static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); +} + +static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); +} + +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_set_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_clear_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_read32(priv, addr) & mask) == (bits & mask)) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_grab_nic_access_silent(struct iwl_priv *priv) +{ + int ret; + + lockdep_assert_held(&priv->reg_lock); + + /* this bit wakes up the NIC */ + __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + if (ret < 0) { + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + return -EIO; + } + + return 0; +} + +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret = iwl_grab_nic_access_silent(priv); + if (ret) { + u32 val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + } + + return ret; +} + +void iwl_release_nic_access(struct iwl_priv *priv) +{ + lockdep_assert_held(&priv->reg_lock); + __iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + value = iwl_read32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return value; +} + +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout) +{ + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); + return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); +} + +static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + iwl_write32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); + iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); +} + +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return val; +} + +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + __iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, + (__iwl_read_prph(priv, reg) & mask) | bits); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + __iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words) +{ + unsigned long flags; + int offs; + u32 *vals = buf; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + + iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); + + for (offs = 0; offs < words; offs++) + vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + u32 value; + + _iwl_read_targ_mem_words(priv, addr, &value, 1); + + return value; +} + +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0203a3bbf872..869edc580ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -35,494 +35,58 @@ #include "iwl-debug.h" #include "iwl-devtrace.h" -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * and the current line number and caller function name are printed in addition - * to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's name and __LINE__ to the double - * prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl_read_direct32 calls the non-check version of - * _iwl_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguration of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) { trace_iwlwifi_dev_iowrite8(priv, ofs, val); iowrite8(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u8 val) -{ - IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); - _iwl_write8(priv, ofs, val); -} -#define iwl_write8(priv, ofs, val) \ - __iwl_write8(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) -#endif - - -static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); iowrite32(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl_write32(priv, ofs, val); -} -#define iwl_write32(priv, ofs, val) \ - __iwl_write32(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) -#endif - -static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) { u32 val = ioread32(priv->hw_base + ofs); trace_iwlwifi_dev_ioread32(priv, ofs, val); return val; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) -{ - IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl_read32(priv, ofs); -} -#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) -#else -#define iwl_read32(p, o) _iwl_read32(p, o) -#endif - -#define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); - IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", - addr, bits, mask, - unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); - return ret; -} -#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ - __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) -#else -#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) | mask; - IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_set_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_set_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_clear_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) & ~mask; - IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_clear_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_clear_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline int _iwl_grab_nic_access(struct iwl_priv *priv) -{ - int ret; - u32 val; - - /* this bit wakes up the NIC */ - _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* - * These bits say the device is running, and should keep running for - * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), - * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. - * Each direction takes approximately 1/4 millisecond; with this - * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a - * series of register accesses are expected (e.g. reading Event Log), - * to keep device from sleeping. - * - * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that - * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). - * - * 5000 series and later (including 1000 series) have non-volatile SRAM, - * and do not save/restore SRAM when power cycling. - */ - ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); - if (ret < 0) { - val = _iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); - _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - return -EIO; - } - - return 0; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_grab_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); - return _iwl_grab_nic_access(priv); -} -#define iwl_grab_nic_access(priv) \ - __iwl_grab_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_grab_nic_access(priv) \ - _iwl_grab_nic_access(priv) -#endif - -static inline void _iwl_release_nic_access(struct iwl_priv *priv) -{ - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_release_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - - IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); - _iwl_release_nic_access(priv); -} -#define iwl_release_nic_access(priv) \ - __iwl_release_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_release_nic_access(priv) \ - _iwl_release_nic_access(priv) -#endif - -static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - return _iwl_read32(priv, reg); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_direct32(const char *f, u32 l, - struct iwl_priv *priv, u32 reg) -{ - u32 value = _iwl_read_direct32(priv, reg); - IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, - f, l); - return value; -} -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -#else -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = _iwl_read_direct32(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; - -} -#endif - -static inline void _iwl_write_direct32(struct iwl_priv *priv, - u32 reg, u32 value) -{ - _iwl_write32(priv, reg, value); -} -static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, reg, value); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_reg_buf(struct iwl_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - iwl_write_direct32(priv, reg, *values); - } -} - -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, - u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_direct32(priv, addr) & mask) == mask) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_direct_bit(const char *f, u32 l, - struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); - - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, ret, f, l); - return ret; -} -#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ - __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) -#else -#define iwl_poll_direct_bit _iwl_poll_direct_bit -#endif - -static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - rmb(); - return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); -} -static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return val; -} - -static inline void _iwl_write_prph(struct iwl_priv *priv, - u32 addr, u32 val) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); -} - -static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_prph(priv, addr, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -#define _iwl_set_bits_prph(priv, reg, mask) \ - _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) - -static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_prph(priv, reg, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); -static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, - u32 bits, u32 mask) -{ - unsigned long reg_flags; +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_mask_prph(priv, reg, bits, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +int iwl_grab_nic_access_silent(struct iwl_priv *priv); +int iwl_grab_nic_access(struct iwl_priv *priv); +void iwl_release_nic_access(struct iwl_priv *priv); -static inline void iwl_clear_bits_prph(struct iwl_priv - *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - u32 val; +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - _iwl_write_prph(priv, reg, (val & ~mask)); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) -{ - unsigned long reg_flags; - u32 value; - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask); +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); - rmb(); - value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} +#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ + do { \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + _iwl_read_targ_mem_words(priv, addr, buf, \ + (bufsize) / sizeof(u32));\ + } while (0) -static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, - u32 len, u32 *values) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); - - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 46ccdf406e8e..439187f903c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -48,35 +48,42 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); -static const struct { - u16 tpt; /* Mb/s */ - u8 on_time; - u8 off_time; -} blink_tbl[] = -{ - {300, 25, 25}, - {200, 40, 40}, - {100, 55, 55}, - {70, 65, 65}, - {50, 75, 75}, - {20, 85, 85}, - {10, 95, 95}, - {5, 110, 110}, - {1, 130, 130}, - {0, 167, 167}, - /* SOLID_ON */ - {-1, IWL_LED_SOLID, 0} +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ +static const struct ieee80211_tpt_blink iwl_blink[] = { + { .throughput = 0, .blink_time = 334 }, + { .throughput = 1 * 1024 - 1, .blink_time = 260 }, + { .throughput = 5 * 1024 - 1, .blink_time = 220 }, + { .throughput = 10 * 1024 - 1, .blink_time = 190 }, + { .throughput = 20 * 1024 - 1, .blink_time = 170 }, + { .throughput = 50 * 1024 - 1, .blink_time = 150 }, + { .throughput = 70 * 1024 - 1, .blink_time = 130 }, + { .throughput = 100 * 1024 - 1, .blink_time = 110 }, + { .throughput = 200 * 1024 - 1, .blink_time = 80 }, + { .throughput = 300 * 1024 - 1, .blink_time = 50 }, }; -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ -#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) +/* Set led register off */ +void iwlagn_led_enable(struct iwl_priv *priv) +{ + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); +} /* * Adjust led blink rate to compensate on a MAC Clock difference on every HW - * Led blink rate analysis showed an average deviation of 0% on 3945, - * 5% on 4965 HW and 20% on 5000 series and up. + * Led blink rate analysis showed an average deviation of 20% on 5000 series + * and up. * Need to compensate on the led on/off time per HW according to the deviation * to achieve the desired led frequency * The calculation is: (100-averageDeviation)/100 * blinkTime @@ -96,134 +103,126 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, return (u8)((time * compensation) >> 6); } +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = led_cmd, + .flags = CMD_ASYNC, + .callback = NULL, + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + /* Set led pattern command */ -static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) +static int iwl_led_cmd(struct iwl_priv *priv, + unsigned long on, + unsigned long off) { struct iwl_led_cmd led_cmd = { .id = IWL_LED_LINK, .interval = IWL_DEF_LED_INTRVL }; + int ret; + + if (!test_bit(STATUS_READY, &priv->status)) + return -EBUSY; - BUG_ON(idx > IWL_MAX_BLINK_TBL); + if (priv->blink_on == on && priv->blink_off == off) + return 0; + + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } - IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); - led_cmd.on = - iwl_blink_compensation(priv, blink_tbl[idx].on_time, + led_cmd.on = iwl_blink_compensation(priv, on, priv->cfg->base_params->led_compensation); - led_cmd.off = - iwl_blink_compensation(priv, blink_tbl[idx].off_time, + led_cmd.off = iwl_blink_compensation(priv, off, priv->cfg->base_params->led_compensation); - return priv->cfg->ops->led->cmd(priv, &led_cmd); + ret = iwl_send_led_cmd(priv, &led_cmd); + if (!ret) { + priv->blink_on = on; + priv->blink_off = off; + } + return ret; } -int iwl_led_start(struct iwl_priv *priv) +static void iwl_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - return priv->cfg->ops->led->on(priv); -} -EXPORT_SYMBOL(iwl_led_start); + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); + unsigned long on = 0; -int iwl_led_associate(struct iwl_priv *priv) -{ - IWL_DEBUG_LED(priv, "Associated\n"); - if (priv->cfg->led_mode == IWL_LED_BLINK) - priv->allow_blinking = 1; - priv->last_blink_time = jiffies; + if (brightness > 0) + on = IWL_LED_SOLID; - return 0; + iwl_led_cmd(priv, on, 0); } -EXPORT_SYMBOL(iwl_led_associate); -int iwl_led_disassociate(struct iwl_priv *priv) +static int iwl_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - priv->allow_blinking = 0; - - return 0; -} -EXPORT_SYMBOL(iwl_led_disassociate); + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); -/* - * calculate blink rate according to last second Tx/Rx activities - */ -static int iwl_get_blink_rate(struct iwl_priv *priv) -{ - int i; - /* count both tx and rx traffic to be able to - * handle traffic in either direction - */ - u64 current_tpt = priv->tx_stats.data_bytes + - priv->rx_stats.data_bytes; - s64 tpt = current_tpt - priv->led_tpt; - - if (tpt < 0) /* wraparound */ - tpt = -tpt; - - IWL_DEBUG_LED(priv, "tpt %lld current_tpt %llu\n", - (long long)tpt, - (unsigned long long)current_tpt); - priv->led_tpt = current_tpt; - - if (!priv->allow_blinking) - i = IWL_MAX_BLINK_TBL; - else - for (i = 0; i < IWL_MAX_BLINK_TBL; i++) - if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) - break; - - IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); - return i; + return iwl_led_cmd(priv, *delay_on, *delay_off); } -/* - * this function called from handler. Since setting Led command can - * happen very frequent we postpone led command to be called from - * REPLY handler so we know ucode is up - */ -void iwl_leds_background(struct iwl_priv *priv) +void iwl_leds_init(struct iwl_priv *priv) { - u8 blink_idx; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - priv->last_blink_time = 0; - return; - } - if (iwl_is_rfkill(priv)) { - priv->last_blink_time = 0; - return; + int mode = led_mode; + int ret; + + if (mode == IWL_LED_DEFAULT) + mode = priv->cfg->led_mode; + + priv->led.name = kasprintf(GFP_KERNEL, "%s-led", + wiphy_name(priv->hw->wiphy)); + priv->led.brightness_set = iwl_led_brightness_set; + priv->led.blink_set = iwl_led_blink_set; + priv->led.max_brightness = 1; + + switch (mode) { + case IWL_LED_DEFAULT: + WARN_ON(1); + break; + case IWL_LED_BLINK: + priv->led.default_trigger = + ieee80211_create_tpt_led_trigger(priv->hw, + IEEE80211_TPT_LEDTRIG_FL_CONNECTED, + iwl_blink, ARRAY_SIZE(iwl_blink)); + break; + case IWL_LED_RF_STATE: + priv->led.default_trigger = + ieee80211_get_radio_led_name(priv->hw); + break; } - if (!priv->allow_blinking) { - priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { - priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX); - } + ret = led_classdev_register(&priv->pci_dev->dev, &priv->led); + if (ret) { + kfree(priv->led.name); return; } - if (!priv->last_blink_time || - !time_after(jiffies, priv->last_blink_time + - msecs_to_jiffies(1000))) - return; - - blink_idx = iwl_get_blink_rate(priv); - /* call only if blink rate change */ - if (blink_idx != priv->last_blink_rate) - iwl_led_pattern(priv, blink_idx); - - priv->last_blink_time = jiffies; - priv->last_blink_rate = blink_idx; + priv->led_registered = true; } -EXPORT_SYMBOL(iwl_leds_background); -void iwl_leds_init(struct iwl_priv *priv) +void iwl_leds_exit(struct iwl_priv *priv) { - priv->last_blink_rate = 0; - priv->last_blink_time = 0; - priv->allow_blinking = 0; - if (led_mode != IWL_LED_DEFAULT && - led_mode != priv->cfg->led_mode) - priv->cfg->led_mode = led_mode; + if (!priv->led_registered) + return; + + led_classdev_unregister(&priv->led); + kfree(priv->led.name); } -EXPORT_SYMBOL(iwl_leds_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 9079b33486ef..1c93dfef6933 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -31,23 +31,14 @@ struct iwl_priv; #define IWL_LED_SOLID 11 -#define IWL_LED_NAME_LEN 31 #define IWL_DEF_LED_INTRVL cpu_to_le32(1000) #define IWL_LED_ACTIVITY (0<<1) #define IWL_LED_LINK (1<<1) -enum led_type { - IWL_LED_TRG_TX, - IWL_LED_TRG_RX, - IWL_LED_TRG_ASSOC, - IWL_LED_TRG_RADIO, - IWL_LED_TRG_MAX, -}; - /* * LED mode - * IWL_LED_DEFAULT: use system default + * IWL_LED_DEFAULT: use device default * IWL_LED_RF_STATE: turn LED on/off based on RF state * LED ON = RF ON * LED OFF = RF OFF @@ -59,10 +50,8 @@ enum iwl_led_mode { IWL_LED_BLINK, }; +void iwlagn_led_enable(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv); -void iwl_leds_background(struct iwl_priv *priv); -int iwl_led_start(struct iwl_priv *priv); -int iwl_led_associate(struct iwl_priv *priv); -int iwl_led_disassociate(struct iwl_priv *priv); +void iwl_leds_exit(struct iwl_priv *priv); #endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c deleted file mode 100644 index bb1a742a98a0..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ /dev/null @@ -1,662 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include <linux/kernel.h> -#include <net/mac80211.h> - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-helpers.h" -#include "iwl-legacy.h" - -static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!ctx->is_active) - return; - - ctx->qos_data.def_qos_parm.qos_flags = 0; - - if (ctx->qos_data.qos_active) - ctx->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (ctx->ht.enabled) - ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", - ctx->qos_data.qos_active, - ctx->qos_data.def_qos_parm.qos_flags); - - iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, - sizeof(struct iwl_qosparam_cmd), - &ctx->qos_data.def_qos_parm, NULL); -} - -/** - * iwl_legacy_mac_config - mac80211 config callback - */ -int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_channel *channel = conf->channel; - struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct iwl_rxon_context *ctx; - unsigned long flags = 0; - int ret = 0; - u16 ch; - int scan_active = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; - - if (WARN_ON(!priv->cfg->ops->legacy)) - return -EOPNOTSUPP; - - mutex_lock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", - channel->hw_value, changed); - - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - } - - if (changed & (IEEE80211_CONF_CHANGE_SMPS | - IEEE80211_CONF_CHANGE_CHANNEL)) { - /* mac80211 uses static for non-HT which is what we want */ - priv->current_ht_config.smps = conf->smps_mode; - - /* - * Recalculate chain counts. - * - * If monitor mode is enabled then mac80211 will - * set up the SM PS mode to OFF if an HT channel is - * configured. - */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - for_each_context(priv, ctx) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - } - - /* during scanning mac80211 will delay channel setting until - * scan finish with changed = 0 - */ - if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { - if (scan_active) - goto set_ch_out; - - ch = channel->hw_value; - ch_info = iwl_get_channel_info(priv, channel->band, ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - ret = -EINVAL; - goto set_ch_out; - } - - spin_lock_irqsave(&priv->lock, flags); - - for_each_context(priv, ctx) { - /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { - ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else - ctx->ht.is_40mhz = false; - - /* - * Default to no protection. Protection mode will - * later be set from BSS config in iwl_ht_conf - */ - ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; - - /* if we are switching from ht to 2.4 clear flags - * from any ht related info since 2.4 does not - * support ht */ - if ((le16_to_cpu(ctx->staging.channel) != ch)) - ctx->staging.flags = 0; - - iwl_set_rxon_channel(priv, channel, ctx); - iwl_set_rxon_ht(priv, ht_conf); - - iwl_set_flags_for_band(priv, ctx, channel->band, - ctx->vif); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->cfg->ops->legacy->update_bcast_stations) - ret = priv->cfg->ops->legacy->update_bcast_stations(priv); - - set_ch_out: - /* The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - } - - if (changed & (IEEE80211_CONF_CHANGE_PS | - IEEE80211_CONF_CHANGE_IDLE)) { - ret = iwl_power_update_mode(priv, false); - if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", - priv->tx_power_user_lmt, conf->power_level); - - iwl_set_tx_power(priv, conf->power_level, false); - } - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - goto out; - } - - if (scan_active) - goto out; - - for_each_context(priv, ctx) { - if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) - iwlcore_commit_rxon(priv, ctx); - else - IWL_DEBUG_INFO(priv, - "Not re-sending same RXON configuration.\n"); - if (ht_changed[ctx->ctxid]) - iwl_update_qos(priv, ctx); - } - -out: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - return ret; -} -EXPORT_SYMBOL(iwl_legacy_mac_config); - -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - /* IBSS can only be the IWL_RXON_CTX_BSS context */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - if (WARN_ON(!priv->cfg->ops->legacy)) - return; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); - spin_unlock_irqrestore(&priv->lock, flags); - - spin_lock_irqsave(&priv->lock, flags); - - /* new association get rid of ibss beacon skb */ - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - priv->beacon_skb = NULL; - - priv->timestamp = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_scan_cancel_timeout(priv, 100); - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} -EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf); - -static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_vif *vif) -{ - struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct ieee80211_sta *sta; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - IWL_DEBUG_ASSOC(priv, "enter:\n"); - - if (!ctx->ht.enabled) - return; - - ctx->ht.protection = - bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - ctx->ht.non_gf_sta_present = - !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - - ht_conf->single_chain_sufficient = false; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int maxstreams; - - maxstreams = (ht_cap->mcs.tx_params & - IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) - >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - maxstreams += 1; - - if ((ht_cap->mcs.rx_mask[1] == 0) && - (ht_cap->mcs.rx_mask[2] == 0)) - ht_conf->single_chain_sufficient = true; - if (maxstreams <= 1) - ht_conf->single_chain_sufficient = true; - } else { - /* - * If at all, this can only happen through a race - * when the AP disconnects us while we're still - * setting up the connection, in that case mac80211 - * will soon tell us about that. - */ - ht_conf->single_chain_sufficient = true; - } - rcu_read_unlock(); - break; - case NL80211_IFTYPE_ADHOC: - ht_conf->single_chain_sufficient = true; - break; - default: - break; - } - - IWL_DEBUG_ASSOC(priv, "leave\n"); -} - -static inline void iwl_set_no_assoc(struct iwl_priv *priv, - struct ieee80211_vif *vif) -{ - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - iwl_led_disassociate(priv); - /* - * inform the ucode that there is no longer an - * association and that no more packets should be - * sent - */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - ctx->staging.assoc_id = 0; - iwlcore_commit_rxon(priv, ctx); -} - -static void iwlcore_beacon_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); - - if (!skb) - return; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - lockdep_assert_held(&priv->mutex); - - if (!priv->beacon_ctx) { - IWL_ERR(priv, "update beacon but no beacon context!\n"); - dev_kfree_skb(skb); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - priv->beacon_skb = skb; - - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return; - } - - priv->cfg->ops->legacy->post_associate(priv); -} - -void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - int ret; - - if (WARN_ON(!priv->cfg->ops->legacy)) - return; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (!iwl_is_alive(priv)) - return; - - mutex_lock(&priv->mutex); - - if (changes & BSS_CHANGED_QOS) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ctx->qos_data.qos_active = bss_conf->qos; - iwl_update_qos(priv, ctx); - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (changes & BSS_CHANGED_BEACON_ENABLED) { - /* - * the add_interface code must make sure we only ever - * have a single interface that could be beaconing at - * any time. - */ - if (vif->bss_conf.enable_beacon) - priv->beacon_ctx = ctx; - else - priv->beacon_ctx = NULL; - } - - if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) { - dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = ieee80211_beacon_get(hw, vif); - } - - if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP) - iwl_send_rxon_timing(priv, ctx); - - if (changes & BSS_CHANGED_BSSID) { - IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); - - /* - * If there is currently a HW scan going on in the - * background then we need to cancel it else the RXON - * below/in post_associate will fail. - */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* mac80211 only sets assoc when in STATION mode */ - if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { - memcpy(ctx->staging.bssid_addr, - bss_conf->bssid, ETH_ALEN); - - /* currently needed in a few places */ - memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); - } else { - ctx->staging.filter_flags &= - ~RXON_FILTER_ASSOC_MSK; - } - - } - - /* - * This needs to be after setting the BSSID in case - * mac80211 decides to do both changes at once because - * it will invoke post_associate. - */ - if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON) - iwlcore_beacon_update(hw, vif); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - } - - if (changes & BSS_CHANGED_ERP_CTS_PROT) { - IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) - ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; - if (bss_conf->use_cts_prot) - ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; - else - ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; - } - - if (changes & BSS_CHANGED_BASIC_RATES) { - /* XXX use this information - * - * To do that, remove code from iwl_set_rate() and put something - * like this here: - * - if (A-band) - ctx->staging.ofdm_basic_rates = - bss_conf->basic_rates; - else - ctx->staging.ofdm_basic_rates = - bss_conf->basic_rates >> 4; - ctx->staging.cck_basic_rates = - bss_conf->basic_rates & 0xF; - */ - } - - if (changes & BSS_CHANGED_HT) { - iwl_ht_conf(priv, vif); - - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); - if (bss_conf->assoc) { - priv->timestamp = bss_conf->timestamp; - - iwl_led_associate(priv); - - if (!iwl_is_rfkill(priv)) - priv->cfg->ops->legacy->post_associate(priv); - } else - iwl_set_no_assoc(priv, vif); - } - - if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) { - IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n", - changes); - ret = iwl_send_rxon_assoc(priv, ctx); - if (!ret) { - /* Sync active_rxon with latest change. */ - memcpy((void *)&ctx->active, - &ctx->staging, - sizeof(struct iwl_rxon_cmd)); - } - } - - if (changes & BSS_CHANGED_BEACON_ENABLED) { - if (vif->bss_conf.enable_beacon) { - memcpy(ctx->staging.bssid_addr, - bss_conf->bssid, ETH_ALEN); - memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); - iwl_led_associate(priv); - priv->cfg->ops->legacy->config_ap(priv); - } else - iwl_set_no_assoc(priv, vif); - } - - if (changes & BSS_CHANGED_IBSS) { - ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif, - bss_conf->ibss_joined); - if (ret) - IWL_ERR(priv, "failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", - bss_conf->bssid); - } - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} -EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed); - -irqreturn_t iwl_isr_legacy(int irq, void *data) -{ - struct iwl_priv *priv = data; - u32 inta, inta_mask; - u32 inta_fh; - unsigned long flags; - if (!priv) - return IRQ_NONE; - - spin_lock_irqsave(&priv->lock, flags); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the tasklet will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* Discover which interrupts are active/pending */ - inta = iwl_read32(priv, CSR_INT); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!inta && !inta_fh) { - IWL_DEBUG_ISR(priv, - "Ignore interrupt, inta == 0, inta_fh == 0\n"); - goto none; - } - - if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { - /* Hardware disappeared. It might have already raised - * an interrupt */ - IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); - goto unplugged; - } - - IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - - inta &= ~CSR_INT_BIT_SCD; - - /* iwl_irq_tasklet() will service interrupts and re-enable them */ - if (likely(inta || inta_fh)) - tasklet_schedule(&priv->irq_tasklet); - -unplugged: - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; - -none: - /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_NONE; -} -EXPORT_SYMBOL(iwl_isr_legacy); - -/* - * iwl_legacy_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this - * function. - */ -void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - __le16 fc, __le32 *tx_flags) -{ - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - *tx_flags |= TX_CMD_FLG_RTS_MSK; - *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - if (!ieee80211_is_mgmt(fc)) - return; - - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - break; - } - } else if (info->control.rates[0].flags & - IEEE80211_TX_RC_USE_CTS_PROTECT) { - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - } -} -EXPORT_SYMBOL(iwl_legacy_tx_cmd_protection); diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.h b/drivers/net/wireless/iwlwifi/iwl-legacy.h deleted file mode 100644 index 9f7b2f935964..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.h +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef __iwl_legacy_h__ -#define __iwl_legacy_h__ - -/* mac80211 handlers */ -int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw); -void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes); -void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - __le16 fc, __le32 *tx_flags); - -irqreturn_t iwl_isr_legacy(int irq, void *data); - -#endif /* __iwl_legacy_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 1eec18d909d8..595c930b28ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -188,9 +188,10 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, table = range_0; } - BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); - - *cmd = table[lvl].cmd; + if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM)) + memset(cmd, 0, sizeof(*cmd)); + else + *cmd = table[lvl].cmd; if (period == 0) { skip = 0; @@ -226,8 +227,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (iwl_advanced_bt_coexist(priv)) { if (!priv->cfg->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else @@ -313,8 +313,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (iwl_advanced_bt_coexist(priv)) { if (!priv->cfg->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else @@ -356,17 +355,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, dtimper = priv->hw->conf.ps_dtim_period ?: 1; - if (priv->cfg->base_params->broken_powersave) - iwl_power_sleep_cam_cmd(priv, cmd); - else if (priv->cfg->base_params->supports_idle && - priv->hw->conf.flags & IEEE80211_CONF_IDLE) + if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); - else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && - priv->cfg->ops->lib->tt_ops.tt_power_mode && - priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) { + else if (iwl_tt_is_low_power_state(priv)) { /* in thermal throttling low power state */ iwl_static_sleep_cmd(priv, cmd, - priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); + iwl_tt_current_power_mode(priv), dtimper); } else if (!enabled) iwl_power_sleep_cam_cmd(priv, cmd); else if (priv->power_data.debug_sleep_level_override >= 0) @@ -428,7 +422,6 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, return ret; } -EXPORT_SYMBOL(iwl_power_set_mode); int iwl_power_update_mode(struct iwl_priv *priv, bool force) { @@ -437,7 +430,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) iwl_power_build_cmd(priv, &cmd); return iwl_power_set_mode(priv, &cmd, force); } -EXPORT_SYMBOL(iwl_power_update_mode); /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) @@ -451,4 +443,3 @@ void iwl_power_initialize(struct iwl_priv *priv) memset(&priv->power_data.sleep_cmd, 0, sizeof(priv->power_data.sleep_cmd)); } -EXPORT_SYMBOL(iwl_power_initialize); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index fe012032c28c..59635d784e27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 86f5123bccda..f00d188b2cfc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,7 +91,6 @@ #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) @@ -99,152 +98,6 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) /** - * BSM (Bootstrap State Machine) - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down when the embedded control - * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). - * - * When powering back up after sleeps (or during initial uCode load), the BSM - * internally loads the short bootstrap program from the special SRAM into the - * embedded processor's instruction SRAM, and starts the processor so it runs - * the bootstrap program. - * - * This bootstrap program loads (via PCI busmaster DMA) instructions and data - * images for a uCode program from host DRAM locations. The host driver - * indicates DRAM locations and sizes for instruction and data images via the - * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, - * the new program starts automatically. - * - * The uCode used for open-source drivers includes two programs: - * - * 1) Initialization -- performs hardware calibration and sets up some - * internal data, then notifies host via "initialize alive" notification - * (struct iwl_init_alive_resp) that it has completed all of its work. - * After signal from host, it then loads and starts the runtime program. - * The initialization program must be used when initially setting up the - * NIC after loading the driver. - * - * 2) Runtime/Protocol -- performs all normal runtime operations. This - * notifies host via "alive" notification (struct iwl_alive_resp) that it - * is ready to be used. - * - * When initializing the NIC, the host driver does the following procedure: - * - * 1) Load bootstrap program (instructions only, no data image for bootstrap) - * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND - * - * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction - * images in host DRAM. - * - * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: - * BSM_WR_MEM_SRC_REG = 0 - * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND - * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image - * - * 4) Load bootstrap into instruction SRAM: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START - * - * 5) Wait for load completion: - * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 - * - * 6) Enable future boot loads whenever NIC's power management triggers it: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN - * - * 7) Start the NIC by removing all reset bits: - * CSR_RESET = 0 - * - * The bootstrap uCode (already in instruction SRAM) loads initialization - * uCode. Initialization uCode performs data initialization, sends - * "initialize alive" notification to host, and waits for a signal from - * host to load runtime code. - * - * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction - * images in host DRAM. The last register loaded must be the instruction - * byte count register ("1" in MSbit tells initialization uCode to load - * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD - * - * 5) Wait for "alive" notification, then issue normal runtime commands. - * - * Data caching during power-downs: - * - * Just before the embedded controller powers down (e.g for automatic - * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) - * a current snapshot of the embedded processor's data SRAM into host DRAM. - * This caches the data while the embedded processor's memory is powered down. - * Location and size are controlled by BSM_DRAM_DATA_* registers. - * - * NOTE: Instruction SRAM does not need to be saved, since that doesn't - * change during operation; the original image (from uCode distribution - * file) can be used for reload. - * - * When powering back up, the BSM loads the bootstrap program. Bootstrap looks - * at the BSM_DRAM_* registers, which now point to the runtime instruction - * image and the cached (modified) runtime data (*not* the initialization - * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the - * uCode from where it left off before the power-down. - * - * NOTE: Initialization uCode does *not* run as part of the save/restore - * procedure. - * - * This save/restore method is mostly for autonomous power management during - * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and - * RFKILL should use complete restarts (with total re-initialization) of uCode, - * allowing total shutdown (including BSM memory). - * - * Note that, during normal operation, the host DRAM that held the initial - * startup data for the runtime code is now being used as a backup data cache - * for modified data! If you need to completely re-initialize the NIC, make - * sure that you use the runtime data image from the uCode distribution file, - * not the modified/saved runtime data. You may want to store a separate - * "clean" runtime data image in DRAM to avoid disk reads of distribution file. - */ - -/* BSM bit fields */ -#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ -#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ -#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ - -/* BSM addresses */ -#define BSM_BASE (PRPH_BASE + 0x3400) -#define BSM_END (PRPH_BASE + 0x3800) - -#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ -#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ -#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ -#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ -#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ - -/* - * Pointers and size regs for bootstrap load and data SRAM save/restore. - * NOTE: 3945 pointers use bits 31:0 of DRAM address. - * 4965 pointers use bits 35:4 of DRAM address. - */ -#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) -#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) -#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) -#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) - -/* - * BSM special memory, stays powered on during power-save sleeps. - * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) - */ -#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) -#define BSM_SRAM_SIZE (1024) /* bytes */ - - -/* 3945 Tx scheduler registers */ -#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) -#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) -#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) -#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) -#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) -#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) -#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) -#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) - -/** * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs @@ -254,17 +107,7 @@ * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * - * Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows - * (cf. default_queue_to_tx_fifo in iwl-4965.c): - * - * 0 -- EDCA BK (background) frames, lowest priority - * 1 -- EDCA BE (best effort) frames, normal priority - * 2 -- EDCA VI (video) frames, higher priority - * 3 -- EDCA VO (voice) and management frames, highest priority - * 4 -- Commands (e.g. RXON, etc.) - * 5 -- unused (HCCA) - * 6 -- unused (HCCA) - * 7 -- not used by driver (device-internal only) + * Tx DMA FIFOs have dedicated purposes. * * For 5000 series and up, they are used differently * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): @@ -298,7 +141,7 @@ * Tx completion may end up being out-of-order). * * The driver must maintain the queue's Byte Count table in host DRAM - * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * for this mode. * This mode does not support fragmentation. * * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. @@ -311,7 +154,7 @@ * * Driver controls scheduler operation via 3 means: * 1) Scheduler registers - * 2) Shared scheduler data base in internal 4956 SRAM + * 2) Shared scheduler data base in internal SRAM * 3) Shared data in host DRAM * * Initialization: @@ -330,201 +173,10 @@ * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. */ #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 64 -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define IWL49_SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ - (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) -#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 -#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ - (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - #define IWL_SCD_TXFIFO_POS_TID (0) #define IWL_SCD_TXFIFO_POS_RA (4) #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 87a6fd84d4d2..0053e9ea9021 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -29,6 +29,7 @@ #include <linux/etherdevice.h> #include <linux/slab.h> +#include <linux/sched.h> #include <net/mac80211.h> #include <asm/unaligned.h> #include "iwl-eeprom.h" @@ -37,7 +38,15 @@ #include "iwl-sta.h" #include "iwl-io.h" #include "iwl-helpers.h" -/************************** RX-FUNCTIONS ****************************/ +#include "iwl-agn-calib.h" +#include "iwl-agn.h" + +/****************************************************************************** + * + * RX path functions + * + ******************************************************************************/ + /* * Rx theory of operation * @@ -118,7 +127,6 @@ int iwl_rx_queue_space(const struct iwl_rx_queue *q) s = 0; return s; } -EXPORT_SYMBOL(iwl_rx_queue_space); /** * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue @@ -170,7 +178,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q exit_unlock: spin_unlock_irqrestore(&q->lock, flags); } -EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); int iwl_rx_queue_alloc(struct iwl_priv *priv) { @@ -211,10 +218,56 @@ err_rb: err_bd: return -ENOMEM; } -EXPORT_SYMBOL(iwl_rx_queue_alloc); +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ + +static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + + IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} -void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + /* + * MULTI-FIXME + * See iwl_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl_rxon_cmd *rxon = (void *)&ctx->active; + + if (priv->switch_rxon.switch_in_progress) { + if (!le32_to_cpu(csa->status) && + (csa->channel == priv->switch_rxon.channel)) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", + le16_to_cpu(csa->channel)); + iwl_chswitch_done(priv, true); + } else { + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + iwl_chswitch_done(priv, false); + } + } +} + + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -229,48 +282,505 @@ void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, memcpy(&priv->measure_report, report, sizeof(*report)); priv->measurement_status |= MEASUREMENT_READY; } -EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); -void iwl_recover_from_statistics(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " + "notification for %s:\n", len, + get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); +} + +static void iwl_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw; +#ifdef CONFIG_IWLWIFI_DEBUG + u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status); + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + + IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d " + "tsf:0x%.8x%.8x rate:%d\n", + status & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ +#define ACK_CNT_RATIO (50) +#define BA_TIMEOUT_CNT (5) +#define BA_TIMEOUT_MAX (16) + +/** + * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. + * + * When the ACK count ratio is low and aggregated BA timeout retries exceeding + * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal + * operation state. + */ +static bool iwl_good_ack_health(struct iwl_priv *priv, + struct statistics_tx *cur) +{ + int actual_delta, expected_delta, ba_timeout_delta; + struct statistics_tx *old; + + if (priv->_agn.agg_tids_count) + return true; + + old = &priv->statistics.tx; + + actual_delta = le32_to_cpu(cur->actual_ack_cnt) - + le32_to_cpu(old->actual_ack_cnt); + expected_delta = le32_to_cpu(cur->expected_ack_cnt) - + le32_to_cpu(old->expected_ack_cnt); + + /* Values should not be negative, but we do not trust the firmware */ + if (actual_delta <= 0 || expected_delta <= 0) + return true; + + ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) - + le32_to_cpu(old->agg.ba_timeout); + + if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO && + ba_timeout_delta > BA_TIMEOUT_CNT) { + IWL_DEBUG_RADIO(priv, "deltas: actual %d expected %d ba_timeout %d\n", + actual_delta, expected_delta, ba_timeout_delta); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* + * This is ifdef'ed on DEBUGFS because otherwise the + * statistics aren't available. If DEBUGFS is set but + * DEBUG is not, these will just compile out. + */ + IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", + priv->delta_stats.tx.rx_detected_cnt); + IWL_DEBUG_RADIO(priv, + "ack_or_ba_timeout_collision delta %d\n", + priv->delta_stats.tx.ack_or_ba_timeout_collision); +#endif + + if (ba_timeout_delta >= BA_TIMEOUT_MAX) + return false; + } + + return true; +} + +/** + * iwl_good_plcp_health - checks for plcp error. + * + * When the plcp error is exceeding the thresholds, reset the radio + * to improve the throughput. + */ +static bool iwl_good_plcp_health(struct iwl_priv *priv, + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + unsigned int msecs) +{ + int delta; + int threshold = priv->cfg->base_params->plcp_delta_threshold; + + if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { + IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); + return true; + } + + delta = le32_to_cpu(cur_ofdm->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) + + le32_to_cpu(cur_ofdm_ht->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err); + + /* Can be negative if firmware reset statistics */ + if (delta <= 0) + return true; + + if ((delta * 100 / msecs) > threshold) { + IWL_DEBUG_RADIO(priv, + "plcp health threshold %u delta %d msecs %u\n", + threshold, delta, msecs); + return false; + } + + return true; +} + +static void iwl_recover_from_statistics(struct iwl_priv *priv, + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + struct statistics_tx *tx, + unsigned long stamp) +{ + unsigned int msecs; + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (iwl_is_any_associated(priv)) { - if (priv->cfg->ops->lib->check_ack_health) { - if (!priv->cfg->ops->lib->check_ack_health( - priv, pkt)) { - /* - * low ack count detected - * restart Firmware - */ - IWL_ERR(priv, "low ack count detected, " - "restart firmware\n"); - if (!iwl_force_reset(priv, IWL_FW_RESET, false)) - return; - } + + msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); + + /* Only gather statistics and update time stamp when not associated */ + if (!iwl_is_any_associated(priv)) + return; + + /* Do not check/recover when do not have enough statistics data */ + if (msecs < 99) + return; + + if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) { + IWL_ERR(priv, "low ack count detected, restart firmware\n"); + if (!iwl_force_reset(priv, IWL_FW_RESET, false)) + return; + } + + if (iwlagn_mod_params.plcp_check && + !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) + iwl_force_reset(priv, IWL_RF_RESET, false); +} + +/* Calculate noise level, based on measurements during network silence just + * before arriving beacon. This measurement can be done only if we know + * exactly when to expect beacons, therefore only when we're associated. */ +static void iwl_rx_calc_noise(struct iwl_priv *priv) +{ + struct statistics_rx_non_phy *rx_info; + int num_active_rx = 0; + int total_silence = 0; + int bcn_silence_a, bcn_silence_b, bcn_silence_c; + int last_rx_noise; + + rx_info = &priv->statistics.rx_non_phy; + + bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + bcn_silence_b = + le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; + bcn_silence_c = + le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; + + if (bcn_silence_a) { + total_silence += bcn_silence_a; + num_active_rx++; + } + if (bcn_silence_b) { + total_silence += bcn_silence_b; + num_active_rx++; + } + if (bcn_silence_c) { + total_silence += bcn_silence_c; + num_active_rx++; + } + + /* Average among active antennas */ + if (num_active_rx) + last_rx_noise = (total_silence / num_active_rx) - 107; + else + last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", + bcn_silence_a, bcn_silence_b, bcn_silence_c, + last_rx_noise); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* + * based on the assumption of all statistics counter are in DWORD + * FIXME: This function is for debugging, do not deal with + * the case of counters roll-over. + */ +static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, + __le32 *max_delta, __le32 *accum, int size) +{ + int i; + + for (i = 0; + i < size / sizeof(__le32); + i++, prev++, cur++, delta++, max_delta++, accum++) { + if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) { + *delta = cpu_to_le32( + le32_to_cpu(*cur) - le32_to_cpu(*prev)); + le32_add_cpu(accum, le32_to_cpu(*delta)); + if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta)) + *max_delta = *delta; } - if (priv->cfg->ops->lib->check_plcp_health) { - if (!priv->cfg->ops->lib->check_plcp_health( - priv, pkt)) { - /* - * high plcp error detected - * reset Radio - */ - iwl_force_reset(priv, IWL_RF_RESET, false); - } + } +} + +static void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +#define ACCUM(_name) \ + accum_stats((__le32 *)&priv->statistics._name, \ + (__le32 *)_name, \ + (__le32 *)&priv->delta_stats._name, \ + (__le32 *)&priv->max_delta_stats._name, \ + (__le32 *)&priv->accum_stats._name, \ + sizeof(*_name)); + + ACCUM(common); + ACCUM(rx_non_phy); + ACCUM(rx_ofdm); + ACCUM(rx_ofdm_ht); + ACCUM(rx_cck); + ACCUM(tx); + if (bt_activity) + ACCUM(bt_activity); +#undef ACCUM +} +#else +static inline void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +} +#endif + +static void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + unsigned long stamp = jiffies; + const int reg_recalib_period = 60; + int change; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + __le32 *flag; + struct statistics_general_common *common; + struct statistics_rx_non_phy *rx_non_phy; + struct statistics_rx_phy *rx_ofdm; + struct statistics_rx_ht_phy *rx_ofdm_ht; + struct statistics_rx_phy *rx_cck; + struct statistics_tx *tx; + struct statistics_bt_activity *bt_activity; + + len -= sizeof(struct iwl_cmd_header); /* skip header */ + + IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n", + len); + + if (len == sizeof(struct iwl_bt_notif_statistics)) { + struct iwl_bt_notif_statistics *stats; + stats = &pkt->u.stats_bt; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general.common; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = &stats->general.activity; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* handle this exception directly */ + priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills; + le32_add_cpu(&priv->statistics.accum_num_bt_kills, + le32_to_cpu(stats->rx.general.num_bt_kills)); +#endif + } else if (len == sizeof(struct iwl_notif_statistics)) { + struct iwl_notif_statistics *stats; + stats = &pkt->u.stats; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = NULL; + } else { + WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", + len, sizeof(struct iwl_bt_notif_statistics), + sizeof(struct iwl_notif_statistics)); + return; + } + + change = common->temperature != priv->statistics.common.temperature || + (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); + + iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, + rx_ofdm_ht, rx_cck, tx, bt_activity); + + iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); + + priv->statistics.flag = *flag; + memcpy(&priv->statistics.common, common, sizeof(*common)); + memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy)); + memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm)); + memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht)); + memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck)); + memcpy(&priv->statistics.tx, tx, sizeof(*tx)); +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (bt_activity) + memcpy(&priv->statistics.bt_activity, bt_activity, + sizeof(*bt_activity)); +#endif + + priv->rx_statistics_jiffies = stamp; + + set_bit(STATUS_STATISTICS, &priv->status); + + /* Reschedule the statistics timer to occur in + * reg_recalib_period seconds to ensure we get a + * thermal update even if the uCode doesn't give + * us one */ + mod_timer(&priv->statistics_periodic, jiffies + + msecs_to_jiffies(reg_recalib_period * 1000)); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { + iwl_rx_calc_noise(priv); + queue_work(priv->workqueue, &priv->run_time_calib_work); + } + if (priv->cfg->ops->lib->temp_ops.temperature && change) + priv->cfg->ops->lib->temp_ops.temperature(priv); +} + +static void iwl_rx_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + + if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { +#ifdef CONFIG_IWLWIFI_DEBUGFS + memset(&priv->accum_stats, 0, + sizeof(priv->accum_stats)); + memset(&priv->delta_stats, 0, + sizeof(priv->delta_stats)); + memset(&priv->max_delta_stats, 0, + sizeof(priv->max_delta_stats)); +#endif + IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); + } + iwl_rx_statistics(priv, rxb); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On", + (flags & CT_CARD_DISABLED) ? + "Reached" : "Not reached"); + + if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | + CT_CARD_DISABLED)) { + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + iwl_write_direct32(priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + if (!(flags & RXON_CARD_DISABLED)) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_write_direct32(priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } + if (flags & CT_CARD_DISABLED) + iwl_tt_enter_ct_kill(priv); + } + if (!(flags & CT_CARD_DISABLED)) + iwl_tt_exit_ct_kill(priv); + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (!(flags & RXON_CARD_DISABLED)) + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_missed_beacon_notif *missed_beacon; + + missed_beacon = &pkt->u.missed_beacon; + if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > + priv->missed_beacon_threshold) { + IWL_DEBUG_CALIB(priv, + "missed bcn cnsq %d totl %d rcd %d expctd %d\n", + le32_to_cpu(missed_beacon->consecutive_missed_beacons), + le32_to_cpu(missed_beacon->total_missed_becons), + le32_to_cpu(missed_beacon->num_recvd_beacons), + le32_to_cpu(missed_beacon->num_expected_beacons)); + if (!test_bit(STATUS_SCANNING, &priv->status)) + iwl_init_sensitivity(priv); } } -EXPORT_SYMBOL(iwl_recover_from_statistics); + +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +static void iwl_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + + priv->_agn.last_phy_res_valid = true; + memcpy(&priv->_agn.last_phy_res, pkt->u.raw, + sizeof(struct iwl_rx_phy_res)); +} /* * returns non-zero if packet should be dropped */ -int iwl_set_decrypted_flag(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - u32 decrypt_res, - struct ieee80211_rx_status *stats) +static int iwl_set_decrypted_flag(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + u32 decrypt_res, + struct ieee80211_rx_status *stats) { u16 fc = le16_to_cpu(hdr->frame_control); @@ -315,4 +825,283 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, } return 0; } -EXPORT_SYMBOL(iwl_set_decrypted_flag); + +static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + u16 len, + u32 ampdu_status, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) +{ + struct sk_buff *skb; + __le16 fc = hdr->frame_control; + struct iwl_rxon_context *ctx; + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT(priv, + "Dropping packet while interface is not open.\n"); + return; + } + + /* In case of HW accelerated crypto and bad decryption, drop */ + if (!iwlagn_mod_params.sw_crypto && + iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + return; + + skb = dev_alloc_skb(128); + if (!skb) { + IWL_ERR(priv, "dev_alloc_skb failed\n"); + return; + } + + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + + iwl_update_stats(priv, false, fc, len); + + /* + * Wake any queues that were stopped due to a passive channel tx + * failure. This can happen because the regulatory enforcement in + * the device waits for a beacon before allowing transmission, + * sometimes even after already having transmitted frames for the + * association because the new RXON may reset the information. + */ + if (unlikely(ieee80211_is_beacon(fc))) { + for_each_context(priv, ctx) { + if (!ctx->last_tx_rejected) + continue; + if (compare_ether_addr(hdr->addr3, + ctx->active.bssid_addr)) + continue; + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } + } + + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + + ieee80211_rx(priv->hw, skb); + rxb->page = NULL; +} + +static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) +{ + u32 decrypt_out = 0; + + if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == + RX_RES_STATUS_STATION_FOUND) + decrypt_out |= (RX_RES_STATUS_STATION_FOUND | + RX_RES_STATUS_NO_STATION_INFO_MISMATCH); + + decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); + + /* packet was not encrypted */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_NONE) + return decrypt_out; + + /* packet was encrypted with unknown alg */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_ERR) + return decrypt_out; + + /* decryption was not done in HW */ + if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != + RX_MPDU_RES_STATUS_DEC_DONE_MSK) + return decrypt_out; + + switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { + + case RX_RES_STATUS_SEC_TYPE_CCMP: + /* alg is CCM: check MIC only */ + if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) + /* Bad MIC */ + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + + break; + + case RX_RES_STATUS_SEC_TYPE_TKIP: + if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { + /* Bad TTAK */ + decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; + break; + } + /* fall through if TTAK OK */ + default: + if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + break; + } + + IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", + decrypt_in, decrypt_out); + + return decrypt_out; +} + +/* Called for REPLY_RX (legacy ABG frames), or + * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +static void iwl_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_rx_phy_res *phy_res; + __le32 rx_pkt_status; + struct iwl_rx_mpdu_res_start *amsdu; + u32 len; + u32 ampdu_status; + u32 rate_n_flags; + + /** + * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. + * REPLY_RX: physical layer info is in this buffer + * REPLY_RX_MPDU_CMD: physical layer info was sent in separate + * command and cached in priv->last_phy_res + * + * Here we set up local variables depending on which command is + * received. + */ + if (pkt->hdr.cmd == REPLY_RX) { + phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt); + + len = le16_to_cpu(phy_res->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt + len); + ampdu_status = le32_to_cpu(rx_pkt_status); + } else { + if (!priv->_agn.last_phy_res_valid) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return; + } + phy_res = &priv->_agn.last_phy_res; + amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); + ampdu_status = iwl_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); + } + + if ((unlikely(phy_res->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", + phy_res->cfg_phy_cnt); + return; + } + + if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || + !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(rx_pkt_status)); + return; + } + + /* This will be used in several places later */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); + + /* rx_status carries information about the packet to mac80211 */ + rx_status.mactime = le64_to_cpu(phy_res->timestamp); + rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel), + rx_status.band); + rx_status.rate_idx = + iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); + rx_status.flag = 0; + + /* TSF isn't reliable. In order to allow smooth user experience, + * this W/A doesn't propagate it to the mac80211 */ + /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ + + priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); + + /* Find max signal strength (dBm) among 3 antenna/receiver chains */ + rx_status.signal = priv->cfg->ops->utils->calc_rssi(priv, phy_res); + + iwl_dbg_log_rx_data_frame(priv, len, header); + IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n", + rx_status.signal, (unsigned long long)rx_status.mactime); + + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bit field. This is undefined by radiotap, + * it wants an actual antenna number but I always get "7" + * for most legacy frames I receive indicating that the + * same frame was received on all three RX chains. + * + * I think this field should be removed in favor of a + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + rx_status.antenna = + (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; + + /* set the preamble flag if appropriate */ + if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + rx_status.flag |= RX_FLAG_SHORTPRE; + + /* Set up the HT phy flags */ + if (rate_n_flags & RATE_MCS_HT_MSK) + rx_status.flag |= RX_FLAG_HT; + if (rate_n_flags & RATE_MCS_HT40_MSK) + rx_status.flag |= RX_FLAG_40MHZ; + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status.flag |= RX_FLAG_SHORT_GI; + + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); +} + +/** + * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + */ +void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); + + handlers = priv->rx_handlers; + + handlers[REPLY_ERROR] = iwl_rx_reply_error; + handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; + handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; + handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + + /* + * The same handler is used for both the REPLY to a discrete + * statistics request from the host as well as for the periodic + * statistics notifications (after received beacons) from the uCode. + */ + handlers[REPLY_STATISTICS_CMD] = iwl_rx_reply_statistics; + handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + + iwl_setup_rx_scan_handlers(priv); + + handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; + handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; + + /* Rx handlers */ + handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; + handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; + + /* block ack */ + handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; + + /* Set up hardware specific Rx handlers */ + priv->cfg->ops->lib->rx_handler_setup(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 12d9363d0afe..d60d630cb93a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -101,7 +101,7 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) ieee80211_scan_completed(priv->hw, aborted); } - priv->is_internal_short_scan = false; + priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } @@ -143,7 +143,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); iwl_force_scan_end(priv); } else - IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n"); + IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); } /** @@ -155,7 +155,6 @@ int iwl_scan_cancel(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->abort_scan); return 0; } -EXPORT_SYMBOL(iwl_scan_cancel); /** * iwl_scan_cancel_timeout - Cancel any currently executing HW scan @@ -180,7 +179,6 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) return test_bit(STATUS_SCAN_HW, &priv->status); } -EXPORT_SYMBOL(iwl_scan_cancel_timeout); /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl_rx_reply_scan(struct iwl_priv *priv, @@ -257,8 +255,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + iwl_advanced_bt_coexist(priv) && priv->bt_status != scan_notif->bt_status) { if (scan_notif->bt_status) { /* BT on */ @@ -289,7 +286,6 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl_rx_scan_complete_notif; } -EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, enum ieee80211_band band, @@ -302,7 +298,6 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, return IWL_ACTIVE_DWELL_TIME_24 + IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); } -EXPORT_SYMBOL(iwl_get_active_dwell_time); u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, enum ieee80211_band band, @@ -334,7 +329,6 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, return passive; } -EXPORT_SYMBOL(iwl_get_passive_dwell_time); void iwl_init_scan_params(struct iwl_priv *priv) { @@ -344,12 +338,11 @@ void iwl_init_scan_params(struct iwl_priv *priv) if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } -EXPORT_SYMBOL(iwl_init_scan_params); -static int __must_check iwl_scan_initiate(struct iwl_priv *priv, - struct ieee80211_vif *vif, - bool internal, - enum ieee80211_band band) +int __must_check iwl_scan_initiate(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum iwl_scan_type scan_type, + enum ieee80211_band band) { int ret; @@ -377,17 +370,19 @@ static int __must_check iwl_scan_initiate(struct iwl_priv *priv, } IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", - internal ? "internal short " : ""); + scan_type == IWL_SCAN_NORMAL ? "" : + scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " : + "internal short "); set_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = internal; + priv->scan_type = scan_type; priv->scan_start = jiffies; priv->scan_band = band; ret = priv->cfg->ops->utils->request_scan(priv, vif); if (ret) { clear_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = false; + priv->scan_type = IWL_SCAN_NORMAL; return ret; } @@ -412,7 +407,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (test_bit(STATUS_SCANNING, &priv->status) && - !priv->is_internal_short_scan) { + priv->scan_type != IWL_SCAN_NORMAL) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); ret = -EAGAIN; goto out_unlock; @@ -426,11 +421,11 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, * If an internal scan is in progress, just set * up the scan_request as per above. */ - if (priv->is_internal_short_scan) { + if (priv->scan_type != IWL_SCAN_NORMAL) { IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n"); ret = 0; } else - ret = iwl_scan_initiate(priv, vif, false, + ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, req->channels[0]->band); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -440,7 +435,6 @@ out_unlock: return ret; } -EXPORT_SYMBOL(iwl_mac_hw_scan); /* * internal short scan, this function should only been called while associated. @@ -460,7 +454,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) mutex_lock(&priv->mutex); - if (priv->is_internal_short_scan == true) { + if (priv->scan_type == IWL_SCAN_RADIO_RESET) { IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); goto unlock; } @@ -470,7 +464,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) goto unlock; } - if (iwl_scan_initiate(priv, NULL, true, priv->band)) + if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band)) IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); unlock: mutex_unlock(&priv->mutex); @@ -537,7 +531,6 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, return (u16)len; } -EXPORT_SYMBOL(iwl_fill_probe_req); static void iwl_bg_abort_scan(struct work_struct *work) { @@ -558,8 +551,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) container_of(work, struct iwl_priv, scan_completed); bool aborted; - IWL_DEBUG_SCAN(priv, "Completed %sscan.\n", - priv->is_internal_short_scan ? "internal short " : ""); + IWL_DEBUG_SCAN(priv, "Completed scan.\n"); cancel_delayed_work(&priv->scan_check); @@ -574,7 +566,13 @@ static void iwl_bg_scan_completed(struct work_struct *work) goto out_settings; } - if (priv->is_internal_short_scan && !aborted) { + if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->_agn.offchan_tx_skb) { + ieee80211_tx_status_irqsafe(priv->hw, + priv->_agn.offchan_tx_skb); + priv->_agn.offchan_tx_skb = NULL; + } + + if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { int err; /* Check if mac80211 requested scan during our internal scan */ @@ -582,7 +580,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) goto out_complete; /* If so request a new scan */ - err = iwl_scan_initiate(priv, priv->scan_vif, false, + err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, priv->scan_request->channels[0]->band); if (err) { IWL_DEBUG_SCAN(priv, @@ -622,7 +620,6 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); } -EXPORT_SYMBOL(iwl_setup_scan_deferred_work); void iwl_cancel_scan_deferred_work(struct iwl_priv *priv) { @@ -636,4 +633,3 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv) mutex_unlock(&priv->mutex); } } -EXPORT_SYMBOL(iwl_cancel_scan_deferred_work); diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h deleted file mode 100644 index c4ca0b5d77da..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_spectrum_h__ -#define __iwl_spectrum_h__ -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __packed; - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __packed; - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 49493d176515..3c8cebde16cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -169,7 +169,6 @@ int iwl_send_add_sta(struct iwl_priv *priv, return ret; } -EXPORT_SYMBOL(iwl_send_add_sta); static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, struct ieee80211_sta *sta, @@ -234,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_station_entry *station; int i; u8 sta_id = IWL_INVALID_STATION; - u16 rate; if (is_ap) sta_id = ctx->ap_sta_id; @@ -307,16 +305,9 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, */ iwl_set_ht_add_station(priv, sta_id, sta, ctx); - /* 3945 only */ - rate = (priv->band == IEEE80211_BAND_5GHZ) ? - IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); - return sta_id; } -EXPORT_SYMBOL_GPL(iwl_prep_station); #define STA_WAIT_TIMEOUT (HZ/2) @@ -379,7 +370,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, *sta_id_r = sta_id; return ret; } -EXPORT_SYMBOL(iwl_add_station_common); /** * iwl_sta_ucode_deactivate - deactivate ucode status for a station @@ -504,7 +494,8 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -513,7 +504,6 @@ out_err: spin_unlock_irqrestore(&priv->sta_lock, flags); return -EINVAL; } -EXPORT_SYMBOL_GPL(iwl_remove_station); /** * iwl_clear_ucode_stations - clear ucode station table bits @@ -548,7 +538,6 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv, if (!cleared) IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); } -EXPORT_SYMBOL(iwl_clear_ucode_stations); /** * iwl_restore_stations() - Restore driver known stations to device @@ -625,7 +614,6 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else IWL_DEBUG_INFO(priv, "Restoring all known stations .... complete.\n"); } -EXPORT_SYMBOL(iwl_restore_stations); void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -668,7 +656,6 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) priv->stations[sta_id].sta.sta.addr, ret); iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); } -EXPORT_SYMBOL(iwl_reprogram_ap_sta); int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { @@ -680,7 +667,6 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv) return WEP_INVALID_OFFSET; } -EXPORT_SYMBOL(iwl_get_free_ucode_key_index); void iwl_dealloc_bcast_stations(struct iwl_priv *priv) { @@ -694,13 +680,13 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv) priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; kfree(priv->stations[i].lq); priv->stations[i].lq = NULL; } spin_unlock_irqrestore(&priv->sta_lock, flags); } -EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations); #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_dump_lq_cmd(struct iwl_priv *priv, @@ -791,7 +777,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_dump_lq_cmd(priv, lq); - BUG_ON(init && (cmd.flags & CMD_ASYNC)); + if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) + return -EINVAL; if (is_lq_table_valid(priv, ctx, lq)) ret = iwl_send_cmd(priv, &cmd); @@ -810,7 +797,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, } return ret; } -EXPORT_SYMBOL(iwl_send_lq_cmd); int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -832,4 +818,3 @@ int iwl_mac_sta_remove(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); return ret; } -EXPORT_SYMBOL(iwl_mac_sta_remove); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 206f1e1a0caf..ff64027ff4cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c new file mode 100644 index 000000000000..89b6696622c1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <net/net_namespace.h> +#include <linux/netdevice.h> +#include <net/cfg80211.h> +#include <net/mac80211.h> +#include <net/netlink.h> + + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-fh.h" +#include "iwl-io.h" +#include "iwl-agn.h" +#include "iwl-testmode.h" + + +/* The TLVs used in the gnl message policy between the kernel module and + * user space application. iwl_testmode_gnl_msg_policy is to be carried + * through the NL80211_CMD_TESTMODE channel regulated by nl80211. + * See iwl-testmode.h + */ +static +struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { + [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, }, + [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, }, + + [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, }, + [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, }, + [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, }, +}; + +/* + * See the struct iwl_rx_packet in iwl-commands.h for the format of the + * received events from the device + */ +static inline int get_event_length(struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + if (pkt) + return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + else + return 0; +} + + +/* + * This function multicasts the spontaneous messages from the device to the + * user space. It is invoked whenever there is a received messages + * from the device. This function is called within the ISR of the rx handlers + * in iwlagn driver. + * + * The parsing of the message content is left to the user space application, + * The message content is treated as unattacked raw data and is encapsulated + * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space. + * + * @priv: the instance of iwlwifi device + * @rxb: pointer to rx data content received by the ISR + * + * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[]. + * For the messages multicasting to the user application, the mandatory + * TLV fields are : + * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT + * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content + */ + +static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hw *hw = priv->hw; + struct sk_buff *skb; + void *data; + int length; + + data = (void *)rxb_addr(rxb); + length = get_event_length(rxb); + + if (!data || length == 0) + return; + + skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, + GFP_ATOMIC); + if (skb == NULL) { + IWL_DEBUG_INFO(priv, + "Run out of memory for messages to user space ?\n"); + return; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data); + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + kfree_skb(skb); + IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); +} + +void iwl_testmode_init(struct iwl_priv *priv) +{ + priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; +} + +/* + * This function handles the user application commands to the ucode. + * + * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and + * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the + * host command to the ucode. + * + * If any mandatory field is missing, -ENOMSG is replied to the user space + * application; otherwise, the actual execution result of the host command to + * ucode is replied. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_host_cmd cmd; + + memset(&cmd, 0, sizeof(struct iwl_host_cmd)); + + if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] || + !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { + IWL_DEBUG_INFO(priv, + "Error finding ucode command mandatory fields\n"); + return -ENOMSG; + } + + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); + cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + " len %d\n", cmd.id, cmd.flags, cmd.len); + /* ok, let's submit the command to ucode */ + return iwl_send_cmd(priv, &cmd); +} + + +/* + * This function handles the user application commands for register access. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the + * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32, + * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating + * the success of the command execution. + * + * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read + * value is returned with IWL_TM_ATTR_REG_VALUE32. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + u32 ofs, val32; + u8 val8; + struct sk_buff *skb; + int status = 0; + + if (!tb[IWL_TM_ATTR_REG_OFFSET]) { + IWL_DEBUG_INFO(priv, "Error finding register offset\n"); + return -ENOMSG; + } + ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); + IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_REG_READ32: + val32 = iwl_read32(priv, ofs); + IWL_INFO(priv, "32bit value to read 0x%x\n", val32); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + if (!tb[IWL_TM_ATTR_REG_VALUE32]) { + IWL_DEBUG_INFO(priv, + "Error finding value to write\n"); + return -ENOMSG; + } else { + val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); + IWL_INFO(priv, "32bit value to write 0x%x\n", val32); + iwl_write32(priv, ofs, val32); + } + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + if (!tb[IWL_TM_ATTR_REG_VALUE8]) { + IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + return -ENOMSG; + } else { + val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); + IWL_INFO(priv, "8bit value to write 0x%x\n", val8); + iwl_write8(priv, ofs, val8); + } + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + return -ENOSYS; + } + + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + + +static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + ret = iwlagn_init_alive_start(priv); + if (ret) { + IWL_DEBUG_INFO(priv, + "Error configuring init calibration: %d\n", ret); + goto cfg_init_calib_error; + } + + ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ); + if (ret) + IWL_DEBUG_INFO(priv, "Error detecting" + " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); + return ret; + +cfg_init_calib_error: + iwlagn_remove_notification(priv, &calib_wait); + return ret; +} + +/* + * This function handles the user application commands for driver. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned + * value of the actual command execution is replied to the user application. + * + * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP + * is used for carry the message while IWL_TM_ATTR_COMMAND must set to + * IWL_TM_CMD_DEV2APP_SYNC_RSP. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct sk_buff *skb; + unsigned char *rsp_data_ptr = NULL; + int status = 0, rsp_data_len = 0; + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + rsp_data_ptr = (unsigned char *)priv->cfg->name; + rsp_data_len = strlen(priv->cfg->name); + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, + rsp_data_len + 20); + if (!skb) { + IWL_DEBUG_INFO(priv, + "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, + IWL_TM_CMD_DEV2APP_SYNC_RSP); + NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP, + rsp_data_len, rsp_data_ptr); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", + status); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (status) + IWL_DEBUG_INFO(priv, + "Error loading init ucode: %d\n", status); + break; + + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + iwl_testmode_cfg_init_calib(priv); + iwlagn_stop_device(priv); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + status = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); + if (status) { + IWL_DEBUG_INFO(priv, + "Error loading runtime ucode: %d\n", status); + break; + } + status = iwl_alive_start(priv); + if (status) + IWL_DEBUG_INFO(priv, + "Error starting the device: %d\n", status); + break; + + default: + IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + return -ENOSYS; + } + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + +/* The testmode gnl message handler that takes the gnl message from the + * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then + * invoke the corresponding handlers. + * + * This function is invoked when there is user space application sending + * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated + * by nl80211. + * + * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before + * dispatching it to the corresponding handler. + * + * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application; + * -ENOSYS is replied to the user application if the command is unknown; + * Otherwise, the command is dispatched to the respective handler. + * + * @hw: ieee80211_hw object that represents the device + * @data: pointer to user space message + * @len: length in byte of @data + */ +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct nlattr *tb[IWL_TM_ATTR_MAX - 1]; + struct iwl_priv *priv = hw->priv; + int result; + + result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, + iwl_testmode_gnl_msg_policy); + if (result != 0) { + IWL_DEBUG_INFO(priv, + "Error parsing the gnl message : %d\n", result); + return result; + } + + /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ + if (!tb[IWL_TM_ATTR_COMMAND]) { + IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); + return -ENOMSG; + } + /* in case multiple accesses to the device happens */ + mutex_lock(&priv->mutex); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_UCODE: + IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n"); + result = iwl_testmode_ucode(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_REG_READ32: + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); + result = iwl_testmode_reg(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); + result = iwl_testmode_driver(hw, tb); + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + result = -ENOSYS; + break; + } + + mutex_unlock(&priv->mutex); + return result; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h new file mode 100644 index 000000000000..31f8949f2801 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __IWL_TESTMODE_H__ +#define __IWL_TESTMODE_H__ + +#include <linux/types.h> + + +/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and + * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX). + * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of + * of command from user space and two types of command from kernel space. + * See below. + */ +enum iwl_tm_cmd_t { + /* commands from user application to the uCode, + * the actual uCode host command ID is carried with + * IWL_TM_ATTR_UCODE_CMD_ID */ + IWL_TM_CMD_APP2DEV_UCODE = 1, + + /* commands from user applicaiton to access register */ + IWL_TM_CMD_APP2DEV_REG_READ32, + IWL_TM_CMD_APP2DEV_REG_WRITE32, + IWL_TM_CMD_APP2DEV_REG_WRITE8, + + /* commands fom user space for pure driver level operations */ + IWL_TM_CMD_APP2DEV_GET_DEVICENAME, + IWL_TM_CMD_APP2DEV_LOAD_INIT_FW, + IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB, + IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW, + /* if there is other new command for the driver layer operation, + * append them here */ + + + /* commands from kernel space to carry the synchronous response + * to user application */ + IWL_TM_CMD_DEV2APP_SYNC_RSP, + + /* commands from kernel space to multicast the spontaneous messages + * to user application */ + IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + IWL_TM_CMD_MAX, +}; + +enum iwl_tm_attr_t { + IWL_TM_ATTR_NOT_APPLICABLE = 0, + + /* From user space to kernel space: + * the command either destines to ucode, driver, or register; + * See enum iwl_tm_cmd_t. + * + * From kernel space to user space: + * the command either carries synchronous response, + * or the spontaneous message multicast from the device; + * See enum iwl_tm_cmd_t. */ + IWL_TM_ATTR_COMMAND, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, + * The mandatory fields are : + * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; + * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; + * The optional fields are: + * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload + * to the ucode */ + IWL_TM_ATTR_UCODE_CMD_ID, + IWL_TM_ATTR_UCODE_CMD_DATA, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX, + * The mandatory fields are: + * IWL_TM_ATTR_REG_OFFSET for the offset of the target register; + * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */ + IWL_TM_ATTR_REG_OFFSET, + IWL_TM_ATTR_REG_VALUE8, + IWL_TM_ATTR_REG_VALUE32, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP, + * The mandatory fields are: + * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user + * application command */ + IWL_TM_ATTR_SYNC_RSP, + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + * The mandatory fields are: + * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user + * application */ + IWL_TM_ATTR_UCODE_RX_PKT, + + IWL_TM_ATTR_MAX, +}; + + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 073b6ce6141c..e69597ea43e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -84,7 +84,23 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) } txq->need_update = 0; } -EXPORT_SYMBOL(iwl_txq_update_write_ptr); + +/** + * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's + */ +void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + + if (q->n_bd == 0) + return; + + while (q->write_ptr != q->read_ptr) { + priv->cfg->ops->lib->txq_free_tfd(priv, txq); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + } +} /** * iwl_tx_queue_free - Deallocate DMA queue. @@ -97,17 +113,10 @@ EXPORT_SYMBOL(iwl_txq_update_write_ptr); void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; struct device *dev = &priv->pci_dev->dev; int i; - if (q->n_bd == 0) - return; - - /* first, empty all BD's */ - for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) - priv->cfg->ops->lib->txq_free_tfd(priv, txq); + iwl_tx_queue_unmap(priv, txq_id); /* De-alloc array of command/tx buffers */ for (i = 0; i < TFD_TX_CMD_SLOTS; i++) @@ -131,49 +140,58 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } -EXPORT_SYMBOL(iwl_tx_queue_free); /** - * iwl_cmd_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * 0-fill, but do not free "txq" descriptor structure. + * iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue */ -void iwl_cmd_queue_free(struct iwl_priv *priv) +void iwl_cmd_queue_unmap(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; - struct device *dev = &priv->pci_dev->dev; int i; - bool huge = false; if (q->n_bd == 0) return; - for (; q->read_ptr != q->write_ptr; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - /* we have no way to tell if it is a huge cmd ATM */ + while (q->read_ptr != q->write_ptr) { i = get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) { - huge = true; - continue; + if (txq->meta[i].flags & CMD_MAPPED) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(&txq->meta[i], mapping), + dma_unmap_len(&txq->meta[i], len), + PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } - pci_unmap_single(priv->pci_dev, - dma_unmap_addr(&txq->meta[i], mapping), - dma_unmap_len(&txq->meta[i], len), - PCI_DMA_BIDIRECTIONAL); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } +} + +/** + * iwl_cmd_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +void iwl_cmd_queue_free(struct iwl_priv *priv) +{ + struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + struct device *dev = &priv->pci_dev->dev; + int i; + + iwl_cmd_queue_unmap(priv); /* De-alloc array of command/tx buffers */ for (i = 0; i <= TFD_CMD_SLOTS; i++) @@ -193,7 +211,6 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } -EXPORT_SYMBOL(iwl_cmd_queue_free); /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services @@ -215,7 +232,6 @@ EXPORT_SYMBOL(iwl_cmd_queue_free); * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * See more detailed info in iwl-4965-hw.h. ***************************************************/ int iwl_queue_space(const struct iwl_queue *q) @@ -233,7 +249,6 @@ int iwl_queue_space(const struct iwl_queue *q) s = 0; return s; } -EXPORT_SYMBOL(iwl_queue_space); /** @@ -248,11 +263,13 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, /* 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)); + if (WARN_ON(!is_power_of_2(count))) + return -EINVAL; /* slots_num must be power-of-two size, otherwise * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); + if (WARN_ON(!is_power_of_2(slots_num))) + return -EINVAL; q->low_mark = q->n_window / 4; if (q->low_mark < 4) @@ -369,7 +386,9 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + if (ret) + return ret; /* Tell device where to find queue */ priv->cfg->ops->lib->txq_init(priv, txq); @@ -384,7 +403,6 @@ out_free_arrays: return -ENOMEM; } -EXPORT_SYMBOL(iwl_tx_queue_init); void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id) @@ -404,7 +422,6 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, /* Tell device where to find queue */ priv->cfg->ops->lib->txq_init(priv, txq); } -EXPORT_SYMBOL(iwl_tx_queue_reset); /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -425,22 +442,25 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; - int len; u32 idx; u16 fix_size; bool is_ct_kill = false; - cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - /* If any of the command structures end up being larger than + /* + * 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 * Also, check to see if command buffer should not exceed the size - * of device_cmd and max_cmd_size. */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->flags & CMD_SIZE_HUGE)); - BUG_ON(fix_size > IWL_MAX_CMD_SIZE); + * of device_cmd and max_cmd_size. + */ + if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; + + if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE)) + return -EINVAL; if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { IWL_WARN(priv, "Not sending command - %s KILL\n", @@ -448,35 +468,38 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + /* + * As we only have a single huge buffer, check that the command + * is synchronous (otherwise buffers could end up being reused). + */ + + if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; + + spin_lock_irqsave(&priv->hcmd_lock, flags); + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + IWL_ERR(priv, "No space in command queue\n"); - if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { - is_ct_kill = - priv->cfg->ops->lib->tt_ops.ct_kill_check(priv); - } + is_ct_kill = iwl_check_for_ct_kill(priv); if (!is_ct_kill) { IWL_ERR(priv, "Restarting adapter due to queue full\n"); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } return -ENOSPC; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; - } - idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -493,9 +516,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) INDEX_TO_SEQ(q->write_ptr)); if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; - len = sizeof(struct iwl_device_cmd); - if (idx == TFD_CMD_SLOTS) - len = IWL_MAX_CMD_SIZE; #ifdef CONFIG_IWLWIFI_DEBUG switch (out_cmd->hdr.cmd) { @@ -517,17 +537,20 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr, idx, priv->cmd_queue); } #endif - txq->need_update = 1; - - if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl) - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + idx = -ENOMEM; + goto out; + } + dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_len_set(out_meta, len, fix_size); + out_meta->flags = cmd->flags | CMD_MAPPED; + + txq->need_update = 1; + trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, @@ -538,6 +561,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(priv, txq); + out: spin_unlock_irqrestore(&priv->hcmd_lock, flags); return idx; } @@ -569,7 +593,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, if (nfreed++ > 0) { IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } } @@ -594,6 +618,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -607,14 +632,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -631,6 +648,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) } else if (meta->callback) meta->callback(priv, cmd, pkt); + spin_lock_irqsave(&priv->hcmd_lock, flags); + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(meta->flags & CMD_ASYNC)) { @@ -639,6 +658,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); } -EXPORT_SYMBOL(iwl_tx_cmd_complete); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c deleted file mode 100644 index 371abbf60eac..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ /dev/null @@ -1,4327 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/pci-aspm.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <linux/firmware.h> -#include <linux/etherdevice.h> -#include <linux/if_arp.h> - -#include <net/ieee80211_radiotap.h> -#include <net/mac80211.h> - -#include <asm/div64.h> - -#define DRV_NAME "iwl3945" - -#include "iwl-fh.h" -#include "iwl-3945-fh.h" -#include "iwl-commands.h" -#include "iwl-sta.h" -#include "iwl-3945.h" -#include "iwl-core.h" -#include "iwl-helpers.h" -#include "iwl-dev.h" -#include "iwl-spectrum.h" -#include "iwl-legacy.h" - -/* - * module name, copyright, version, etc. - */ - -#define DRV_DESCRIPTION \ -"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -/* - * add "s" to indicate spectrum measurement included. - * we add it here to be consistent with previous releases in which - * this was configurable. - */ -#define DRV_VERSION IWLWIFI_VERSION VD "s" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" -#define DRV_AUTHOR "<ilw@linux.intel.com>" - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); -MODULE_LICENSE("GPL"); - - /* module parameters */ -struct iwl_mod_params iwl3945_mod_params = { - .sw_crypto = 1, - .restart_fw = 1, - /* the rest are 0 by default */ -}; - -/** - * iwl3945_get_antenna_flags - Get antenna flags for RXON command - * @priv: eeprom and antenna fields are used to determine antenna flags - * - * priv->eeprom39 is used to determine if antenna AUX/MAIN are reversed - * iwl3945_mod_params.antenna specifies the antenna diversity mode: - * - * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself - * IWL_ANTENNA_MAIN - Force MAIN antenna - * IWL_ANTENNA_AUX - Force AUX antenna - */ -__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) -{ - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - - switch (iwl3945_mod_params.antenna) { - case IWL_ANTENNA_DIVERSITY: - return 0; - - case IWL_ANTENNA_MAIN: - if (eeprom->antenna_switch_type) - return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; - return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; - - case IWL_ANTENNA_AUX: - if (eeprom->antenna_switch_type) - return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; - return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; - } - - /* bad antenna selector value */ - IWL_ERR(priv, "Bad antenna selector value (0x%x)\n", - iwl3945_mod_params.antenna); - - return 0; /* "diversity" is default if error */ -} - -static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - __le16 key_flags = 0; - int ret; - - key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - - if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; - key_flags &= ~STA_KEY_FLG_INVALID; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; - 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); - - if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) - == STA_KEY_FLG_NO_ENC) - priv->stations[sta_id].sta.key.key_offset = - iwl_get_free_ucode_key_index(priv); - /* else, we are overriding an existing key => no need to allocated room - * in uCode. */ - - WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, - "no space for a new key"); - - 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; - - IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); - - ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return ret; -} - -static int iwl3945_set_tkip_dynamic_key_info(struct iwl_priv *priv, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - return -EOPNOTSUPP; -} - -static int iwl3945_set_wep_dynamic_key_info(struct iwl_priv *priv, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - return -EOPNOTSUPP; -} - -static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) -{ - unsigned long flags; - struct iwl_addsta_cmd sta_cmd; - - spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations[sta_id].sta.key, 0, - sizeof(struct iwl4965_keyinfo)); - priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} - -static int iwl3945_set_dynamic_key(struct iwl_priv *priv, - struct ieee80211_key_conf *keyconf, u8 sta_id) -{ - int ret = 0; - - keyconf->hw_key_idx = HW_KEY_DYNAMIC; - - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); - break; - case WLAN_CIPHER_SUITE_TKIP: - ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id); - break; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id); - break; - default: - IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__, - keyconf->cipher); - ret = -EINVAL; - } - - IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n", - keyconf->cipher, keyconf->keylen, keyconf->keyidx, - sta_id, ret); - - return ret; -} - -static int iwl3945_remove_static_key(struct iwl_priv *priv) -{ - int ret = -EOPNOTSUPP; - - return ret; -} - -static int iwl3945_set_static_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key) -{ - if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) - return -EOPNOTSUPP; - - IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher); - return -EINVAL; -} - -static void iwl3945_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO(priv, "%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 iwl3945_frame, list)); - priv->frames_count--; - } - - if (priv->frames_count) { - IWL_WARN(priv, "%d frames still in use. Did we lose one?\n", - priv->frames_count); - priv->frames_count = 0; - } -} - -static struct iwl3945_frame *iwl3945_get_free_frame(struct iwl_priv *priv) -{ - struct iwl3945_frame *frame; - struct list_head *element; - if (list_empty(&priv->free_frames)) { - frame = kzalloc(sizeof(*frame), GFP_KERNEL); - if (!frame) { - IWL_ERR(priv, "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 iwl3945_frame, list); -} - -static void iwl3945_free_frame(struct iwl_priv *priv, struct iwl3945_frame *frame) -{ - memset(frame, 0, sizeof(*frame)); - list_add(&frame->list, &priv->free_frames); -} - -unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - int left) -{ - - if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->beacon_skb) - return 0; - - if (priv->beacon_skb->len > left) - return 0; - - memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - - return priv->beacon_skb->len; -} - -static int iwl3945_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl3945_frame *frame; - unsigned int frame_size; - int rc; - u8 rate; - - frame = iwl3945_get_free_frame(priv); - - if (!frame) { - IWL_ERR(priv, "Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } - - rate = iwl_rate_get_lowest_plcp(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); - - frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); - - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); - - iwl3945_free_frame(priv, frame); - - return rc; -} - -static void iwl3945_unset_hw_params(struct iwl_priv *priv) -{ - if (priv->_3945.shared_virt) - dma_free_coherent(&priv->pci_dev->dev, - sizeof(struct iwl3945_shared), - priv->_3945.shared_virt, - priv->_3945.shared_phys); -} - -static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - struct iwl_device_cmd *cmd, - struct sk_buff *skb_frag, - int sta_id) -{ - struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - - tx_cmd->sec_ctl = 0; - - switch (keyinfo->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); - IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); - break; - - case WLAN_CIPHER_SUITE_TKIP: - break; - - case WLAN_CIPHER_SUITE_WEP104: - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - /* fall through */ - case WLAN_CIPHER_SUITE_WEP40: - tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | - (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; - - memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen); - - IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " - "with key %d\n", info->control.hw_key->hw_key_idx); - break; - - default: - IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher); - break; - } -} - -/* - * handle build REPLY_TX command notification. - */ -static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, u8 std_id) -{ - struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - __le32 tx_flags = tx_cmd->tx_flags; - __le16 fc = hdr->frame_control; - - tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - tx_flags |= TX_CMD_FLG_ACK_MSK; - if (ieee80211_is_mgmt(fc)) - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_resp(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; - } - - tx_cmd->sta_id = std_id; - if (ieee80211_has_morefrags(fc)) - tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - - if (ieee80211_is_data_qos(fc)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tx_cmd->tid_tspec = qc[0] & 0xf; - tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags); - - tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if (ieee80211_is_mgmt(fc)) { - if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); - else - tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); - } else { - tx_cmd->timeout.pm_frame_timeout = 0; - } - - tx_cmd->driver_txop = 0; - tx_cmd->tx_flags = tx_flags; - tx_cmd->next_frame_len = 0; -} - -/* - * start REPLY_TX command process - */ -static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl3945_tx_cmd *tx_cmd; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; - struct iwl_device_cmd *out_cmd; - struct iwl_cmd_meta *out_meta; - dma_addr_t phys_addr; - dma_addr_t txcmd_phys; - int txq_id = skb_get_queue_mapping(skb); - u16 len, idx, hdr_len; - u8 id; - u8 unicast; - u8 sta_id; - u8 tid = 0; - __le16 fc; - u8 wait_write_ptr = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); - goto drop_unlock; - } - - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { - IWL_ERR(priv, "ERROR: No TX rate available.\n"); - goto drop_unlock; - } - - unicast = !is_multicast_ether_addr(hdr->addr1); - id = 0; - - fc = hdr->frame_control; - -#ifdef CONFIG_IWLWIFI_DEBUG - if (ieee80211_is_auth(fc)) - IWL_DEBUG_TX(priv, "Sending AUTH frame\n"); - else if (ieee80211_is_assoc_req(fc)) - IWL_DEBUG_TX(priv, "Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_req(fc)) - IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - hdr_len = ieee80211_hdrlen(fc); - - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast( - priv, &priv->contexts[IWL_RXON_CTX_BSS], - info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop; - } - - IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id); - - if (ieee80211_is_data_qos(fc)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - if (unlikely(tid >= MAX_TID_COUNT)) - goto drop; - } - - /* Descriptor for chosen Tx queue */ - txq = &priv->txq[txq_id]; - q = &txq->q; - - if ((iwl_queue_space(q) < q->high_mark)) - goto drop; - - spin_lock_irqsave(&priv->lock, flags); - - idx = get_cmd_index(q, q->write_ptr, 0); - - /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->write_ptr].skb = skb; - txq->txb[q->write_ptr].ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - /* Init first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = txq->cmd[idx]; - out_meta = &txq->meta[idx]; - tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; - memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(tx_cmd, 0, sizeof(*tx_cmd)); - - /* - * Set up the Tx-command (not MAC!) header. - * Store the chosen Tx queue and TFD index within the sequence field; - * after Tx, uCode's Tx response will return this value so driver can - * locate the frame within the tx queue and do post-tx processing. - */ - out_cmd->hdr.cmd = REPLY_TX; - out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdr_len); - - - if (info->control.hw_key) - iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, sta_id); - - /* TODO need this for burst mode later on */ - iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, sta_id); - - /* set is_hcca to 0; it probably will never be implemented */ - iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0); - - /* Total # bytes to be transmitted */ - len = (u16)skb->len; - tx_cmd->len = cpu_to_le16(len); - - iwl_dbg_log_tx_data_frame(priv, len, hdr); - iwl_update_stats(priv, true, fc, len); - tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; - tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; - - if (!ieee80211_has_morefrags(hdr->frame_control)) { - txq->need_update = 1; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n", - le16_to_cpu(out_cmd->hdr.sequence)); - IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, - ieee80211_hdrlen(fc)); - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = sizeof(struct iwl3945_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; - len = (len + 3) & ~3; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, - len, PCI_DMA_TODEVICE); - /* we do not map meta data ... so we can safely access address to - * provide to unmap command*/ - dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, len); - - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - txcmd_phys, len, 1, 0); - - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { - phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, - len, PCI_DMA_TODEVICE); - priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - phys_addr, len, - 0, U32_PAD(len)); - } - - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - - if ((iwl_queue_space(q) < q->high_mark) - && priv->mac80211_registered) { - if (wait_write_ptr) { - spin_lock_irqsave(&priv->lock, flags); - txq->need_update = 1; - iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - } - - iwl_stop_queue(priv, txq); - } - - return 0; - -drop_unlock: - spin_unlock_irqrestore(&priv->lock, flags); -drop: - return -1; -} - -static int iwl3945_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl_spectrum_cmd spectrum; - struct iwl_rx_packet *pkt; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) - add_time = iwl_usecs_to_beacons(priv, - le64_to_cpu(params->start_time) - priv->_3945.last_tsf, - le16_to_cpu(ctx->timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) - spectrum.start_time = - iwl_add_beacon_time(priv, - priv->_3945.last_beacon_time, add_time, - le16_to_cpu(ctx->timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (ctx->active.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - pkt = (struct iwl_rx_packet *)cmd.reply_page; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (pkt->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n", - pkt->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - iwl_free_pages(priv, cmd.reply_page); - - return rc; -} - -static void iwl3945_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->alive_start; - iwl3945_disable_events(priv); - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else - IWL_WARN(priv, "uCode did not respond OK.\n"); -} - -static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = rxb_addr(rxb); -#endif - - IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); -} - -static void iwl3945_bg_beacon_update(struct work_struct *work) -{ - struct iwl_priv *priv = - container_of(work, struct iwl_priv, beacon_update); - struct sk_buff *beacon; - - /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, - priv->contexts[IWL_RXON_CTX_BSS].vif); - - if (!beacon) { - IWL_ERR(priv, "update beacon failed\n"); - return; - } - - mutex_lock(&priv->mutex); - /* new beacon skb is allocated every time; dispose previous.*/ - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - priv->beacon_skb = beacon; - mutex_unlock(&priv->mutex); - - iwl3945_send_beacon_cmd(priv); -} - -static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); -#ifdef CONFIG_IWLWIFI_DEBUG - u8 rate = beacon->beacon_notify_hdr.rate; - - IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d " - "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, - beacon->beacon_notify_hdr.failure_frame, - le32_to_cpu(beacon->ibss_mgr_status), - le32_to_cpu(beacon->high_tsf), - le32_to_cpu(beacon->low_tsf), rate); -#endif - - priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!test_bit(STATUS_EXIT_PENDING, &priv->status))) - queue_work(priv->workqueue, &priv->beacon_update); -} - -/* Handle notification from uCode that card's power state is changing - * due to software, hardware, or critical temperature RFKILL */ -static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); - unsigned long status = priv->status; - - IWL_WARN(priv, "Card state received: HW:%s SW:%s\n", - (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On"); - - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - if (flags & HW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - - iwl_scan_cancel(priv); - - if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status))) - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); - else - wake_up_interruptible(&priv->wait_command_queue); -} - -/** - * iwl3945_setup_rx_handlers - Initialize Rx handler callbacks - * - * Setup the RX handlers for each of the reply types sent from the uCode - * to the host. - * - * This function chains into the hardware specific files for them to setup - * any hardware specific handlers as well. - */ -static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) -{ - priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive; - priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; - priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; - priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif; - - /* - * The same handler is used for both the REPLY to a discrete - * statistics request from the host as well as for the periodic - * statistics notifications (after received beacons) from the uCode. - */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_reply_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; - - iwl_setup_rx_scan_handlers(priv); - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; - - /* Set up hardware specific Rx handlers */ - iwl3945_hw_rx_handler_setup(priv); -} - -/************************** RX-FUNCTIONS ****************************/ -/* - * Rx theory of operation - * - * The host allocates 32 DMA target addresses and passes the host address - * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is - * 0 to 31 - * - * Rx Queue Indexes - * The host/firmware share two index registers for managing the Rx buffers. - * - * The READ index maps to the first position that the firmware may be writing - * to -- the driver can read up to (but not including) this position and get - * good data. - * The READ index is managed by the firmware once the card is enabled. - * - * The WRITE index maps to the last position the driver has read from -- the - * position preceding WRITE is the last slot the firmware can place a packet. - * - * The queue is empty (no good data) if WRITE = READ - 1, and is full if - * WRITE = READ. - * - * During initialization, the host sets up the READ queue position to the first - * INDEX position, and WRITE to the last (READ - 1 wrapped) - * - * When the firmware places a packet in a buffer, it will advance the READ index - * and fire the RX interrupt. The driver can then query the READ index and - * process as many packets as possible, moving the WRITE index forward as it - * resets the Rx queue buffers with new memory. - * - * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl3945_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) - * + A received packet is processed and handed to the kernel network stack, - * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free - * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ - * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there - * were enough free buffers and RX_STALLED is set it is cleared. - * - * - * Driver sequence: - * - * iwl3945_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl3945_rx_queue_restock - * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx - * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl3945_rx_replenish - * - * -- enable interrupts -- - * ISR - iwl3945_rx() Detach iwl_rx_mem_buffers from pool up to the - * READ INDEX, detaching the SKB from the pool. - * Moves the packet buffer from queue to rx_used. - * Calls iwl3945_rx_queue_restock to refill any empty - * slots. - * ... - * - */ - -/** - * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv, - dma_addr_t dma_addr) -{ - return cpu_to_le32((u32)dma_addr); -} - -/** - * iwl3945_rx_queue_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -static void iwl3945_rx_queue_restock(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl_rx_mem_buffer *rxb; - unsigned long flags; - int write; - - spin_lock_irqsave(&rxq->lock, flags); - write = rxq->write & ~0x7; - while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { - /* Get next free Rx buffer, remove from free list */ - element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - - /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma); - rxq->queue[rxq->write] = rxb; - rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; - rxq->free_count--; - } - spin_unlock_irqrestore(&rxq->lock, flags); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(priv->workqueue, &priv->rx_replenish); - - - /* If we've added more space for the firmware to place data, tell it. - * Increment device's write pointer in multiples of 8. */ - if ((rxq->write_actual != (rxq->write & ~0x7)) - || (abs(rxq->write - rxq->read) > 7)) { - spin_lock_irqsave(&rxq->lock, flags); - rxq->need_update = 1; - spin_unlock_irqrestore(&rxq->lock, flags); - iwl_rx_queue_update_write_ptr(priv, rxq); - } -} - -/** - * iwl3945_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. - * - * Also restock the Rx queue via iwl3945_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) - */ -static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl_rx_mem_buffer *rxb; - struct page *page; - unsigned long flags; - gfp_t gfp_mask = priority; - - while (1) { - spin_lock_irqsave(&rxq->lock, flags); - - if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); - return; - } - spin_unlock_irqrestore(&rxq->lock, flags); - - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - - if (priv->hw_params.rx_page_order > 0) - gfp_mask |= __GFP_COMP; - - /* Alloc a new receive buffer */ - page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); - if (!page) { - if (net_ratelimit()) - IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); - if ((rxq->free_count <= RX_LOW_WATERMARK) && - net_ratelimit()) - IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n", - priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL", - rxq->free_count); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ - break; - } - - spin_lock_irqsave(&rxq->lock, flags); - if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); - __free_pages(page, priv->hw_params.rx_page_order); - return; - } - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - spin_unlock_irqrestore(&rxq->lock, flags); - - rxb->page = page; - /* Get physical address of RB/SKB */ - rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, - PAGE_SIZE << priv->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - - spin_lock_irqsave(&rxq->lock, flags); - - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - priv->alloc_rxb_page++; - - spin_unlock_irqrestore(&rxq->lock, flags); - } -} - -void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - unsigned long flags; - int i; - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].page != NULL) { - pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - __iwl_free_pages(priv, rxq->pool[i].page); - rxq->pool[i].page = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); -} - -void iwl3945_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - unsigned long flags; - - iwl3945_rx_allocate(priv, GFP_KERNEL); - - spin_lock_irqsave(&priv->lock, flags); - iwl3945_rx_queue_restock(priv); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwl3945_rx_replenish_now(struct iwl_priv *priv) -{ - iwl3945_rx_allocate(priv, GFP_ATOMIC); - - iwl3945_rx_queue_restock(priv); -} - - -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have its SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed - */ -static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - int i; - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].page != NULL) { - pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - __iwl_free_pages(priv, rxq->pool[i].page); - rxq->pool[i].page = NULL; - } - } - - dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->bd_dma); - dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); - rxq->bd = NULL; - rxq->rb_stts = NULL; -} - - -/* Convert linear signal-to-noise ratio into dB */ -static u8 ratio2dB[100] = { -/* 0 1 2 3 4 5 6 7 8 9 */ - 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ - 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ - 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ - 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ - 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ - 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ - 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ - 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ - 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ - 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ -}; - -/* Calculates a relative dB value from a ratio of linear - * (i.e. not dB) signal levels. - * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int iwl3945_calc_db_from_ratio(int sig_ratio) -{ - /* 1000:1 or higher just report as 60 dB */ - if (sig_ratio >= 1000) - return 60; - - /* 100:1 or higher, divide by 10 and use table, - * add 20 dB to make up for divide by 10 */ - if (sig_ratio >= 100) - return 20 + (int)ratio2dB[sig_ratio/10]; - - /* We shouldn't see this */ - if (sig_ratio < 1) - return 0; - - /* Use table for ratios 1:1 - 99:1 */ - return (int)ratio2dB[sig_ratio]; -} - -/** - * iwl3945_rx_handle - Main entry function for receiving responses from uCode - * - * Uses the priv->rx_handlers callback function array to invoke - * the appropriate handlers, including command responses, - * frame-received notifications, and other notifications. - */ -static void iwl3945_rx_handle(struct iwl_priv *priv) -{ - struct iwl_rx_mem_buffer *rxb; - struct iwl_rx_packet *pkt; - struct iwl_rx_queue *rxq = &priv->rxq; - u32 r, i; - int reclaim; - unsigned long flags; - u8 fill_rx = 0; - u32 count = 8; - int total_empty = 0; - - /* uCode's read index (stored in shared DRAM) indicates the last Rx - * buffer that the driver may process (last buffer filled by ucode). */ - r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; - i = rxq->read; - - /* calculate total frames need to be restock after handling RX */ - total_empty = r - rxq->write_actual; - if (total_empty < 0) - total_empty += RX_QUEUE_SIZE; - - if (total_empty > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - /* Rx interrupt, but nothing sent from uCode */ - if (i == r) - IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); - - while (i != r) { - int len; - - rxb = rxq->queue[i]; - - /* If an RXB doesn't have a Rx queue slot associated with it, - * then a bug has been introduced in the queue refilling - * routines -- catch it here */ - BUG_ON(rxb == NULL); - - rxq->queue[i] = NULL; - - pci_unmap_page(priv->pci_dev, rxb->page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - pkt = rxb_addr(rxb); - - len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - trace_iwlwifi_dev_rx(priv, pkt, len); - - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && - (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && - (pkt->hdr.cmd != REPLY_TX); - - /* Based on type of command response or notification, - * handle those that need handling via function in - * rx_handlers table. See iwl3945_setup_rx_handlers() */ - if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); - priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; - priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); - } else { - /* No handling needed */ - IWL_DEBUG_RX(priv, - "r %d i %d No handler needed for %s, 0x%02x\n", - r, i, get_cmd_string(pkt->hdr.cmd), - pkt->hdr.cmd); - } - - /* - * XXX: After here, we should always check rxb->page - * against NULL before touching it or its virtual - * memory (pkt). Because some rx_handler might have - * already taken or freed the pages. - */ - - if (reclaim) { - /* Invoke any callbacks, transfer the buffer to caller, - * and fire off the (possibly) blocking iwl_send_cmd() - * as we reclaim the driver command queue */ - if (rxb->page) - iwl_tx_cmd_complete(priv, rxb); - else - IWL_WARN(priv, "Claim null rxb?\n"); - } - - /* Reuse the page if possible. For notification packets and - * SKBs that fail to Rx correctly, add them back into the - * rx_free list for reuse later. */ - spin_lock_irqsave(&rxq->lock, flags); - if (rxb->page != NULL) { - rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page, - 0, PAGE_SIZE << priv->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } else - list_add_tail(&rxb->list, &rxq->rx_used); - - spin_unlock_irqrestore(&rxq->lock, flags); - - i = (i + 1) & RX_QUEUE_MASK; - /* If there are a lot of unused frames, - * restock the Rx queue so ucode won't assert. */ - if (fill_rx) { - count++; - if (count >= 8) { - rxq->read = i; - iwl3945_rx_replenish_now(priv); - count = 0; - } - } - } - - /* Backtrack one entry */ - rxq->read = i; - if (fill_rx) - iwl3945_rx_replenish_now(priv); - else - iwl3945_rx_queue_restock(priv); -} - -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - -static const char *desc_lookup(int i) -{ - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } - - return "UNKNOWN"; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -void iwl3945_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 i; - u32 desc, time, count, base, data1; - u32 blink1, blink2, ilink1, ilink2; - - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - - if (!iwl3945_hw_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); - return; - } - - - count = iwl_read_targ_mem(priv, base); - - if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { - IWL_ERR(priv, "Start IWL Error Log Dump:\n"); - IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", - priv->status, count); - } - - IWL_ERR(priv, "Desc Time asrtPC blink2 " - "ilink1 nmiPC Line\n"); - for (i = ERROR_START_OFFSET; - i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET; - i += ERROR_ELEM_SIZE) { - desc = iwl_read_targ_mem(priv, base + i); - time = - iwl_read_targ_mem(priv, base + i + 1 * sizeof(u32)); - blink1 = - iwl_read_targ_mem(priv, base + i + 2 * sizeof(u32)); - blink2 = - iwl_read_targ_mem(priv, base + i + 3 * sizeof(u32)); - ilink1 = - iwl_read_targ_mem(priv, base + i + 4 * sizeof(u32)); - ilink2 = - iwl_read_targ_mem(priv, base + i + 5 * sizeof(u32)); - data1 = - iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32)); - - IWL_ERR(priv, - "%-13s (0x%X) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", - desc_lookup(desc), desc, time, blink1, blink2, - ilink1, ilink2, data1); - trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0, - 0, blink1, blink2, ilink1, ilink2); - } -} - -#define EVENT_START_OFFSET (6 * sizeof(u32)) - -/** - * iwl3945_print_event_log - Dump error event log to syslog - * - */ -static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode, - int pos, char **buf, size_t bufsz) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - unsigned long reg_flags; - - if (num_events == 0) - return pos; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - - /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); - rmb(); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (mode == 0) { - /* data, ev */ - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "0x%08x:%04u\n", - time, ev); - } else { - IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); - trace_iwlwifi_dev_ucode_event(priv, 0, - time, ev); - } - } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "%010u:0x%08x:%04u\n", - time, data, ev); - } else { - IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", - time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, - data, ev); - } - } - } - - /* Allow device to power down */ - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return pos; -} - -/** - * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog - */ -static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, - u32 num_wraps, u32 next_entry, - u32 size, u32 mode, - int pos, char **buf, size_t bufsz) -{ - /* - * display the newest DEFAULT_LOG_ENTRIES entries - * i.e the entries just before the next ont that uCode would fill. - */ - if (num_wraps) { - if (next_entry < size) { - pos = iwl3945_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode, - pos, buf, bufsz); - pos = iwl3945_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); - } else - pos = iwl3945_print_event_log(priv, next_entry - size, - size, mode, - pos, buf, bufsz); - } else { - if (next_entry < size) - pos = iwl3945_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); - else - pos = iwl3945_print_event_log(priv, next_entry - size, - size, mode, - pos, buf, bufsz); - } - return pos; -} - -#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) - -int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display) -{ - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - int pos = 0; - size_t bufsz = 0; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!iwl3945_hw_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return -EINVAL; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - if (capacity > priv->cfg->base_params->max_event_log_size) { - IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", - capacity, priv->cfg->base_params->max_event_log_size); - capacity = priv->cfg->base_params->max_event_log_size; - } - - if (next_entry > priv->cfg->base_params->max_event_log_size) { - IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", - next_entry, priv->cfg->base_params->max_event_log_size); - next_entry = priv->cfg->base_params->max_event_log_size; - } - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return pos; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log) - size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; -#else - size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; -#endif - - IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n", - size); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - if (full_log) - bufsz = capacity * 48; - else - bufsz = size * 48; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - } - if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { - /* if uCode has wrapped back to top of log, - * start at the oldest entry, - * i.e the next one that uCode would fill. - */ - if (num_wraps) - pos = iwl3945_print_event_log(priv, next_entry, - capacity - next_entry, mode, - pos, buf, bufsz); - - /* (then/else) start at top of log */ - pos = iwl3945_print_event_log(priv, 0, next_entry, mode, - pos, buf, bufsz); - } else - pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#else - pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#endif - return pos; -} - -static void iwl3945_irq_tasklet(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR39_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR39_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - "Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* uCode wakes up after power-down sleep */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); - - priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl3945_rx_handle(priv); - priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "Tx interrupt\n"); - priv->isr_stats.tx++; - - iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); - iwl_write_direct32(priv, FH39_TCSR_CREDIT - (FH39_SRVC_CHNL), 0x0); - handled |= CSR_INT_BIT_FH_TX; - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~priv->inta_mask) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif -} - -static int iwl3945_get_single_channel_for_scan(struct iwl_priv *priv, - struct ieee80211_vif *vif, - enum ieee80211_band band, - struct iwl3945_scan_channel *scan_ch) -{ - const struct ieee80211_supported_band *sband; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int added = 0; - u8 channel = 0; - - sband = iwl_get_hw_mode(priv, band); - if (!sband) { - IWL_ERR(priv, "invalid band\n"); - return added; - } - - active_dwell = iwl_get_active_dwell_time(priv, band, 0); - passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); - - if (passive_dwell <= active_dwell) - passive_dwell = active_dwell + 1; - - - channel = iwl_get_single_channel_number(priv, band); - - if (channel) { - scan_ch->channel = channel; - scan_ch->type = 0; /* passive */ - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set txpower levels to defaults */ - scan_ch->tpc.dsp_atten = 110; - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); - added++; - } else - IWL_ERR(priv, "no valid channel found\n"); - return added; -} - -static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, - enum ieee80211_band band, - u8 is_active, u8 n_probes, - struct iwl3945_scan_channel *scan_ch, - struct ieee80211_vif *vif) -{ - struct ieee80211_channel *chan; - const struct ieee80211_supported_band *sband; - const struct iwl_channel_info *ch_info; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int added, i; - - sband = iwl_get_hw_mode(priv, band); - if (!sband) - return 0; - - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); - passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); - - if (passive_dwell <= active_dwell) - passive_dwell = active_dwell + 1; - - for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { - chan = priv->scan_request->channels[i]; - - if (chan->band != band) - continue; - - scan_ch->channel = chan->hw_value; - - ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n", - scan_ch->channel); - continue; - } - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* If passive , set up for auto-switch - * and use long active_dwell time. - */ - if (!is_active || is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) { - scan_ch->type = 0; /* passive */ - if (IWL_UCODE_API(priv->ucode_ver) == 1) - scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); - } else { - scan_ch->type = 1; /* active */ - } - - /* Set direct probe bits. These may be used both for active - * scan channels (probes gets sent right away), - * or for passive channels (probes get se sent only after - * hearing clear Rx packet).*/ - if (IWL_UCODE_API(priv->ucode_ver) >= 2) { - if (n_probes) - scan_ch->type |= IWL39_SCAN_PROBE_MASK(n_probes); - } else { - /* uCode v1 does not allow setting direct probe bits on - * passive channel. */ - if ((scan_ch->type & 1) && n_probes) - scan_ch->type |= IWL39_SCAN_PROBE_MASK(n_probes); - } - - /* Set txpower levels to defaults */ - scan_ch->tpc.dsp_atten = 110; - /* scan_pwr_info->tpc.dsp_atten; */ - - /*scan_pwr_info->tpc.tx_gain; */ - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; - else { - scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); - /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level: - * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; - */ - } - - IWL_DEBUG_SCAN(priv, "Scanning %d [%s %d]\n", - scan_ch->channel, - (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", - (scan_ch->type & 1) ? - active_dwell : passive_dwell); - - scan_ch++; - added++; - } - - IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added); - return added; -} - -static void iwl3945_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ - int i; - - for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { - rates[i].bitrate = iwl3945_rates[i].ieee * 5; - rates[i].hw_value = i; /* Rate scaling will work on indexes */ - rates[i].hw_value_short = i; - rates[i].flags = 0; - if ((i > IWL39_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { - /* - * If CCK != 1M then set short preamble rate flag. - */ - rates[i].flags |= (iwl3945_rates[i].plcp == 10) ? - 0 : IEEE80211_RATE_SHORT_PREAMBLE; - } - } -} - -/****************************************************************************** - * - * uCode download functions - * - ******************************************************************************/ - -static void iwl3945_dealloc_ucode_pci(struct iwl_priv *priv) -{ - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); -} - -/** - * iwl3945_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 len) -{ - u32 val; - u32 save_len = len; - int rc = 0; - u32 errcnt; - - IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, - IWL39_RTC_INST_LOWER_BOUND); - - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { - /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - rc = -EIO; - errcnt++; - if (errcnt >= 20) - break; - } - } - - - if (!errcnt) - IWL_DEBUG_INFO(priv, - "ucode image in INSTRUCTION memory is good\n"); - - return rc; -} - - -/** - * iwl3945_verify_inst_sparse - verify runtime uCode image in card vs. host, - * using sample data 100 bytes apart. If these sample points are good, - * it's a pretty good bet that everything between them is good, too. - */ -static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) -{ - u32 val; - int rc = 0; - u32 errcnt = 0; - u32 i; - - IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { - /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, - i + IWL39_RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { -#if 0 /* Enable this if you want to see details */ - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - i, val, *image); -#endif - rc = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } - } - - return rc; -} - - -/** - * iwl3945_verify_ucode - determine which instruction image is in SRAM, - * and verify its contents - */ -static int iwl3945_verify_ucode(struct iwl_priv *priv) -{ - __le32 *image; - u32 len; - int rc = 0; - - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl3945_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); - return 0; - } - - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - rc = iwl3945_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); - return 0; - } - - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - rc = iwl3945_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); - return 0; - } - - IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl3945_verify_inst_full(priv, image, len); - - return rc; -} - -static void iwl3945_nic_start(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - -#define IWL3945_UCODE_GET(item) \ -static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode)\ -{ \ - return le32_to_cpu(ucode->u.v1.item); \ -} - -static u32 iwl3945_ucode_get_header_size(u32 api_ver) -{ - return 24; -} - -static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode) -{ - return (u8 *) ucode->u.v1.data; -} - -IWL3945_UCODE_GET(inst_size); -IWL3945_UCODE_GET(data_size); -IWL3945_UCODE_GET(init_size); -IWL3945_UCODE_GET(init_data_size); -IWL3945_UCODE_GET(boot_size); - -/** - * iwl3945_read_ucode - Read uCode images from disk file. - * - * Copy into buffers for card to fetch via bus-mastering - */ -static int iwl3945_read_ucode(struct iwl_priv *priv) -{ - const struct iwl_ucode_header *ucode; - int ret = -EINVAL, index; - const struct firmware *ucode_raw; - /* firmware file name contains uCode/driver compatibility version */ - const char *name_pre = priv->cfg->fw_name_pre; - const unsigned int api_max = priv->cfg->ucode_api_max; - const unsigned int api_min = priv->cfg->ucode_api_min; - char buf[25]; - u8 *src; - size_t len; - u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; - - /* Ask kernel firmware_class module to get the boot firmware off disk. - * request_firmware() is synchronous, file is in memory on return. */ - for (index = api_max; index >= api_min; index--) { - sprintf(buf, "%s%u%s", name_pre, index, ".ucode"); - ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERR(priv, "%s firmware file req failed: %d\n", - buf, ret); - if (ret == -ENOENT) - continue; - else - goto error; - } else { - if (index < api_max) - IWL_ERR(priv, "Loaded firmware %s, " - "which is deprecated. " - " Please use API v%u instead.\n", - buf, api_max); - IWL_DEBUG_INFO(priv, "Got firmware '%s' file " - "(%zd bytes) from disk\n", - buf, ucode_raw->size); - break; - } - } - - if (ret < 0) - goto error; - - /* Make sure that we got at least our header! */ - if (ucode_raw->size < iwl3945_ucode_get_header_size(1)) { - IWL_ERR(priv, "File size way too small!\n"); - ret = -EINVAL; - goto err_release; - } - - /* Data from ucode file: header followed by uCode images */ - ucode = (struct iwl_ucode_header *)ucode_raw->data; - - priv->ucode_ver = le32_to_cpu(ucode->ver); - api_ver = IWL_UCODE_API(priv->ucode_ver); - inst_size = iwl3945_ucode_get_inst_size(ucode); - data_size = iwl3945_ucode_get_data_size(ucode); - init_size = iwl3945_ucode_get_init_size(ucode); - init_data_size = iwl3945_ucode_get_init_data_size(ucode); - boot_size = iwl3945_ucode_get_boot_size(ucode); - src = iwl3945_ucode_get_data(ucode); - - /* api_ver should match the api version forming part of the - * firmware filename ... but we don't check for that and only rely - * on the API version read from firmware header from here on forward */ - - if (api_ver < api_min || api_ver > api_max) { - IWL_ERR(priv, "Driver unable to support your firmware API. " - "Driver supports v%u, firmware is v%u.\n", - api_max, api_ver); - priv->ucode_ver = 0; - ret = -EINVAL; - goto err_release; - } - if (api_ver != api_max) - IWL_ERR(priv, "Firmware has old API version. Expected %u, " - "got %u. New firmware can be obtained " - "from http://www.intellinuxwireless.org.\n", - api_max, api_ver); - - IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u\n", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver)); - - snprintf(priv->hw->wiphy->fw_version, - sizeof(priv->hw->wiphy->fw_version), - "%u.%u.%u.%u", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver)); - - IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", - inst_size); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n", - data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n", - init_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n", - init_data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n", - boot_size); - - - /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size != iwl3945_ucode_get_header_size(api_ver) + - inst_size + data_size + init_size + - init_data_size + boot_size) { - - IWL_DEBUG_INFO(priv, - "uCode file size %zd does not match expected size\n", - ucode_raw->size); - ret = -EINVAL; - goto err_release; - } - - /* Verify that uCode images will fit in card's SRAM */ - if (inst_size > IWL39_MAX_INST_SIZE) { - IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n", - inst_size); - ret = -EINVAL; - goto err_release; - } - - if (data_size > IWL39_MAX_DATA_SIZE) { - IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n", - data_size); - ret = -EINVAL; - goto err_release; - } - if (init_size > IWL39_MAX_INST_SIZE) { - IWL_DEBUG_INFO(priv, - "uCode init instr len %d too large to fit in\n", - init_size); - ret = -EINVAL; - goto err_release; - } - if (init_data_size > IWL39_MAX_DATA_SIZE) { - IWL_DEBUG_INFO(priv, - "uCode init data len %d too large to fit in\n", - init_data_size); - ret = -EINVAL; - goto err_release; - } - if (boot_size > IWL39_MAX_BSM_SIZE) { - IWL_DEBUG_INFO(priv, - "uCode boot instr len %d too large to fit in\n", - boot_size); - ret = -EINVAL; - goto err_release; - } - - /* Allocate ucode buffers for card's bus-master loading ... */ - - /* Runtime instructions and 2 copies of data: - * 1) unmodified from disk - * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - priv->ucode_data_backup.len = data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_data_backup.v_addr) - goto err_pci_alloc; - - /* Initialization instructions and data */ - if (init_size && init_data_size) { - priv->ucode_init.len = init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) - goto err_pci_alloc; - } - - /* Bootstrap (instructions only, no data) */ - if (boot_size) { - priv->ucode_boot.len = boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) - goto err_pci_alloc; - } - - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - len = inst_size; - IWL_DEBUG_INFO(priv, - "Copying (but not loading) uCode instr len %zd\n", len); - memcpy(priv->ucode_code.v_addr, src, len); - src += len; - - IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* Runtime data (2nd block) - * NOTE: Copy into backup buffer will be done in iwl3945_up() */ - len = data_size; - IWL_DEBUG_INFO(priv, - "Copying (but not loading) uCode data len %zd\n", len); - memcpy(priv->ucode_data.v_addr, src, len); - memcpy(priv->ucode_data_backup.v_addr, src, len); - src += len; - - /* Initialization instructions (3rd block) */ - if (init_size) { - len = init_size; - IWL_DEBUG_INFO(priv, - "Copying (but not loading) init instr len %zd\n", len); - memcpy(priv->ucode_init.v_addr, src, len); - src += len; - } - - /* Initialization data (4th block) */ - if (init_data_size) { - len = init_data_size; - IWL_DEBUG_INFO(priv, - "Copying (but not loading) init data len %zd\n", len); - memcpy(priv->ucode_init_data.v_addr, src, len); - src += len; - } - - /* Bootstrap instructions (5th block) */ - len = boot_size; - IWL_DEBUG_INFO(priv, - "Copying (but not loading) boot instr len %zd\n", len); - memcpy(priv->ucode_boot.v_addr, src, len); - - /* We have our copies now, allow OS release its copies */ - release_firmware(ucode_raw); - return 0; - - err_pci_alloc: - IWL_ERR(priv, "failed to allocate pci memory\n"); - ret = -ENOMEM; - iwl3945_dealloc_ucode_pci(priv); - - err_release: - release_firmware(ucode_raw); - - error: - return ret; -} - - -/** - * iwl3945_set_ucode_ptrs - Set uCode address location - * - * Tell initialization uCode where to find runtime uCode. - * - * BSM registers initially contain pointers to initialization uCode. - * We need to replace them to load runtime uCode inst and data, - * and to save runtime data when powering down. - */ -static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) -{ - dma_addr_t pinst; - dma_addr_t pdata; - - /* bits 31:0 for 3945 */ - pinst = priv->ucode_code.p_addr; - pdata = priv->ucode_data_backup.p_addr; - - /* Tell bootstrap uCode where to find image to load */ - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, - priv->ucode_data.len); - - /* Inst byte count must be last to set up, bit 31 signals uCode - * that all new ptr/size info is in place */ - iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, - priv->ucode_code.len | BSM_DRAM_INST_LOAD); - - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); - - return 0; -} - -/** - * iwl3945_init_alive_start - Called after REPLY_ALIVE notification received - * - * Called after REPLY_ALIVE notification received from "initialize" uCode. - * - * Tell "initialize" uCode to go ahead and load the runtime uCode. - */ -static void iwl3945_init_alive_start(struct iwl_priv *priv) -{ - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); - goto restart; - } - - /* Bootstrap uCode has loaded initialize uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl3945_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - /* Send pointers to protocol/runtime uCode image ... init code will - * load and launch runtime uCode, which will send us another "Alive" - * notification. */ - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - if (iwl3945_set_ucode_ptrs(priv)) { - /* Runtime instruction load won't happen; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); - goto restart; - } - return; - - restart: - queue_work(priv->workqueue, &priv->restart); -} - -/** - * iwl3945_alive_start - called after REPLY_ALIVE notification received - * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl3945_init_alive_start()). - */ -static void iwl3945_alive_start(struct iwl_priv *priv) -{ - int thermal_spin = 0; - u32 rfkill; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - - if (priv->card_alive.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Alive failed.\n"); - goto restart; - } - - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl3945_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); - goto restart; - } - - rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); - IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); - - if (rfkill & 0x1) { - clear_bit(STATUS_RF_KILL_HW, &priv->status); - /* if RFKILL is not on, then wait for thermal - * sensor in adapter to kick in */ - while (iwl3945_hw_get_temperature(priv) == 0) { - thermal_spin++; - udelay(10); - } - - if (thermal_spin) - IWL_DEBUG_INFO(priv, "Thermal calibration took %dus\n", - thermal_spin * 10); - } else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - /* After the ALIVE response, we can send commands to 3945 uCode */ - set_bit(STATUS_ALIVE, &priv->status); - - /* Enable watchdog to monitor the driver tx queues */ - iwl_setup_watchdog(priv); - - if (iwl_is_rfkill(priv)) - return; - - ieee80211_wake_queues(priv->hw); - - priv->active_rate = IWL_RATES_MASK; - - iwl_power_update_mode(priv, true); - - if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) { - struct iwl3945_rxon_cmd *active_rxon = - (struct iwl3945_rxon_cmd *)(&ctx->active); - - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - } else { - /* Initialize our rx_config data */ - iwl_connection_init_rx_config(priv, ctx); - } - - /* Configure Bluetooth device coexistence support */ - priv->cfg->ops->hcmd->send_bt_config(priv); - - /* Configure the adapter for unassociated operation */ - iwl3945_commit_rxon(priv, ctx); - - iwl3945_reg_txpower_periodic(priv); - - iwl_leds_init(priv); - - IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - set_bit(STATUS_READY, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); -} - -static void iwl3945_cancel_deferred_work(struct iwl_priv *priv); - -static void __iwl3945_down(struct iwl_priv *priv) -{ - unsigned long flags; - int exit_pending; - - IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); - - iwl_scan_cancel_timeout(priv, 200); - - exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); - - /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set - * to prevent rearm timer */ - del_timer_sync(&priv->watchdog); - - /* Station information will now be cleared in device */ - iwl_clear_ucode_stations(priv, NULL); - iwl_dealloc_bcast_stations(priv); - iwl_clear_driver_stations(priv); - - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - - /* Wipe out the EXIT_PENDING status bit if we are not actually - * exiting the module */ - if (!exit_pending) - clear_bit(STATUS_EXIT_PENDING, &priv->status); - - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - /* If we have not previously called iwl3945_init() then - * clear all bits but the RF Kill bits and return */ - if (!iwl_is_init(priv)) { - priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill - * bit and continue taking the NIC down. */ - priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - - iwl3945_hw_txq_ctx_stop(priv); - iwl3945_hw_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); - - exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = NULL; - - /* clear out any free frames */ - iwl3945_clear_free_frames(priv); -} - -static void iwl3945_down(struct iwl_priv *priv) -{ - mutex_lock(&priv->mutex); - __iwl3945_down(priv); - mutex_unlock(&priv->mutex); - - iwl3945_cancel_deferred_work(priv); -} - -#define MAX_HW_RESTARTS 5 - -static int iwl3945_alloc_bcast_station(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - unsigned long flags; - u8 sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(priv, "Unable to prepare broadcast station\n"); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return -EINVAL; - } - - priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; - priv->stations[sta_id].used |= IWL_STA_BCAST; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return 0; -} - -static int __iwl3945_up(struct iwl_priv *priv) -{ - int rc, i; - - rc = iwl3945_alloc_bcast_station(priv); - if (rc) - return rc; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); - return -EIO; - } - - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERR(priv, "ucode not available for device bring up\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else { - set_bit(STATUS_RF_KILL_HW, &priv->status); - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return -ENODEV; - } - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - rc = iwl3945_hw_nic_init(priv); - if (rc) { - IWL_ERR(priv, "Unable to int nic\n"); - return rc; - } - - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - - /* We return success when we resume from suspend and rf_kill is on. */ - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) - return 0; - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - rc = priv->cfg->ops->lib->load_ucode(priv); - - if (rc) { - IWL_ERR(priv, - "Unable to set up bootstrap uCode: %d\n", rc); - continue; - } - - /* start card; "initialize" will load runtime ucode */ - iwl3945_nic_start(priv); - - IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); - - return 0; - } - - set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl3945_down(priv); - clear_bit(STATUS_EXIT_PENDING, &priv->status); - - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); - return -EIO; -} - - -/***************************************************************************** - * - * Workqueue callbacks - * - *****************************************************************************/ - -static void iwl3945_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl3945_init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl3945_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl3945_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -/* - * 3945 cannot interrupt driver when hardware rf kill switch toggles; - * driver must poll CSR_GP_CNTRL_REG register for change. This register - * *is* readable even when device has been SW_RESET into low power mode - * (e.g. during RF KILL). - */ -static void iwl3945_rfkill_poll(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, _3945.rfkill_poll.work); - bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status); - bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL) - & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); - - if (new_rfkill != old_rfkill) { - if (new_rfkill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill); - - IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", - new_rfkill ? "disable radio" : "enable radio"); - } - - /* Keep this running, even if radio now enabled. This will be - * cancelled in mac_start() if system decides to start again */ - queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll, - round_jiffies_relative(2 * HZ)); - -} - -int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_SCAN_CMD, - .len = sizeof(struct iwl3945_scan_cmd), - .flags = CMD_SIZE_HUGE, - }; - struct iwl3945_scan_cmd *scan; - u8 n_probes = 0; - enum ieee80211_band band; - bool is_active = false; - int ret; - - lockdep_assert_held(&priv->mutex); - - if (!priv->scan_cmd) { - priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) + - IWL_MAX_SCAN_SIZE, GFP_KERNEL); - if (!priv->scan_cmd) { - IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n"); - return -ENOMEM; - } - } - scan = priv->scan_cmd; - memset(scan, 0, sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE); - - scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; - scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - - if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) { - u16 interval = 0; - u32 extra; - u32 suspend_time = 100; - u32 scan_suspend_time = 100; - unsigned long flags; - - IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->is_internal_short_scan) - interval = 0; - else - interval = vif->bss_conf.beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - scan->suspend_time = 0; - scan->max_out_time = cpu_to_le32(200 * 1024); - if (!interval) - interval = suspend_time; - /* - * suspend time format: - * 0-19: beacon interval in usec (time before exec.) - * 20-23: 0 - * 24-31: number of beacons (suspend between channels) - */ - - extra = (suspend_time / interval) << 24; - scan_suspend_time = 0xFF0FFFFF & - (extra | ((suspend_time % interval) * 1024)); - - scan->suspend_time = cpu_to_le32(scan_suspend_time); - IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", - scan_suspend_time, interval); - } - - if (priv->is_internal_short_scan) { - IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); - } else if (priv->scan_request->n_ssids) { - int i, p = 0; - IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - for (i = 0; i < priv->scan_request->n_ssids; i++) { - /* always does wildcard anyway */ - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } - is_active = true; - } else - IWL_DEBUG_SCAN(priv, "Kicking off passive scan.\n"); - - /* We don't build a direct scan probe request; the uCode will do - * that based on the direct_mask added to each channel entry */ - scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; - scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id; - scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - /* flags + rate selection */ - - switch (priv->scan_band) { - case IEEE80211_BAND_2GHZ: - scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - scan->tx_cmd.rate = IWL_RATE_1M_PLCP; - band = IEEE80211_BAND_2GHZ; - break; - case IEEE80211_BAND_5GHZ: - scan->tx_cmd.rate = IWL_RATE_6M_PLCP; - band = IEEE80211_BAND_5GHZ; - break; - default: - IWL_WARN(priv, "Invalid scan band\n"); - return -EIO; - } - - /* - * If active scaning is requested but a certain channel - * is marked passive, we can do active scanning if we - * detect transmissions. - */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_DISABLED; - - if (!priv->is_internal_short_scan) { - scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - vif->addr, - priv->scan_request->ie, - priv->scan_request->ie_len, - IWL_MAX_SCAN_SIZE - sizeof(*scan))); - } else { - /* use bcast addr, will not be transmitted but must be valid */ - scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - iwl_bcast_addr, NULL, 0, - IWL_MAX_SCAN_SIZE - sizeof(*scan))); - } - /* select Rx antennas */ - scan->flags |= iwl3945_get_antenna_flags(priv); - - if (priv->is_internal_short_scan) { - scan->channel_count = - iwl3945_get_single_channel_for_scan(priv, vif, band, - (void *)&scan->data[le16_to_cpu( - scan->tx_cmd.len)]); - } else { - scan->channel_count = - iwl3945_get_channels_for_scan(priv, band, is_active, n_probes, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif); - } - - if (scan->channel_count == 0) { - IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); - return -EIO; - } - - cmd.len += le16_to_cpu(scan->tx_cmd.len) + - scan->channel_count * sizeof(struct iwl3945_scan_channel); - cmd.data = scan; - scan->len = cpu_to_le16(cmd.len); - - set_bit(STATUS_SCAN_HW, &priv->status); - ret = iwl_send_cmd_sync(priv, &cmd); - if (ret) - clear_bit(STATUS_SCAN_HW, &priv->status); - return ret; -} - -void iwl3945_post_scan(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - /* - * Since setting the RXON may have been deferred while - * performing the scan, fire one off if needed - */ - if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) - iwl3945_commit_rxon(priv, ctx); -} - -static void iwl3945_bg_restart(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - struct iwl_rxon_context *ctx; - mutex_lock(&priv->mutex); - for_each_context(priv, ctx) - ctx->vif = NULL; - priv->is_open = 0; - mutex_unlock(&priv->mutex); - iwl3945_down(priv); - ieee80211_restart_hw(priv->hw); - } else { - iwl3945_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl3945_up(priv); - mutex_unlock(&priv->mutex); - } -} - -static void iwl3945_bg_rx_replenish(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, rx_replenish); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl3945_rx_replenish(priv); - mutex_unlock(&priv->mutex); -} - -void iwl3945_post_associate(struct iwl_priv *priv) -{ - int rc = 0; - struct ieee80211_conf *conf = NULL; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - if (!ctx->vif || !priv->is_open) - return; - - if (ctx->vif->type == NL80211_IFTYPE_AP) { - IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__); - return; - } - - IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", - ctx->vif->bss_conf.aid, ctx->active.bssid_addr); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl_scan_cancel_timeout(priv, 200); - - conf = ieee80211_get_hw_conf(priv->hw); - - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv, ctx); - - rc = iwl_send_rxon_timing(priv, ctx); - if (rc) - IWL_WARN(priv, "REPLY_RXON_TIMING failed - " - "Attempting to continue.\n"); - - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - - ctx->staging.assoc_id = cpu_to_le16(ctx->vif->bss_conf.aid); - - IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", - ctx->vif->bss_conf.aid, ctx->vif->bss_conf.beacon_int); - - if (ctx->vif->bss_conf.use_short_preamble) - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (ctx->vif->bss_conf.use_short_slot) - ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - } - - iwl3945_commit_rxon(priv, ctx); - - switch (ctx->vif->type) { - case NL80211_IFTYPE_STATION: - iwl3945_rate_scale_init(priv->hw, IWL_AP_ID); - break; - case NL80211_IFTYPE_ADHOC: - iwl3945_send_beacon_cmd(priv); - break; - default: - IWL_ERR(priv, "%s Should not be called in %d mode\n", - __func__, ctx->vif->type); - break; - } -} - -/***************************************************************************** - * - * mac80211 entry point functions - * - *****************************************************************************/ - -#define UCODE_READY_TIMEOUT (2 * HZ) - -static int iwl3945_mac_start(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - /* we should be verifying the device is ready to be opened */ - mutex_lock(&priv->mutex); - - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - - if (!priv->ucode_code.len) { - ret = iwl3945_read_ucode(priv); - if (ret) { - IWL_ERR(priv, "Could not read microcode: %d\n", ret); - mutex_unlock(&priv->mutex); - goto out_release_irq; - } - } - - ret = __iwl3945_up(priv); - - mutex_unlock(&priv->mutex); - - if (ret) - goto out_release_irq; - - IWL_DEBUG_INFO(priv, "Start UP work.\n"); - - /* Wait for START_ALIVE from ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERR(priv, - "Wait for START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - ret = -ETIMEDOUT; - goto out_release_irq; - } - } - - /* ucode is running and will send rfkill notifications, - * no need to poll the killswitch state anymore */ - cancel_delayed_work(&priv->_3945.rfkill_poll); - - iwl_led_start(priv); - - priv->is_open = 1; - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; - -out_release_irq: - priv->is_open = 0; - IWL_DEBUG_MAC80211(priv, "leave - failed\n"); - return ret; -} - -static void iwl3945_mac_stop(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!priv->is_open) { - IWL_DEBUG_MAC80211(priv, "leave - skip\n"); - return; - } - - priv->is_open = 0; - - iwl3945_down(priv); - - flush_workqueue(priv->workqueue); - - /* start polling the killswitch state again */ - queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll, - round_jiffies_relative(2 * HZ)); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - - if (iwl3945_tx_skb(priv, skb)) - dev_kfree_skb_any(skb); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return NETDEV_TX_OK; -} - -void iwl3945_config_ap(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct ieee80211_vif *vif = ctx->vif; - int rc = 0; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* The following should be done only at AP bring up */ - if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) { - - /* RXON - unassoc (to set timing command) */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv, ctx); - - /* RXON Timing */ - rc = iwl_send_rxon_timing(priv, ctx); - if (rc) - IWL_WARN(priv, "REPLY_RXON_TIMING failed - " - "Attempting to continue.\n"); - - ctx->staging.assoc_id = 0; - - if (vif->bss_conf.use_short_preamble) - ctx->staging.flags |= - RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) - ctx->staging.flags |= - RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_SLOT_MSK; - } - /* restore RXON assoc */ - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv, ctx); - } - iwl3945_send_beacon_cmd(priv); - - /* FIXME - we need to add code here to detect a totally new - * configuration, reset the AP, unassoc, rxon timing, assoc, - * clear sta table, add BCAST sta... */ -} - -static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct iwl_priv *priv = hw->priv; - int ret = 0; - u8 sta_id = IWL_INVALID_STATION; - u8 static_key; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (iwl3945_mod_params.sw_crypto) { - IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); - return -EOPNOTSUPP; - } - - static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS); - - if (!static_key) { - sta_id = iwl_sta_id_or_broadcast( - priv, &priv->contexts[IWL_RXON_CTX_BSS], sta); - if (sta_id == IWL_INVALID_STATION) - return -EINVAL; - } - - mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); - - switch (cmd) { - case SET_KEY: - if (static_key) - ret = iwl3945_set_static_key(priv, key); - else - ret = iwl3945_set_dynamic_key(priv, key, sta_id); - IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n"); - break; - case DISABLE_KEY: - if (static_key) - ret = iwl3945_remove_static_key(priv); - else - ret = iwl3945_clear_sta_key_info(priv, sta_id); - IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n"); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} - -static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl3945_sta_priv *sta_priv = (void *)sta->drv_priv; - int ret; - bool is_ap = vif->type == NL80211_IFTYPE_STATION; - u8 sta_id; - - IWL_DEBUG_INFO(priv, "received request to add station %pM\n", - sta->addr); - mutex_lock(&priv->mutex); - IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", - sta->addr); - sta_priv->common.sta_id = IWL_INVALID_STATION; - - - ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS], - sta->addr, is_ap, sta, &sta_id); - if (ret) { - IWL_ERR(priv, "Unable to add station %pM (%d)\n", - sta->addr, ret); - /* Should we return success if return code is EEXIST ? */ - mutex_unlock(&priv->mutex); - return ret; - } - - sta_priv->common.sta_id = sta_id; - - /* Initialize rate scaling */ - IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", - sta->addr); - iwl3945_rs_rate_init(priv, sta, sta_id); - mutex_unlock(&priv->mutex); - - return 0; -} - -static void iwl3945_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct iwl_priv *priv = hw->priv; - __le32 filter_or = 0, filter_nand = 0; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - -#define CHK(test, flag) do { \ - if (*total_flags & (test)) \ - filter_or |= (flag); \ - else \ - filter_nand |= (flag); \ - } while (0) - - IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", - changed_flags, *total_flags); - - CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); - CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); - -#undef CHK - - mutex_lock(&priv->mutex); - - ctx->staging.filter_flags &= ~filter_nand; - ctx->staging.filter_flags |= filter_or; - - /* - * Not committing directly because hardware can perform a scan, - * but even if hw is ready, committing here breaks for some reason, - * we'll eventually commit the filter flags change anyway. - */ - - mutex_unlock(&priv->mutex); - - /* - * Receiving all multicast frames is always enabled by the - * default flags setup in iwl_connection_init_rx_config() - * since we currently do not support programming multicast - * filters into the device. - */ - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | - FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; -} - - -/***************************************************************************** - * - * sysfs attributes - * - *****************************************************************************/ - -#ifdef CONFIG_IWLWIFI_DEBUG - -/* - * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) - * used for controlling the debug level. - * - * See the level definitions in iwl for details. - * - * The debug_level being managed using sysfs below is a per device debug - * level that is used instead of the global debug level if it (the per - * device debug level) is set. - */ -static ssize_t show_debug_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); -} -static ssize_t store_debug_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 0, &val); - if (ret) - IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); - else { - priv->debug_level = val; - if (iwl_alloc_traffic_mem(priv)) - IWL_ERR(priv, - "Not enough memory to generate traffic log\n"); - } - return strnlen(buf, count); -} - -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); - -#endif /* CONFIG_IWLWIFI_DEBUG */ - -static ssize_t show_temperature(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", iwl3945_hw_get_temperature(priv)); -} - -static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); - -static ssize_t show_tx_power(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); -} - -static ssize_t store_tx_power(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - char *p = (char *)buf; - u32 val; - - val = simple_strtoul(p, &p, 10); - if (p == buf) - IWL_INFO(priv, ": %s is not in decimal form.\n", buf); - else - iwl3945_hw_reg_set_txpower(priv, val); - - return count; -} - -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); - -static ssize_t show_flags(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - return sprintf(buf, "0x%04X\n", ctx->active.flags); -} - -static ssize_t store_flags(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - u32 flags = simple_strtoul(buf, NULL, 0); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - mutex_lock(&priv->mutex); - if (le32_to_cpu(ctx->staging.flags) != flags) { - /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) - IWL_WARN(priv, "Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n", - flags); - ctx->staging.flags = cpu_to_le32(flags); - iwl3945_commit_rxon(priv, ctx); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); - -static ssize_t show_filter_flags(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - return sprintf(buf, "0x%04X\n", - le32_to_cpu(ctx->active.filter_flags)); -} - -static ssize_t store_filter_flags(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - u32 filter_flags = simple_strtoul(buf, NULL, 0); - - mutex_lock(&priv->mutex); - if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) { - /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) - IWL_WARN(priv, "Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = " - "0x%04X\n", filter_flags); - ctx->staging.filter_flags = - cpu_to_le32(filter_flags); - iwl3945_commit_rxon(priv, ctx); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, - store_filter_flags); - -static ssize_t show_measurement(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_spectrum_notification measure_report; - u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *)&measure_report; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!(priv->measurement_status & MEASUREMENT_READY)) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } - memcpy(&measure_report, &priv->measure_report, size); - priv->measurement_status = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static ssize_t store_measurement(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct ieee80211_measurement_params params = { - .channel = le16_to_cpu(ctx->active.channel), - .start_time = cpu_to_le64(priv->_3945.last_tsf), - .duration = cpu_to_le16(1), - }; - u8 type = IWL_MEASURE_BASIC; - u8 buffer[32]; - u8 channel; - - if (count) { - char *p = buffer; - strncpy(buffer, buf, min(sizeof(buffer), count)); - channel = simple_strtoul(p, NULL, 0); - if (channel) - params.channel = channel; - - p = buffer; - while (*p && *p != ' ') - p++; - if (*p) - type = simple_strtoul(p + 1, NULL, 0); - } - - IWL_DEBUG_INFO(priv, "Invoking measurement of type %d on " - "channel %d (for '%s')\n", type, params.channel, buf); - iwl3945_get_measurement(priv, ¶ms, type); - - return count; -} - -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, - show_measurement, store_measurement); - -static ssize_t store_retry_rate(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - priv->retry_rate = simple_strtoul(buf, NULL, 0); - if (priv->retry_rate <= 0) - priv->retry_rate = 1; - - return count; -} - -static ssize_t show_retry_rate(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d", priv->retry_rate); -} - -static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, - store_retry_rate); - - -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* all this shit doesn't belong into sysfs anyway */ - return 0; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); - -static ssize_t show_antenna(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", iwl3945_mod_params.antenna); -} - -static ssize_t store_antenna(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv __maybe_unused = dev_get_drvdata(d); - int ant; - - if (count == 0) - return 0; - - if (sscanf(buf, "%1i", &ant) != 1) { - IWL_DEBUG_INFO(priv, "not in hex or decimal form.\n"); - return count; - } - - if ((ant >= 0) && (ant <= 2)) { - IWL_DEBUG_INFO(priv, "Setting antenna select to %d.\n", ant); - iwl3945_mod_params.antenna = (enum iwl3945_antenna)ant; - } else - IWL_DEBUG_INFO(priv, "Bad antenna select value %d.\n", ant); - - - return count; -} - -static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); - -static ssize_t show_status(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - if (!iwl_is_alive(priv)) - return -EAGAIN; - return sprintf(buf, "0x%08x\n", (int)priv->status); -} - -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); - -static ssize_t dump_error_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - char *p = (char *)buf; - - if (p[0] == '1') - iwl3945_dump_nic_error_log(priv); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); - -/***************************************************************************** - * - * driver setup and tear down - * - *****************************************************************************/ - -static void iwl3945_setup_deferred_work(struct iwl_priv *priv) -{ - priv->workqueue = create_singlethread_workqueue(DRV_NAME); - - init_waitqueue_head(&priv->wait_command_queue); - - INIT_WORK(&priv->restart, iwl3945_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); - INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); - INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll); - - iwl_setup_scan_deferred_work(priv); - - iwl3945_hw_setup_deferred_work(priv); - - init_timer(&priv->watchdog); - priv->watchdog.data = (unsigned long)priv; - priv->watchdog.function = iwl_bg_watchdog; - - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl3945_irq_tasklet, (unsigned long)priv); -} - -static void iwl3945_cancel_deferred_work(struct iwl_priv *priv) -{ - iwl3945_hw_cancel_deferred_work(priv); - - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->alive_start); - cancel_work_sync(&priv->beacon_update); - - iwl_cancel_scan_deferred_work(priv); -} - -static struct attribute *iwl3945_sysfs_entries[] = { - &dev_attr_antenna.attr, - &dev_attr_channels.attr, - &dev_attr_dump_errors.attr, - &dev_attr_flags.attr, - &dev_attr_filter_flags.attr, - &dev_attr_measurement.attr, - &dev_attr_retry_rate.attr, - &dev_attr_status.attr, - &dev_attr_temperature.attr, - &dev_attr_tx_power.attr, -#ifdef CONFIG_IWLWIFI_DEBUG - &dev_attr_debug_level.attr, -#endif - NULL -}; - -static struct attribute_group iwl3945_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = iwl3945_sysfs_entries, -}; - -struct ieee80211_ops iwl3945_hw_ops = { - .tx = iwl3945_mac_tx, - .start = iwl3945_mac_start, - .stop = iwl3945_mac_stop, - .add_interface = iwl_mac_add_interface, - .remove_interface = iwl_mac_remove_interface, - .change_interface = iwl_mac_change_interface, - .config = iwl_legacy_mac_config, - .configure_filter = iwl3945_configure_filter, - .set_key = iwl3945_mac_set_key, - .conf_tx = iwl_mac_conf_tx, - .reset_tsf = iwl_legacy_mac_reset_tsf, - .bss_info_changed = iwl_legacy_mac_bss_info_changed, - .hw_scan = iwl_mac_hw_scan, - .sta_add = iwl3945_mac_sta_add, - .sta_remove = iwl_mac_sta_remove, - .tx_last_beacon = iwl_mac_tx_last_beacon, -}; - -static int iwl3945_init_drv(struct iwl_priv *priv) -{ - int ret; - struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; - - priv->retry_rate = 1; - priv->beacon_skb = NULL; - - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); - - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - - priv->iw_mode = NL80211_IFTYPE_STATION; - priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; - - /* initialize force reset */ - priv->force_reset[IWL_RF_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_RF_RESET; - priv->force_reset[IWL_FW_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_FW_RELOAD; - - - priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; - priv->tx_power_next = IWL_DEFAULT_TX_POWER; - - if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { - IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n", - eeprom->version); - ret = -EINVAL; - goto err; - } - ret = iwl_init_channel_map(priv); - if (ret) { - IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); - goto err; - } - - /* Set up txpower settings in driver for all channels */ - if (iwl3945_txpower_set_from_eeprom(priv)) { - ret = -EIO; - goto err_free_channel_map; - } - - ret = iwlcore_init_geos(priv); - if (ret) { - IWL_ERR(priv, "initializing geos failed: %d\n", ret); - goto err_free_channel_map; - } - iwl3945_init_hw_rates(priv, priv->ieee_rates); - - return 0; - -err_free_channel_map: - iwl_free_channel_map(priv); -err: - return ret; -} - -#define IWL3945_MAX_PROBE_REQUEST 200 - -static int iwl3945_setup_mac(struct iwl_priv *priv) -{ - int ret; - struct ieee80211_hw *hw = priv->hw; - - hw->rate_control_algorithm = "iwl-3945-rs"; - hw->sta_data_size = sizeof(struct iwl3945_sta_priv); - hw->vif_data_size = sizeof(struct iwl_vif_priv); - - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SPECTRUM_MGMT; - - if (!priv->cfg->base_params->broken_powersave) - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - - hw->wiphy->interface_modes = - priv->contexts[IWL_RXON_CTX_BSS].interface_modes; - - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS; - - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; - /* we create the 802.11 header and a zero-length SSID element */ - hw->wiphy->max_scan_ie_len = IWL3945_MAX_PROBE_REQUEST - 24 - 2; - - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); - return ret; - } - priv->mac80211_registered = 1; - - return 0; -} - -static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = 0, i; - struct iwl_priv *priv; - struct ieee80211_hw *hw; - struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); - struct iwl3945_eeprom *eeprom; - unsigned long flags; - - /*********************** - * 1. Allocating HW data - * ********************/ - - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - hw = iwl_alloc_all(cfg); - if (hw == NULL) { - pr_err("Can not allocate network device\n"); - err = -ENOMEM; - goto out; - } - priv = hw->priv; - SET_IEEE80211_DEV(hw, &pdev->dev); - - priv->cmd_queue = IWL39_CMD_QUEUE_NUM; - - /* 3945 has only one valid context */ - priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); - - for (i = 0; i < NUM_IWL_RXON_CTX; i++) - priv->contexts[i].ctxid = i; - - priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; - priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; - priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; - priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; - priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; - priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; - priv->contexts[IWL_RXON_CTX_BSS].interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; - priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; - priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; - - /* - * Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. - */ - if (iwl3945_mod_params.disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); - iwl3945_hw_ops.hw_scan = NULL; - } - - - IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); - priv->cfg = cfg; - priv->pci_dev = pdev; - priv->inta_mask = CSR_INI_SET_MASK; - - if (iwl_alloc_traffic_mem(priv)) - IWL_ERR(priv, "Not enough memory to generate traffic log\n"); - - /*************************** - * 2. Initializing PCI bus - * *************************/ - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | - PCIE_LINK_STATE_CLKPM); - - if (pci_enable_device(pdev)) { - err = -ENODEV; - goto out_ieee80211_free_hw; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - IWL_WARN(priv, "No suitable DMA available.\n"); - goto out_pci_disable_device; - } - - pci_set_drvdata(pdev, priv); - err = pci_request_regions(pdev, DRV_NAME); - if (err) - goto out_pci_disable_device; - - /*********************** - * 3. Read REV Register - * ********************/ - priv->hw_base = pci_iomap(pdev, 0, 0); - if (!priv->hw_base) { - err = -ENODEV; - goto out_pci_release_regions; - } - - IWL_DEBUG_INFO(priv, "pci_resource_len = 0x%08llx\n", - (unsigned long long) pci_resource_len(pdev, 0)); - IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); - - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); - - /* these spin locks will be used in apm_ops.init and EEPROM access - * we should init now - */ - spin_lock_init(&priv->reg_lock); - spin_lock_init(&priv->lock); - - /* - * stop and reset the on-board processor just in case it is in a - * strange state ... like being left stranded by a primary kernel - * and this is now the kdump kernel trying to start up - */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /*********************** - * 4. Read EEPROM - * ********************/ - - /* Read the EEPROM */ - err = iwl_eeprom_init(priv); - if (err) { - IWL_ERR(priv, "Unable to init EEPROM\n"); - goto out_iounmap; - } - /* MAC Address location in EEPROM same for 3945/4965 */ - eeprom = (struct iwl3945_eeprom *)priv->eeprom; - IWL_DEBUG_INFO(priv, "MAC address: %pM\n", eeprom->mac_address); - SET_IEEE80211_PERM_ADDR(priv->hw, eeprom->mac_address); - - /*********************** - * 5. Setup HW Constants - * ********************/ - /* Device-specific setup */ - if (iwl3945_hw_set_hw_params(priv)) { - IWL_ERR(priv, "failed to set hw settings\n"); - goto out_eeprom_free; - } - - /*********************** - * 6. Setup priv - * ********************/ - - err = iwl3945_init_drv(priv); - if (err) { - IWL_ERR(priv, "initializing driver failed\n"); - goto out_unset_hw_params; - } - - IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s\n", - priv->cfg->name); - - /*********************** - * 7. Setup Services - * ********************/ - - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - pci_enable_msi(priv->pci_dev); - - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, - IRQF_SHARED, DRV_NAME, priv); - if (err) { - IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); - goto out_disable_msi; - } - - err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); - if (err) { - IWL_ERR(priv, "failed to create sysfs device attributes\n"); - goto out_release_irq; - } - - iwl_set_rxon_channel(priv, - &priv->bands[IEEE80211_BAND_2GHZ].channels[5], - &priv->contexts[IWL_RXON_CTX_BSS]); - iwl3945_setup_deferred_work(priv); - iwl3945_setup_rx_handlers(priv); - iwl_power_initialize(priv); - - /********************************* - * 8. Setup and Register mac80211 - * *******************************/ - - iwl_enable_interrupts(priv); - - err = iwl3945_setup_mac(priv); - if (err) - goto out_remove_sysfs; - - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - - /* Start monitoring the killswitch */ - queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll, - 2 * HZ); - - return 0; - - out_remove_sysfs: - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - out_release_irq: - free_irq(priv->pci_dev->irq, priv); - out_disable_msi: - pci_disable_msi(priv->pci_dev); - iwlcore_free_geos(priv); - iwl_free_channel_map(priv); - out_unset_hw_params: - iwl3945_unset_hw_params(priv); - out_eeprom_free: - iwl_eeprom_free(priv); - out_iounmap: - pci_iounmap(pdev, priv->hw_base); - out_pci_release_regions: - pci_release_regions(pdev); - out_pci_disable_device: - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - out_ieee80211_free_hw: - iwl_free_traffic_mem(priv); - ieee80211_free_hw(priv->hw); - out: - return err; -} - -static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - unsigned long flags; - - if (!priv) - return; - - IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); - - iwl_dbgfs_unregister(priv); - - set_bit(STATUS_EXIT_PENDING, &priv->status); - - if (priv->mac80211_registered) { - ieee80211_unregister_hw(priv->hw); - priv->mac80211_registered = 0; - } else { - iwl3945_down(priv); - } - - /* - * Make sure device is reset to low power before unloading driver. - * This may be redundant with iwl_down(), but there are paths to - * run iwl_down() without calling apm_ops.stop(), and there are - * paths to avoid running iwl_down() at all before leaving driver. - * This (inexpensive) call *makes sure* device is reset. - */ - iwl_apm_stop(priv); - - /* make sure we flush any pending irq or - * tasklet for the driver - */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_synchronize_irq(priv); - - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - - cancel_delayed_work_sync(&priv->_3945.rfkill_poll); - - iwl3945_dealloc_ucode_pci(priv); - - if (priv->rxq.bd) - iwl3945_rx_queue_free(priv, &priv->rxq); - iwl3945_hw_txq_ctx_free(priv); - - iwl3945_unset_hw_params(priv); - - /*netif_stop_queue(dev); */ - flush_workqueue(priv->workqueue); - - /* ieee80211_unregister_hw calls iwl3945_mac_stop, which flushes - * priv->workqueue... so we can't take down the workqueue - * until now... */ - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - iwl_free_traffic_mem(priv); - - free_irq(pdev->irq, priv); - pci_disable_msi(pdev); - - pci_iounmap(pdev, priv->hw_base); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - - iwl_free_channel_map(priv); - iwlcore_free_geos(priv); - kfree(priv->scan_cmd); - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - ieee80211_free_hw(priv->hw); -} - - -/***************************************************************************** - * - * driver and module entry point - * - *****************************************************************************/ - -static struct pci_driver iwl3945_driver = { - .name = DRV_NAME, - .id_table = iwl3945_hw_card_ids, - .probe = iwl3945_pci_probe, - .remove = __devexit_p(iwl3945_pci_remove), - .driver.pm = IWL_PM_OPS, -}; - -static int __init iwl3945_init(void) -{ - - int ret; - pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); - pr_info(DRV_COPYRIGHT "\n"); - - ret = iwl3945_rate_control_register(); - if (ret) { - pr_err("Unable to register rate control algorithm: %d\n", ret); - return ret; - } - - ret = pci_register_driver(&iwl3945_driver); - if (ret) { - pr_err("Unable to initialize PCI module\n"); - goto error_register; - } - - return ret; - -error_register: - iwl3945_rate_control_unregister(); - return ret; -} - -static void __exit iwl3945_exit(void) -{ - pci_unregister_driver(&iwl3945_driver); - iwl3945_rate_control_unregister(); -} - -MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); - -module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO); -MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO); -MODULE_PARM_DESC(swcrypto, - "using software crypto (default 1 [software])\n"); -#ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "debug output mask"); -#endif -module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, - int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); -module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); - -module_exit(iwl3945_exit); -module_init(iwl3945_init); |