diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
59 files changed, 3706 insertions, 2665 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9dc84a7..afa0bb8 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,7 +1,7 @@ # WIFI obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o -iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o +iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o @@ -13,6 +13,7 @@ iwlwifi-objs += iwl-6000.o iwlwifi-objs += iwl-1000.o iwlwifi-objs += iwl-2000.o iwlwifi-objs += iwl-pci.o +iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1ef7bfc..605ee3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -84,13 +84,13 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) static void iwl1000_nic_config(struct iwl_priv *priv) { /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* Setting digital SVR for 1000 card to 1.32V */ /* locking is acquired in iwl_set_bits_mask_prph() function */ - iwl_set_bits_mask_prph(bus(priv), APMG_DIGITAL_SVR_REG, + iwl_set_bits_mask_prph(trans(priv), APMG_DIGITAL_SVR_REG, APMG_SVR_DIGITAL_VOLTAGE_1_32, ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); } @@ -120,7 +120,7 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl1000_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) @@ -128,10 +128,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -148,8 +144,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl1000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl1000_lib = { @@ -195,6 +189,8 @@ static struct iwl_ht_params iwl1000_ht_params = { .ucode_api_max = IWL1000_UCODE_API_MAX, \ .ucode_api_ok = IWL1000_UCODE_API_OK, \ .ucode_api_min = IWL1000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ @@ -217,6 +213,8 @@ struct iwl_cfg iwl1000_bg_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, \ .ucode_api_ok = IWL100_UCODE_API_OK, \ .ucode_api_min = IWL100_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0946933..e6e8c79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -87,7 +87,7 @@ static void iwl2000_nic_config(struct iwl_priv *priv) iwl_rf_config(priv); if (cfg(priv)->iq_invert) - iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, + iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); } @@ -116,7 +116,7 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -124,10 +124,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -144,8 +140,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl2000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl2000_lib = { @@ -244,6 +238,8 @@ static struct iwl_bt_params iwl2030_bt_params = { .ucode_api_max = IWL2000_UCODE_API_MAX, \ .ucode_api_ok = IWL2000_UCODE_API_OK, \ .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -270,6 +266,8 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = { .ucode_api_max = IWL2030_UCODE_API_MAX, \ .ucode_api_ok = IWL2030_UCODE_API_OK, \ .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ @@ -292,6 +290,8 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .ucode_api_max = IWL105_UCODE_API_MAX, \ .ucode_api_ok = IWL105_UCODE_API_OK, \ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -320,6 +320,8 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .ucode_api_max = IWL135_UCODE_API_MAX, \ .ucode_api_ok = IWL135_UCODE_API_OK, \ .ucode_api_min = IWL135_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b3a365f..1527dec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 @@ -73,7 +73,7 @@ static void iwl5000_nic_config(struct iwl_priv *priv) * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_set_bits_mask_prph(bus(priv), APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); @@ -162,7 +162,7 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } -static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl5000_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) @@ -170,10 +170,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -187,11 +183,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5000_sensitivity; - - return 0; } -static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) +static void iwl5150_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) @@ -199,10 +193,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -216,8 +206,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5150_sensitivity; - - return 0; } static void iwl5150_temperature(struct iwl_priv *priv) @@ -360,6 +348,8 @@ static struct iwl_ht_params iwl5000_ht_params = { .fw_name_pre = IWL5000_FW_PRE, \ .ucode_api_max = IWL5000_UCODE_API_MAX, \ .ucode_api_min = IWL5000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .lib = &iwl5000_lib, \ @@ -403,6 +393,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, + .max_inst_size = IWLAGN_RTC_INST_SIZE, + .max_data_size = IWLAGN_RTC_DATA_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .lib = &iwl5000_lib, @@ -416,6 +408,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5150_FW_PRE, \ .ucode_api_max = IWL5150_UCODE_API_MAX, \ .ucode_api_min = IWL5150_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .lib = &iwl5150_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 54b7533..223e60a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -82,7 +82,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ if (iwl_eeprom_calib_version(priv->shrd) >= 6) - iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, + iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -90,9 +90,9 @@ static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ if (iwl_eeprom_calib_version(priv->shrd) >= 6) - iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, + iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); - iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, + iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_6050_1x2); } @@ -104,7 +104,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) /* no locking required for register write */ if (cfg(priv)->pa_type == IWL_PA_INTERNAL) { /* 2x2 IPA phy type */ - iwl_write32(bus(priv), CSR_GP_DRIVER_REG, + iwl_write32(trans(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); } /* do additional nic configuration if needed */ @@ -137,7 +137,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl6000_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) @@ -145,10 +145,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -167,7 +163,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl6000_sensitivity; - return 0; } static int iwl6000_hw_channel_switch(struct iwl_priv *priv, @@ -351,6 +346,8 @@ static struct iwl_bt_params iwl6000_bt_params = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .lib = &iwl6000_lib, \ @@ -386,11 +383,24 @@ struct iwl_cfg iwl6005_2agn_d_cfg = { .ht_params = &iwl6000_ht_params, }; +struct iwl_cfg iwl6005_2agn_mow1_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; +struct iwl_cfg iwl6005_2agn_mow2_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + #define IWL_DEVICE_6030 \ .fw_name_pre = IWL6030_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .lib = &iwl6030_lib, \ @@ -460,6 +470,8 @@ struct iwl_cfg iwl130_bg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, \ .ucode_api_ok = IWL6000_UCODE_API_OK, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ @@ -489,6 +501,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ .lib = &iwl6000_lib, \ @@ -514,6 +528,8 @@ struct iwl_cfg iwl6050_2abg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .lib = &iwl6000_lib, \ .additional_nic_config = iwl6150_additional_nic_config, \ .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ @@ -539,6 +555,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_ok = IWL6000_UCODE_API_OK, .ucode_api_min = IWL6000_UCODE_API_MIN, + .max_inst_size = IWL60_RTC_INST_SIZE, + .max_data_size = IWL60_RTC_DATA_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .lib = &iwl6000_lib, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 50ff849..988ee45 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +68,8 @@ #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-agn.h" +#include "iwl-wifi.h" +#include "iwl-ucode.h" /***************************************************************************** * INIT calibrations framework @@ -634,7 +636,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) data->last_bad_plcp_cnt_cck = 0; data->last_fa_cnt_cck = 0; - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) ret |= iwl_enhance_sensitivity_write(priv); else ret |= iwl_sensitivity_write(priv); @@ -745,7 +747,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) iwl_enhance_sensitivity_write(priv); else iwl_sensitivity_write(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index 10275ce..9ed6683 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 123ef5e..d0ec0ab 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 64cf439..5be0d36 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -77,7 +77,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO; - if (IWL_UCODE_API(priv->ucode_ver) == 1) + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) == 1) tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1; else tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; @@ -700,7 +700,7 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv, priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; /* schedule to send runtime bt_config */ - queue_work(priv->shrd->workqueue, &priv->bt_runtime_config); + queue_work(priv->workqueue, &priv->bt_runtime_config); } } @@ -745,7 +745,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = coex->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } } @@ -959,7 +959,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, struct ieee80211_key_conf *key, void *_data) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct wowlan_key_data *data = _data; struct iwl_rxon_context *ctx = data->ctx; struct aes_sc *aes_sc, *aes_tx_sc = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 334b5ae..a7d6713 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 @@ -38,6 +38,7 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-agn.h" +#include "iwl-op-mode.h" #define RS_NAME "iwl-agn-rs" @@ -892,7 +893,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false); - queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency); + queue_work(priv->workqueue, &priv->bt_full_concurrency); } } @@ -909,7 +910,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r; + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); enum mac80211_rate_control_flags mac_flags; u32 tx_rate; @@ -2737,7 +2739,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb = txrc->skb; struct ieee80211_supported_band *sband = txrc->sband; - struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r; + struct iwl_op_mode *op_mode __maybe_unused = + (struct iwl_op_mode *)priv_r; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; int rate_idx; @@ -2805,9 +2809,10 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; - struct iwl_priv *priv; + struct iwl_op_mode *op_mode __maybe_unused = + (struct iwl_op_mode *)priv_rate; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); - priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); return &sta_priv->lq_sta; @@ -3074,7 +3079,8 @@ static void rs_free(void *priv_rate) static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { - struct iwl_priv *priv __maybe_unused = priv_r; + struct iwl_op_mode *op_mode __maybe_unused = priv_r; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); IWL_DEBUG_RATE(priv, "enter\n"); IWL_DEBUG_RATE(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 6675b3c..203b1c1 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index b22b297..30bb5bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. @@ -581,7 +581,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { iwlagn_rx_calc_noise(priv); - queue_work(priv->shrd->workqueue, &priv->run_time_calib_work); + queue_work(priv->workqueue, &priv->run_time_calib_work); } if (cfg(priv)->lib->temperature && change) cfg(priv)->lib->temperature(priv); @@ -628,16 +628,16 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | CT_CARD_DISABLED)) { - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C, + iwl_write_direct32(trans(priv), HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C, + iwl_write_direct32(trans(priv), HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } if (flags & CT_CARD_DISABLED) @@ -1141,10 +1141,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) } -int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, +int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); int err = 0; /* @@ -1172,20 +1173,22 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, wake_up_all(&priv->shrd->notif_waitq); } - if (priv->pre_rx_handler) + if (priv->pre_rx_handler && + priv->shrd->ucode_owner == IWL_OWNERSHIP_TM) 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() */ - if (priv->rx_handlers[pkt->hdr.cmd]) { - priv->rx_handlers_stats[pkt->hdr.cmd]++; - err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); - } else { - /* No handling needed */ - IWL_DEBUG_RX(priv, - "No handler needed for %s, 0x%02x\n", - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + else { + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + priv->rx_handlers_stats[pkt->hdr.cmd]++; + err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); + } else { + /* No handling needed */ + IWL_DEBUG_RX(priv, + "No handler needed for %s, 0x%02x\n", + get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + } } return err; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 1c66594..73653a6 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 @@ -549,7 +549,7 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf, int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = conf->channel; @@ -805,7 +805,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); int ret; bool force = false; @@ -900,6 +900,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, } } + /* + * If the ucode decides to do beacon filtering before + * association, it will lose beacons that are needed + * before sending frames out on passive channels. This + * causes association failures on those channels. Enable + * receiving beacons in such cases. + */ + + if (vif->type == NL80211_IFTYPE_STATION) { + if (!bss_conf->assoc) + ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + ctx->staging.filter_flags &= + ~RXON_FILTER_BCON_AWARE_MSK; + } + if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index e483cfa..f1298cd 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -35,9 +35,12 @@ #include "iwl-trans.h" /* priv->shrd->sta_lock must be held */ -static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) +static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { - + if (sta_id >= IWLAGN_STATION_COUNT) { + IWL_ERR(priv, "invalid sta_id %u", sta_id); + return -EINVAL; + } if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u " "addr %pM\n", @@ -53,6 +56,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", sta_id, priv->stations[sta_id].sta.sta.addr); } + return 0; } static int iwl_process_add_sta_resp(struct iwl_priv *priv, @@ -77,8 +81,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); - iwl_sta_ucode_activate(priv, sta_id); - ret = 0; + ret = iwl_sta_ucode_activate(priv, sta_id); break; case ADD_STA_NO_ROOM_IN_TABLE: IWL_ERR(priv, "Adding station %d failed, no room in table.\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index b0dff7a..56d7c0e 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. @@ -178,19 +178,19 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) if (tt->state == IWL_TI_CT_KILL) { if (priv->thermal_throttle.ct_kill_toggle) { - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; } else { - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = true; } - iwl_read32(bus(priv), CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&bus(priv)->reg_lock, flags); - if (!iwl_grab_nic_access(bus(priv))) - iwl_release_nic_access(bus(priv)); - spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); + iwl_read32(trans(priv), CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&trans(priv)->reg_lock, flags); + if (!iwl_grab_nic_access(trans(priv))) + iwl_release_nic_access(trans(priv)); + spin_unlock_irqrestore(&trans(priv)->reg_lock, flags); /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a @@ -568,7 +568,7 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_enter); + queue_work(priv->workqueue, &priv->ct_enter); } void iwl_tt_exit_ct_kill(struct iwl_priv *priv) @@ -577,7 +577,7 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_exit); + queue_work(priv->workqueue, &priv->ct_exit); } static void iwl_bg_tt_work(struct work_struct *work) @@ -600,7 +600,7 @@ void iwl_tt_handler(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n"); - queue_work(priv->shrd->workqueue, &priv->tt_work); + queue_work(priv->workqueue, &priv->tt_work); } /* Thermal throttling initialization diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index 7282a23..86bbf47 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 63bbc60..5f78567 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -322,7 +322,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the @@ -331,6 +331,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) * counter. * For now set the counter to just 1 since we do not * support uAPSD yet. + * + * FIXME: If we get two non-bufferable frames one + * after the other, we might only send out one of + * them because this is racy. */ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } @@ -983,7 +987,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv, if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { IWL_ERR(priv, "Tx flush command to flush out all frames\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) - queue_work(priv->shrd->workqueue, &priv->tx_flush); + queue_work(priv->workqueue, &priv->tx_flush); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b5c7c5f..e0fef9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -34,7 +34,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> @@ -42,6 +41,7 @@ #include <asm/div64.h> +#include "iwl-ucode.h" #include "iwl-eeprom.h" #include "iwl-wifi.h" #include "iwl-dev.h" @@ -50,8 +50,8 @@ #include "iwl-agn-calib.h" #include "iwl-agn.h" #include "iwl-shared.h" -#include "iwl-bus.h" #include "iwl-trans.h" +#include "iwl-op-mode.h" /****************************************************************************** * @@ -315,7 +315,7 @@ static void iwl_bg_statistics_periodic(unsigned long data) static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, u32 start_idx, u32 num_events, - u32 mode) + u32 capacity, u32 mode) { u32 i; u32 ptr; /* SRAM byte address of log data */ @@ -328,87 +328,125 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&bus(priv)->reg_lock, reg_flags); - if (iwl_grab_nic_access(bus(priv))) { - spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags); + spin_lock_irqsave(&trans(priv)->reg_lock, reg_flags); + if (iwl_grab_nic_access(trans(priv))) { + spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags); return; } /* Set starting address; reads will auto-increment */ - iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, ptr); rmb(); /* + * Refuse to read more than would have fit into the log from + * the current start_idx. This used to happen due to the race + * described below, but now WARN because the code below should + * prevent it from happening here. + */ + if (WARN_ON(num_events > capacity - start_idx)) + num_events = capacity - start_idx; + + /* * "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_read32(bus(priv), HBUS_TARG_MEM_RDAT); - time = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + ev = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + time = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); if (mode == 0) { - trace_iwlwifi_dev_ucode_cont_event(priv, - 0, time, ev); + trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); - trace_iwlwifi_dev_ucode_cont_event(priv, - time, data, ev); + data = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + trace_iwlwifi_dev_ucode_cont_event(priv, time, + data, ev); } } /* Allow device to power down */ - iwl_release_nic_access(bus(priv)); - spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags); + iwl_release_nic_access(trans(priv)); + spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags); } static void iwl_continuous_event_trace(struct iwl_priv *priv) { u32 capacity; /* event log capacity in # entries */ + struct { + u32 capacity; + u32 mode; + u32 wrap_counter; + u32 write_counter; + } __packed read; u32 base; /* SRAM byte address of event log header */ 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 */ - base = priv->shrd->device_pointers.error_event_table; + base = priv->shrd->device_pointers.log_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - capacity = iwl_read_targ_mem(bus(priv), base); - num_wraps = iwl_read_targ_mem(bus(priv), - base + (2 * sizeof(u32))); - mode = iwl_read_targ_mem(bus(priv), base + (1 * sizeof(u32))); - next_entry = iwl_read_targ_mem(bus(priv), - base + (3 * sizeof(u32))); + iwl_read_targ_mem_words(trans(priv), base, &read, sizeof(read)); + + capacity = read.capacity; + mode = read.mode; + num_wraps = read.wrap_counter; + next_entry = read.write_counter; } else return; + /* + * Unfortunately, the uCode doesn't use temporary variables. + * Therefore, it can happen that we read next_entry == capacity, + * which really means next_entry == 0. + */ + if (unlikely(next_entry == capacity)) + next_entry = 0; + /* + * Additionally, the uCode increases the write pointer before + * the wraps counter, so if the write pointer is smaller than + * the old write pointer (wrap occurred) but we read that no + * wrap occurred, we actually read between the next_entry and + * num_wraps update (this does happen in practice!!) -- take + * that into account by increasing num_wraps. + */ + if (unlikely(next_entry < priv->event_log.next_entry && + num_wraps == priv->event_log.num_wraps)) + num_wraps++; + if (num_wraps == priv->event_log.num_wraps) { - iwl_print_cont_event_trace(priv, - base, priv->event_log.next_entry, - next_entry - priv->event_log.next_entry, - mode); + iwl_print_cont_event_trace( + priv, base, priv->event_log.next_entry, + next_entry - priv->event_log.next_entry, + capacity, mode); + priv->event_log.non_wraps_count++; } else { - if ((num_wraps - priv->event_log.num_wraps) > 1) + if (num_wraps - priv->event_log.num_wraps > 1) priv->event_log.wraps_more_count++; else priv->event_log.wraps_once_count++; + trace_iwlwifi_dev_ucode_wrap_event(priv, num_wraps - priv->event_log.num_wraps, next_entry, priv->event_log.next_entry); + if (next_entry < priv->event_log.next_entry) { - iwl_print_cont_event_trace(priv, base, - priv->event_log.next_entry, - capacity - priv->event_log.next_entry, - mode); + iwl_print_cont_event_trace( + priv, base, priv->event_log.next_entry, + capacity - priv->event_log.next_entry, + capacity, mode); - iwl_print_cont_event_trace(priv, base, 0, - next_entry, mode); + iwl_print_cont_event_trace( + priv, base, 0, next_entry, capacity, mode); } else { - iwl_print_cont_event_trace(priv, base, - next_entry, capacity - next_entry, - mode); + iwl_print_cont_event_trace( + priv, base, next_entry, + capacity - next_entry, + capacity, mode); - iwl_print_cont_event_trace(priv, base, 0, - next_entry, mode); + iwl_print_cont_event_trace( + priv, base, 0, next_entry, capacity, mode); } } + priv->event_log.num_wraps = num_wraps; priv->event_log.next_entry = next_entry; } @@ -452,7 +490,7 @@ static void iwl_bg_tx_flush(struct work_struct *work) iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); } -static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) +void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) { int i; @@ -475,6 +513,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) 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].bcast_sta_id = IWLAGN_BROADCAST_ID; priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = BIT(NL80211_IFTYPE_ADHOC); priv->contexts[IWL_RXON_CTX_BSS].interface_modes = @@ -509,609 +548,6 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); } -static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); - -#define UCODE_EXPERIMENTAL_INDEX 100 -#define UCODE_EXPERIMENTAL_TAG "exp" - -static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) -{ - const char *name_pre = cfg(priv)->fw_name_pre; - char tag[8]; - - if (first) { -#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE - priv->fw_index = UCODE_EXPERIMENTAL_INDEX; - strcpy(tag, UCODE_EXPERIMENTAL_TAG); - } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) { -#endif - priv->fw_index = cfg(priv)->ucode_api_max; - sprintf(tag, "%d", priv->fw_index); - } else { - priv->fw_index--; - sprintf(tag, "%d", priv->fw_index); - } - - if (priv->fw_index < cfg(priv)->ucode_api_min) { - IWL_ERR(priv, "no suitable firmware found!\n"); - return -ENOENT; - } - - sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); - - IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n", - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) - ? "EXPERIMENTAL " : "", - priv->firmware_name); - - return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, - bus(priv)->dev, - GFP_KERNEL, priv, iwl_ucode_callback); -} - -struct iwlagn_firmware_pieces { - const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; - size_t inst_size, data_size, init_size, init_data_size, - wowlan_inst_size, wowlan_data_size; - - u32 build; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; -}; - -static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, - const struct firmware *ucode_raw, - struct iwlagn_firmware_pieces *pieces) -{ - struct iwl_ucode_header *ucode = (void *)ucode_raw->data; - u32 api_ver, hdr_size; - const u8 *src; - - priv->ucode_ver = le32_to_cpu(ucode->ver); - api_ver = IWL_UCODE_API(priv->ucode_ver); - - switch (api_ver) { - default: - 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); - src = ucode->u.v2.data; - break; - case 0: - case 1: - case 2: - hdr_size = 24; - if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); - return -EINVAL; - } - pieces->build = 0; - pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); - pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); - pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); - pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); - src = ucode->u.v1.data; - break; - } - - /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size != hdr_size + pieces->inst_size + - pieces->data_size + pieces->init_size + - pieces->init_data_size) { - - IWL_ERR(priv, - "uCode file size %d does not match expected size\n", - (int)ucode_raw->size); - return -EINVAL; - } - - pieces->inst = src; - src += pieces->inst_size; - pieces->data = src; - src += pieces->data_size; - pieces->init = src; - src += pieces->init_size; - pieces->init_data = src; - src += pieces->init_data_size; - - return 0; -} - -static int iwlagn_load_firmware(struct iwl_priv *priv, - const struct firmware *ucode_raw, - struct iwlagn_firmware_pieces *pieces, - struct iwlagn_ucode_capabilities *capa) -{ - struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; - struct iwl_ucode_tlv *tlv; - size_t len = ucode_raw->size; - const u8 *data; - int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; - int tmp; - u64 alternatives; - u32 tlv_len; - enum iwl_ucode_tlv_type tlv_type; - const u8 *tlv_data; - - if (len < sizeof(*ucode)) { - IWL_ERR(priv, "uCode has invalid length: %zd\n", len); - return -EINVAL; - } - - if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { - IWL_ERR(priv, "invalid uCode magic: 0X%x\n", - le32_to_cpu(ucode->magic)); - return -EINVAL; - } - - /* - * Check which alternatives are present, and "downgrade" - * when the chosen alternative is not present, warning - * the user when that happens. Some files may not have - * any alternatives, so don't warn in that case. - */ - alternatives = le64_to_cpu(ucode->alternatives); - tmp = wanted_alternative; - if (wanted_alternative > 63) - wanted_alternative = 63; - while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) - wanted_alternative--; - if (wanted_alternative && wanted_alternative != tmp) - IWL_WARN(priv, - "uCode alternative %d not available, choosing %d\n", - tmp, wanted_alternative); - - priv->ucode_ver = le32_to_cpu(ucode->ver); - pieces->build = le32_to_cpu(ucode->build); - data = ucode->data; - - len -= sizeof(*ucode); - - while (len >= sizeof(*tlv)) { - u16 tlv_alt; - - len -= sizeof(*tlv); - tlv = (void *)data; - - tlv_len = le32_to_cpu(tlv->length); - tlv_type = le16_to_cpu(tlv->type); - tlv_alt = le16_to_cpu(tlv->alternative); - tlv_data = tlv->data; - - if (len < tlv_len) { - IWL_ERR(priv, "invalid TLV len: %zd/%u\n", - len, tlv_len); - return -EINVAL; - } - len -= ALIGN(tlv_len, 4); - data += sizeof(*tlv) + ALIGN(tlv_len, 4); - - /* - * Alternative 0 is always valid. - * - * Skip alternative TLVs that are not selected. - */ - if (tlv_alt != 0 && tlv_alt != wanted_alternative) - continue; - - switch (tlv_type) { - case IWL_UCODE_TLV_INST: - pieces->inst = tlv_data; - pieces->inst_size = tlv_len; - break; - case IWL_UCODE_TLV_DATA: - pieces->data = tlv_data; - pieces->data_size = tlv_len; - break; - case IWL_UCODE_TLV_INIT: - pieces->init = tlv_data; - pieces->init_size = tlv_len; - break; - case IWL_UCODE_TLV_INIT_DATA: - pieces->init_data = tlv_data; - pieces->init_data_size = tlv_len; - break; - case IWL_UCODE_TLV_BOOT: - IWL_ERR(priv, "Found unexpected BOOT ucode\n"); - break; - case IWL_UCODE_TLV_PROBE_MAX_LEN: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - capa->max_probe_length = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_PAN: - if (tlv_len) - goto invalid_tlv_len; - 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)) - goto invalid_tlv_len; - pieces->init_evtlog_ptr = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - pieces->init_evtlog_size = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_INIT_ERRLOG_PTR: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - pieces->init_errlog_ptr = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - pieces->inst_evtlog_ptr = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - pieces->inst_evtlog_size = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - pieces->inst_errlog_ptr = - le32_to_cpup((__le32 *)tlv_data); - break; - case IWL_UCODE_TLV_ENHANCE_SENS_TBL: - if (tlv_len) - goto invalid_tlv_len; - priv->enhance_sensitivity_table = true; - break; - case IWL_UCODE_TLV_WOWLAN_INST: - pieces->wowlan_inst = tlv_data; - pieces->wowlan_inst_size = tlv_len; - break; - case IWL_UCODE_TLV_WOWLAN_DATA: - pieces->wowlan_data = tlv_data; - pieces->wowlan_data_size = tlv_len; - break; - case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: - if (tlv_len != sizeof(u32)) - goto invalid_tlv_len; - capa->standard_phy_calibration_size = - le32_to_cpup((__le32 *)tlv_data); - break; - default: - IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); - break; - } - } - - if (len) { - IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len); - iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len); - return -EINVAL; - } - - return 0; - - invalid_tlv_len: - IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); - iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len); - - return -EINVAL; -} - -/** - * iwl_ucode_callback - callback when firmware was loaded - * - * If loaded successfully, copies the firmware into buffers - * for the card to fetch (via DMA). - */ -static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) -{ - struct iwl_priv *priv = context; - struct iwl_ucode_header *ucode; - int err; - struct iwlagn_firmware_pieces pieces; - const unsigned int api_max = cfg(priv)->ucode_api_max; - unsigned int api_ok = cfg(priv)->ucode_api_ok; - const unsigned int api_min = cfg(priv)->ucode_api_min; - u32 api_ver; - char buildstr[25]; - u32 build; - struct iwlagn_ucode_capabilities ucode_capa = { - .max_probe_length = 200, - .standard_phy_calibration_size = - IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, - }; - - if (!api_ok) - api_ok = api_max; - - memset(&pieces, 0, sizeof(pieces)); - - if (!ucode_raw) { - if (priv->fw_index <= api_ok) - IWL_ERR(priv, - "request for firmware file '%s' failed.\n", - priv->firmware_name); - goto try_again; - } - - IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", - priv->firmware_name, ucode_raw->size); - - /* Make sure that we got at least the API version number */ - if (ucode_raw->size < 4) { - IWL_ERR(priv, "File size way too small!\n"); - goto try_again; - } - - /* Data from ucode file: header followed by uCode images */ - ucode = (struct iwl_ucode_header *)ucode_raw->data; - - if (ucode->ver) - err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces); - else - err = iwlagn_load_firmware(priv, ucode_raw, &pieces, - &ucode_capa); - - if (err) - goto try_again; - - api_ver = IWL_UCODE_API(priv->ucode_ver); - build = pieces.build; - - /* - * api_ver should match the api version forming part of the - * firmware filename ... but we don't check for that and only rely - * on the API version read from firmware header from here on forward - */ - /* no api version check required for experimental uCode */ - if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) { - 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); - goto try_again; - } - - if (api_ver < api_ok) { - if (api_ok != api_max) - IWL_ERR(priv, "Firmware has old API version, " - "expected v%u through v%u, got v%u.\n", - api_ok, api_max, api_ver); - else - IWL_ERR(priv, "Firmware has old API version, " - "expected v%u, got v%u.\n", - api_max, api_ver); - IWL_ERR(priv, "New firmware can be obtained from " - "http://www.intellinuxwireless.org/.\n"); - } - } - - if (build) - sprintf(buildstr, " build %u%s", build, - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) - ? " (EXP)" : ""); - else - buildstr[0] = '\0'; - - IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), - buildstr); - - snprintf(priv->hw->wiphy->fw_version, - sizeof(priv->hw->wiphy->fw_version), - "%u.%u.%u.%u%s", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), - buildstr); - - /* - * For any of the failures below (before allocating pci memory) - * we will try to load a version with a smaller API -- maybe the - * user just got a corrupted version of the latest API. - */ - - IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n", - pieces.inst_size); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n", - pieces.data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n", - pieces.init_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", - pieces.init_data_size); - - /* Verify that uCode images will fit in card's SRAM */ - if (pieces.inst_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n", - pieces.inst_size); - goto try_again; - } - - if (pieces.data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode data len %Zd too large to fit in\n", - pieces.data_size); - goto try_again; - } - - if (pieces.init_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n", - pieces.init_size); - goto try_again; - } - - if (pieces.init_data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n", - pieces.init_data_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 */ - if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code, - pieces.inst, pieces.inst_size)) - goto err_pci_alloc; - if (iwl_alloc_fw_desc(bus(priv), &trans(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) { - if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code, - pieces.init, pieces.init_size)) - goto err_pci_alloc; - if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data, - pieces.init_data, pieces.init_data_size)) - goto err_pci_alloc; - } - - /* WoWLAN instructions and data */ - if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { - if (iwl_alloc_fw_desc(bus(priv), - &trans(priv)->ucode_wowlan.code, - pieces.wowlan_inst, - pieces.wowlan_inst_size)) - goto err_pci_alloc; - if (iwl_alloc_fw_desc(bus(priv), - &trans(priv)->ucode_wowlan.data, - pieces.wowlan_data, - pieces.wowlan_data_size)) - goto err_pci_alloc; - } - - /* Now that we can no longer fail, copy information */ - - /* - * The (size - 16) / 12 formula is based on the information recorded - * for each event, which is of mode 1 (including timestamp) for all - * new microcodes that include this information. - */ - priv->init_evtlog_ptr = pieces.init_evtlog_ptr; - if (pieces.init_evtlog_size) - priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; - else - priv->init_evtlog_size = - cfg(priv)->base_params->max_event_log_size; - priv->init_errlog_ptr = pieces.init_errlog_ptr; - priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr; - if (pieces.inst_evtlog_size) - priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; - else - priv->inst_evtlog_size = - cfg(priv)->base_params->max_event_log_size; - priv->inst_errlog_ptr = pieces.inst_errlog_ptr; -#ifndef CONFIG_IWLWIFI_P2P - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; -#endif - - priv->new_scan_threshold_behaviour = - !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - - if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; - - /* - * if not PAN, then don't support P2P -- might be a uCode - * packaging bug or due to the eeprom check above - */ - if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; - - if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { - priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; - priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - } else { - priv->sta_key_max_num = STA_KEY_MAX_NUM; - priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - } - /* - * figure out the offset of chain noise reset and gain commands - * base on the size of standard phy calibration commands table size - */ - if (ucode_capa.standard_phy_calibration_size > - IWL_MAX_PHY_CALIBRATE_TBL_SIZE) - ucode_capa.standard_phy_calibration_size = - IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; - - priv->phy_calib_chain_noise_reset_cmd = - ucode_capa.standard_phy_calibration_size; - priv->phy_calib_chain_noise_gain_cmd = - ucode_capa.standard_phy_calibration_size + 1; - - /* initialize all valid contexts */ - iwl_init_context(priv, ucode_capa.flags); - - /************************************************** - * This is still part of probe() in a sense... - * - * 9. Setup and register with mac80211 and debugfs - **************************************************/ - err = iwlagn_mac_setup_register(priv, &ucode_capa); - if (err) - goto out_unbind; - - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - - /* We have our copies now, allow OS release its copies */ - release_firmware(ucode_raw); - complete(&priv->firmware_loading_complete); - return; - - try_again: - /* try next, if any */ - if (iwl_request_firmware(priv, false)) - goto out_unbind; - release_firmware(ucode_raw); - return; - - err_pci_alloc: - IWL_ERR(priv, "failed to allocate pci memory\n"); - iwl_dealloc_ucode(trans(priv)); - out_unbind: - complete(&priv->firmware_loading_complete); - device_release_driver(bus(priv)->dev); - release_firmware(ucode_raw); -} - static void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; @@ -1120,7 +556,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) int ret = 0; spin_lock_irqsave(&priv->shrd->lock, flags); - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->shrd->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; @@ -1182,7 +618,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) .valid = cpu_to_le32(valid_tx_ant), }; - if (IWL_UCODE_API(priv->ucode_ver) > 1) { + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) > 1) { IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); return iwl_trans_send_cmd_pdu(trans(priv), TX_ANT_CONFIGURATION_CMD, @@ -1205,9 +641,6 @@ int iwl_alive_start(struct iwl_priv *priv) int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - /*TODO: this should go to the transport layer */ - iwl_reset_ict(trans(priv)); - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); /* After the ALIVE response, we can send host commands to the uCode */ @@ -1219,6 +652,11 @@ int iwl_alive_start(struct iwl_priv *priv) if (iwl_is_rfkill(priv->shrd)) return -ERFKILL; + if (priv->event_log.ucode_trace) { + /* start collecting data now */ + mod_timer(&priv->ucode_trace, jiffies); + } + /* download priority table before any calibration request */ if (cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist) { @@ -1300,14 +738,14 @@ int iwl_alive_start(struct iwl_priv *priv) return iwl_power_update_mode(priv, true); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv); - -void __iwl_down(struct iwl_priv *priv) +void iwl_down(struct iwl_priv *priv) { int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); + lockdep_assert_held(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, 200); /* @@ -1365,15 +803,6 @@ void __iwl_down(struct iwl_priv *priv) priv->beacon_skb = NULL; } -void iwl_down(struct iwl_priv *priv) -{ - mutex_lock(&priv->shrd->mutex); - __iwl_down(priv); - mutex_unlock(&priv->shrd->mutex); - - iwl_cancel_deferred_work(priv); -} - /***************************************************************************** * * Workqueue callbacks @@ -1431,7 +860,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv) bt_status = priv->bt_status; bt_is_sco = priv->bt_is_sco; - __iwl_down(priv); + iwl_down(priv); priv->bt_full_concurrent = bt_full_concurrent; priv->bt_ci_compliance = bt_ci_compliance; @@ -1501,7 +930,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work) static void iwl_setup_deferred_work(struct iwl_priv *priv) { - priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME); + priv->workqueue = create_singlethread_workqueue(DRV_NAME); init_waitqueue_head(&priv->shrd->wait_command_queue); @@ -1532,7 +961,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.function = iwl_bg_watchdog; } -static void iwl_cancel_deferred_work(struct iwl_priv *priv) +void iwl_cancel_deferred_work(struct iwl_priv *priv) { if (cfg(priv)->lib->cancel_deferred_work) cfg(priv)->lib->cancel_deferred_work(priv); @@ -1649,18 +1078,11 @@ static void iwl_uninit_drv(struct iwl_priv *priv) #endif } - - -static u32 iwl_hw_detect(struct iwl_priv *priv) -{ - return iwl_read32(bus(priv), CSR_HW_REV); -} - /* Size of one Rx buffer in host DRAM */ #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) -static int iwl_set_hw_params(struct iwl_priv *priv) +static void iwl_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.amsdu_size_8K) hw_params(priv).rx_page_order = @@ -1680,39 +1102,39 @@ static int iwl_set_hw_params(struct iwl_priv *priv) hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout; /* Device-specific setup */ - return cfg(priv)->lib->set_hw_params(priv); + cfg(priv)->lib->set_hw_params(priv); } static void iwl_debug_config(struct iwl_priv *priv) { - dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUG " + dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUG " #ifdef CONFIG_IWLWIFI_DEBUG "enabled\n"); #else "disabled\n"); #endif - dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS " + dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS " #ifdef CONFIG_IWLWIFI_DEBUGFS "enabled\n"); #else "disabled\n"); #endif - dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING " + dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING " #ifdef CONFIG_IWLWIFI_DEVICE_TRACING "enabled\n"); #else "disabled\n"); #endif - dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE " + dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE " #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE "enabled\n"); #else "disabled\n"); #endif - dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_P2P " + dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_P2P " #ifdef CONFIG_IWLWIFI_P2P "enabled\n"); #else @@ -1720,46 +1142,43 @@ static void iwl_debug_config(struct iwl_priv *priv) #endif } -int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, - struct iwl_cfg *cfg) +static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans) { + struct iwl_fw *fw = &nic(trans)->fw; int err = 0; struct iwl_priv *priv; struct ieee80211_hw *hw; + struct iwl_op_mode *op_mode; u16 num_mac; - u32 hw_rev; + u32 ucode_flags; /************************ * 1. Allocating HW data ************************/ hw = iwl_alloc_all(); if (!hw) { - pr_err("%s: Cannot allocate network device\n", cfg->name); + pr_err("%s: Cannot allocate network device\n", + cfg(trans)->name); err = -ENOMEM; goto out; } - priv = hw->priv; - priv->shrd = &priv->_shrd; - bus->shrd = priv->shrd; - priv->shrd->bus = bus; + op_mode = hw->priv; + op_mode->ops = &iwl_dvm_ops; + priv = IWL_OP_MODE_GET_DVM(op_mode); + priv->shrd = trans->shrd; priv->shrd->priv = priv; - priv->shrd->trans = trans_ops->alloc(priv->shrd); - if (priv->shrd->trans == NULL) { - err = -ENOMEM; - goto out_free_traffic_mem; - } + iwl_trans_configure(trans(priv), op_mode); /* At this point both hw and priv are allocated. */ - SET_IEEE80211_DEV(hw, bus(priv)->dev); + SET_IEEE80211_DEV(priv->hw, trans(priv)->dev); - /* what debugging capabilities we have */ + /* show what debugging capabilities we have */ iwl_debug_config(priv); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); - cfg(priv) = cfg; /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = @@ -1778,41 +1197,29 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, /* these spin locks will be used in apm_ops.init and EEPROM access * we should init now */ - spin_lock_init(&bus(priv)->reg_lock); + spin_lock_init(&trans(priv)->reg_lock); spin_lock_init(&priv->shrd->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(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - /*********************** * 3. Read REV register ***********************/ - hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - cfg(priv)->name, hw_rev); + cfg(priv)->name, trans(priv)->hw_rev); - err = iwl_trans_request_irq(trans(priv)); + err = iwl_trans_start_hw(trans(priv)); if (err) - goto out_free_trans; - - if (iwl_trans_prepare_card_hw(trans(priv))) { - err = -EIO; - IWL_WARN(priv, "Failed, HW not ready\n"); - goto out_free_trans; - } + goto out_free_traffic_mem; /***************** * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv, hw_rev); + err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev); + /* Reset chip to save power until we load uCode during "up". */ + iwl_trans_stop_hw(trans(priv)); if (err) { IWL_ERR(priv, "Unable to init EEPROM\n"); - goto out_free_trans; + goto out_free_traffic_mem; } err = iwl_eeprom_check_version(priv); if (err) @@ -1838,11 +1245,23 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, /************************ * 5. Setup HW constants ************************/ - if (iwl_set_hw_params(priv)) { - err = -ENOENT; - IWL_ERR(priv, "failed to set hw parameters\n"); - goto out_free_eeprom; - } + iwl_set_hw_params(priv); + + ucode_flags = fw->ucode_capa.flags; + +#ifndef CONFIG_IWLWIFI_P2P + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; +#endif + if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + + /* + * if not PAN, then don't support P2P -- might be a uCode + * packaging bug or due to the eeprom check above + */ + if (!(ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)) + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; + /******************* * 6. Setup priv @@ -1860,51 +1279,68 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, iwl_setup_rx_handlers(priv); iwl_testmode_init(priv); - /********************************************* - * 8. Enable interrupts - *********************************************/ + iwl_power_initialize(priv); + iwl_tt_initialize(priv); - iwl_enable_rfkill_int(priv); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%s", fw->fw_version); - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(bus(priv), - CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->shrd->status); + priv->new_scan_threshold_behaviour = + !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)); + if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { + priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; + priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + } else { + priv->sta_key_max_num = STA_KEY_MAX_NUM; + priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + } - iwl_power_initialize(priv); - iwl_tt_initialize(priv); + priv->phy_calib_chain_noise_reset_cmd = + fw->ucode_capa.standard_phy_calibration_size; + priv->phy_calib_chain_noise_gain_cmd = + fw->ucode_capa.standard_phy_calibration_size + 1; - init_completion(&priv->firmware_loading_complete); + /* initialize all valid contexts */ + iwl_init_context(priv, ucode_flags); - err = iwl_request_firmware(priv, true); + /************************************************** + * This is still part of probe() in a sense... + * + * 9. Setup and register with mac80211 and debugfs + **************************************************/ + err = iwlagn_mac_setup_register(priv, &fw->ucode_capa); if (err) goto out_destroy_workqueue; - return 0; + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, + "failed to create debugfs files. Ignoring error: %d\n", + err); + + return op_mode; out_destroy_workqueue: - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv->shrd); -out_free_trans: - iwl_trans_free(trans(priv)); out_free_traffic_mem: iwl_free_traffic_mem(priv); ieee80211_free_hw(priv->hw); out: - return err; + op_mode = NULL; + return op_mode; } -void __devexit iwl_remove(struct iwl_priv * priv) +static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) { - wait_for_completion(&priv->firmware_loading_complete); + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + wait_for_completion(&nic(priv)->request_firmware_complete); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); @@ -1924,22 +1360,20 @@ void __devexit iwl_remove(struct iwl_priv * priv) /*This will stop the queues, move the device to low power state */ iwl_trans_stop_device(trans(priv)); - iwl_dealloc_ucode(trans(priv)); + iwl_dealloc_ucode(nic(priv)); iwl_eeprom_free(priv->shrd); /*netif_stop_queue(dev); */ - flush_workqueue(priv->shrd->workqueue); + flush_workqueue(priv->workqueue); /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes - * priv->shrd->workqueue... so we can't take down the workqueue + * priv->workqueue... so we can't take down the workqueue * until now... */ - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_free_traffic_mem(priv); - iwl_trans_free(trans(priv)); - iwl_uninit_drv(priv); dev_kfree_skb(priv->beacon_skb); @@ -1947,6 +1381,16 @@ void __devexit iwl_remove(struct iwl_priv * priv) ieee80211_free_hw(priv->hw); } +const struct iwl_op_mode_ops iwl_dvm_ops = { + .start = iwl_op_mode_dvm_start, + .stop = iwl_op_mode_dvm_stop, + .rx = iwl_rx_dispatch, + .queue_full = iwl_stop_sw_queue, + .queue_not_full = iwl_wake_sw_queue, + .hw_rf_kill = iwl_set_hw_rfkill_state, + .free_skb = iwl_free_skb, + .nic_error = iwl_nic_error, +}; /***************************************************************************** * @@ -2054,7 +1498,7 @@ MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)"); module_param_named(led_mode, iwlagn_mod_params.led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " - "1=On(RF On)/Off(RF Off), 2=blinking (default: 0)"); + "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)"); module_param_named(power_save, iwlagn_mod_params.power_save, bool, S_IRUGO); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index f84fb3c..cb484e2 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,16 +65,10 @@ #include "iwl-dev.h" -struct iwlagn_ucode_capabilities { - u32 max_probe_length; - u32 standard_phy_calibration_size; - u32 flags; -}; +struct iwl_ucode_capabilities; extern struct ieee80211_ops iwlagn_hw_ops; -int iwl_reset_ict(struct iwl_trans *trans); - static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) { hdr->op_code = cmd; @@ -83,14 +77,23 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) hdr->data_valid = 1; } -void __iwl_down(struct iwl_priv *priv); void iwl_down(struct iwl_priv *priv); +void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); +int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state); +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_nic_error(struct iwl_op_mode *op_mode); /* MAC80211 */ struct ieee80211_hw *iwl_alloc_all(void); int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa); + struct iwl_ucode_capabilities *capa); void iwlagn_mac_unregister(struct iwl_priv *priv); /* RXON */ @@ -109,6 +112,7 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf, int iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct iwl_device_cmd *cmd); +void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags); /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); @@ -388,4 +392,14 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) } #endif +#ifdef CONFIG_IWLWIFI_DEBUG +void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid); +#else +static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) +{ +} +#endif + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h deleted file mode 100644 index 940d503..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-bus.h +++ /dev/null @@ -1,209 +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) 2007 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#ifndef __iwl_bus_h__ -#define __iwl_bus_h__ - -#include <linux/types.h> -#include <linux/spinlock.h> - -/** - * DOC: Bus layer - role and goal - * - * iwl-bus.h defines the API to the bus layer of the iwlwifi driver. - * The bus layer is responsible for doing very basic bus operations that are - * listed in the iwl_bus_ops structure. - * The bus layer registers to the bus driver, advertises the supported HW and - * gets notifications about enumeration, suspend, resume. - * For the moment, the bus layer is not a linux kernel module as itself, and - * the module_init function of the driver must call the bus specific - * registration functions. These functions are listed at the end of this file. - * For the moment, there is only one implementation of this interface: PCI-e. - * This implementation is iwl-pci.c - */ - -/** - * DOC: encapsulation and type safety - * - * The iwl_bus describes the data that is shared amongst all the bus layer - * implementations. This data is visible to other layers. Data in the bus - * specific area is not visible outside the bus specific implementation. - * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other - * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go - * when the transport layer needs to call a function of another layer. - * - * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the - * bus layer. Type safety is still kept since functions that gets iwl_priv gets - * a typed pointer (as opposed to void *). - */ - -/** - * DOC: probe flow - * - * The module_init calls the bus specific registration function. The - * registration to the bus layer will trigger an enumeration of the bus which - * will call the bus specific probe function. - * The first thing this function must do is to allocate the memory needed by - * iwl_bus + the bus_specific data. - * Once the bus specific probe function has configured the hardware, it - * chooses the appropriate transport layer and calls iwl_probe that will run - * the bus independent probe flow. - * - * Note: The bus specific code must set the following data in iwl_bus before it - * calls iwl_probe: - * * bus->dev - * * bus->irq - * * bus->ops - */ - -struct iwl_shared; -struct iwl_bus; - -/** - * struct iwl_bus_ops - bus specific operations - * @get_pm_support: must returns true if the bus can go to sleep - * @apm_config: will be called during the config of the APM - * @get_hw_id_string: prints the hw_id in the provided buffer - * @get_hw_id: get hw_id in u32 - * @write8: write a byte to register at offset ofs - * @write32: write a dword to register at offset ofs - * @wread32: read a dword at register at offset ofs - */ -struct iwl_bus_ops { - bool (*get_pm_support)(struct iwl_bus *bus); - void (*apm_config)(struct iwl_bus *bus); - void (*get_hw_id_string)(struct iwl_bus *bus, char buf[], int buf_len); - u32 (*get_hw_id)(struct iwl_bus *bus); - void (*write8)(struct iwl_bus *bus, u32 ofs, u8 val); - void (*write32)(struct iwl_bus *bus, u32 ofs, u32 val); - u32 (*read32)(struct iwl_bus *bus, u32 ofs); -}; - -/** - * struct iwl_bus - bus common data - * - * This data is common to all bus layer implementations. - * - * @dev - pointer to struct device * that represents the device - * @ops - pointer to iwl_bus_ops - * @shrd - pointer to iwl_shared which holds shared data from the upper layer - * NB: for the time being this needs to be set by the upper layer since - * it allocates the shared data - * @irq - the irq number for the device - * @reg_lock - protect hw register access - */ -struct iwl_bus { - struct device *dev; - const struct iwl_bus_ops *ops; - struct iwl_shared *shrd; - - unsigned int irq; - spinlock_t reg_lock; - - /* pointer to bus specific struct */ - /*Ensure that this pointer will always be aligned to sizeof pointer */ - char bus_specific[0] __attribute__((__aligned__(sizeof(void *)))); -}; - -static inline bool bus_get_pm_support(struct iwl_bus *bus) -{ - return bus->ops->get_pm_support(bus); -} - -static inline void bus_apm_config(struct iwl_bus *bus) -{ - bus->ops->apm_config(bus); -} - -static inline void bus_get_hw_id_string(struct iwl_bus *bus, char buf[], - int buf_len) -{ - bus->ops->get_hw_id_string(bus, buf, buf_len); -} - -static inline u32 bus_get_hw_id(struct iwl_bus *bus) -{ - return bus->ops->get_hw_id(bus); -} - -static inline void bus_write8(struct iwl_bus *bus, u32 ofs, u8 val) -{ - bus->ops->write8(bus, ofs, val); -} - -static inline void bus_write32(struct iwl_bus *bus, u32 ofs, u32 val) -{ - bus->ops->write32(bus, ofs, val); -} - -static inline u32 bus_read32(struct iwl_bus *bus, u32 ofs) -{ - return bus->ops->read32(bus, ofs); -} - -/***************************************************** -* Bus layer registration functions -******************************************************/ -int __must_check iwl_pci_register_driver(void); -void iwl_pci_unregister_driver(void); - -#endif /* __iwl_bus_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h index e1d7825..1ad14bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-cfg.h +++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -80,6 +80,8 @@ extern struct iwl_cfg iwl6005_2abg_cfg; extern struct iwl_cfg iwl6005_2bg_cfg; extern struct iwl_cfg iwl6005_2agn_sff_cfg; extern struct iwl_cfg iwl6005_2agn_d_cfg; +extern struct iwl_cfg iwl6005_2agn_mow1_cfg; +extern struct iwl_cfg iwl6005_2agn_mow2_cfg; extern struct iwl_cfg iwl1030_bgn_cfg; extern struct iwl_cfg iwl1030_bg_cfg; extern struct iwl_cfg iwl6030_2agn_cfg; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f822ac4..c20618d 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7bcfa78..275e089 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -38,10 +38,10 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-power.h" -#include "iwl-agn.h" #include "iwl-shared.h" #include "iwl-agn.h" #include "iwl-trans.h" +#include "iwl-wifi.h" const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -203,10 +203,9 @@ int iwl_init_geos(struct iwl_priv *priv) if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && cfg(priv)->sku & EEPROM_SKU_CAP_BAND_52GHZ) { - char buf[32]; - bus_get_hw_id_string(bus(priv), buf, sizeof(buf)); IWL_INFO(priv, "Incorrectly detected BG card as ABG. " - "Please send your %s to maintainer.\n", buf); + "Please send your %s to maintainer.\n", + trans(priv)->hw_id_str); cfg(priv)->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; } @@ -644,7 +643,7 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv, * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the ch->band */ -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx) { enum ieee80211_band band = ch->band; @@ -652,7 +651,7 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, if ((le16_to_cpu(ctx->staging.channel) == channel) && (priv->band == band)) - return 0; + return; ctx->staging.channel = cpu_to_le16(channel); if (band == IEEE80211_BAND_5GHZ) @@ -664,7 +663,6 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); - return 0; } void iwl_set_flags_for_band(struct iwl_priv *priv, @@ -832,11 +830,16 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, } #endif -void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) +static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; unsigned long reload_jiffies; +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) + iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); +#endif + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->shrd->status); @@ -876,136 +879,13 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) if (iwlagn_mod_params.restart_fw) { IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); - queue_work(priv->shrd->workqueue, &priv->restart); + queue_work(priv->workqueue, &priv->restart); } else IWL_DEBUG_FW_ERRORS(priv, "Detected FW error, but not restarting\n"); } } -static int iwl_apm_stop_master(struct iwl_priv *priv) -{ - int ret = 0; - - /* stop device's busmaster DMA activity */ - iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - ret = iwl_poll_bit(bus(priv), CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret) - IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n"); - - IWL_DEBUG_INFO(priv, "stop master\n"); - - return ret; -} - -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->shrd->status); - - /* Stop device's DMA activity */ - iwl_apm_stop_master(priv); - - /* Reset the entire device */ - iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - /* - * Clear "initialization complete" bit to move adapter from - * D0A* (powered-up Active) --> D0U* (Uninitialized) state. - */ - iwl_clear_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); -} - - -/* - * Start up NIC'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 - */ -int iwl_apm_init(struct iwl_priv *priv) -{ - int ret = 0; - IWL_DEBUG_INFO(priv, "Init card's basic functions\n"); - - /* - * Use "set_bit" below rather than "write", to preserve any hardware - * bits already set by default after reset. - */ - - /* Disable L0S exit timer (platform NMI Work/Around) */ - iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* - * Disable L0s without affecting L1; - * don't wait for ICH L0s (ICH bug W/A) - */ - iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(bus(priv), CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); - - /* - * Enable HAP INTA (interrupt from management bus) to - * wake device's PCI Express link L1a -> L0s - */ - iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); - - bus_apm_config(bus(priv)); - - /* Configure analog phase-lock-loop before activating to D0A */ - if (cfg(priv)->base_params->pll_cfg_val) - iwl_set_bit(bus(priv), CSR_ANA_PLL_CFG, - cfg(priv)->base_params->pll_cfg_val); - - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* - * 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. - */ - iwl_write_prph(bus(priv), APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(20); - - /* Disable L1-Active */ - iwl_set_bits_prph(bus(priv), APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - set_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status); - -out: - return ret; -} - - int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret; @@ -1580,8 +1460,17 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, return cpu_to_le32(res); } -void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state) +void iwl_nic_error(struct iwl_op_mode *op_mode) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + iwlagn_fw_error(priv, false); +} + +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); } @@ -1590,8 +1479,9 @@ void iwl_nic_config(struct iwl_priv *priv) cfg(priv)->lib->nic_config(priv); } -void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info; info = IEEE80211_SKB_CB(skb); @@ -1599,12 +1489,16 @@ void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) dev_kfree_skb_any(skb); } -void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac) +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + ieee80211_stop_queue(priv->hw, ac); } -void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac) +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + ieee80211_wake_queue(priv->hw, ac); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7bf76ab..42630f5e 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,7 +76,7 @@ struct iwl_cmd; struct iwl_lib_ops { /* set hw dependent parameters */ - int (*set_hw_params)(struct iwl_priv *priv); + void (*set_hw_params)(struct iwl_priv *priv); /* setup BT Rx handler */ void (*bt_rx_handler_setup)(struct iwl_priv *priv); /* setup BT related deferred work */ @@ -169,7 +169,7 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx); void iwl_set_flags_for_band(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -197,6 +197,8 @@ const char *get_ctrl_string(int cmd); void iwl_clear_traffic_stats(struct iwl_priv *priv); void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len); +void iwl_reset_traffic_log(struct iwl_priv *priv); + #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { @@ -297,12 +299,6 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) cfg(priv)->bt_params->advanced_bt_coexist; } -static inline void iwl_enable_rfkill_int(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); - iwl_write32(bus(priv), CSR_INT_MASK, CSR_INT_BIT_RF_KILL); -} - extern bool bt_siso_mode; #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index fbc3095..5f96ce1 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c new file mode 100644 index 0000000..4bc2e70 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debug.c @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include <linux/interrupt.h> +#include "iwl-debug.h" + +#define __iwl_fn(fn) \ +void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \ +{ \ + struct va_format vaf = { \ + .fmt = fmt, \ + }; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.va = &args; \ + dev_ ##fn(dev, "%pV", &vaf); \ + trace_iwlwifi_ ##fn(&vaf); \ + va_end(args); \ +} + +__iwl_fn(warn) +__iwl_fn(info) +__iwl_fn(crit) + +void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + if (!trace_only) { + if (rfkill_prefix) + dev_err(dev, "(RFKILL) %pV", &vaf); + else + dev_err(dev, "%pV", &vaf); + } + trace_iwlwifi_err(&vaf); + va_end(args); +} + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(shared) & level && + (!limit || net_ratelimit())) + dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', + function, &vaf); +#endif + trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); + va_end(args); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index f8fc239..01b2330 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -29,16 +29,34 @@ #ifndef __iwl_debug_h__ #define __iwl_debug_h__ -#include "iwl-bus.h" #include "iwl-shared.h" +#include "iwl-devtrace.h" struct iwl_priv; -/*No matter what is m (priv, bus, trans), this will work */ -#define IWL_ERR(m, f, a...) dev_err(bus(m)->dev, f, ## a) -#define IWL_WARN(m, f, a...) dev_warn(bus(m)->dev, f, ## a) -#define IWL_INFO(m, f, a...) dev_info(bus(m)->dev, f, ## a) -#define IWL_CRIT(m, f, a...) dev_crit(bus(m)->dev, f, ## a) +void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace, + const char *fmt, ...); +void __iwl_warn(struct device *dev, const char *fmt, ...); +void __iwl_info(struct device *dev, const char *fmt, ...); +void __iwl_crit(struct device *dev, const char *fmt, ...); + +/* No matter what is m (priv, bus, trans), this will work */ +#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a) +#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a) +#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a) +#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a) + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...); +#else +static inline void +__iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{} +#endif #define iwl_print_hex_error(m, p, len) \ do { \ @@ -46,53 +64,35 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) -#ifdef CONFIG_IWLWIFI_DEBUG -#define IWL_DEBUG(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level)) \ - dev_err(bus(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) - -#define IWL_DEBUG_LIMIT(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level) && \ - net_ratelimit()) \ - dev_err(bus(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) +#define IWL_DEBUG(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, false, __func__, fmt, ##args) +#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, true, __func__, fmt, ##args) +#ifdef CONFIG_IWLWIFI_DEBUG #define iwl_print_hex_dump(m, level, p, len) \ do { \ if (iwl_get_debug_level((m)->shrd) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) - -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, ...) \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ do { \ - if (!iwl_is_rfkill(p->shrd)) \ - dev_err(bus(p)->dev, "%s%c %s " fmt, \ - "", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ - else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO) \ - dev_err(bus(p)->dev, "%s%c %s " fmt, \ - "(RFKILL) ", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, \ + !(iwl_get_debug_level((m)->shrd) & IWL_DL_RADIO),\ + fmt, ##args); \ } while (0) - #else -#define IWL_DEBUG(m, level, fmt, args...) -#define IWL_DEBUG_LIMIT(m, level, fmt, args...) #define iwl_print_hex_dump(m, level, p, len) -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...) \ -do { \ - if (!iwl_is_rfkill(p->shrd)) \ - IWL_ERR(p, fmt, ##args); \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ +do { \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, true, fmt, ##args); \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 04a3343..ad74138e 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -40,6 +40,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn.h" +#include "iwl-wifi.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -234,12 +235,12 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); priv->dbgfs_sram_offset = 0x800000; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) - priv->dbgfs_sram_len = trans->ucode_init.data.len; + if (nic->shrd->ucode_type == IWL_UCODE_INIT) + priv->dbgfs_sram_len = nic->fw.ucode_init.data.len; else - priv->dbgfs_sram_len = trans->ucode_rt.data.len; + priv->dbgfs_sram_len = nic->fw.ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -263,7 +264,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, sram = priv->dbgfs_sram_offset & ~0x3; /* read the first u32 from sram */ - val = iwl_read_targ_mem(bus(priv), sram); + val = iwl_read_targ_mem(trans(priv), sram); for (; len; len--) { /* put the address at the start of every line */ @@ -282,7 +283,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (++offset == 4) { sram += 4; offset = 0; - val = iwl_read_targ_mem(bus(priv), sram); + val = iwl_read_targ_mem(trans(priv), sram); } /* put in extra spaces and split lines for human readability */ @@ -342,7 +343,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, priv->wowlan_sram, - trans(priv)->ucode_wowlan.data.len); + nic(priv)->fw.ucode_wowlan.data.len); } static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2055,7 +2056,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, const size_t bufsz = sizeof(buf); u32 pwrsave_status; - pwrsave_status = iwl_read32(bus(priv), CSR_GP_CNTRL) & + pwrsave_status = iwl_read32(trans(priv), CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK; pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); @@ -2131,9 +2132,10 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, if (trace) { priv->event_log.ucode_trace = true; - /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */ - mod_timer(&priv->ucode_trace, - jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); + if (iwl_is_alive(priv->shrd)) { + /* start collecting data now */ + mod_timer(&priv->ucode_trace, jiffies); + } } else { priv->event_log.ucode_trace = false; del_timer_sync(&priv->ucode_trace); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e54a4d1..6e5bf0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 @@ -47,9 +47,9 @@ #include "iwl-power.h" #include "iwl-agn-rs.h" #include "iwl-agn-tt.h" -#include "iwl-bus.h" #include "iwl-trans.h" #include "iwl-shared.h" +#include "iwl-op-mode.h" struct iwl_tx_queue; @@ -292,114 +292,6 @@ struct iwl_vif_priv { u8 ibss_bssid_sta_id; }; -/* v1/v2 uCode file layout */ -struct iwl_ucode_header { - __le32 ver; /* major/minor/API/serial */ - union { - struct { - __le32 inst_size; /* bytes of runtime code */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of init code */ - __le32 init_data_size; /* bytes of init data */ - __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ - } v1; - struct { - __le32 build; /* build number */ - __le32 inst_size; /* bytes of runtime code */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of init code */ - __le32 init_data_size; /* bytes of init data */ - __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ - } v2; - } u; -}; - -/* - * new TLV uCode file layout - * - * The new TLV file format contains TLVs, that each specify - * some piece of data. To facilitate "groups", for example - * different instruction image with different capabilities, - * bundled with the same init image, an alternative mechanism - * is provided: - * When the alternative field is 0, that means that the item - * is always valid. When it is non-zero, then it is only - * valid in conjunction with items of the same alternative, - * in which case the driver (user) selects one alternative - * to use. - */ - -enum iwl_ucode_tlv_type { - IWL_UCODE_TLV_INVALID = 0, /* unused */ - IWL_UCODE_TLV_INST = 1, - IWL_UCODE_TLV_DATA = 2, - IWL_UCODE_TLV_INIT = 3, - IWL_UCODE_TLV_INIT_DATA = 4, - IWL_UCODE_TLV_BOOT = 5, - IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ - IWL_UCODE_TLV_PAN = 7, - IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, - IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, - IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, - IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11, - IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12, - IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, - IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, - IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, - IWL_UCODE_TLV_WOWLAN_INST = 16, - IWL_UCODE_TLV_WOWLAN_DATA = 17, - 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). - * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. - */ -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), - IWL_UCODE_TLV_FLAGS_P2P = BIT(3), -}; - -struct iwl_ucode_tlv { - __le16 type; /* see above */ - __le16 alternative; /* see comment */ - __le32 length; /* not including type/length fields */ - u8 data[0]; -} __packed; - -#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 - -struct iwl_tlv_ucode_header { - /* - * The TLV style ucode header is distinguished from - * the v1/v2 style header by first four bytes being - * zero, as such is an invalid combination of - * major/minor/API/serial versions. - */ - __le32 zero; - __le32 magic; - u8 human_readable[64]; - __le32 ver; /* major/minor/API/serial */ - __le32 build; - __le64 alternatives; /* bitmask of valid alternatives */ - /* - * The data contained herein has a TLV layout, - * see above for the TLV header and types. - * Note that each TLV is padded to a length - * that is a multiple of 4 for alignment. - */ - u8 data[0]; -}; - struct iwl_sensitivity_ranges { u16 min_nrg_cck; u16 max_nrg_cck; @@ -550,9 +442,6 @@ struct iwl_chain_noise_data { u8 state; }; -#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ -#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ - enum { MEASUREMENT_READY = (1 << 0), MEASUREMENT_ACTIVE = (1 << 1), @@ -661,7 +550,7 @@ struct traffic_stats { * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */ -#define UCODE_TRACE_PERIOD (100) +#define UCODE_TRACE_PERIOD (10) /* * iwl_event_log: current uCode event log position @@ -804,11 +693,11 @@ struct iwl_testmode_trace { dma_addr_t dma_addr; bool trace_enabled; }; -struct iwl_testmode_sram { +struct iwl_testmode_mem { u32 buff_size; u32 num_chunks; u8 *buff_addr; - bool sram_readed; + bool read_in_progress; }; #endif @@ -818,10 +707,16 @@ struct iwl_wipan_noa_data { u8 data[]; }; +#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \ + ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific)) + +#define IWL_MAC80211_GET_DVM(_hw) \ + ((struct iwl_priv *) ((struct iwl_op_mode *) \ + (_hw)->priv)->op_mode_specific) + struct iwl_priv { /*data shared among all the driver's layers */ - struct iwl_shared _shrd; struct iwl_shared *shrd; /* ieee device used by generic ieee processing code */ @@ -830,6 +725,8 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct kmem_cache *tx_cmd_pool; + struct workqueue_struct *workqueue; + enum ieee80211_band band; void (*pre_rx_handler)(struct iwl_priv *priv, @@ -894,13 +791,6 @@ struct iwl_priv { /* EEPROM MAC addresses */ struct mac_address addresses[2]; - /* uCode images, save to reload in case of failure */ - int fw_index; /* firmware we're trying to load */ - u32 ucode_ver; /* version of ucode, copy of - iwl_ucode.ver */ - - char firmware_name[25]; - struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; __le16 switch_channel; @@ -910,7 +800,6 @@ struct iwl_priv { u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; - bool enhance_sensitivity_table; __le16 sensitivity_tbl[HD_TABLE_SIZE]; __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES]; @@ -978,11 +867,6 @@ struct iwl_priv { 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 @@ -1073,7 +957,7 @@ struct iwl_priv { bool led_registered; #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace testmode_trace; - struct iwl_testmode_sram testmode_sram; + struct iwl_testmode_mem testmode_mem; u32 tm_fixed_rate; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 2a2c8de..91f45e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2012 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 9b212a8..96e6233 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2012 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 @@ -34,6 +34,11 @@ #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} +#undef DECLARE_EVENT_CLASS +#define DECLARE_EVENT_CLASS(...) +#undef DEFINE_EVENT +#define DEFINE_EVENT(evt_class, name, proto, ...) \ +static inline void trace_ ## name(proto) {} #endif #define PRIV_ENTRY __field(void *, priv) @@ -164,6 +169,66 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, ); #undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(iwlwifi_msg_event, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf), + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_warn, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_crit, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +TRACE_EVENT(iwlwifi_dbg, + TP_PROTO(u32 level, bool in_interrupt, const char *function, + struct va_format *vaf), + TP_ARGS(level, in_interrupt, function, vaf), + TP_STRUCT__entry( + __field(u32, level) + __field(u8, in_interrupt) + __string(function, function) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __entry->level = level; + __entry->in_interrupt = in_interrupt; + __assign_str(function, function); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + +#undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi TRACE_EVENT(iwlwifi_dev_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c new file mode 100644 index 0000000..8ff5256 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 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 - 2012 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/completion.h> + +#include "iwl-drv.h" +#include "iwl-trans.h" +#include "iwl-wifi.h" +#include "iwl-op-mode.h" + +int iwl_drv_start(struct iwl_shared *shrd, + struct iwl_trans *trans, struct iwl_cfg *cfg) +{ + int ret; + + shrd->cfg = cfg; + + shrd->nic = kzalloc(sizeof(*shrd->nic), GFP_KERNEL); + if (!shrd->nic) { + dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_nic"); + return -ENOMEM; + } + shrd->nic->shrd = shrd; + + init_completion(&shrd->nic->request_firmware_complete); + + ret = iwl_request_firmware(shrd->nic, true); + + if (ret) { + dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); + kfree(shrd->nic); + } + + return ret; +} + +void iwl_drv_stop(struct iwl_shared *shrd) +{ + /* op_mode can be NULL if its start failed */ + if (shrd->nic->op_mode) + iwl_op_mode_stop(shrd->nic->op_mode); + + kfree(shrd->nic); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h new file mode 100644 index 0000000..90534a2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * 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 - 2012 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 - 2012 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_drv_h__ +#define __iwl_drv_h__ + +#include "iwl-shared.h" + +/** + * DOC: Driver system flows - drv component + * + * This component implements the system flows such as bus enumeration, bus + * removal. Bus dependent parts of system flows (such as iwl_pci_probe) are in + * bus specific files (transport files). This is the code that is common among + * different buses. + * + * This component is also in charge of managing the several implementations of + * the wifi flows: it will allow to have several fw API implementation. These + * different implementations will differ in the way they implement mac80211's + * handlers too. + + * The init flow wrt to the drv component looks like this: + * 1) The bus specific component is called from module_init + * 2) The bus specific component registers the bus driver + * 3) The bus driver calls the probe function + * 4) The bus specific component configures the bus + * 5) The bus specific component calls to the drv bus agnostic part + * (iwl_drv_start) + * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback + * 7) iwl_ucode_callback parses the fw file + * 8) iwl_ucode_callback starts the wifi implementation to matches the fw + */ + +/** + * iwl_drv_start - start the drv + * + * @shrd: the shrd area + * @trans_ops: the ops of the transport + * @cfg: device specific constants / virtual functions + * + * TODO: review the parameters given to this function + * + * starts the driver: fetches the firmware. This should be called by bus + * specific system flows implementations. For example, the bus specific probe + * function should do bus related operations only, and then call to this + * function. + */ +int iwl_drv_start(struct iwl_shared *shrd, + struct iwl_trans *trans, struct iwl_cfg *cfg); + +/** + * iwl_drv_stop - stop the drv + * + * @shrd: the shrd area + * + * TODO: review the parameters given to this function + * + * Stop the driver. This should be called by bus specific system flows + * implementations. For example, the bus specific remove function should first + * call this function and then do the bus related operations only. + */ +void iwl_drv_stop(struct iwl_shared *shrd); + +#endif /* __iwl_drv_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index c1eda97..07e93787 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -149,23 +149,27 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * 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_bus *bus) + +#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ + +static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) { u16 count; int ret; for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { /* Request semaphore */ - iwl_set_bit(bus, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(bus, CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(trans, 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(bus, + IWL_DEBUG_EEPROM(trans, "Acquired semaphore after %d tries.\n", count+1); return ret; @@ -175,16 +179,17 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus) return ret; } -static void iwl_eeprom_release_semaphore(struct iwl_bus *bus) +static void iwl_eeprom_release_semaphore(struct iwl_trans *trans) { - iwl_clear_bit(bus, CSR_HW_IF_CONFIG_REG, + iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); } static int iwl_eeprom_verify_signature(struct iwl_trans *trans) { - u32 gp = iwl_read32(bus(trans), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & + CSR_EEPROM_GP_VALID_MSK; int ret = 0; IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp); @@ -303,19 +308,20 @@ void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac) * ******************************************************************************/ -static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode) +static void iwl_set_otp_access(struct iwl_trans *trans, + enum iwl_access_mode mode) { - iwl_read32(bus, CSR_OTP_GP_REG); + iwl_read32(trans, CSR_OTP_GP_REG); if (mode == IWL_OTP_ACCESS_ABSOLUTE) - iwl_clear_bit(bus, CSR_OTP_GP_REG, + iwl_clear_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); else - iwl_set_bit(bus, CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) +static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev) { u32 otpgp; int nvm_type; @@ -323,7 +329,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) /* OTP only valid for CP/PP and after */ switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: - IWL_ERR(bus, "Unknown hardware type\n"); + IWL_ERR(trans, "Unknown hardware type\n"); return -ENOENT; case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: @@ -332,7 +338,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) nvm_type = NVM_DEVICE_TYPE_EEPROM; break; default: - otpgp = iwl_read32(bus, CSR_OTP_GP_REG); + otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) nvm_type = NVM_DEVICE_TYPE_OTP; else @@ -342,73 +348,74 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) return nvm_type; } -static int iwl_init_otp_access(struct iwl_bus *bus) +static int iwl_init_otp_access(struct iwl_trans *trans) { int ret; /* Enable 40MHz radio clock */ - iwl_write32(bus, CSR_GP_CNTRL, - iwl_read32(bus, CSR_GP_CNTRL) | + iwl_write32(trans, CSR_GP_CNTRL, + iwl_read32(trans, CSR_GP_CNTRL) | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_bit(bus, CSR_GP_CNTRL, + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) - IWL_ERR(bus, "Time out access OTP\n"); + IWL_ERR(trans, "Time out access OTP\n"); else { - iwl_set_bits_prph(bus, APMG_PS_CTRL_REG, + iwl_set_bits_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_prph(bus, APMG_PS_CTRL_REG, + iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); /* * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (cfg(bus)->base_params->shadow_ram_support) - iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG, + if (cfg(trans)->base_params->shadow_ram_support) + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; } -static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data) +static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, + __le16 *eeprom_data) { int ret = 0; u32 r; u32 otpgp; - iwl_write32(bus, CSR_EEPROM_REG, + iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(bus, CSR_EEPROM_REG, + ret = iwl_poll_bit(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { - IWL_ERR(bus, "Time out reading OTP[%d]\n", addr); + IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret; } - r = iwl_read32(bus, CSR_EEPROM_REG); + r = iwl_read32(trans, CSR_EEPROM_REG); /* check for ECC errors: */ - otpgp = iwl_read32(bus, CSR_OTP_GP_REG); + otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgement */ - iwl_set_bit(bus, CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n"); + IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL; } if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgement */ - iwl_set_bit(bus, CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(bus, "Correctable OTP ECC error, continue read\n"); + IWL_ERR(trans, "Correctable OTP ECC error, continue read\n"); } *eeprom_data = cpu_to_le16(r >> 16); return 0; @@ -417,20 +424,20 @@ static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data) /* * iwl_is_otp_empty: check for empty OTP */ -static bool iwl_is_otp_empty(struct iwl_bus *bus) +static bool iwl_is_otp_empty(struct iwl_trans *trans) { u16 next_link_addr = 0; __le16 link_value; bool is_empty = false; /* locate the beginning of OTP link list */ - if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) { + if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) { if (!link_value) { - IWL_ERR(bus, "OTP is empty\n"); + IWL_ERR(trans, "OTP is empty\n"); is_empty = true; } } else { - IWL_ERR(bus, "Unable to read first block of OTP list.\n"); + IWL_ERR(trans, "Unable to read first block of OTP list.\n"); is_empty = true; } @@ -447,7 +454,7 @@ static bool iwl_is_otp_empty(struct iwl_bus *bus) * we should read and used to configure the device. * only perform this operation if shadow RAM is disabled */ -static int iwl_find_otp_image(struct iwl_bus *bus, +static int iwl_find_otp_image(struct iwl_trans *trans, u16 *validblockaddr) { u16 next_link_addr = 0, valid_addr; @@ -455,10 +462,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus, int usedblocks = 0; /* set addressing mode to absolute to traverse the link list */ - iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE); + iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE); /* checking for empty OTP or error */ - if (iwl_is_otp_empty(bus)) + if (iwl_is_otp_empty(trans)) return -EINVAL; /* @@ -472,9 +479,9 @@ static int iwl_find_otp_image(struct iwl_bus *bus, */ valid_addr = next_link_addr; next_link_addr = le16_to_cpu(link_value) * sizeof(u16); - IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n", + IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n", usedblocks, next_link_addr); - if (iwl_read_otp_word(bus, next_link_addr, &link_value)) + if (iwl_read_otp_word(trans, next_link_addr, &link_value)) return -EINVAL; if (!link_value) { /* @@ -489,10 +496,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= cfg(bus)->base_params->max_ll_items); + } while (usedblocks <= cfg(trans)->base_params->max_ll_items); /* OTP has no valid blocks */ - IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n"); + IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n"); return -EINVAL; } @@ -652,65 +659,62 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) +int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev) { - struct iwl_shared *shrd = priv->shrd; __le16 *e; - u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP); + u32 gp = iwl_read32(trans, CSR_EEPROM_GP); int sz; int ret; u16 addr; u16 validblockaddr = 0; u16 cache_addr = 0; - trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev); - if (trans(priv)->nvm_device_type == -ENOENT) + trans->nvm_device_type = iwl_get_nvm_type(trans, hw_rev); + if (trans->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - sz = cfg(priv)->base_params->eeprom_size; - IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz); - shrd->eeprom = kzalloc(sz, GFP_KERNEL); - if (!shrd->eeprom) { + sz = cfg(trans)->base_params->eeprom_size; + IWL_DEBUG_EEPROM(trans, "NVM size = %d\n", sz); + trans->shrd->eeprom = kzalloc(sz, GFP_KERNEL); + if (!trans->shrd->eeprom) { ret = -ENOMEM; goto alloc_err; } - e = (__le16 *)shrd->eeprom; - - iwl_apm_init(priv); + e = (__le16 *)trans->shrd->eeprom; - ret = iwl_eeprom_verify_signature(trans(priv)); + ret = iwl_eeprom_verify_signature(trans); if (ret < 0) { - IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); + IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); ret = -ENOENT; goto err; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = iwl_eeprom_acquire_semaphore(bus(priv)); + ret = iwl_eeprom_acquire_semaphore(trans); if (ret < 0) { - IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); + IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; goto err; } - if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + if (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - ret = iwl_init_otp_access(bus(priv)); + ret = iwl_init_otp_access(trans); if (ret) { - IWL_ERR(priv, "Failed to initialize OTP access.\n"); + IWL_ERR(trans, "Failed to initialize OTP access.\n"); ret = -ENOENT; goto done; } - iwl_write32(bus(priv), CSR_EEPROM_GP, - iwl_read32(bus(priv), CSR_EEPROM_GP) & + iwl_write32(trans, CSR_EEPROM_GP, + iwl_read32(trans, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - iwl_set_bit(bus(priv), CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ - if (!cfg(priv)->base_params->shadow_ram_support) { - if (iwl_find_otp_image(bus(priv), &validblockaddr)) { + if (!cfg(trans)->base_params->shadow_ram_support) { + if (iwl_find_otp_image(trans, &validblockaddr)) { ret = -ENOENT; goto done; } @@ -719,7 +723,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) addr += sizeof(u16)) { __le16 eeprom_data; - ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data); + ret = iwl_read_otp_word(trans, addr, &eeprom_data); if (ret) goto done; e[cache_addr / 2] = eeprom_data; @@ -730,36 +734,35 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - iwl_write32(bus(priv), CSR_EEPROM_REG, + iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG, + ret = iwl_poll_bit(trans, CSR_EEPROM_REG, 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 EEPROM[%d]\n", addr); + IWL_ERR(trans, + "Time out reading EEPROM[%d]\n", addr); goto done; } - r = iwl_read32(bus(priv), CSR_EEPROM_REG); + r = iwl_read32(trans, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } - IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n", - (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) + IWL_DEBUG_EEPROM(trans, "NVM Type: %s, version: 0x%x\n", + (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", - iwl_eeprom_query16(shrd, EEPROM_VERSION)); + iwl_eeprom_query16(trans->shrd, EEPROM_VERSION)); ret = 0; done: - iwl_eeprom_release_semaphore(bus(priv)); + iwl_eeprom_release_semaphore(trans); err: if (ret) - iwl_eeprom_free(priv->shrd); - /* Reset chip to save power until we load uCode during "up". */ - iwl_apm_stop(priv); + iwl_eeprom_free(trans->shrd); alloc_err: return ret; } @@ -1072,7 +1075,7 @@ void iwl_rf_config(struct iwl_priv *priv) /* write radio config values to register */ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) { - iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans(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)); @@ -1084,7 +1087,7 @@ void iwl_rf_config(struct iwl_priv *priv) WARN_ON(1); /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 9fa937e..cbb8611 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,6 +67,7 @@ struct iwl_priv; struct iwl_shared; +struct iwl_trans; /* * EEPROM access time values: @@ -305,7 +306,7 @@ struct iwl_eeprom_ops { }; -int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); +int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev); void iwl_eeprom_free(struct iwl_shared *shrd); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 5bede9d..9020809 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index d57ea64..e2e3b5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -34,41 +34,41 @@ #define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline void __iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask) +static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) { - iwl_write32(bus, reg, iwl_read32(bus, reg) | mask); + iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); } -static inline void __iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask) +static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) { - iwl_write32(bus, reg, iwl_read32(bus, reg) & ~mask); + iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); } -void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask) +void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - __iwl_set_bit(bus, reg, mask); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + __iwl_set_bit(trans, reg, mask); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask) +void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - __iwl_clear_bit(bus, reg, mask); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + __iwl_clear_bit(trans, reg, mask); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -int iwl_poll_bit(struct iwl_bus *bus, u32 addr, +int iwl_poll_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout) { int t = 0; do { - if ((iwl_read32(bus, addr) & mask) == (bits & mask)) + if ((iwl_read32(trans, addr) & mask) == (bits & mask)) return t; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; @@ -77,14 +77,15 @@ int iwl_poll_bit(struct iwl_bus *bus, u32 addr, return -ETIMEDOUT; } -int iwl_grab_nic_access_silent(struct iwl_bus *bus) +int iwl_grab_nic_access_silent(struct iwl_trans *trans) { int ret; - lockdep_assert_held(&bus->reg_lock); + lockdep_assert_held(&trans->reg_lock); /* this bit wakes up the NIC */ - __iwl_set_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + __iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * These bits say the device is running, and should keep running for @@ -105,70 +106,70 @@ int iwl_grab_nic_access_silent(struct iwl_bus *bus) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bit(bus, CSR_GP_CNTRL, + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (ret < 0) { - iwl_write32(bus, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } return 0; } -int iwl_grab_nic_access(struct iwl_bus *bus) +int iwl_grab_nic_access(struct iwl_trans *trans) { - int ret = iwl_grab_nic_access_silent(bus); + int ret = iwl_grab_nic_access_silent(trans); if (ret) { - u32 val = iwl_read32(bus, CSR_GP_CNTRL); - IWL_ERR(bus, + u32 val = iwl_read32(trans, CSR_GP_CNTRL); + IWL_ERR(trans, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); } return ret; } -void iwl_release_nic_access(struct iwl_bus *bus) +void iwl_release_nic_access(struct iwl_trans *trans) { - lockdep_assert_held(&bus->reg_lock); - __iwl_clear_bit(bus, CSR_GP_CNTRL, + lockdep_assert_held(&trans->reg_lock); + __iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } -u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg) +u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { u32 value; unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); - value = iwl_read32(bus, reg); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + value = iwl_read32(trans, reg); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); return value; } -void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value) +void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - if (!iwl_grab_nic_access(bus)) { - iwl_write32(bus, reg, value); - iwl_release_nic_access(bus); + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_grab_nic_access(trans)) { + iwl_write32(trans, reg, value); + iwl_release_nic_access(trans); } - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask, +int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout) { int t = 0; do { - if ((iwl_read_direct32(bus, addr) & mask) == mask) + if ((iwl_read_direct32(trans, addr) & mask) == mask) return t; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; @@ -177,135 +178,135 @@ int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask, return -ETIMEDOUT; } -static inline u32 __iwl_read_prph(struct iwl_bus *bus, u32 reg) +static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg) { - iwl_write32(bus, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + iwl_write32(trans, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); rmb(); - return iwl_read32(bus, HBUS_TARG_PRPH_RDAT); + return iwl_read32(trans, HBUS_TARG_PRPH_RDAT); } -static inline void __iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val) +static inline void __iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val) { - iwl_write32(bus, HBUS_TARG_PRPH_WADDR, + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); wmb(); - iwl_write32(bus, HBUS_TARG_PRPH_WDAT, val); + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -u32 iwl_read_prph(struct iwl_bus *bus, u32 reg) +u32 iwl_read_prph(struct iwl_trans *trans, u32 reg) { unsigned long flags; u32 val; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); - val = __iwl_read_prph(bus, reg); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + val = __iwl_read_prph(trans, reg); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); return val; } -void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val) +void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - if (!iwl_grab_nic_access(bus)) { - __iwl_write_prph(bus, addr, val); - iwl_release_nic_access(bus); + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_grab_nic_access(trans)) { + __iwl_write_prph(trans, addr, val); + iwl_release_nic_access(trans); } - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask) +void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); - __iwl_write_prph(bus, reg, __iwl_read_prph(bus, reg) | mask); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + __iwl_write_prph(trans, reg, __iwl_read_prph(trans, reg) | mask); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg, +void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg, u32 bits, u32 mask) { unsigned long flags; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); - __iwl_write_prph(bus, reg, - (__iwl_read_prph(bus, reg) & mask) | bits); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + __iwl_write_prph(trans, reg, + (__iwl_read_prph(trans, reg) & mask) | bits); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask) +void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask) { unsigned long flags; u32 val; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); - val = __iwl_read_prph(bus, reg); - __iwl_write_prph(bus, reg, (val & ~mask)); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + val = __iwl_read_prph(trans, reg); + __iwl_write_prph(trans, reg, (val & ~mask)); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr, +void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr, void *buf, int words) { unsigned long flags; int offs; u32 *vals = buf; - spin_lock_irqsave(&bus->reg_lock, flags); - iwl_grab_nic_access(bus); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); - iwl_write32(bus, HBUS_TARG_MEM_RADDR, addr); + iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); rmb(); for (offs = 0; offs < words; offs++) - vals[offs] = iwl_read32(bus, HBUS_TARG_MEM_RDAT); + vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(bus); - spin_unlock_irqrestore(&bus->reg_lock, flags); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); } -u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr) +u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr) { u32 value; - _iwl_read_targ_mem_words(bus, addr, &value, 1); + _iwl_read_targ_mem_words(trans, addr, &value, 1); return value; } -int _iwl_write_targ_mem_words(struct iwl_bus *bus, u32 addr, +int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr, void *buf, int words) { unsigned long flags; int offs, result = 0; u32 *vals = buf; - spin_lock_irqsave(&bus->reg_lock, flags); - if (!iwl_grab_nic_access(bus)) { - iwl_write32(bus, HBUS_TARG_MEM_WADDR, addr); + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_grab_nic_access(trans)) { + iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); wmb(); for (offs = 0; offs < words; offs++) - iwl_write32(bus, HBUS_TARG_MEM_WDAT, vals[offs]); - iwl_release_nic_access(bus); + iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]); + iwl_release_nic_access(trans); } else result = -EBUSY; - spin_unlock_irqrestore(&bus->reg_lock, flags); + spin_unlock_irqrestore(&trans->reg_lock, flags); return result; } -int iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val) +int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val) { - return _iwl_write_targ_mem_words(bus, addr, &val, 1); + return _iwl_write_targ_mem_words(trans, addr, &val, 1); } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index aae2eeb..782486f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -31,63 +31,63 @@ #include "iwl-devtrace.h" #include "iwl-shared.h" -#include "iwl-bus.h" +#include "iwl-trans.h" -static inline void iwl_write8(struct iwl_bus *bus, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) { - trace_iwlwifi_dev_iowrite8(priv(bus), ofs, val); - bus_write8(bus, ofs, val); + trace_iwlwifi_dev_iowrite8(priv(trans), ofs, val); + iwl_trans_write8(trans, ofs, val); } -static inline void iwl_write32(struct iwl_bus *bus, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) { - trace_iwlwifi_dev_iowrite32(priv(bus), ofs, val); - bus_write32(bus, ofs, val); + trace_iwlwifi_dev_iowrite32(priv(trans), ofs, val); + iwl_trans_write32(trans, ofs, val); } -static inline u32 iwl_read32(struct iwl_bus *bus, u32 ofs) +static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) { - u32 val = bus_read32(bus, ofs); - trace_iwlwifi_dev_ioread32(priv(bus), ofs, val); + u32 val = iwl_trans_read32(trans, ofs); + trace_iwlwifi_dev_ioread32(priv(trans), ofs, val); return val; } -void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask); -void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask); +void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); -int iwl_poll_bit(struct iwl_bus *bus, u32 addr, +int iwl_poll_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout); -int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask, +int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout); -int iwl_grab_nic_access_silent(struct iwl_bus *bus); -int iwl_grab_nic_access(struct iwl_bus *bus); -void iwl_release_nic_access(struct iwl_bus *bus); +int iwl_grab_nic_access_silent(struct iwl_trans *trans); +int iwl_grab_nic_access(struct iwl_trans *trans); +void iwl_release_nic_access(struct iwl_trans *trans); -u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg); -void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value); +u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); +void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); -u32 iwl_read_prph(struct iwl_bus *bus, u32 reg); -void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val); -void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask); -void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg, +u32 iwl_read_prph(struct iwl_trans *trans, u32 reg); +void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg, u32 bits, u32 mask); -void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask); +void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask); -void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr, +void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr, void *buf, int words); -#define iwl_read_targ_mem_words(bus, addr, buf, bufsize) \ +#define iwl_read_targ_mem_words(trans, addr, buf, bufsize) \ do { \ BUILD_BUG_ON((bufsize) % sizeof(u32)); \ - _iwl_read_targ_mem_words(bus, addr, buf, \ + _iwl_read_targ_mem_words(trans, addr, buf, \ (bufsize) / sizeof(u32));\ } while (0) -int _iwl_write_targ_mem_words(struct iwl_bus *bus, u32 addr, +int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr, void *buf, int words); -u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr); -int iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val); +u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr); +int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 14dcbfc..5c7741f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 @@ -71,7 +71,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* Set led register off */ void iwlagn_led_enable(struct iwl_priv *priv) { - iwl_write32(bus(priv), CSR_LED_REG, CSR_LED_REG_TRUN_ON); + iwl_write32(trans(priv), CSR_LED_REG, CSR_LED_REG_TRUN_ON); } /* @@ -107,9 +107,10 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) }; u32 reg; - reg = iwl_read32(bus(priv), CSR_LED_REG); + reg = iwl_read32(trans(priv), CSR_LED_REG); if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(bus(priv), CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + iwl_write32(trans(priv), CSR_LED_REG, + reg & CSR_LED_BSM_CTRL_MSK); return iwl_trans_send_cmd(trans(priv), &cmd); } @@ -177,6 +178,10 @@ void iwl_leds_init(struct iwl_priv *priv) int mode = iwlagn_mod_params.led_mode; int ret; + if (mode == IWL_LED_DISABLE) { + IWL_INFO(priv, "Led disabled\n"); + return; + } if (mode == IWL_LED_DEFAULT) mode = cfg(priv)->led_mode; @@ -202,7 +207,7 @@ void iwl_leds_init(struct iwl_priv *priv) break; } - ret = led_classdev_register(bus(priv)->dev, &priv->led); + ret = led_classdev_register(trans(priv)->dev, &priv->led); if (ret) { kfree(priv->led.name); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 2550b3c..b02a853 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index f980e57..03f7705 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -35,7 +35,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> @@ -43,6 +42,7 @@ #include <asm/div64.h> +#include "iwl-ucode.h" #include "iwl-eeprom.h" #include "iwl-wifi.h" #include "iwl-dev.h" @@ -51,8 +51,8 @@ #include "iwl-agn-calib.h" #include "iwl-agn.h" #include "iwl-shared.h" -#include "iwl-bus.h" #include "iwl-trans.h" +#include "iwl-op-mode.h" /***************************************************************************** * @@ -136,7 +136,7 @@ iwlagn_iface_combinations_p2p[] = { * other mac80211 functions grouped here. */ int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa) { int ret; struct ieee80211_hw *hw = priv->hw; @@ -195,8 +195,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; - if (trans(priv)->ucode_wowlan.code.len && - device_can_wakeup(bus(priv)->dev)) { + if (nic(priv)->fw.ucode_wowlan.code.len && + device_can_wakeup(trans(priv)->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -234,7 +234,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; - hw->wiphy->hw_version = bus_get_hw_id(bus(priv)); + hw->wiphy->hw_version = trans(priv)->hw_id; iwl_leds_init(priv); @@ -296,7 +296,7 @@ static int __iwl_up(struct iwl_priv *priv) error: set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); - __iwl_down(priv); + iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); IWL_ERR(priv, "Unable to initialize device.\n"); @@ -305,7 +305,7 @@ static int __iwl_up(struct iwl_priv *priv) static int iwlagn_mac_start(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -332,7 +332,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) static void iwlagn_mac_stop(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -341,14 +341,19 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; + mutex_lock(&priv->shrd->mutex); iwl_down(priv); + mutex_unlock(&priv->shrd->mutex); - flush_workqueue(priv->shrd->workqueue); + iwl_cancel_deferred_work(priv); + + flush_workqueue(priv->workqueue); /* User space software may expect getting rfkill changes - * even if interface is down */ - iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF); - iwl_enable_rfkill_int(priv); + * even if interface is down, trans->down will leave the RF + * kill interrupt enabled + */ + iwl_trans_stop_hw(trans(priv)); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -357,7 +362,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); if (iwlagn_mod_params.sw_crypto) return; @@ -384,7 +389,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, static int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; int ret; @@ -405,10 +410,10 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, if (ret) goto error; - device_set_wakeup_enable(bus(priv)->dev, true); + device_set_wakeup_enable(trans(priv)->dev, true); /* Now let the ucode operate on its own */ - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); goto out; @@ -426,7 +431,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, static int iwlagn_mac_resume(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct ieee80211_vif *vif; unsigned long flags; @@ -436,32 +441,33 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); base = priv->shrd->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - spin_lock_irqsave(&bus(priv)->reg_lock, flags); - ret = iwl_grab_nic_access_silent(bus(priv)); + spin_lock_irqsave(&trans(priv)->reg_lock, flags); + ret = iwl_grab_nic_access_silent(trans(priv)); if (ret == 0) { - iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base); - status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(bus(priv)); + iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, base); + status = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + iwl_release_nic_access(trans(priv)); } - spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); + spin_unlock_irqrestore(&trans(priv)->reg_lock, flags); #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); if (!priv->wowlan_sram) priv->wowlan_sram = - kzalloc(trans->ucode_wowlan.data.len, + kzalloc(nic->fw.ucode_wowlan.data.len, GFP_KERNEL); if (priv->wowlan_sram) _iwl_read_targ_mem_words( - bus(priv), 0x800000, priv->wowlan_sram, - trans->ucode_wowlan.data.len / 4); + trans(priv), 0x800000, + priv->wowlan_sram, + nic->fw.ucode_wowlan.data.len / 4); } #endif } @@ -471,7 +477,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) priv->shrd->wowlan = false; - device_set_wakeup_enable(bus(priv)->dev, false); + device_set_wakeup_enable(trans(priv)->dev, false); iwlagn_prepare_restart(priv); @@ -491,7 +497,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 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); @@ -506,7 +512,7 @@ static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key); } @@ -516,7 +522,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; int ret; @@ -620,7 +626,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret = -EINVAL; struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; @@ -686,7 +692,7 @@ 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_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; bool is_ap = vif->type == NL80211_IFTYPE_STATION; @@ -729,7 +735,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = ch_switch->channel; @@ -816,7 +822,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); __le32 filter_or = 0, filter_nand = 0; struct iwl_rxon_context *ctx; @@ -863,7 +869,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); mutex_lock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -900,7 +906,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, enum nl80211_channel_type channel_type, int duration) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; int err = 0; @@ -990,7 +996,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; @@ -1010,7 +1016,7 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, const u8 *bssid, enum ieee80211_tx_sync_type type) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; int ret; @@ -1064,7 +1070,7 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, const u8 *bssid, enum ieee80211_tx_sync_type type) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; @@ -1088,7 +1094,7 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, enum ieee80211_rssi_event rssi_event) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -1113,9 +1119,9 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - queue_work(priv->shrd->workqueue, &priv->beacon_update); + queue_work(priv->workqueue, &priv->beacon_update); return 0; } @@ -1124,7 +1130,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; unsigned long flags; @@ -1167,7 +1173,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); return priv->ibss_manager == IWL_IBSS_MANAGER; } @@ -1221,7 +1227,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *tmp, *ctx = NULL; int err; @@ -1318,7 +1324,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv, static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1346,7 +1352,7 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 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; @@ -1432,7 +1438,7 @@ static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1478,7 +1484,7 @@ static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int ret; @@ -1517,7 +1523,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int sta_id; @@ -1585,15 +1591,18 @@ struct ieee80211_ops iwlagn_hw_ops = { struct ieee80211_hw *iwl_alloc_all(void) { struct iwl_priv *priv; + struct iwl_op_mode *op_mode; /* 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); + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) + + sizeof(struct iwl_op_mode), &iwlagn_hw_ops); if (!hw) goto out; - priv = hw->priv; + op_mode = hw->priv; + priv = IWL_OP_MODE_GET_DVM(op_mode); priv->hw = hw; out: diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h new file mode 100644 index 0000000..d4fc9be --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 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 - 2012 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_op_mode_h__ +#define __iwl_op_mode_h__ + +struct iwl_op_mode; +struct iwl_trans; +struct sk_buff; +struct iwl_device_cmd; +struct iwl_rx_mem_buffer; + +/** + * DOC: Operational mode - what is it ? + * + * The operational mode (a.k.a. op_mode) is the layer that implements + * mac80211's handlers. It knows two APIs: mac80211's and the fw's. It uses + * the transport API to access the HW. The op_mode doesn't need to know how the + * underlying HW works, since the transport layer takes care of that. + * + * There can be several op_mode: i.e. different fw APIs will require two + * different op_modes. This is why the op_mode is virtualized. + */ + +/** + * DOC: Life cycle of the Operational mode + * + * The operational mode has a very simple life cycle. + * + * 1) The driver layer (iwl-drv.c) chooses the op_mode based on the + * capabilities advertized by the fw file (in TLV format). + * 2) The driver layer starts the op_mode (ops->start) + * 3) The op_mode registers registers mac80211 + * 4) The op_mode is governed by mac80211 + * 5) The driver layer stops the op_mode + */ + +/** + * struct iwl_op_mode_ops - op_mode specific operations + * + * The op_mode exports its ops so that external components can start it and + * interact with it. The driver layer typically calls the start and stop + * handlers, the transport layer calls the others. + * + * All the handlers MUST be implemented + * + * @start: start the op_mode. The transport layer is already allocated. + * May sleep + * @stop: stop the op_mode. Must free all the memory allocated. + * May sleep + * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the + * HCMD the this Rx responds to. + * Must be atomic. + * @queue_full: notifies that a HW queue is full. Ac is the ac of the queue + * Must be atomic + * @queue_not_full: notifies that a HW queue is not full any more. + * Ac is the ac of the queue. Must be atomic + * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that + * the radio is killed. Must be atomic. + * @free_skb: allows the transport layer to free skbs that haven't been + * reclaimed by the op_mode. This can happen when the driver is freed and + * there are Tx packets pending in the transport layer. + * Must be atomic + * @nic_error: error notification. Must be atomic + */ +struct iwl_op_mode_ops { + struct iwl_op_mode *(*start)(struct iwl_trans *trans); + void (*stop)(struct iwl_op_mode *op_mode); + int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); + void (*queue_full)(struct iwl_op_mode *op_mode, u8 ac); + void (*queue_not_full)(struct iwl_op_mode *op_mode, u8 ac); + void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); + void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); + void (*nic_error)(struct iwl_op_mode *op_mode); +}; + +/** + * struct iwl_op_mode - operational mode + * + * This holds an implementation of the mac80211 / fw API. + * + * @ops - pointer to its own ops + */ +struct iwl_op_mode { + const struct iwl_op_mode_ops *ops; + const struct iwl_trans *trans; + + char op_mode_specific[0] __aligned(sizeof(void *)); +}; + +static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) +{ + might_sleep(); + + op_mode->ops->stop(op_mode); +} + +static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + return op_mode->ops->rx(op_mode, rxb, cmd); +} + +static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, u8 ac) +{ + op_mode->ops->queue_full(op_mode, ac); +} + +static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, + u8 ac) +{ + op_mode->ops->queue_not_full(op_mode, ac); +} + +static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, + bool state) +{ + op_mode->ops->hw_rf_kill(op_mode, state); +} + +static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, + struct sk_buff *skb) +{ + op_mode->ops->free_skb(op_mode, skb); +} + +static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode) +{ + op_mode->ops->nic_error(op_mode); +} + +/***************************************************** +* Op mode layers implementations +******************************************************/ +extern const struct iwl_op_mode_ops iwl_dvm_ops; + +#endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index fb30ea7..06e0041 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,118 +64,13 @@ #include <linux/pci.h> #include <linux/pci-aspm.h> -#include "iwl-bus.h" #include "iwl-io.h" #include "iwl-shared.h" #include "iwl-trans.h" #include "iwl-csr.h" #include "iwl-cfg.h" - -/* PCI registers */ -#define PCI_CFG_RETRY_TIMEOUT 0x041 -#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01 -#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02 - -struct iwl_pci_bus { - /* basic pci-network driver stuff */ - struct pci_dev *pci_dev; - - /* pci hardware address support */ - void __iomem *hw_base; -}; - -#define IWL_BUS_GET_PCI_BUS(_iwl_bus) \ - ((struct iwl_pci_bus *) ((_iwl_bus)->bus_specific)) - -#define IWL_BUS_GET_PCI_DEV(_iwl_bus) \ - ((IWL_BUS_GET_PCI_BUS(_iwl_bus))->pci_dev) - -static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus) -{ - int pos; - u16 pci_lnk_ctl; - - struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); - - pos = pci_pcie_cap(pci_dev); - pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); - return pci_lnk_ctl; -} - -static bool iwl_pci_is_pm_supported(struct iwl_bus *bus) -{ - u16 lctl = iwl_pciexp_link_ctrl(bus); - - return !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); -} - -static void iwl_pci_apm_config(struct iwl_bus *bus) -{ - /* - * HW bug W/A for instability in PCIe bus L0S->L1 transition. - * Check if BIOS (or OS) enabled L1-ASPM on this device. - * If so (likely), disable L0S, so device moves directly L0->L1; - * costs negligible amount of power savings. - * If not (unlikely), enable L0S, so there is at least some - * power savings, even without L1. - */ - u16 lctl = iwl_pciexp_link_ctrl(bus); - - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == - PCI_CFG_LINK_CTRL_VAL_L1_EN) { - /* L1-ASPM enabled; disable(!) L0S */ - iwl_set_bit(bus, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - dev_printk(KERN_INFO, bus->dev, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ - iwl_clear_bit(bus, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - dev_printk(KERN_INFO, bus->dev, "L1 Disabled; Enabling L0S\n"); - } -} - -static void iwl_pci_get_hw_id_string(struct iwl_bus *bus, char buf[], - int buf_len) -{ - struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); - - snprintf(buf, buf_len, "PCI ID: 0x%04X:0x%04X", pci_dev->device, - pci_dev->subsystem_device); -} - -static u32 iwl_pci_get_hw_id(struct iwl_bus *bus) -{ - struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); - - return (pci_dev->device << 16) + pci_dev->subsystem_device; -} - -static void iwl_pci_write8(struct iwl_bus *bus, u32 ofs, u8 val) -{ - iowrite8(val, IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs); -} - -static void iwl_pci_write32(struct iwl_bus *bus, u32 ofs, u32 val) -{ - iowrite32(val, IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs); -} - -static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs) -{ - u32 val = ioread32(IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs); - return val; -} - -static const struct iwl_bus_ops bus_ops_pci = { - .get_pm_support = iwl_pci_is_pm_supported, - .apm_config = iwl_pci_apm_config, - .get_hw_id_string = iwl_pci_get_hw_id_string, - .get_hw_id = iwl_pci_get_hw_id, - .write8 = iwl_pci_write8, - .write32 = iwl_pci_write32, - .read32 = iwl_pci_read32, -}; +#include "iwl-drv.h" +#include "iwl-trans.h" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -263,9 +158,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)}, {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)}, {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */ - {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */ + {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)}, + {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */ + {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */ /* 6x30 Series */ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)}, @@ -346,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {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, 0x4860, iwl6035_2agn_cfg)}, /* 105 Series */ {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, @@ -362,132 +258,71 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); +/* PCI registers */ +#define PCI_CFG_RETRY_TIMEOUT 0x041 + 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); - struct iwl_bus *bus; - struct iwl_pci_bus *pci_bus; - u16 pci_cmd; + struct iwl_shared *shrd; + struct iwl_trans *iwl_trans; int err; - bus = kzalloc(sizeof(*bus) + sizeof(*pci_bus), GFP_KERNEL); - if (!bus) { + shrd = kzalloc(sizeof(*iwl_trans->shrd), GFP_KERNEL); + if (!shrd) { dev_printk(KERN_ERR, &pdev->dev, - "Couldn't allocate iwl_pci_bus"); + "Couldn't allocate iwl_shared"); err = -ENOMEM; - goto out_no_pci; - } - - pci_bus = IWL_BUS_GET_PCI_BUS(bus); - pci_bus->pci_dev = pdev; - - pci_set_drvdata(pdev, bus); - - /* W/A - seems to solve weird behavior. We need to remove this if we - * don't want to stay in L1 all the time. This wastes a lot of power */ - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | - PCIE_LINK_STATE_CLKPM); - - if (pci_enable_device(pdev)) { - err = -ENODEV; - goto out_no_pci; + goto out_free_bus; } - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); - if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); - /* both attempts failed: */ - if (err) { - dev_printk(KERN_ERR, bus->dev, - "No suitable DMA available.\n"); - goto out_pci_disable_device; - } +#ifdef CONFIG_IWLWIFI_IDI + iwl_trans = iwl_trans_idi_alloc(shrd, pdev, ent); + if (iwl_trans == NULL) { + err = -ENOMEM; + goto out_free_bus; } - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - dev_printk(KERN_ERR, bus->dev, "pci_request_regions failed"); - goto out_pci_disable_device; - } + shrd->trans = iwl_trans; + pci_set_drvdata(pdev, iwl_trans); - pci_bus->hw_base = pci_iomap(pdev, 0, 0); - if (!pci_bus->hw_base) { - dev_printk(KERN_ERR, bus->dev, "pci_iomap failed"); - err = -ENODEV; - goto out_pci_release_regions; + err = iwl_drv_start(shrd, iwl_trans, cfg); +#else + iwl_trans = iwl_trans_pcie_alloc(shrd, pdev, ent); + if (iwl_trans == NULL) { + err = -ENOMEM; + goto out_free_bus; } - dev_printk(KERN_INFO, &pdev->dev, - "pci_resource_len = 0x%08llx\n", - (unsigned long long) pci_resource_len(pdev, 0)); - dev_printk(KERN_INFO, &pdev->dev, - "pci_resource_base = %p\n", pci_bus->hw_base); - - dev_printk(KERN_INFO, &pdev->dev, - "HW Revision ID = 0x%X\n", pdev->revision); + shrd->trans = iwl_trans; + pci_set_drvdata(pdev, iwl_trans); - /* 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); - - err = pci_enable_msi(pdev); + err = iwl_drv_start(shrd, iwl_trans, cfg); +#endif if (err) - dev_printk(KERN_ERR, &pdev->dev, - "pci_enable_msi failed(0X%x)", err); - - /* TODO: Move this away, not needed if not MSI */ - /* enable rfkill interrupt: hw bug w/a */ - pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); - if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { - pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); - } - - bus->dev = &pdev->dev; - bus->irq = pdev->irq; - bus->ops = &bus_ops_pci; + goto out_free_trans; - err = iwl_probe(bus, &trans_ops_pcie, cfg); - if (err) - goto out_disable_msi; return 0; -out_disable_msi: - pci_disable_msi(pdev); - pci_iounmap(pdev, pci_bus->hw_base); -out_pci_release_regions: +out_free_trans: + iwl_trans_free(iwl_trans); pci_set_drvdata(pdev, NULL); - pci_release_regions(pdev); -out_pci_disable_device: - pci_disable_device(pdev); -out_no_pci: - kfree(bus); +out_free_bus: + kfree(shrd); return err; } static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus); - struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); + struct iwl_shared *shrd = iwl_trans->shrd; - iwl_remove(shrd->priv); + iwl_drv_stop(shrd); + iwl_trans_free(shrd->trans); - pci_disable_msi(pci_dev); - pci_iounmap(pci_dev, pci_bus->hw_base); - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); - pci_set_drvdata(pci_dev, NULL); + pci_set_drvdata(pdev, NULL); - kfree(bus); + kfree(shrd); } #ifdef CONFIG_PM_SLEEP @@ -495,22 +330,20 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) static int iwl_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_trans_suspend(shrd->trans); + return iwl_trans_suspend(iwl_trans); } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -523,7 +356,7 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_trans_resume(shrd->trans); + return iwl_trans_resume(iwl_trans); } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 2b188a6..fd008c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. @@ -436,7 +436,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - priv->power_data.bus_pm = bus_get_pm_support(bus(priv)); + priv->power_data.bus_pm = trans(priv)->pm_support; priv->power_data.debug_sleep_level_override = -1; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 5f7b720..07a19fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 bebdd82..a4d1101 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index a645472..42ee1c4 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -218,7 +218,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) int iwl_scan_cancel(struct iwl_priv *priv) { IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); - queue_work(priv->shrd->workqueue, &priv->abort_scan); + queue_work(priv->workqueue, &priv->abort_scan); return 0; } @@ -354,7 +354,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, */ set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status); clear_bit(STATUS_SCAN_HW, &priv->shrd->status); - queue_work(priv->shrd->workqueue, &priv->scan_completed); + queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && iwl_advanced_bt_coexist(priv) && @@ -374,7 +374,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = scan_notif->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } return 0; @@ -414,10 +414,25 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) for_each_context(priv, ctx) { u16 value; - if (!iwl_is_associated_ctx(ctx)) - continue; - if (ctx->staging.dev_type == RXON_DEV_TYPE_P2P) + switch (ctx->staging.dev_type) { + case RXON_DEV_TYPE_P2P: + /* no timing constraints */ continue; + case RXON_DEV_TYPE_ESS: + default: + /* timing constraints if associated */ + if (!iwl_is_associated_ctx(ctx)) + continue; + break; + case RXON_DEV_TYPE_CP: + case RXON_DEV_TYPE_2STA: + /* + * These seem to always have timers for TBTT + * active in uCode even when not associated yet. + */ + break; + } + value = ctx->beacon_int; if (!value) value = IWL_PASSIVE_DWELL_BASE; @@ -935,7 +950,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, return ret; } - queue_delayed_work(priv->shrd->workqueue, &priv->scan_check, + queue_delayed_work(priv->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); return 0; @@ -948,7 +963,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, */ void iwl_internal_short_hw_scan(struct iwl_priv *priv) { - queue_work(priv->shrd->workqueue, &priv->start_internal_scan); + queue_work(priv->workqueue, &priv->start_internal_scan); } static void iwl_bg_start_internal_scan(struct work_struct *work) diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index dc55cc4..a644162 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,7 +94,6 @@ * This implementation is iwl-pci.c */ -struct iwl_bus; struct iwl_priv; struct iwl_trans; struct iwl_sensitivity_ranges; @@ -102,7 +101,7 @@ struct iwl_trans_ops; #define DRV_NAME "iwlwifi" #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation" #define DRV_AUTHOR "<ilw@linux.intel.com>" extern struct iwl_mod_params iwlagn_mod_params; @@ -173,8 +172,6 @@ struct iwl_mod_params { * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) * @sku: sku read from EEPROM * @rx_page_order: Rx buffer page order - * @max_inst_size: for ucode use - * @max_data_size: for ucode use * @ct_kill_threshold: temperature threshold - in hw dependent unit * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * relevant for 1000, 6000 and up @@ -192,8 +189,6 @@ struct iwl_hw_params { bool shadow_reg_enable; u16 sku; u32 rx_page_order; - u32 max_inst_size; - u32 max_data_size; u32 ct_kill_threshold; u32 ct_kill_exit_threshold; unsigned int wd_timeout; @@ -264,11 +259,13 @@ enum iwl_pa_type { * LED ON = RF ON * LED OFF = RF OFF * IWL_LED_BLINK: adjust led blink rate based on blink table + * IWL_LED_DISABLE: led disabled */ enum iwl_led_mode { IWL_LED_DEFAULT, IWL_LED_RF_STATE, IWL_LED_BLINK, + IWL_LED_DISABLE, }; /** @@ -281,6 +278,8 @@ enum iwl_led_mode { * @ucode_api_ok: oldest version of the uCode API that is OK to load * without a warning, for use in transitions * @ucode_api_min: Lowest version of uCode API supported by driver. + * @max_inst_size: The maximal length of the fw inst section + * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna * @sku: sku information from EEPROM @@ -318,6 +317,8 @@ struct iwl_cfg { const unsigned int ucode_api_max; const unsigned int ucode_api_ok; const unsigned int ucode_api_min; + const u32 max_data_size; + const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; u16 sku; @@ -356,8 +357,8 @@ struct iwl_cfg { * @cfg: see struct iwl_cfg * @priv: pointer to the upper layer data * @trans: pointer to the transport layer data + * @nic: pointer to the nic data * @hw_params: see struct iwl_hw_params - * @workqueue: the workqueue used by all the layers of the driver * @lock: protect general shared data * @sta_lock: protects the station table. * If lock and sta_lock are needed, lock must be acquired first. @@ -383,13 +384,12 @@ struct iwl_shared { bool wowlan; u8 valid_contexts; - struct iwl_bus *bus; struct iwl_cfg *cfg; struct iwl_priv *priv; struct iwl_trans *trans; + struct iwl_nic *nic; struct iwl_hw_params hw_params; - struct workqueue_struct *workqueue; spinlock_t lock; spinlock_t sta_lock; struct mutex mutex; @@ -414,10 +414,10 @@ struct iwl_shared { }; -/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */ +/*Whatever _m is (iwl_trans, iwl_priv, these macros will work */ #define priv(_m) ((_m)->shrd->priv) #define cfg(_m) ((_m)->shrd->cfg) -#define bus(_m) ((_m)->shrd->bus) +#define nic(_m) ((_m)->shrd->nic) #define trans(_m) ((_m)->shrd->trans) #define hw_params(_m) ((_m)->shrd->hw_params) @@ -529,26 +529,11 @@ enum iwl_rxon_context_id { NUM_IWL_RXON_CTX }; -int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, - struct iwl_cfg *cfg); -void __devexit iwl_remove(struct iwl_priv * priv); -struct iwl_device_cmd; -int __must_check iwl_rx_dispatch(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - struct iwl_device_cmd *cmd); - int iwlagn_hw_valid_rtc_data_addr(u32 addr); -void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); void iwl_nic_config(struct iwl_priv *priv); -void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb); -void iwl_apm_stop(struct iwl_priv *priv); -int iwl_apm_init(struct iwl_priv *priv); -void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); const char *get_cmd_string(u8 cmd); bool iwl_check_for_ct_kill(struct iwl_priv *priv); -void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac); -void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac); /* notification wait support */ void iwl_abort_notification_waits(struct iwl_shared *shrd); @@ -568,20 +553,6 @@ void __releases(wait_entry) iwl_remove_notification(struct iwl_shared *shrd, struct iwl_notification_wait *wait_entry); -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_reset_traffic_log(struct iwl_priv *priv); -#endif /* CONFIG_IWLWIFI_DEBUGFS */ - -#ifdef CONFIG_IWLWIFI_DEBUG -void iwl_print_rx_config_cmd(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid); -#else -static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid) -{ -} -#endif - #define IWL_CMD(x) case x: return #x #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index 4a5cddd..23eea06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -78,7 +78,14 @@ #include "iwl-agn.h" #include "iwl-testmode.h" #include "iwl-trans.h" -#include "iwl-bus.h" +#include "iwl-fh.h" + + +/* Periphery registers absolute lower bound. This is used in order to + * differentiate registery access through HBUS_TARG_PRPH_* and + * HBUS_TARG_MEM_* accesses. + */ +#define IWL_TM_ABS_PRPH_START (0xA00000) /* 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 @@ -109,12 +116,15 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, }, - [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, }, [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, }, [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, }, + [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, }, }; /* @@ -168,7 +178,7 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, GFP_ATOMIC); if (skb == NULL) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Run out of memory for messages to user space ?\n"); return; } @@ -179,24 +189,24 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, nla_put_failure: kfree_skb(skb); - IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); + IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n"); } void iwl_testmode_init(struct iwl_priv *priv) { priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; priv->testmode_trace.trace_enabled = false; - priv->testmode_sram.sram_readed = false; + priv->testmode_mem.read_in_progress = false; } -static void iwl_sram_cleanup(struct iwl_priv *priv) +static void iwl_mem_cleanup(struct iwl_priv *priv) { - if (priv->testmode_sram.sram_readed) { - kfree(priv->testmode_sram.buff_addr); - priv->testmode_sram.buff_addr = NULL; - priv->testmode_sram.buff_size = 0; - priv->testmode_sram.num_chunks = 0; - priv->testmode_sram.sram_readed = false; + if (priv->testmode_mem.read_in_progress) { + kfree(priv->testmode_mem.buff_addr); + priv->testmode_mem.buff_addr = NULL; + priv->testmode_mem.buff_size = 0; + priv->testmode_mem.num_chunks = 0; + priv->testmode_mem.read_in_progress = false; } } @@ -205,7 +215,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) if (priv->testmode_trace.trace_enabled) { if (priv->testmode_trace.cpu_addr && priv->testmode_trace.dma_addr) - dma_free_coherent(bus(priv)->dev, + dma_free_coherent(trans(priv)->dev, priv->testmode_trace.total_size, priv->testmode_trace.cpu_addr, priv->testmode_trace.dma_addr); @@ -222,9 +232,10 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) void iwl_testmode_cleanup(struct iwl_priv *priv) { iwl_trace_cleanup(priv); - iwl_sram_cleanup(priv); + iwl_mem_cleanup(priv); } + /* * This function handles the user application commands to the ucode. * @@ -233,35 +244,80 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) * 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. + * application; otherwise, waits for the host command to be sent and checks + * the return code. In case or error, it is returned, otherwise a reply is + * allocated and the reply RX packet + * is returned. * * @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_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_host_cmd cmd; + struct iwl_rx_packet *pkt; + struct sk_buff *skb; + void *reply_buf; + u32 reply_len; + int ret; + bool cmd_want_skb; 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"); + IWL_ERR(priv, "Missing ucode command mandatory fields\n"); return -ENOMSG; } - cmd.flags = CMD_ON_DEMAND; + cmd.flags = CMD_ON_DEMAND | CMD_SYNC; + cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]); + if (cmd_want_skb) + cmd.flags |= CMD_WANT_SKB; + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," " len %d\n", cmd.id, cmd.flags, cmd.len[0]); - /* ok, let's submit the command to ucode */ - return iwl_trans_send_cmd(trans(priv), &cmd); + + ret = iwl_trans_send_cmd(trans(priv), &cmd); + if (ret) { + IWL_ERR(priv, "Failed to send hcmd\n"); + return ret; + } + if (!cmd_want_skb) + return ret; + + /* Handling return of SKB to the user */ + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (!pkt) { + IWL_ERR(priv, "HCMD received a null response packet\n"); + return ret; + } + + reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20); + reply_buf = kmalloc(reply_len, GFP_KERNEL); + if (!skb || !reply_buf) { + kfree_skb(skb); + kfree(reply_buf); + return -ENOMEM; + } + + /* The reply is in a page, that we cannot send to user space. */ + memcpy(reply_buf, &(pkt->hdr), reply_len); + iwl_free_pages(priv->shrd, cmd.reply_page); + + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf); + return cfg80211_testmode_reply(skb); + +nla_put_failure: + IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n"); + return -ENOMSG; } @@ -284,84 +340,69 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) */ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; - u32 ofs, val32; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + u32 ofs, val32, cmd; 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"); + IWL_ERR(priv, "Missing 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])) { + /* Allow access only to FH/CSR/HBUS in direct mode. + Since we don't have the upper bounds for the CSR and HBUS segments, + we will use only the upper bound of FH for sanity check. */ + cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); + if ((cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 || + cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 || + cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) && + (ofs >= FH_MEM_UPPER_BOUND)) { + IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n", + FH_MEM_UPPER_BOUND); + return -EINVAL; + } + + switch (cmd) { case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: - val32 = iwl_read32(bus(priv), ofs); + val32 = iwl_read_direct32(trans(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"); + IWL_ERR(priv, "Memory allocation fail\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); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_DEBUG_INFO(priv, - "Error finding value to write\n"); + IWL_ERR(priv, "Missing 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(bus(priv), ofs, val32); + iwl_write_direct32(trans(priv), ofs, val32); } break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: if (!tb[IWL_TM_ATTR_REG_VALUE8]) { - IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + IWL_ERR(priv, "Missing 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(bus(priv), ofs, val8); - } - break; - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - val32 = iwl_read_prph(bus(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_INDIRECT_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_write_prph(bus(priv), ofs, val32); + iwl_write8(trans(priv), ofs, val8); } break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + IWL_ERR(priv, "Unknown testmode register command ID\n"); return -ENOSYS; } @@ -383,14 +424,13 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) NULL, NULL); ret = iwl_init_alive_start(trans(priv)); if (ret) { - IWL_DEBUG_INFO(priv, - "Error configuring init calibration: %d\n", ret); + IWL_ERR(priv, "Fail init calibration: %d\n", ret); goto cfg_init_calib_error; } ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ); if (ret) - IWL_DEBUG_INFO(priv, "Error detecting" + IWL_ERR(priv, "Error detecting" " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); return ret; @@ -417,12 +457,12 @@ cfg_init_calib_error: */ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_trans *trans = trans(priv); struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; int status = 0, rsp_data_len = 0; - u32 devid; + u32 devid, inst_size = 0, data_size = 0; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: @@ -431,8 +471,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -441,15 +480,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) rsp_data_len, rsp_data_ptr); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (status) - IWL_DEBUG_INFO(priv, - "Error loading init ucode: %d\n", status); + IWL_ERR(priv, "Error loading init ucode: %d\n", status); break; case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: @@ -460,13 +497,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading runtime ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -475,13 +512,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trans_stop_device(trans); status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading WOWLAN ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -490,8 +527,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, cfg(priv)->base_params->eeprom_size + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -501,55 +537,87 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", + status); } else return -EFAULT; break; case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: if (!tb[IWL_TM_ATTR_FIXRATE]) { - IWL_DEBUG_INFO(priv, - "Error finding fixrate setting\n"); + IWL_ERR(priv, "Missing fixrate setting\n"); return -ENOMSG; } priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); break; case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: - IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); + IWL_INFO(priv, "uCode version raw: 0x%x\n", + nic(priv)->fw.ucode_ver); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, + nic(priv)->fw.ucode_ver); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: - devid = bus_get_hw_id(bus(priv)); + devid = trans(priv)->hw_id; IWL_INFO(priv, "hw version: 0x%x\n", devid); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); + break; + + case IWL_TM_CMD_APP2DEV_GET_FW_INFO: + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8); + if (!skb) { + IWL_ERR(priv, "Memory allocation fail\n"); + return -ENOMEM; + } + switch (priv->shrd->ucode_type) { + case IWL_UCODE_REGULAR: + inst_size = nic(priv)->fw.ucode_rt.code.len; + data_size = nic(priv)->fw.ucode_rt.data.len; + break; + case IWL_UCODE_INIT: + inst_size = nic(priv)->fw.ucode_init.code.len; + data_size = nic(priv)->fw.ucode_init.data.len; + break; + case IWL_UCODE_WOWLAN: + inst_size = nic(priv)->fw.ucode_wowlan.code.len; + data_size = nic(priv)->fw.ucode_wowlan.data.len; + break; + case IWL_UCODE_NONE: + IWL_ERR(priv, "No uCode has not been loaded\n"); + break; + default: + IWL_ERR(priv, "Unsupported uCode type\n"); + break; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size); + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_ERR(priv, "Error sending msg : %d\n", status); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + IWL_ERR(priv, "Unknown testmode driver command ID\n"); return -ENOSYS; } return status; @@ -574,10 +642,10 @@ nla_put_failure: */ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct sk_buff *skb; int status = 0; - struct device *dev = bus(priv)->dev; + struct device *dev = trans(priv)->dev; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: @@ -612,8 +680,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, sizeof(priv->testmode_trace.dma_addr) + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); iwl_trace_cleanup(priv); return -ENOMEM; } @@ -622,9 +689,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) (u64 *)&priv->testmode_trace.dma_addr); status = cfg80211_testmode_reply(skb); if (status < 0) { - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); } priv->testmode_trace.num_chunks = DIV_ROUND_UP(priv->testmode_trace.buff_size, @@ -635,7 +700,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trace_cleanup(priv); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); + IWL_ERR(priv, "Unknown testmode mem command ID\n"); return -ENOSYS; } return status; @@ -652,7 +717,7 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb, struct sk_buff *skb, struct netlink_callback *cb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int idx, length; if (priv->testmode_trace.trace_enabled && @@ -696,11 +761,11 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb, */ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); u8 owner; if (!tb[IWL_TM_ATTR_UCODE_OWNER]) { - IWL_DEBUG_INFO(priv, "Error finding ucode owner\n"); + IWL_ERR(priv, "Missing ucode owner\n"); return -ENOMSG; } @@ -708,9 +773,86 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) priv->shrd->ucode_owner = owner; else { - IWL_DEBUG_INFO(priv, "Invalid owner\n"); + IWL_ERR(priv, "Invalid owner\n"); + return -EINVAL; + } + return 0; +} + +static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) +{ + struct iwl_trans *trans = trans(priv); + unsigned long flags; + int i; + + if (size & 0x3) return -EINVAL; + priv->testmode_mem.buff_size = size; + priv->testmode_mem.buff_addr = + kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL); + if (priv->testmode_mem.buff_addr == NULL) + return -ENOMEM; + + /* Hard-coded periphery absolute address */ + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_RADDR, + addr | (3 << 24)); + for (i = 0; i < size; i += 4) + *(u32 *)(priv->testmode_mem.buff_addr + i) = + iwl_read32(trans, HBUS_TARG_PRPH_RDAT); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { /* target memory (SRAM) */ + _iwl_read_targ_mem_words(trans, addr, + priv->testmode_mem.buff_addr, + priv->testmode_mem.buff_size / 4); } + + priv->testmode_mem.num_chunks = + DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE); + priv->testmode_mem.read_in_progress = true; + return 0; + +} + +static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, + u32 size, unsigned char *buf) +{ + struct iwl_trans *trans = trans(priv); + u32 val, i; + unsigned long flags; + + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + /* Periphery writes can be 1-3 bytes long, or DWORDs */ + if (size < 4) { + memcpy(&val, buf, size); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, + (addr & 0x0000FFFF) | + ((size - 1) << 24)); + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); + iwl_release_nic_access(trans); + /* needed after consecutive writes w/o read */ + mmiowb(); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { + if (size % 4) + return -EINVAL; + for (i = 0; i < size; i += 4) + iwl_write_prph(trans, addr+i, + *(u32 *)(buf+i)); + } + } else if (iwlagn_hw_valid_rtc_data_addr(addr) || + (IWLAGN_RTC_INST_LOWER_BOUND <= addr && + addr < IWLAGN_RTC_INST_UPPER_BOUND)) { + _iwl_write_targ_mem_words(trans, addr, buf, size/4); + } else + return -EINVAL; return 0; } @@ -730,83 +872,60 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ -static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) +static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw, + struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; - u32 base, ofs, size, maxsize; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + u32 addr, size, cmd; + unsigned char *buf; - if (priv->testmode_sram.sram_readed) + /* Both read and write should be blocked, for atomicity */ + if (priv->testmode_mem.read_in_progress) return -EBUSY; - if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { - IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); + cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); + if (!tb[IWL_TM_ATTR_MEM_ADDR]) { + IWL_ERR(priv, "Error finding memory offset address\n"); return -ENOMSG; } - ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); - if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { - IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); + addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]); + if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) { + IWL_ERR(priv, "Error finding size for memory reading\n"); return -ENOMSG; } - size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); - switch (priv->shrd->ucode_type) { - case IWL_UCODE_REGULAR: - maxsize = trans(priv)->ucode_rt.data.len; - break; - case IWL_UCODE_INIT: - maxsize = trans(priv)->ucode_init.data.len; - break; - case IWL_UCODE_WOWLAN: - maxsize = trans(priv)->ucode_wowlan.data.len; - break; - case IWL_UCODE_NONE: - IWL_DEBUG_INFO(priv, "Error, uCode does not been loaded\n"); - return -ENOSYS; - default: - IWL_DEBUG_INFO(priv, "Error, unsupported uCode type\n"); - return -ENOSYS; - } - if ((ofs + size) > maxsize) { - IWL_DEBUG_INFO(priv, "Invalid offset/size: out of range\n"); - return -EINVAL; - } - priv->testmode_sram.buff_size = (size / 4) * 4; - priv->testmode_sram.buff_addr = - kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); - if (priv->testmode_sram.buff_addr == NULL) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); - return -ENOMEM; + size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]); + + if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) + return iwl_testmode_indirect_read(priv, addr, size); + else { + if (!tb[IWL_TM_ATTR_BUFFER_DUMP]) + return -EINVAL; + buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]); + return iwl_testmode_indirect_write(priv, addr, size, buf); } - base = 0x800000; - _iwl_read_targ_mem_words(bus(priv), base + ofs, - priv->testmode_sram.buff_addr, - priv->testmode_sram.buff_size / 4); - priv->testmode_sram.num_chunks = - DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); - priv->testmode_sram.sram_readed = true; - return 0; } -static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, +static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, struct nlattr **tb, struct sk_buff *skb, struct netlink_callback *cb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int idx, length; - if (priv->testmode_sram.sram_readed) { + if (priv->testmode_mem.read_in_progress) { idx = cb->args[4]; - if (idx >= priv->testmode_sram.num_chunks) { - iwl_sram_cleanup(priv); + if (idx >= priv->testmode_mem.num_chunks) { + iwl_mem_cleanup(priv); return -ENOENT; } length = DUMP_CHUNK_SIZE; - if (((idx + 1) == priv->testmode_sram.num_chunks) && - (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE)) - length = priv->testmode_sram.buff_size % + if (((idx + 1) == priv->testmode_mem.num_chunks) && + (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE)) + length = priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE; - NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length, - priv->testmode_sram.buff_addr + + NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length, + priv->testmode_mem.buff_addr + (DUMP_CHUNK_SIZE * idx)); idx++; cb->args[4] = idx; @@ -841,20 +960,19 @@ static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 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); + IWL_ERR(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"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } /* in case multiple accesses to the device happens */ @@ -868,8 +986,6 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); result = iwl_testmode_reg(hw, tb); break; @@ -882,6 +998,7 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: + case IWL_TM_CMD_APP2DEV_GET_FW_INFO: IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); result = iwl_testmode_driver(hw, tb); break; @@ -898,13 +1015,15 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) result = iwl_testmode_ownership(hw, tb); break; - case IWL_TM_CMD_APP2DEV_READ_SRAM: - IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n"); - result = iwl_testmode_sram(hw, tb); + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + IWL_DEBUG_INFO(priv, "testmode indirect memory cmd " + "to driver\n"); + result = iwl_testmode_indirect_mem(hw, tb); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + IWL_ERR(priv, "Unknown testmode command\n"); result = -ENOSYS; break; } @@ -918,7 +1037,7 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int result; u32 cmd; @@ -929,15 +1048,14 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result) { - IWL_DEBUG_INFO(priv, - "Error parsing the gnl message : %d\n", result); + IWL_ERR(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"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); @@ -951,9 +1069,9 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); result = iwl_testmode_trace_dump(hw, tb, skb, cb); break; - case IWL_TM_CMD_APP2DEV_DUMP_SRAM: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n"); - result = iwl_testmode_sram_dump(hw, tb, skb, cb); + result = iwl_testmode_buffer_dump(hw, tb, skb, cb); break; default: result = -EINVAL; diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index 26138f1..69b2e80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -99,7 +99,7 @@ * to user application * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT: * commands from kernel space to multicast the spontaneous messages - * to user application + * to user application, or reply of host commands * @IWL_TM_CMD_DEV2APP_EEPROM_RSP: * commands from kernel space to carry the eeprom response * to user application @@ -109,18 +109,19 @@ * if application has the ownership, the only host command from * testmode will deliver to uCode. Default owner is driver * - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: - * commands from user applicaiton to indirectly access peripheral register - * - * @IWL_TM_CMD_APP2DEV_READ_SRAM: - * @IWL_TM_CMD_APP2DEV_DUMP_SRAM: - * commands from user applicaiton to read data in sram - * - * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Weak On Wireless LAN uCode image + * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Wake On Wireless LAN uCode image * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device - * + * @IWL_TM_CMD_APP2DEV_GET_FW_INFO: + * retrieve information of existing loaded uCode image + * + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + * Commands to read/write data from periphery or SRAM memory ranges. + * Fore reading, a READ command is sent from the userspace and the data + * is returned when the user calls a DUMP command. + * For writing, only a WRITE command is used. */ enum iwl_tm_cmd_t { IWL_TM_CMD_APP2DEV_UCODE = 1, @@ -140,14 +141,18 @@ enum iwl_tm_cmd_t { IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, IWL_TM_CMD_APP2DEV_OWNERSHIP = 17, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19, - IWL_TM_CMD_APP2DEV_READ_SRAM = 20, - IWL_TM_CMD_APP2DEV_DUMP_SRAM = 21, + RESERVED_18 = 18, + RESERVED_19 = 19, + RESERVED_20 = 20, + RESERVED_21 = 21, IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW = 22, IWL_TM_CMD_APP2DEV_GET_FW_VERSION = 23, IWL_TM_CMD_APP2DEV_GET_DEVICE_ID = 24, - IWL_TM_CMD_MAX = 25, + IWL_TM_CMD_APP2DEV_GET_FW_INFO = 25, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28, + IWL_TM_CMD_MAX = 29, }; /* @@ -168,8 +173,6 @@ enum iwl_tm_cmd_t { * 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 * @@ -218,16 +221,19 @@ enum iwl_tm_cmd_t { * The mandatory fields are: * IWL_TM_ATTR_UCODE_OWNER for the new owner * - * @IWL_TM_ATTR_SRAM_ADDR: - * @IWL_TM_ATTR_SRAM_SIZE: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM, + * @IWL_TM_ATTR_MEM_ADDR: + * @IWL_TM_ATTR_BUFFER_SIZE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ + * or IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE. * The mandatory fields are: - * IWL_TM_ATTR_SRAM_ADDR for the address in sram - * IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading + * IWL_TM_ATTR_MEM_ADDR for the address in SRAM/periphery to read/write + * IWL_TM_ATTR_BUFFER_SIZE for the buffer size of data to read/write. * - * @IWL_TM_ATTR_SRAM_DUMP: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM, - * IWL_TM_ATTR_SRAM_DUMP for the data in sram + * @IWL_TM_ATTR_BUFFER_DUMP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP, + * IWL_TM_ATTR_BUFFER_DUMP is used for the data that was read. + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE, + * this attribute contains the data to write. * * @IWL_TM_ATTR_FW_VERSION: * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION, @@ -237,6 +243,19 @@ enum iwl_tm_cmd_t { * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_DEVICE_ID, * IWL_TM_ATTR_DEVICE_ID for the device ID information * + * @IWL_TM_ATTR_FW_TYPE: + * @IWL_TM_ATTR_FW_INST_SIZE: + * @IWL_TM_ATTR_FW_DATA_SIZE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_INFO, + * The mandatory fields are: + * IWL_TM_ATTR_FW_TYPE for the uCode type (INIT/RUNTIME/...) + * IWL_TM_ATTR_FW_INST_SIZE for the size of instruction section + * IWL_TM_ATTR_FW_DATA_SIZE for the size of data section + * + * @IWL_TM_ATTR_UCODE_CMD_SKB: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag + * indicates that the user wants to receive the response of the command + * in a reply SKB. If it's not present, the response is not returned. */ enum iwl_tm_attr_t { IWL_TM_ATTR_NOT_APPLICABLE = 0, @@ -254,12 +273,16 @@ enum iwl_tm_attr_t { IWL_TM_ATTR_TRACE_DUMP = 12, IWL_TM_ATTR_FIXRATE = 13, IWL_TM_ATTR_UCODE_OWNER = 14, - IWL_TM_ATTR_SRAM_ADDR = 15, - IWL_TM_ATTR_SRAM_SIZE = 16, - IWL_TM_ATTR_SRAM_DUMP = 17, + IWL_TM_ATTR_MEM_ADDR = 15, + IWL_TM_ATTR_BUFFER_SIZE = 16, + IWL_TM_ATTR_BUFFER_DUMP = 17, IWL_TM_ATTR_FW_VERSION = 18, IWL_TM_ATTR_DEVICE_ID = 19, - IWL_TM_ATTR_MAX = 20, + IWL_TM_ATTR_FW_TYPE = 20, + IWL_TM_ATTR_FW_INST_SIZE = 21, + IWL_TM_ATTR_FW_DATA_SIZE = 22, + IWL_TM_ATTR_UCODE_CMD_SKB = 23, + IWL_TM_ATTR_MAX = 24, }; /* uCode trace buffer */ @@ -271,4 +294,7 @@ enum iwl_tm_attr_t { /* Maximum data size of each dump it packet */ #define DUMP_CHUNK_SIZE (PAGE_SIZE - 1024) +/* Address offset of data segment in SRAM */ +#define SRAM_DATA_SEG_OFFSET 0x800000 + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index f6debf9..5b26b71 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -40,6 +40,7 @@ #include "iwl-trans.h" #include "iwl-debug.h" #include "iwl-io.h" +#include "iwl-op-mode.h" struct iwl_tx_queue; struct iwl_queue; @@ -201,6 +202,7 @@ struct iwl_tx_queue { * @rxq: all the RX queue data * @rx_replenish: work that will be called when buffers need to be allocated * @trans: pointer to the generic transport area + * @irq_requested: true when the irq has been requested * @scd_base_addr: scheduler sram base address in SRAM * @scd_bc_tbls: pointer to the byte count table of the scheduler * @kw: keep warm address @@ -211,6 +213,8 @@ struct iwl_tx_queue { * @txq_ctx_active_msk: what queue is active * queue_stopped: tracks what queue is stopped * queue_stop_count: tracks what SW queue is stopped + * @pci_dev: basic pci-network driver stuff + * @hw_base: pci hardware address support */ struct iwl_trans_pcie { struct iwl_rx_queue rxq; @@ -223,9 +227,11 @@ struct iwl_trans_pcie { int ict_index; u32 inta; bool use_ict; + bool irq_requested; struct tasklet_struct irq_tasklet; struct isr_statistics isr_stats; + spinlock_t irq_lock; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; @@ -241,6 +247,10 @@ struct iwl_trans_pcie { #define IWL_MAX_HW_QUEUES 32 unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; atomic_t queue_stop_count[4]; + + /* PCI bus related data */ + struct pci_dev *pci_dev; + void __iomem *hw_base; }; #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ @@ -258,7 +268,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, /***************************************************** * ICT ******************************************************/ -int iwl_reset_ict(struct iwl_trans *trans); +void iwl_reset_ict(struct iwl_trans *trans); void iwl_disable_ict(struct iwl_trans *trans); int iwl_alloc_isr_ict(struct iwl_trans *trans); void iwl_free_isr_ict(struct iwl_trans *trans); @@ -311,12 +321,12 @@ static inline void iwl_disable_interrupts(struct iwl_trans *trans) clear_bit(STATUS_INT_ENABLED, &trans->shrd->status); /* disable interrupts from uCode/NIC to host */ - iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + iwl_write32(trans, CSR_INT_MASK, 0x00000000); /* acknowledge/clear/reset any interrupts still pending * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(bus(trans), CSR_INT, 0xffffffff); - iwl_write32(bus(trans), CSR_FH_INT_STATUS, 0xffffffff); + iwl_write32(trans, CSR_INT, 0xffffffff); + iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } @@ -327,7 +337,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &trans->shrd->status); - iwl_write32(bus(trans), CSR_INT_MASK, trans_pcie->inta_mask); + iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } /* @@ -365,7 +375,7 @@ static inline void iwl_wake_queue(struct iwl_trans *trans, if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) { if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) { - iwl_wake_sw_queue(priv(trans), ac); + iwl_op_mode_queue_not_full(trans->op_mode, ac); IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s", hwq, ac, msg); } else { @@ -388,7 +398,7 @@ static inline void iwl_stop_queue(struct iwl_trans *trans, if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) { if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) { - iwl_stop_sw_queue(priv(trans), ac); + iwl_op_mode_queue_full(trans->op_mode, ac); IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d" " stop count %d. %s", hwq, ac, atomic_read(&trans_pcie-> diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 65d1f05..2c910fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -34,6 +34,12 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-trans-pcie-int.h" +#include "iwl-wifi.h" +#include "iwl-op-mode.h" + +#ifdef CONFIG_IWLWIFI_IDI +#include "iwl-amfh.h" +#endif /****************************************************************************** * @@ -140,30 +146,30 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, /* shadow register enabled */ /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); - iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual); + iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); } else { /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { - reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); + reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup," " GP1 = 0x%x\n", reg); - iwl_set_bit(bus(trans), CSR_GP_CNTRL, + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; } q->write_actual = (q->write & ~0x7); - iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, + iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); /* Else device is assumed to be awake */ } else { /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); - iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, + iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); } } @@ -223,7 +229,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) /* If the pre-allocated buffer pool is dropping low, schedule to * refill it */ if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); + schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. @@ -308,7 +314,7 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) BUG_ON(rxb->page); rxb->page = page; /* Get physical address of the RB */ - rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0, + rxb->page_dma = dma_map_page(trans->dev, page, 0, PAGE_SIZE << hw_params(trans).rx_page_order, DMA_FROM_DEVICE); /* dma address must be no more than 36 bits */ @@ -327,13 +333,14 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) void iwlagn_rx_replenish(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; iwlagn_rx_allocate(trans, GFP_KERNEL); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwlagn_rx_queue_restock(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static void iwlagn_rx_replenish_now(struct iwl_trans *trans) @@ -347,14 +354,8 @@ void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - struct iwl_trans *trans = trans_pcie->trans; - - if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) - return; - mutex_lock(&trans->shrd->mutex); - iwlagn_rx_replenish(trans); - mutex_unlock(&trans->shrd->mutex); + iwlagn_rx_replenish(trans_pcie->trans); } /** @@ -414,7 +415,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) rxq->queue[i] = NULL; - dma_unmap_page(bus(trans)->dev, rxb->page_dma, + dma_unmap_page(trans->dev, rxb->page_dma, PAGE_SIZE << hw_params(trans).rx_page_order, DMA_FROM_DEVICE); pkt = rxb_addr(rxb); @@ -460,7 +461,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) "reclaim is false, SEQ_RX_FRAME unset: %s\n", get_cmd_string(pkt->hdr.cmd)); - err = iwl_rx_dispatch(priv(trans), rxb, cmd); + err = iwl_op_mode_rx(trans->op_mode, rxb, cmd); /* * XXX: After here, we should always check rxb->page @@ -485,7 +486,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) * rx_free list for reuse later. */ spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { - rxb->page_dma = dma_map_page(bus(trans)->dev, rxb->page, + rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, PAGE_SIZE << hw_params(trans).rx_page_order, DMA_FROM_DEVICE); @@ -590,17 +591,17 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) { u32 base; struct iwl_error_event_table table; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); base = trans->shrd->device_pointers.error_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_errlog_ptr; + base = nic->init_errlog_ptr; } else { if (!base) - base = priv->inst_errlog_ptr; + base = nic->inst_errlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { @@ -612,7 +613,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) return; } - iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table)); + iwl_read_targ_mem_words(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -622,7 +623,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) trans_pcie->isr_stats.err_code = table.error_id; - trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, + trace_iwlwifi_dev_ucode_error(priv(nic), table.error_id, table.tsf_low, table.data1, table.data2, table.line, table.blink1, table.blink2, table.ilink1, table.ilink2, table.bcon_time, table.gp1, @@ -670,12 +671,11 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) */ static void iwl_irq_handle_error(struct iwl_trans *trans) { - struct iwl_priv *priv = priv(trans); /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ - if (cfg(priv)->internal_wimax_coex && - (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & + if (cfg(trans)->internal_wimax_coex && + (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || - (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & + (iwl_read_prph(trans, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { /* * Keep the restart process from trying to send host @@ -683,24 +683,20 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) */ clear_bit(STATUS_READY, &trans->shrd->status); clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); - wake_up(&priv->shrd->wait_command_queue); + wake_up(&trans->shrd->wait_command_queue); IWL_ERR(trans, "RF is used by WiMAX\n"); return; } IWL_ERR(trans, "Loaded firmware version: %s\n", - priv->hw->wiphy->fw_version); + nic(trans)->fw.fw_version); iwl_dump_nic_error_log(trans); iwl_dump_csr(trans); iwl_dump_fh(trans, NULL, false); iwl_dump_nic_event_log(trans, false, NULL, false); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) - iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); -#endif - iwlagn_fw_error(priv, false); + iwl_op_mode_nic_error(trans->op_mode); } #define EVENT_START_OFFSET (4 * sizeof(u32)) @@ -719,7 +715,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ unsigned long reg_flags; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); if (num_events == 0) return pos; @@ -727,10 +723,10 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (mode == 0) @@ -741,18 +737,18 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags); - iwl_grab_nic_access(bus(trans)); + spin_lock_irqsave(&trans->reg_lock, reg_flags); + iwl_grab_nic_access(trans); /* Set starting address; reads will auto-increment */ - iwl_write32(bus(trans), HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(trans, 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_read32(bus(trans), HBUS_TARG_MEM_RDAT); - time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); + ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + time = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -760,13 +756,13 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { - trace_iwlwifi_dev_ucode_event(priv, 0, + trace_iwlwifi_dev_ucode_event(priv(trans), 0, time, ev); IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", time, ev); } } else { - data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); + data = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -774,15 +770,15 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, } else { IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, + trace_iwlwifi_dev_ucode_event(priv(trans), time, data, ev); } } } /* Allow device to power down */ - iwl_release_nic_access(bus(trans)); - spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, reg_flags); return pos; } @@ -836,17 +832,17 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, u32 logsize; int pos = 0; size_t bufsz = 0; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - logsize = priv->init_evtlog_size; + logsize = nic->init_evtlog_size; if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { - logsize = priv->inst_evtlog_size; + logsize = nic->inst_evtlog_size; if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { @@ -859,10 +855,10 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, } /* event log header */ - capacity = iwl_read_targ_mem(bus(trans), base); - mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); + capacity = iwl_read_targ_mem(trans, base); + mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); if (capacity > logsize) { IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " @@ -945,7 +941,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, @@ -958,7 +954,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) * hardware bugs here by ACKing all the possible interrupts so that * interrupt coalescing can still be achieved. */ - iwl_write32(bus(trans), CSR_INT, + iwl_write32(trans, CSR_INT, trans_pcie->inta | ~trans_pcie->inta_mask); inta = trans_pcie->inta; @@ -966,7 +962,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) { /* just for debug */ - inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); + inta_mask = iwl_read32(trans, CSR_INT_MASK); IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", inta, inta_mask); } @@ -975,7 +971,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* saved interrupt in inta variable now we can reset trans_pcie->inta */ trans_pcie->inta = 0; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { @@ -1014,7 +1010,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* HW RF KILL switch toggled */ if (inta & CSR_INT_BIT_RF_KILL) { int hw_rf_kill = 0; - if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & + if (!(iwl_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; @@ -1035,7 +1031,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) else clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); - iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1078,12 +1074,12 @@ void iwl_irq_tasklet(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Rx interrupt\n"); 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(bus(trans), CSR_FH_INT_STATUS, + iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; - iwl_write32(bus(trans), + iwl_write32(trans, CSR_INT, CSR_INT_BIT_RX_PERIODIC); } /* Sending RX interrupt require many steps to be done in the @@ -1098,10 +1094,13 @@ void iwl_irq_tasklet(struct iwl_trans *trans) */ /* Disable periodic interrupt; we use it as just a one-shot. */ - iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, + iwl_write8(trans, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); +#ifdef CONFIG_IWLWIFI_IDI + iwl_amfh_rx_handler(); +#else iwl_rx_handle(trans); - +#endif /* * Enable periodic interrupt in 8 msec only if we received * real RX interrupt (instead of just periodic int), to catch @@ -1110,7 +1109,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) * to extend the periodic interrupt; one-shot is enough. */ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) - iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, + iwl_write8(trans, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_ENA); isr_stats->rx++; @@ -1118,7 +1117,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); + iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); isr_stats->tx++; handled |= CSR_INT_BIT_FH_TX; @@ -1142,8 +1141,10 @@ void iwl_irq_tasklet(struct iwl_trans *trans) if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status)) iwl_enable_interrupts(trans); /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv(trans)); + else if (handled & CSR_INT_BIT_RF_KILL) { + IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); + iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); + } } /****************************************************************************** @@ -1164,7 +1165,7 @@ void iwl_free_isr_ict(struct iwl_trans *trans) IWL_TRANS_GET_PCIE_TRANS(trans); if (trans_pcie->ict_tbl) { - dma_free_coherent(bus(trans)->dev, ICT_SIZE, + dma_free_coherent(trans->dev, ICT_SIZE, trans_pcie->ict_tbl, trans_pcie->ict_tbl_dma); trans_pcie->ict_tbl = NULL; @@ -1184,7 +1185,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans) IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->ict_tbl = - dma_alloc_coherent(bus(trans)->dev, ICT_SIZE, + dma_alloc_coherent(trans->dev, ICT_SIZE, &trans_pcie->ict_tbl_dma, GFP_KERNEL); if (!trans_pcie->ict_tbl) @@ -1213,7 +1214,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans) /* Device is going up inform it about using ICT interrupt table, * also we need to tell the driver to start using ICT interrupt. */ -int iwl_reset_ict(struct iwl_trans *trans) +void iwl_reset_ict(struct iwl_trans *trans) { u32 val; unsigned long flags; @@ -1221,9 +1222,9 @@ int iwl_reset_ict(struct iwl_trans *trans) IWL_TRANS_GET_PCIE_TRANS(trans); if (!trans_pcie->ict_tbl) - return 0; + return; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); memset(trans_pcie->ict_tbl, 0, ICT_SIZE); @@ -1235,14 +1236,12 @@ int iwl_reset_ict(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); - iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); + iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val); trans_pcie->use_ict = true; trans_pcie->ict_index = 0; - iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask); + iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); - - return 0; + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* Device is going down disable ict interrupt usage */ @@ -1253,9 +1252,9 @@ void iwl_disable_ict(struct iwl_trans *trans) unsigned long flags; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->use_ict = false; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static irqreturn_t iwl_isr(int irq, void *data) @@ -1274,17 +1273,17 @@ static irqreturn_t iwl_isr(int irq, void *data) trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_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(bus(trans), CSR_INT_MASK); /* just for debug */ - iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ + iwl_write32(trans, CSR_INT_MASK, 0x00000000); /* Discover which interrupts are active/pending */ - inta = iwl_read32(bus(trans), CSR_INT); + inta = iwl_read32(trans, CSR_INT); /* Ignore interrupt if there's nothing in NIC to service. * This may be due to IRQ shared with another device, @@ -1303,7 +1302,7 @@ static irqreturn_t iwl_isr(int irq, void *data) #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { - inta_fh = iwl_read32(bus(trans), CSR_FH_INT_STATUS); + inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); } @@ -1318,7 +1317,7 @@ static irqreturn_t iwl_isr(int irq, void *data) iwl_enable_interrupts(trans); unplugged: - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1328,7 +1327,7 @@ static irqreturn_t iwl_isr(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } @@ -1362,15 +1361,15 @@ irqreturn_t iwl_isr_ict(int irq, void *data) trace_iwlwifi_dev_irq(priv(trans)); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_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(bus(trans), CSR_INT_MASK); /* just for debug */ - iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ + iwl_write32(trans, CSR_INT_MASK, 0x00000000); /* Ignore interrupt if there's nothing in NIC to service. @@ -1433,7 +1432,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) iwl_enable_interrupts(trans); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1444,6 +1443,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index bd29568..4e1e74e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -35,6 +35,7 @@ #include "iwl-prph.h" #include "iwl-io.h" #include "iwl-agn-hw.h" +#include "iwl-op-mode.h" #include "iwl-trans-pcie-int.h" #define IWL_TX_CRC_SIZE 4 @@ -100,7 +101,7 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) if (hw_params(trans).shadow_reg_enable) { /* shadow register enabled */ - iwl_write32(bus(trans), HBUS_TARG_WRPTR, + iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); } else { /* if we're trying to save power */ @@ -108,18 +109,18 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); + reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup," " GP1 = 0x%x\n", txq_id, reg); - iwl_set_bit(bus(trans), CSR_GP_CNTRL, + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return; } - iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, + iwl_write_direct32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); /* @@ -128,7 +129,7 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) * trying to tx (during RFKILL, we're not trying to tx). */ } else - iwl_write32(bus(trans), HBUS_TARG_WRPTR, + iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); } txq->need_update = 0; @@ -190,14 +191,14 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, /* Unmap tx_cmd */ if (num_tbs) - dma_unmap_single(bus(trans)->dev, + dma_unmap_single(trans->dev, dma_unmap_addr(meta, mapping), dma_unmap_len(meta, len), DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) - dma_unmap_single(bus(trans)->dev, iwl_tfd_tb_get_addr(tfd, i), + dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i), iwl_tfd_tb_get_len(tfd, i), dma_dir); } @@ -229,7 +230,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, * freed and that the queue is not empty - free the skb */ if (skb) { - iwl_free_skb(priv(trans), skb); + iwl_op_mode_free_skb(trans->op_mode, skb); txq->skbs[index] = NULL; } } @@ -383,14 +384,14 @@ static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid, tbl_dw_addr = trans_pcie->scd_base_addr + SCD_TRANS_TBL_OFFSET_QUEUE(txq_id); - tbl_dw = iwl_read_targ_mem(bus(trans), tbl_dw_addr); + tbl_dw = iwl_read_targ_mem(trans, 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(bus(trans), tbl_dw_addr, tbl_dw); + iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw); return 0; } @@ -399,7 +400,7 @@ static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, 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(bus(trans), + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); @@ -409,9 +410,9 @@ void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index) { IWL_DEBUG_TX_QUEUES(trans, "Q %d WrPtr: %d", txq_id, index & 0xff); - iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, + iwl_write_direct32(trans, HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); - iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(txq_id), index); + iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), index); } void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, @@ -423,7 +424,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, int active = test_bit(txq_id, &trans_pcie->txq_ctx_active_msk) ? 1 : 0; - iwl_write_prph(bus(trans), SCD_QUEUE_STATUS_BITS(txq_id), + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | @@ -431,9 +432,12 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, txq->sched_retry = scd_retry; - IWL_DEBUG_TX_QUEUES(trans, "%s %s Queue %d on FIFO %d\n", - active ? "Activate" : "Deactivate", - scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); + if (active) + IWL_DEBUG_TX_QUEUES(trans, "Activate %s Queue %d on FIFO %d\n", + scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); + else + IWL_DEBUG_TX_QUEUES(trans, "Deactivate %s Queue %d\n", + scd_retry ? "BA" : "AC/CMD", txq_id); } static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie, @@ -478,7 +482,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, } txq_id = trans_pcie->agg_txq[sta_id][tid]; - if (WARN_ON_ONCE(is_agg_txqid_valid(trans, txq_id) == false)) { + if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) { IWL_ERR(trans, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, @@ -489,7 +493,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, ra_tid = BUILD_RAxTID(sta_id, tid); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Stop this Tx queue before configuring it */ iwlagn_tx_queue_stop_scheduler(trans, txq_id); @@ -498,10 +502,10 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id); /* Set this queue as a chain-building queue */ - iwl_set_bits_prph(bus(trans), SCD_QUEUECHAIN_SEL, (1<<txq_id)); + iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, (1<<txq_id)); /* enable aggregations for the queue */ - iwl_set_bits_prph(bus(trans), SCD_AGGR_SEL, (1<<txq_id)); + iwl_set_bits_prph(trans, SCD_AGGR_SEL, (1<<txq_id)); /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ @@ -510,7 +514,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, iwl_trans_set_wr_ptrs(trans, txq_id, ssn); /* Set up Tx window size and frame limit for this queue */ - iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + + iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), ((frame_limit << @@ -520,7 +524,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); - iwl_set_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id)); /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], @@ -529,7 +533,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, trans_pcie->txq[txq_id].sta_id = sta_id; trans_pcie->txq[txq_id].tid = tid; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* @@ -573,7 +577,7 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u8 txq_id = trans_pcie->agg_txq[sta_id][tid]; - if (WARN_ON_ONCE(is_agg_txqid_valid(trans, txq_id) == false)) { + if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) { IWL_ERR(trans, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, @@ -584,7 +588,7 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) iwlagn_tx_queue_stop_scheduler(trans, txq_id); - iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); + iwl_clear_bits_prph(trans, SCD_AGGR_SEL, (1 << txq_id)); trans_pcie->agg_txq[sta_id][tid] = 0; trans_pcie->txq[txq_id].q.read_ptr = 0; @@ -592,7 +596,7 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) /* supposes that ssn_idx is valid (!= 0xFFF) */ iwl_trans_set_wr_ptrs(trans, txq_id, 0); - iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id)); iwl_txq_ctx_deactivate(trans_pcie, txq_id); iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); return 0; @@ -685,7 +689,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) is_ct_kill = iwl_check_for_ct_kill(priv(trans)); if (!is_ct_kill) { IWL_ERR(trans, "Restarting adapter queue is full\n"); - iwlagn_fw_error(priv(trans), false); + iwl_op_mode_nic_error(trans->op_mode); } return -ENOSPC; } @@ -725,9 +729,9 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans->shrd->cmd_queue); - phys_addr = dma_map_single(bus(trans)->dev, &out_cmd->hdr, copy_size, + phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) { + if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { idx = -ENOMEM; goto out; } @@ -748,10 +752,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) continue; if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) continue; - phys_addr = dma_map_single(bus(trans)->dev, + phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i], cmd->len[i], DMA_BIDIRECTIONAL); - if (dma_mapping_error(bus(trans)->dev, phys_addr)) { + if (dma_mapping_error(trans->dev, phys_addr)) { iwlagn_unmap_tfd(trans, out_meta, &txq->tfds[q->write_ptr], DMA_BIDIRECTIONAL); @@ -818,7 +822,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, if (nfreed++ > 0) { IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - iwlagn_fw_error(priv(trans), false); + iwl_op_mode_nic_error(trans->op_mode); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 324d06d..9f8b239 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,8 +60,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/interrupt.h> #include <linux/debugfs.h> +#include <linux/sched.h> #include <linux/bitops.h> #include <linux/gfp.h> @@ -72,13 +75,15 @@ #include "iwl-shared.h" #include "iwl-eeprom.h" #include "iwl-agn-hw.h" +#include "iwl-core.h" +#include "iwl-ucode.h" static int iwl_trans_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rx_queue *rxq = &trans_pcie->rxq; - struct device *dev = bus(trans)->dev; + struct device *dev = trans->dev; memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); @@ -122,7 +127,7 @@ static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans) /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { - dma_unmap_page(bus(trans)->dev, rxq->pool[i].page_dma, + dma_unmap_page(trans->dev, rxq->pool[i].page_dma, PAGE_SIZE << hw_params(trans).rx_page_order, DMA_FROM_DEVICE); __free_pages(rxq->pool[i].page, @@ -146,17 +151,17 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans, rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; /* Stop Rx DMA */ - iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); /* Reset driver's Rx queue write index */ - iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_BASE_REG, + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG, (u32)(rxq->bd_dma >> 8)); /* Tell device where in DRAM to update its Rx status */ - iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_STTS_WPTR_REG, + iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG, rxq->rb_stts_dma >> 4); /* Enable Rx DMA @@ -167,7 +172,7 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans, * RB timeout 0x10 * 256 RBDs */ - iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | @@ -177,7 +182,7 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans, (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(bus(trans), CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); } static int iwl_rx_init(struct iwl_trans *trans) @@ -215,10 +220,10 @@ static int iwl_rx_init(struct iwl_trans *trans) iwl_trans_rx_hw_init(trans, rxq); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); rxq->need_update = 1; iwl_rx_queue_update_write_ptr(trans, rxq); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return 0; } @@ -242,13 +247,13 @@ static void iwl_trans_pcie_rx_free(struct iwl_trans *trans) iwl_trans_rxq_free_rx_bufs(trans); spin_unlock_irqrestore(&rxq->lock, flags); - dma_free_coherent(bus(trans)->dev, sizeof(__le32) * RX_QUEUE_SIZE, + dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); rxq->bd = NULL; if (rxq->rb_stts) - dma_free_coherent(bus(trans)->dev, + dma_free_coherent(trans->dev, sizeof(struct iwl_rb_status), rxq->rb_stts, rxq->rb_stts_dma); else @@ -261,8 +266,8 @@ static int iwl_trans_rx_stop(struct iwl_trans *trans) { /* stop Rx DMA */ - iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - return iwl_poll_direct_bit(bus(trans), FH_MEM_RSSR_RX_STATUS_REG, + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); } @@ -272,7 +277,7 @@ static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans, if (WARN_ON(ptr->addr)) return -EINVAL; - ptr->addr = dma_alloc_coherent(bus(trans)->dev, size, + ptr->addr = dma_alloc_coherent(trans->dev, size, &ptr->dma, GFP_KERNEL); if (!ptr->addr) return -ENOMEM; @@ -286,7 +291,7 @@ static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans, if (unlikely(!ptr->addr)) return; - dma_free_coherent(bus(trans)->dev, ptr->size, ptr->addr, ptr->dma); + dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma); memset(ptr, 0, sizeof(*ptr)); } @@ -333,7 +338,7 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->tfds = dma_alloc_coherent(bus(trans)->dev, tfd_sz, + txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz, &txq->q.dma_addr, GFP_KERNEL); if (!txq->tfds) { IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); @@ -389,7 +394,7 @@ static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(bus(trans), FH_MEM_CBBC_QUEUE(txq_id), + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); return 0; @@ -443,7 +448,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - struct device *dev = bus(trans)->dev; + struct device *dev = trans->dev; int i; if (WARN_ON(!txq)) return; @@ -581,16 +586,16 @@ static int iwl_tx_init(struct iwl_trans *trans) alloc = true; } - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Turn off all Tx DMA fifos */ - iwl_write_prph(bus(trans), SCD_TXFACT, 0); + iwl_write_prph(trans, SCD_TXFACT, 0); /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(bus(trans), FH_KW_MEM_ADDR_REG, + iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) { @@ -619,36 +624,207 @@ static void iwl_set_pwr_vmain(struct iwl_trans *trans) * to set power to V_AUX, do: if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) - iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, ~APMG_PS_CTRL_MSK_PWR_SRC); */ - iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); } +/* PCI registers */ +#define PCI_CFG_RETRY_TIMEOUT 0x041 +#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01 +#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02 + +static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans) +{ + int pos; + u16 pci_lnk_ctl; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + struct pci_dev *pci_dev = trans_pcie->pci_dev; + + pos = pci_pcie_cap(pci_dev); + pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); + return pci_lnk_ctl; +} + +static void iwl_apm_config(struct iwl_trans *trans) +{ + /* + * HW bug W/A for instability in PCIe bus L0S->L1 transition. + * Check if BIOS (or OS) enabled L1-ASPM on this device. + * If so (likely), disable L0S, so device moves directly L0->L1; + * costs negligible amount of power savings. + * If not (unlikely), enable L0S, so there is at least some + * power savings, even without L1. + */ + u16 lctl = iwl_pciexp_link_ctrl(trans); + + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + dev_printk(KERN_INFO, trans->dev, + "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + dev_printk(KERN_INFO, trans->dev, + "L1 Disabled; Enabling L0S\n"); + } + trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); +} + +/* + * Start up NIC'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 iwl_apm_init(struct iwl_trans *trans) +{ + int ret = 0; + IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); + + /* + * Use "set_bit" below rather than "write", to preserve any hardware + * bits already set by default after reset. + */ + + /* Disable L0S exit timer (platform NMI Work/Around) */ + iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + /* + * Disable L0s without affecting L1; + * don't wait for ICH L0s (ICH bug W/A) + */ + iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Enable HAP INTA (interrupt from management bus) to + * wake device's PCI Express link L1a -> L0s + */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); + + iwl_apm_config(trans); + + /* Configure analog phase-lock-loop before activating to D0A */ + if (cfg(trans)->base_params->pll_cfg_val) + iwl_set_bit(trans, CSR_ANA_PLL_CFG, + cfg(trans)->base_params->pll_cfg_val); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO(trans, "Failed to init the card\n"); + goto out; + } + + /* + * 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. + */ + iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(20); + + /* Disable L1-Active */ + iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + set_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status); + +out: + return ret; +} + +static int iwl_apm_stop_master(struct iwl_trans *trans) +{ + int ret = 0; + + /* stop device's busmaster DMA activity */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret) + IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); + + IWL_DEBUG_INFO(trans, "stop master\n"); + + return ret; +} + +static void iwl_apm_stop(struct iwl_trans *trans) +{ + IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); + + clear_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status); + + /* Stop device's DMA activity */ + iwl_apm_stop_master(trans); + + /* Reset the entire device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); +} + static int iwl_nic_init(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; /* nic_init */ - spin_lock_irqsave(&trans->shrd->lock, flags); - iwl_apm_init(priv(trans)); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); + iwl_apm_init(trans); /* Set interrupt coalescing calibration timer to default (512 usecs) */ - iwl_write8(bus(trans), CSR_INT_COALESCING, + iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); iwl_set_pwr_vmain(trans); iwl_nic_config(priv(trans)); +#ifndef CONFIG_IWLWIFI_IDI /* Allocate the RX queue, or reset if it is already allocated */ iwl_rx_init(trans); +#endif /* Allocate or reset and init all Tx and Command queues */ if (iwl_tx_init(trans)) @@ -656,7 +832,7 @@ static int iwl_nic_init(struct iwl_trans *trans) if (hw_params(trans).shadow_reg_enable) { /* enable shadow regs in HW */ - iwl_set_bit(bus(trans), CSR_MAC_SHADOW_REG_CTRL, + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); } @@ -672,11 +848,11 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) { int ret; - iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); /* See if we got it */ - ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); @@ -686,21 +862,22 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) } /* Note: returns standard 0/-ERROR code */ -static int iwl_trans_pcie_prepare_card_hw(struct iwl_trans *trans) +static int iwl_prepare_card_hw(struct iwl_trans *trans) { int ret; IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); ret = iwl_set_hw_ready(trans); + /* If the card is ready, exit 0 */ if (ret >= 0) return 0; /* If HW is not ready, prepare the conditions to check again */ - iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE); - ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); @@ -767,7 +944,79 @@ static const u8 iwlagn_pan_ac_to_queue[] = { 7, 6, 5, 4, }; -static int iwl_trans_pcie_start_device(struct iwl_trans *trans) +/* + * ucode + */ +static int iwl_load_section(struct iwl_trans *trans, const char *name, + struct fw_desc *image, u32 dst_addr) +{ + dma_addr_t phy_addr = image->p_addr; + u32 byte_cnt = image->len; + int ret; + + trans->ucode_write_complete = 0; + + iwl_write_direct32(trans, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); + + iwl_write_direct32(trans, + FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); + + iwl_write_direct32(trans, + FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + + iwl_write_direct32(trans, + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), + (iwl_get_dma_hi_addr(phy_addr) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); + + iwl_write_direct32(trans, + FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + + iwl_write_direct32(trans, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + + IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name); + ret = wait_event_timeout(trans->shrd->wait_command_queue, + trans->ucode_write_complete, 5 * HZ); + if (!ret) { + IWL_ERR(trans, "Could not load the %s uCode section\n", + name); + return -ETIMEDOUT; + } + + return 0; +} + +static int iwl_load_given_ucode(struct iwl_trans *trans, struct fw_img *image) +{ + int ret = 0; + + ret = iwl_load_section(trans, "INST", &image->code, + IWLAGN_RTC_INST_LOWER_BOUND); + if (ret) + return ret; + + ret = iwl_load_section(trans, "DATA", &image->data, + IWLAGN_RTC_DATA_LOWER_BOUND); + if (ret) + return ret; + + /* Remove all resets to allow NIC to operate */ + iwl_write32(trans, CSR_RESET, 0); + + return 0; +} + +static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw) { int ret; struct iwl_trans_pcie *trans_pcie = @@ -784,25 +1033,25 @@ static int iwl_trans_pcie_start_device(struct iwl_trans *trans) trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE; if ((hw_params(trans).sku & EEPROM_SKU_CAP_AMT_ENABLE) && - iwl_trans_pcie_prepare_card_hw(trans)) { + iwl_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); return -EIO; } /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(bus(trans), CSR_GP_CNTRL) & + if (iwl_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); else set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); if (iwl_is_rfkill(trans->shrd)) { - iwl_set_hw_rfkill_state(priv(trans), true); + iwl_op_mode_hw_rf_kill(trans->op_mode, true); iwl_enable_interrupts(trans); return -ERFKILL; } - iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF); + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_nic_init(trans); if (ret) { @@ -811,31 +1060,39 @@ static int iwl_trans_pcie_start_device(struct iwl_trans *trans) } /* make sure rfkill handshake bits are cleared */ - iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable host interrupts */ - iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF); + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); iwl_enable_interrupts(trans); /* really make sure rfkill handshake bits are cleared */ - iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Load the given image to the HW */ + iwl_load_given_ucode(trans, fw); return 0; } /* * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - * must be called under priv->shrd->lock and mac access + * must be called under the irq lock and with MAC access */ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) { - iwl_write_prph(bus(trans), SCD_TXFACT, mask); + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->irq_lock); + + iwl_write_prph(trans, SCD_TXFACT, mask); } -static void iwl_trans_pcie_tx_start(struct iwl_trans *trans) +static void iwl_tx_start(struct iwl_trans *trans) { const struct queue_to_fifo_ac *queue_to_fifo; struct iwl_trans_pcie *trans_pcie = @@ -845,49 +1102,49 @@ static void iwl_trans_pcie_tx_start(struct iwl_trans *trans) int i, chan; u32 reg_val; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->scd_base_addr = - iwl_read_prph(bus(trans), SCD_SRAM_BASE_ADDR); + iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; /* reset conext data memory */ for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; a += 4) - iwl_write_targ_mem(bus(trans), a, 0); + iwl_write_targ_mem(trans, a, 0); /* reset tx status memory */ for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; a += 4) - iwl_write_targ_mem(bus(trans), a, 0); + iwl_write_targ_mem(trans, a, 0); for (; a < trans_pcie->scd_base_addr + SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num); a += 4) - iwl_write_targ_mem(bus(trans), a, 0); + iwl_write_targ_mem(trans, a, 0); - iwl_write_prph(bus(trans), SCD_DRAM_BASE_ADDR, + iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, trans_pcie->scd_bc_tbls.dma >> 10); /* Enable DMA channel */ for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) - iwl_write_direct32(bus(trans), FH_TCSR_CHNL_TX_CONFIG_REG(chan), + iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); /* Update FH chicken bits */ - reg_val = iwl_read_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG); - iwl_write_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG, + reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG, reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); - iwl_write_prph(bus(trans), SCD_QUEUECHAIN_SEL, + iwl_write_prph(trans, SCD_QUEUECHAIN_SEL, SCD_QUEUECHAIN_SEL_ALL(trans)); - iwl_write_prph(bus(trans), SCD_AGGR_SEL, 0); + iwl_write_prph(trans, SCD_AGGR_SEL, 0); /* initiate the queues */ for (i = 0; i < hw_params(trans).max_txq_num; i++) { - iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(i), 0); - iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, 0 | (i << 8)); - iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + + iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i), 0); - iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + + iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i) + sizeof(u32), ((SCD_WIN_SIZE << @@ -898,7 +1155,7 @@ static void iwl_trans_pcie_tx_start(struct iwl_trans *trans) SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); } - iwl_write_prph(bus(trans), SCD_INTERRUPT_MASK, + iwl_write_prph(trans, SCD_INTERRUPT_MASK, IWL_MASK(0, hw_params(trans).max_txq_num)); /* Activate all Tx DMA/FIFO channels */ @@ -941,13 +1198,19 @@ static void iwl_trans_pcie_tx_start(struct iwl_trans *trans) fifo, 0); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Enable L1-Active */ - iwl_clear_bits_prph(bus(trans), APMG_PCIDEV_STT_REG, + iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } +static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans) +{ + iwl_reset_ict(trans); + iwl_tx_start(trans); +} + /** * iwlagn_txq_ctx_stop - Stop all Tx DMA channels */ @@ -958,23 +1221,23 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_trans_txq_set_sched(trans, 0); /* Stop each Tx DMA channel, and wait for it to be idle */ for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { - iwl_write_direct32(bus(trans), + iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); - if (iwl_poll_direct_bit(bus(trans), FH_TSSR_TX_STATUS_REG, + if (iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG, FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000)) IWL_ERR(trans, "Failing on timeout while stopping" " DMA channel %d [0x%08x]", ch, - iwl_read_direct32(bus(trans), + iwl_read_direct32(trans, FH_TSSR_TX_STATUS_REG)); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); if (!trans_pcie->txq) { IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); @@ -994,9 +1257,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* device going down, Stop using ICT table */ iwl_disable_ict(trans); @@ -1010,34 +1273,37 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) */ if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) { iwl_trans_tx_stop(trans); +#ifndef CONFIG_IWLWIFI_IDI iwl_trans_rx_stop(trans); - +#endif /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(bus(trans), APMG_CLK_DIS_REG, + iwl_write_prph(trans, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); } /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(bus(trans), CSR_GP_CNTRL, + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv(trans)); + iwl_apm_stop(trans); /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* wait to make sure we flush pending tasklet*/ - synchronize_irq(bus(trans)->irq); + synchronize_irq(trans->irq); tasklet_kill(&trans_pcie->irq_tasklet); + cancel_work_sync(&trans_pcie->rx_replenish); + /* stop and reset the on-board processor */ - iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); } static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, @@ -1134,10 +1400,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = dma_map_single(bus(trans)->dev, + txcmd_phys = dma_map_single(trans->dev, &dev_cmd->hdr, firstlen, DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(bus(trans)->dev, txcmd_phys))) + if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) return -1; dma_unmap_addr_set(out_meta, mapping, txcmd_phys); dma_unmap_len_set(out_meta, len, firstlen); @@ -1153,10 +1419,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, * if any (802.11 null frames have no payload). */ secondlen = skb->len - hdr_len; if (secondlen > 0) { - phys_addr = dma_map_single(bus(trans)->dev, skb->data + hdr_len, + phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, secondlen, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) { - dma_unmap_single(bus(trans)->dev, + if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { + dma_unmap_single(trans->dev, dma_unmap_addr(out_meta, mapping), dma_unmap_len(out_meta, len), DMA_BIDIRECTIONAL); @@ -1174,7 +1440,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, offsetof(struct iwl_tx_cmd, scratch); /* take back ownership of DMA buffer to enable update */ - dma_sync_single_for_cpu(bus(trans)->dev, txcmd_phys, firstlen, + dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, DMA_BIDIRECTIONAL); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); @@ -1188,7 +1454,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Set up entry for this TFD in Tx byte-count array */ iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); - dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, + dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, DMA_BIDIRECTIONAL); trace_iwlwifi_dev_tx(priv(trans), @@ -1218,13 +1484,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, return 0; } -static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(bus(trans), CSR_RESET, 0); -} - -static int iwl_trans_pcie_request_irq(struct iwl_trans *trans) +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1232,21 +1492,62 @@ static int iwl_trans_pcie_request_irq(struct iwl_trans *trans) trans_pcie->inta_mask = CSR_INI_SET_MASK; - tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)trans); + if (!trans_pcie->irq_requested) { + tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)trans); - iwl_alloc_isr_ict(trans); + iwl_alloc_isr_ict(trans); - err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED, - DRV_NAME, trans); + err = request_irq(trans->irq, iwl_isr_ict, IRQF_SHARED, + DRV_NAME, trans); + if (err) { + IWL_ERR(trans, "Error allocating IRQ %d\n", + trans->irq); + goto error; + } + + INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish); + trans_pcie->irq_requested = true; + } + + err = iwl_prepare_card_hw(trans); if (err) { - IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq); - iwl_free_isr_ict(trans); - return err; + IWL_ERR(trans, "Error while preparing HW: %d", err); + goto err_free_irq; } - INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish); - return 0; + iwl_apm_init(trans); + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(trans, + CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + else + set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + + iwl_op_mode_hw_rf_kill(trans->op_mode, + test_bit(STATUS_RF_KILL_HW, + &trans->shrd->status)); + + return err; + +err_free_irq: + free_irq(trans->irq, trans); +error: + iwl_free_isr_ict(trans); + tasklet_kill(&trans_pcie->irq_tasklet); + return err; +} + +static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans) +{ + iwl_apm_stop(trans); + + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + + /* Even if we stop the HW, we still want the RF kill interrupt */ + IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); + iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); } static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, @@ -1289,13 +1590,42 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, return 0; } +static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) +{ + iowrite8(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); +} + +static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val) +{ + iowrite32(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); +} + +static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs) +{ + u32 val = ioread32(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); + return val; +} + static void iwl_trans_pcie_free(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + iwl_calib_free_results(trans); iwl_trans_pcie_tx_free(trans); +#ifndef CONFIG_IWLWIFI_IDI iwl_trans_pcie_rx_free(trans); - free_irq(bus(trans)->irq, trans); - iwl_free_isr_ict(trans); +#endif + if (trans_pcie->irq_requested == true) { + free_irq(trans->irq, trans); + iwl_free_isr_ict(trans); + } + + pci_disable_msi(trans_pcie->pci_dev); + pci_iounmap(trans_pcie->pci_dev, trans_pcie->hw_base); + pci_release_regions(trans_pcie->pci_dev); + pci_disable_device(trans_pcie->pci_dev); + trans->shrd->trans = NULL; kfree(trans); } @@ -1315,10 +1645,10 @@ static int iwl_trans_pcie_suspend(struct iwl_trans *trans) * things already :-) */ if (!trans->shrd->wowlan) { - iwl_apm_stop(priv(trans)); + iwl_apm_stop(trans); } else { iwl_disable_interrupts(trans); - iwl_clear_bit(bus(trans), CSR_GP_CNTRL, + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } @@ -1331,7 +1661,7 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) iwl_enable_interrupts(trans); - if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & + if (!(iwl_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rfkill = true; @@ -1340,7 +1670,7 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) else clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); - iwl_set_hw_rfkill_state(priv(trans), hw_rfkill); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); return 0; } @@ -1364,25 +1694,6 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans, } } -const struct iwl_trans_ops trans_ops_pcie; - -static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd) -{ - struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) + - sizeof(struct iwl_trans_pcie), - GFP_KERNEL); - if (iwl_trans) { - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(iwl_trans); - iwl_trans->ops = &trans_ops_pcie; - iwl_trans->shrd = shrd; - trans_pcie->trans = iwl_trans; - spin_lock_init(&iwl_trans->hcmd_lock); - } - - return iwl_trans; -} - static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id, const char *msg) { @@ -1446,9 +1757,9 @@ static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt) IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", q->read_ptr, q->write_ptr); IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n", - iwl_read_prph(bus(trans), SCD_QUEUE_RDPTR(cnt)) + iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) & (TFD_QUEUE_SIZE_MAX - 1), - iwl_read_prph(bus(trans), SCD_QUEUE_WRPTR(cnt))); + iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); return 1; } @@ -1502,7 +1813,7 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) pos += scnprintf(*buf + pos, bufsz - pos, " %34s: 0X%08x\n", get_fh_string(fh_tbl[i]), - iwl_read_direct32(bus(trans), fh_tbl[i])); + iwl_read_direct32(trans, fh_tbl[i])); } return pos; } @@ -1511,7 +1822,7 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { IWL_ERR(trans, " %34s: 0X%08x\n", get_fh_string(fh_tbl[i]), - iwl_read_direct32(bus(trans), fh_tbl[i])); + iwl_read_direct32(trans, fh_tbl[i])); } return 0; } @@ -1581,7 +1892,7 @@ void iwl_dump_csr(struct iwl_trans *trans) for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { IWL_ERR(trans, " %25s: 0X%08x\n", get_csr_string(csr_tbl[i]), - iwl_read32(bus(trans), csr_tbl[i])); + iwl_read32(trans, csr_tbl[i])); } } @@ -1902,13 +2213,12 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, #endif /*CONFIG_IWLWIFI_DEBUGFS */ const struct iwl_trans_ops trans_ops_pcie = { - .alloc = iwl_trans_pcie_alloc, - .request_irq = iwl_trans_pcie_request_irq, - .start_device = iwl_trans_pcie_start_device, - .prepare_card_hw = iwl_trans_pcie_prepare_card_hw, + .start_hw = iwl_trans_pcie_start_hw, + .stop_hw = iwl_trans_pcie_stop_hw, + .fw_alive = iwl_trans_pcie_fw_alive, + .start_fw = iwl_trans_pcie_start_fw, .stop_device = iwl_trans_pcie_stop_device, - .tx_start = iwl_trans_pcie_tx_start, .wake_any_queue = iwl_trans_pcie_wake_any_queue, .send_cmd = iwl_trans_pcie_send_cmd, @@ -1920,8 +2230,6 @@ const struct iwl_trans_ops trans_ops_pcie = { .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc, .tx_agg_setup = iwl_trans_pcie_tx_agg_setup, - .kick_nic = iwl_trans_pcie_kick_nic, - .free = iwl_trans_pcie_free, .stop_queue = iwl_trans_pcie_stop_queue, @@ -1934,4 +2242,117 @@ const struct iwl_trans_ops trans_ops_pcie = { .suspend = iwl_trans_pcie_suspend, .resume = iwl_trans_pcie_resume, #endif + .write8 = iwl_trans_pcie_write8, + .write32 = iwl_trans_pcie_write32, + .read32 = iwl_trans_pcie_read32, }; + +struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, + struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct iwl_trans_pcie *trans_pcie; + struct iwl_trans *trans; + u16 pci_cmd; + int err; + + trans = kzalloc(sizeof(struct iwl_trans) + + sizeof(struct iwl_trans_pcie), GFP_KERNEL); + + if (WARN_ON(!trans)) + return NULL; + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + trans->ops = &trans_ops_pcie; + trans->shrd = shrd; + trans_pcie->trans = trans; + spin_lock_init(&trans->hcmd_lock); + spin_lock_init(&trans_pcie->irq_lock); + + /* W/A - seems to solve weird behavior. We need to remove this if we + * don't want to stay in L1 all the time. This wastes a lot of power */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_no_pci; + } + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); + if (err) { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (!err) + err = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)); + /* both attempts failed: */ + if (err) { + dev_printk(KERN_ERR, &pdev->dev, + "No suitable DMA available.\n"); + goto out_pci_disable_device; + } + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed"); + goto out_pci_disable_device; + } + + trans_pcie->hw_base = pci_iomap(pdev, 0, 0); + if (!trans_pcie->hw_base) { + dev_printk(KERN_ERR, &pdev->dev, "pci_iomap failed"); + err = -ENODEV; + goto out_pci_release_regions; + } + + dev_printk(KERN_INFO, &pdev->dev, + "pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + dev_printk(KERN_INFO, &pdev->dev, + "pci_resource_base = %p\n", trans_pcie->hw_base); + + dev_printk(KERN_INFO, &pdev->dev, + "HW Revision ID = 0x%X\n", pdev->revision); + + /* 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); + + err = pci_enable_msi(pdev); + if (err) + dev_printk(KERN_ERR, &pdev->dev, + "pci_enable_msi failed(0X%x)", err); + + trans->dev = &pdev->dev; + trans->irq = pdev->irq; + trans_pcie->pci_dev = pdev; + trans->hw_rev = iwl_read32(trans, CSR_HW_REV); + trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; + snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), + "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); + + /* TODO: Move this away, not needed if not MSI */ + /* enable rfkill interrupt: hw bug w/a */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); + } + + return trans; + +out_pci_release_regions: + pci_release_regions(pdev); +out_pci_disable_device: + pci_disable_device(pdev); +out_no_pci: + kfree(trans); + return NULL; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index 1b20c4f..506c062 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index e6bf3f5..4e7e6c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,23 +63,75 @@ #ifndef __iwl_trans_h__ #define __iwl_trans_h__ -#include <linux/debugfs.h> -#include <linux/skbuff.h> +#include <linux/ieee80211.h> #include "iwl-shared.h" -#include "iwl-commands.h" +#include "iwl-debug.h" - /*This file includes the declaration that are exported from the transport - * layer */ +/** + * DOC: Transport layer - what is it ? + * + * The tranport layer is the layer that deals with the HW directly. It provides + * an abstraction of the underlying HW to the upper layer. The transport layer + * doesn't provide any policy, algorithm or anything of this kind, but only + * mechanisms to make the HW do something.It is not completely stateless but + * close to it. + * We will have an implementation for each different supported bus. + */ + +/** + * DOC: Life cycle of the transport layer + * + * The transport layer has a very precise life cycle. + * + * 1) A helper function is called during the module initialization and + * registers the bus driver's ops with the transport's alloc function. + * 2) Bus's probe calls to the transport layer's allocation functions. + * Of course this function is bus specific. + * 3) This allocation functions will spawn the upper layer which will + * register mac80211. + * + * 4) At some point (i.e. mac80211's start call), the op_mode will call + * the following sequence: + * start_hw + * start_fw + * + * 5) Then when finished (or reset): + * stop_fw (a.k.a. stop device for the moment) + * stop_hw + * + * 6) Eventually, the free function will be called. + */ struct iwl_priv; struct iwl_shared; +struct iwl_op_mode; +struct fw_img; +struct sk_buff; +struct dentry; +/** + * DOC: Host command section + * + * A host command is a commaned issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), + */ #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) -enum { +/** + * enum CMD_MODE - how to send the host commands ? + * + * @CMD_SYNC: The caller will be stalled until the fw responds to the command + * @CMD_ASYNC: Return right away and don't want for the response + * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the + * response. + * @CMD_ON_DEMAND: This command is sent by the test mode pipe. + */ +enum CMD_MODE { CMD_SYNC = 0, CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), @@ -104,20 +156,29 @@ struct iwl_device_cmd { #define IWL_MAX_CMD_TFDS 2 +/** + * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command + * + * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's + * ring. The transport layer doesn't map the command's buffer to DMA, but + * rather copies it to an previously allocated DMA buffer. This flag tells + * the transport layer not to copy the command, but to map the existing + * buffer. This can save memcpy and is worth with very big comamnds. + */ enum iwl_hcmd_dataflag { IWL_HCMD_DFL_NOCOPY = BIT(0), }; /** * struct iwl_host_cmd - Host command to the uCode + * * @data: array of chunks that composes the data of the host command * @reply_page: pointer to the page that holds the response to the host command * @handler_status: return value of the handler of the command * (put in setup_rx_handlers) - valid for SYNC mode only - * @callback: - * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC + * @flags: can be CMD_* * @len: array of the lenths of the chunks in data - * @dataflags: + * @dataflags: IWL_HCMD_DFL_* * @id: id of the host command */ struct iwl_host_cmd { @@ -133,42 +194,58 @@ struct iwl_host_cmd { /** * struct iwl_trans_ops - transport specific operations - * @alloc: allocates the meta data (not the queues themselves) - * @request_irq: requests IRQ - will be called before the FW load in probe flow - * @start_device: allocates and inits all the resources for the transport - * layer. - * @prepare_card_hw: claim the ownership on the HW. Will be called during - * probe. - * @tx_start: starts and configures all the Tx fifo - usually done once the fw - * is alive. + * + * All the handlers MUST be implemented + * + * @start_hw: starts the HW- from that point on, the HW can send interrupts + * May sleep + * @stop_hw: stops the HW- from that point on, the HW will be in low power but + * will still issue interrupt if the HW RF kill is triggered. + * May sleep + * @start_fw: allocates and inits all the resources for the transport + * layer. Also kick a fw image. + * May sleep + * @fw_alive: called when the fw sends alive notification + * May sleep * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* * @stop_device:stops the whole device (embedded CPU put to reset) + * May sleep * @send_cmd:send a host command + * May sleep only if CMD_SYNC is set * @tx: send an skb + * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. + * Must be atomic * @tx_agg_alloc: allocate resources for a TX BA session + * May sleep * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is - * ready and a successful ADDBA response has been received. + * ready and a successful ADDBA response has been received. + * May sleep * @tx_agg_disable: de-configure a Tx queue to send AMPDUs - * @kick_nic: remove the RESET from the embedded CPU and let it run + * May sleep * @free: release all the ressource for the transport layer itself such as - * irq, tasklet etc... + * irq, tasklet etc... From this point on, the device may not issue + * any interrupt (incl. RFKILL). + * May sleep * @stop_queue: stop a specific queue * @check_stuck_queue: check if a specific queue is stuck * @wait_tx_queue_empty: wait until all tx queues are empty + * May sleep * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. * @suspend: stop the device unless WoWLAN is configured * @resume: resume activity of the device + * @write8: write a u8 to a register at offset ofs from the BAR + * @write32: write a u32 to a register at offset ofs from the BAR + * @read32: read a u32 register at offset ofs from the BAR */ struct iwl_trans_ops { - struct iwl_trans *(*alloc)(struct iwl_shared *shrd); - int (*request_irq)(struct iwl_trans *iwl_trans); - int (*start_device)(struct iwl_trans *trans); - int (*prepare_card_hw)(struct iwl_trans *trans); + int (*start_hw)(struct iwl_trans *iwl_trans); + void (*stop_hw)(struct iwl_trans *iwl_trans); + int (*start_fw)(struct iwl_trans *trans, struct fw_img *fw); + void (*fw_alive)(struct iwl_trans *trans); void (*stop_device)(struct iwl_trans *trans); - void (*tx_start)(struct iwl_trans *trans); void (*wake_any_queue)(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, @@ -191,8 +268,6 @@ struct iwl_trans_ops { enum iwl_rxon_context_id ctx, int sta_id, int tid, int frame_limit, u16 ssn); - void (*kick_nic)(struct iwl_trans *trans); - void (*free)(struct iwl_trans *trans); void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg); @@ -204,18 +279,9 @@ struct iwl_trans_ops { int (*suspend)(struct iwl_trans *trans); int (*resume)(struct iwl_trans *trans); #endif -}; - -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_desc { - dma_addr_t p_addr; /* hardware address */ - void *v_addr; /* software address */ - u32 len; /* size in bytes */ -}; - -struct fw_img { - struct fw_desc code; /* firmware code image */ - struct fw_desc data; /* firmware data image */ + void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); + void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); + u32 (*read32)(struct iwl_trans *trans, u32 ofs); }; /* Opaque calibration results */ @@ -227,67 +293,118 @@ struct iwl_calib_result { }; /** + * enum iwl_trans_state - state of the transport layer + * + * @IWL_TRANS_NO_FW: no fw has sent an alive response + * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response + */ +enum iwl_trans_state { + IWL_TRANS_NO_FW = 0, + IWL_TRANS_FW_ALIVE = 1, +}; + +/** * struct iwl_trans - transport common data + * * @ops - pointer to iwl_trans_ops + * @op_mode - pointer to the op_mode * @shrd - pointer to iwl_shared which holds shared data from the upper layer * @hcmd_lock: protects HCMD + * @reg_lock - protect hw register access + * @dev - pointer to struct device * that represents the device + * @irq - the irq number for the device + * @hw_id: a u32 with the ID of the device / subdevice. + * Set during transport allocation. + * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @ucode_write_complete: indicates that the ucode has been copied. - * @ucode_rt: run time ucode image - * @ucode_init: init ucode image - * @ucode_wowlan: wake on wireless ucode image (optional) * @nvm_device_type: indicates OTP or eeprom + * @pm_support: set to true in start_hw if link pm is supported * @calib_results: list head for init calibration results */ struct iwl_trans { const struct iwl_trans_ops *ops; + struct iwl_op_mode *op_mode; struct iwl_shared *shrd; + enum iwl_trans_state state; spinlock_t hcmd_lock; + spinlock_t reg_lock; - u8 ucode_write_complete; /* the image write is complete */ - struct fw_img ucode_rt; - struct fw_img ucode_init; - struct fw_img ucode_wowlan; + struct device *dev; + unsigned int irq; + u32 hw_rev; + u32 hw_id; + char hw_id_str[52]; + + u8 ucode_write_complete; - /* eeprom related variables */ int nvm_device_type; + bool pm_support; - /* init calibration results */ struct list_head calib_results; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ - char trans_specific[0] __attribute__((__aligned__(sizeof(void *)))); + char trans_specific[0] __aligned(sizeof(void *)); }; -static inline int iwl_trans_request_irq(struct iwl_trans *trans) +static inline void iwl_trans_configure(struct iwl_trans *trans, + struct iwl_op_mode *op_mode) { - return trans->ops->request_irq(trans); + /* + * only set the op_mode for the moment. Later on, this function will do + * more + */ + trans->op_mode = op_mode; } -static inline int iwl_trans_start_device(struct iwl_trans *trans) +static inline int iwl_trans_start_hw(struct iwl_trans *trans) { - return trans->ops->start_device(trans); + might_sleep(); + + return trans->ops->start_hw(trans); } -static inline int iwl_trans_prepare_card_hw(struct iwl_trans *trans) +static inline void iwl_trans_stop_hw(struct iwl_trans *trans) { - return trans->ops->prepare_card_hw(trans); + might_sleep(); + + trans->ops->stop_hw(trans); + + trans->state = IWL_TRANS_NO_FW; } -static inline void iwl_trans_stop_device(struct iwl_trans *trans) +static inline void iwl_trans_fw_alive(struct iwl_trans *trans) { - trans->ops->stop_device(trans); + might_sleep(); + + trans->ops->fw_alive(trans); + + trans->state = IWL_TRANS_FW_ALIVE; +} + +static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) +{ + might_sleep(); + + return trans->ops->start_fw(trans, fw); } -static inline void iwl_trans_tx_start(struct iwl_trans *trans) +static inline void iwl_trans_stop_device(struct iwl_trans *trans) { - trans->ops->tx_start(trans); + might_sleep(); + + trans->ops->stop_device(trans); + + trans->state = IWL_TRANS_NO_FW; } static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->wake_any_queue(trans, ctx, msg); } @@ -295,6 +412,9 @@ static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->send_cmd(trans, cmd); } @@ -305,6 +425,9 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, u8 sta_id, u8 tid) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid); } @@ -312,6 +435,9 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, int tid, int txq_id, int ssn, u32 status, struct sk_buff_head *skbs) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs); } @@ -319,12 +445,22 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_disable(trans, sta_id, tid); } static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_alloc(trans, sta_id, tid); } @@ -334,12 +470,12 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int sta_id, int tid, int frame_limit, u16 ssn) { - trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); -} + might_sleep(); -static inline void iwl_trans_kick_nic(struct iwl_trans *trans) -{ - trans->ops->kick_nic(trans); + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); } static inline void iwl_trans_free(struct iwl_trans *trans) @@ -350,16 +486,25 @@ static inline void iwl_trans_free(struct iwl_trans *trans) static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->stop_queue(trans, q, msg); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->wait_tx_queue_empty(trans); } static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->check_stuck_queue(trans, q); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, @@ -380,18 +525,43 @@ static inline int iwl_trans_resume(struct iwl_trans *trans) } #endif -/***************************************************** -* Transport layers implementations -******************************************************/ -extern const struct iwl_trans_ops trans_ops_pcie; +static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) +{ + trans->ops->write8(trans, ofs, val); +} -int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, - const void *data, size_t len); -void iwl_dealloc_ucode(struct iwl_trans *trans); +static inline void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) +{ + trans->ops->write32(trans, ofs, val); +} + +static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) +{ + return trans->ops->read32(trans, ofs); +} +/***************************************************** +* Utils functions +******************************************************/ int iwl_send_calib_results(struct iwl_trans *trans); int iwl_calib_set(struct iwl_trans *trans, const struct iwl_calib_hdr *cmd, int len); void iwl_calib_free_results(struct iwl_trans *trans); +/***************************************************** +* Transport layers implementations + their allocation function +******************************************************/ +struct pci_dev; +struct pci_device_id; +extern const struct iwl_trans_ops trans_ops_pcie; +struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, + struct pci_dev *pdev, + const struct pci_device_id *ent); +int __must_check iwl_pci_register_driver(void); +void iwl_pci_unregister_driver(void); + +extern const struct iwl_trans_ops trans_ops_idi; +struct iwl_trans *iwl_trans_idi_alloc(struct iwl_shared *shrd, + void *pdev_void, + const void *ent_void); #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 36a1b5b..b16efc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 @@ -32,7 +32,9 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include "iwl-ucode.h" #include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" @@ -42,6 +44,7 @@ #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-fh.h" +#include "iwl-op-mode.h" static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, @@ -80,29 +83,29 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { * ******************************************************************************/ -static void iwl_free_fw_desc(struct iwl_bus *bus, struct fw_desc *desc) +static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(bus->dev, desc->len, + dma_free_coherent(trans(nic)->dev, desc->len, desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; } -static void iwl_free_fw_img(struct iwl_bus *bus, struct fw_img *img) +static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img) { - iwl_free_fw_desc(bus, &img->code); - iwl_free_fw_desc(bus, &img->data); + iwl_free_fw_desc(nic, &img->code); + iwl_free_fw_desc(nic, &img->data); } -void iwl_dealloc_ucode(struct iwl_trans *trans) +void iwl_dealloc_ucode(struct iwl_nic *nic) { - iwl_free_fw_img(bus(trans), &trans->ucode_rt); - iwl_free_fw_img(bus(trans), &trans->ucode_init); - iwl_free_fw_img(bus(trans), &trans->ucode_wowlan); + iwl_free_fw_img(nic, &nic->fw.ucode_rt); + iwl_free_fw_img(nic, &nic->fw.ucode_init); + iwl_free_fw_img(nic, &nic->fw.ucode_wowlan); } -int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, +static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc, const void *data, size_t len) { if (!len) { @@ -110,7 +113,7 @@ int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, return -EINVAL; } - desc->v_addr = dma_alloc_coherent(bus->dev, len, + desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len, &desc->p_addr, GFP_KERNEL); if (!desc->v_addr) return -ENOMEM; @@ -120,97 +123,22 @@ int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, return 0; } -/* - * ucode - */ -static int iwl_load_section(struct iwl_trans *trans, const char *name, - struct fw_desc *image, u32 dst_addr) -{ - struct iwl_bus *bus = bus(trans); - dma_addr_t phy_addr = image->p_addr; - u32 byte_cnt = image->len; - int ret; - - trans->ucode_write_complete = 0; - - iwl_write_direct32(bus, - FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); - - iwl_write_direct32(bus, - FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); - - iwl_write_direct32(bus, - FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), - phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - - iwl_write_direct32(bus, - FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_addr(phy_addr) - << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); - - iwl_write_direct32(bus, - FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), - 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | - 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | - FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); - - iwl_write_direct32(bus, - FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | - FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - - IWL_DEBUG_FW(bus, "%s uCode section being loaded...\n", name); - ret = wait_event_timeout(trans->shrd->wait_command_queue, - trans->ucode_write_complete, 5 * HZ); - if (!ret) { - IWL_ERR(trans, "Could not load the %s uCode section\n", - name); - return -ETIMEDOUT; - } - - return 0; -} - -static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, +static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { switch (ucode_type) { case IWL_UCODE_INIT: - return &trans->ucode_init; + return &nic->fw.ucode_init; case IWL_UCODE_WOWLAN: - return &trans->ucode_wowlan; + return &nic->fw.ucode_wowlan; case IWL_UCODE_REGULAR: - return &trans->ucode_rt; + return &nic->fw.ucode_rt; case IWL_UCODE_NONE: break; } return NULL; } -static int iwl_load_given_ucode(struct iwl_trans *trans, - enum iwl_ucode_type ucode_type) -{ - int ret = 0; - struct fw_img *image = iwl_get_ucode_image(trans, ucode_type); - - - if (!image) { - IWL_ERR(trans, "Invalid ucode requested (%d)\n", - ucode_type); - return -EINVAL; - } - - ret = iwl_load_section(trans, "INST", &image->code, - IWLAGN_RTC_INST_LOWER_BOUND); - if (ret) - return ret; - - return iwl_load_section(trans, "DATA", &image->data, - IWLAGN_RTC_DATA_LOWER_BOUND); -} - /* * Calibration */ @@ -447,7 +375,7 @@ static int iwl_alive_notify(struct iwl_trans *trans) if (!priv->tx_cmd_pool) return -ENOMEM; - iwl_trans_tx_start(trans); + iwl_trans_fw_alive(trans); for_each_context(priv, ctx) ctx->last_tx_rejected = false; @@ -470,23 +398,24 @@ static int iwl_alive_notify(struct iwl_trans *trans) * 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 iwl_verify_inst_sparse(struct iwl_bus *bus, +static int iwl_verify_inst_sparse(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 i; - IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "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(bus, HBUS_TARG_MEM_RADDR, + iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = iwl_read32(bus, HBUS_TARG_MEM_RDAT); + val = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) return -EIO; } @@ -494,27 +423,28 @@ static int iwl_verify_inst_sparse(struct iwl_bus *bus, return 0; } -static void iwl_print_mismatch_inst(struct iwl_bus *bus, +static void iwl_print_mismatch_inst(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 offs; int errors = 0; - IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len); - iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR, + iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); for (offs = 0; offs < len && errors < 20; offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - val = iwl_read32(bus, HBUS_TARG_MEM_RDAT); + val = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(bus, "uCode INST section at " + IWL_ERR(nic, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", offs, val, le32_to_cpu(*image)); errors++; @@ -526,24 +456,24 @@ static void iwl_print_mismatch_inst(struct iwl_bus *bus, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_trans *trans, +static int iwl_verify_ucode(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { - struct fw_img *img = iwl_get_ucode_image(trans, ucode_type); + struct fw_img *img = iwl_get_ucode_image(nic, ucode_type); if (!img) { - IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type); + IWL_ERR(nic, "Invalid ucode requested (%d)\n", ucode_type); return -EINVAL; } - if (!iwl_verify_inst_sparse(bus(trans), &img->code)) { - IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n"); + if (!iwl_verify_inst_sparse(nic, &img->code)) { + IWL_DEBUG_FW(nic, "uCode is good in inst SRAM\n"); return 0; } - IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + IWL_ERR(nic, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(bus(trans), &img->code); + iwl_print_mismatch_inst(nic, &img->code); return -EIO; } @@ -647,28 +577,27 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, { struct iwl_notification_wait alive_wait; struct iwl_alive_data alive_data; + struct fw_img *fw; int ret; enum iwl_ucode_type old_type; - ret = iwl_trans_start_device(trans); - if (ret) - return ret; - iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE, iwl_alive_fn, &alive_data); old_type = trans->shrd->ucode_type; trans->shrd->ucode_type = ucode_type; + fw = iwl_get_ucode_image(nic(trans), ucode_type); + + if (!fw) + return -EINVAL; - ret = iwl_load_given_ucode(trans, ucode_type); + ret = iwl_trans_start_fw(trans, fw); if (ret) { trans->shrd->ucode_type = old_type; iwl_remove_notification(trans->shrd, &alive_wait); return ret; } - iwl_trans_kick_nic(trans); - /* * Some things may run in the background now, but we * just wait for the ALIVE notification here. @@ -692,7 +621,7 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, * skip it for WoWLAN. */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(trans, ucode_type); + ret = iwl_verify_ucode(nic(trans), ucode_type); if (ret) { trans->shrd->ucode_type = old_type; return ret; @@ -721,7 +650,7 @@ int iwl_run_init_ucode(struct iwl_trans *trans) lockdep_assert_held(&trans->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!trans->ucode_init.code.len) + if (!nic(trans)->fw.ucode_init.code.len) return 0; if (trans->shrd->ucode_type != IWL_UCODE_NONE) @@ -756,3 +685,582 @@ int iwl_run_init_ucode(struct iwl_trans *trans) iwl_trans_stop_device(trans); return ret; } + +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); + +#define UCODE_EXPERIMENTAL_TAG "exp" + +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first) +{ + struct iwl_cfg *cfg = cfg(nic); + const char *name_pre = cfg->fw_name_pre; + char tag[8]; + + if (first) { +#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE + nic->fw_index = UCODE_EXPERIMENTAL_INDEX; + strcpy(tag, UCODE_EXPERIMENTAL_TAG); + } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { +#endif + nic->fw_index = cfg->ucode_api_max; + sprintf(tag, "%d", nic->fw_index); + } else { + nic->fw_index--; + sprintf(tag, "%d", nic->fw_index); + } + + if (nic->fw_index < cfg->ucode_api_min) { + IWL_ERR(nic, "no suitable firmware found!\n"); + return -ENOENT; + } + + sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); + + IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n", + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) + ? "EXPERIMENTAL " : "", + nic->firmware_name); + + return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, + trans(nic)->dev, + GFP_KERNEL, nic, iwl_ucode_callback); +} + +struct iwlagn_firmware_pieces { + const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; + size_t inst_size, data_size, init_size, init_data_size, + wowlan_inst_size, wowlan_data_size; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; +}; + +static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, + const struct firmware *ucode_raw, + struct iwlagn_firmware_pieces *pieces) +{ + struct iwl_ucode_header *ucode = (void *)ucode_raw->data; + u32 api_ver, hdr_size, build; + char buildstr[25]; + const u8 *src; + + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); + + switch (api_ver) { + default: + hdr_size = 28; + if (ucode_raw->size < hdr_size) { + IWL_ERR(nic, "File size too small!\n"); + return -EINVAL; + } + 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: + hdr_size = 24; + if (ucode_raw->size < hdr_size) { + IWL_ERR(nic, "File size too small!\n"); + return -EINVAL; + } + build = 0; + pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); + pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); + src = ucode->u.v1.data; + break; + } + + if (build) + sprintf(buildstr, " build %u%s", build, + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) + ? " (EXP)" : ""); + else + buildstr[0] = '\0'; + + snprintf(nic->fw.fw_version, + sizeof(nic->fw.fw_version), + "%u.%u.%u.%u%s", + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), + buildstr); + + /* 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) { + + IWL_ERR(nic, + "uCode file size %d does not match expected size\n", + (int)ucode_raw->size); + return -EINVAL; + } + + pieces->inst = src; + src += pieces->inst_size; + pieces->data = src; + src += pieces->data_size; + pieces->init = src; + src += pieces->init_size; + pieces->init_data = src; + src += pieces->init_data_size; + + return 0; +} + +static int iwl_parse_tlv_firmware(struct iwl_nic *nic, + const struct firmware *ucode_raw, + struct iwlagn_firmware_pieces *pieces, + struct iwl_ucode_capabilities *capa) +{ + struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; + struct iwl_ucode_tlv *tlv; + size_t len = ucode_raw->size; + const u8 *data; + int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; + int tmp; + u64 alternatives; + u32 tlv_len; + enum iwl_ucode_tlv_type tlv_type; + const u8 *tlv_data; + char buildstr[25]; + u32 build; + + if (len < sizeof(*ucode)) { + IWL_ERR(nic, "uCode has invalid length: %zd\n", len); + return -EINVAL; + } + + if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { + IWL_ERR(nic, "invalid uCode magic: 0X%x\n", + le32_to_cpu(ucode->magic)); + return -EINVAL; + } + + /* + * Check which alternatives are present, and "downgrade" + * when the chosen alternative is not present, warning + * the user when that happens. Some files may not have + * any alternatives, so don't warn in that case. + */ + alternatives = le64_to_cpu(ucode->alternatives); + tmp = wanted_alternative; + if (wanted_alternative > 63) + wanted_alternative = 63; + while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) + wanted_alternative--; + if (wanted_alternative && wanted_alternative != tmp) + IWL_WARN(nic, + "uCode alternative %d not available, choosing %d\n", + tmp, wanted_alternative); + + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); + build = le32_to_cpu(ucode->build); + + if (build) + sprintf(buildstr, " build %u%s", build, + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) + ? " (EXP)" : ""); + else + buildstr[0] = '\0'; + + snprintf(nic->fw.fw_version, + sizeof(nic->fw.fw_version), + "%u.%u.%u.%u%s", + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), + buildstr); + + data = ucode->data; + + len -= sizeof(*ucode); + + while (len >= sizeof(*tlv)) { + u16 tlv_alt; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le16_to_cpu(tlv->type); + tlv_alt = le16_to_cpu(tlv->alternative); + tlv_data = tlv->data; + + if (len < tlv_len) { + IWL_ERR(nic, "invalid TLV len: %zd/%u\n", + len, tlv_len); + return -EINVAL; + } + len -= ALIGN(tlv_len, 4); + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + + /* + * Alternative 0 is always valid. + * + * Skip alternative TLVs that are not selected. + */ + if (tlv_alt != 0 && tlv_alt != wanted_alternative) + continue; + + switch (tlv_type) { + case IWL_UCODE_TLV_INST: + pieces->inst = tlv_data; + pieces->inst_size = tlv_len; + break; + case IWL_UCODE_TLV_DATA: + pieces->data = tlv_data; + pieces->data_size = tlv_len; + break; + case IWL_UCODE_TLV_INIT: + pieces->init = tlv_data; + pieces->init_size = tlv_len; + break; + case IWL_UCODE_TLV_INIT_DATA: + pieces->init_data = tlv_data; + pieces->init_data_size = tlv_len; + break; + case IWL_UCODE_TLV_BOOT: + IWL_ERR(nic, "Found unexpected BOOT ucode\n"); + break; + case IWL_UCODE_TLV_PROBE_MAX_LEN: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + capa->max_probe_length = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_PAN: + if (tlv_len) + goto invalid_tlv_len; + 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)) + goto invalid_tlv_len; + pieces->init_evtlog_ptr = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + pieces->init_evtlog_size = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_INIT_ERRLOG_PTR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + pieces->init_errlog_ptr = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + pieces->inst_evtlog_ptr = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + pieces->inst_evtlog_size = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + pieces->inst_errlog_ptr = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_ENHANCE_SENS_TBL: + if (tlv_len) + goto invalid_tlv_len; + nic->fw.enhance_sensitivity_table = true; + break; + case IWL_UCODE_TLV_WOWLAN_INST: + pieces->wowlan_inst = tlv_data; + pieces->wowlan_inst_size = tlv_len; + break; + case IWL_UCODE_TLV_WOWLAN_DATA: + pieces->wowlan_data = tlv_data; + pieces->wowlan_data_size = tlv_len; + break; + case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + capa->standard_phy_calibration_size = + le32_to_cpup((__le32 *)tlv_data); + break; + default: + IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type); + break; + } + } + + if (len) { + IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len); + iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len); + return -EINVAL; + } + + return 0; + + invalid_tlv_len: + IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); + iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len); + + return -EINVAL; +} + +/** + * iwl_ucode_callback - callback when firmware was loaded + * + * If loaded successfully, copies the firmware into buffers + * for the card to fetch (via DMA). + */ +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) +{ + struct iwl_nic *nic = context; + struct iwl_cfg *cfg = cfg(nic); + struct iwl_fw *fw = &nic->fw; + struct iwl_ucode_header *ucode; + int err; + struct iwlagn_firmware_pieces pieces; + const unsigned int api_max = cfg->ucode_api_max; + unsigned int api_ok = cfg->ucode_api_ok; + const unsigned int api_min = cfg->ucode_api_min; + u32 api_ver; + + fw->ucode_capa.max_probe_length = 200; + fw->ucode_capa.standard_phy_calibration_size = + IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; + + if (!api_ok) + api_ok = api_max; + + memset(&pieces, 0, sizeof(pieces)); + + if (!ucode_raw) { + if (nic->fw_index <= api_ok) + IWL_ERR(nic, + "request for firmware file '%s' failed.\n", + nic->firmware_name); + goto try_again; + } + + IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n", + nic->firmware_name, ucode_raw->size); + + /* Make sure that we got at least the API version number */ + if (ucode_raw->size < 4) { + IWL_ERR(nic, "File size way too small!\n"); + goto try_again; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (struct iwl_ucode_header *)ucode_raw->data; + + if (ucode->ver) + err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); + else + err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, + &fw->ucode_capa); + + if (err) + goto try_again; + + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); + + /* + * api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firmware header from here on forward + */ + /* no api version check required for experimental uCode */ + if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { + if (api_ver < api_min || api_ver > api_max) { + IWL_ERR(nic, + "Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + goto try_again; + } + + if (api_ver < api_ok) { + if (api_ok != api_max) + IWL_ERR(nic, "Firmware has old API version, " + "expected v%u through v%u, got v%u.\n", + api_ok, api_max, api_ver); + else + IWL_ERR(nic, "Firmware has old API version, " + "expected v%u, got v%u.\n", + api_max, api_ver); + IWL_ERR(nic, "New firmware can be obtained from " + "http://www.intellinuxwireless.org/.\n"); + } + } + + IWL_INFO(nic, "loaded firmware version %s", nic->fw.fw_version); + + /* + * For any of the failures below (before allocating pci memory) + * we will try to load a version with a smaller API -- maybe the + * user just got a corrupted version of the latest API. + */ + + IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n", + nic->fw.ucode_ver); + IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n", + pieces.inst_size); + IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n", + pieces.data_size); + IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n", + pieces.init_size); + IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n", + pieces.init_data_size); + + /* Verify that uCode images will fit in card's SRAM */ + if (pieces.inst_size > cfg->max_inst_size) { + IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", + pieces.inst_size); + goto try_again; + } + + if (pieces.data_size > cfg->max_data_size) { + IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", + pieces.data_size); + goto try_again; + } + + if (pieces.init_size > cfg->max_inst_size) { + IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", + pieces.init_size); + goto try_again; + } + + if (pieces.init_data_size > cfg->max_data_size) { + IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", + pieces.init_data_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 */ + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code, + pieces.inst, pieces.inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data, + pieces.data, pieces.data_size)) + goto err_pci_alloc; + + /* Initialization instructions and data */ + if (pieces.init_size && pieces.init_data_size) { + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.code, + pieces.init, pieces.init_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.data, + pieces.init_data, pieces.init_data_size)) + goto err_pci_alloc; + } + + /* WoWLAN instructions and data */ + if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.code, + pieces.wowlan_inst, + pieces.wowlan_inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.data, + pieces.wowlan_data, + pieces.wowlan_data_size)) + goto err_pci_alloc; + } + + /* Now that we can no longer fail, copy information */ + + /* + * The (size - 16) / 12 formula is based on the information recorded + * for each event, which is of mode 1 (including timestamp) for all + * new microcodes that include this information. + */ + nic->init_evtlog_ptr = pieces.init_evtlog_ptr; + if (pieces.init_evtlog_size) + nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; + else + nic->init_evtlog_size = + cfg->base_params->max_event_log_size; + nic->init_errlog_ptr = pieces.init_errlog_ptr; + nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; + if (pieces.inst_evtlog_size) + nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; + else + nic->inst_evtlog_size = + cfg->base_params->max_event_log_size; + nic->inst_errlog_ptr = pieces.inst_errlog_ptr; + + /* + * figure out the offset of chain noise reset and gain commands + * base on the size of standard phy calibration commands table size + */ + if (fw->ucode_capa.standard_phy_calibration_size > + IWL_MAX_PHY_CALIBRATE_TBL_SIZE) + fw->ucode_capa.standard_phy_calibration_size = + IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + complete(&nic->request_firmware_complete); + + nic->op_mode = iwl_dvm_ops.start(nic->shrd->trans); + + if (!nic->op_mode) + goto out_unbind; + + return; + + try_again: + /* try next, if any */ + release_firmware(ucode_raw); + if (iwl_request_firmware(nic, false)) + goto out_unbind; + return; + + err_pci_alloc: + IWL_ERR(nic, "failed to allocate pci memory\n"); + iwl_dealloc_ucode(nic); + release_firmware(ucode_raw); + out_unbind: + complete(&nic->request_firmware_complete); + device_release_driver(trans(nic)->dev); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h new file mode 100644 index 0000000..8bebeb0 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h @@ -0,0 +1,220 @@ +/****************************************************************************** + * + * 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 - 2012 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 - 2012 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_ucode_h__ +#define __iwl_ucode_h__ + +#include <linux/netdevice.h> + +/* v1/v2 uCode file layout */ +struct iwl_ucode_header { + __le32 ver; /* major/minor/API/serial */ + union { + struct { + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v1; + struct { + __le32 build; /* build number */ + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v2; + } u; +}; + +/* + * new TLV uCode file layout + * + * The new TLV file format contains TLVs, that each specify + * some piece of data. To facilitate "groups", for example + * different instruction image with different capabilities, + * bundled with the same init image, an alternative mechanism + * is provided: + * When the alternative field is 0, that means that the item + * is always valid. When it is non-zero, then it is only + * valid in conjunction with items of the same alternative, + * in which case the driver (user) selects one alternative + * to use. + */ + +enum iwl_ucode_tlv_type { + IWL_UCODE_TLV_INVALID = 0, /* unused */ + IWL_UCODE_TLV_INST = 1, + IWL_UCODE_TLV_DATA = 2, + IWL_UCODE_TLV_INIT = 3, + IWL_UCODE_TLV_INIT_DATA = 4, + IWL_UCODE_TLV_BOOT = 5, + IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ + IWL_UCODE_TLV_PAN = 7, + IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, + IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, + IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, + IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11, + IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12, + IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, + IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, + IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + IWL_UCODE_TLV_WOWLAN_INST = 16, + IWL_UCODE_TLV_WOWLAN_DATA = 17, + 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). + * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. + */ +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), + IWL_UCODE_TLV_FLAGS_P2P = BIT(3), +}; + +struct iwl_ucode_tlv { + __le16 type; /* see above */ + __le16 alternative; /* see comment */ + __le32 length; /* not including type/length fields */ + u8 data[0]; +}; + +#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 + +struct iwl_tlv_ucode_header { + /* + * The TLV style ucode header is distinguished from + * the v1/v2 style header by first four bytes being + * zero, as such is an invalid combination of + * major/minor/API/serial versions. + */ + __le32 zero; + __le32 magic; + u8 human_readable[64]; + __le32 ver; /* major/minor/API/serial */ + __le32 build; + __le64 alternatives; /* bitmask of valid alternatives */ + /* + * The data contained herein has a TLV layout, + * see above for the TLV header and types. + * Note that each TLV is padded to a length + * that is a multiple of 4 for alignment. + */ + u8 data[0]; +}; + +struct iwl_ucode_capabilities { + u32 max_probe_length; + u32 standard_phy_calibration_size; + u32 flags; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + dma_addr_t p_addr; /* hardware address */ + void *v_addr; /* software address */ + u32 len; /* size in bytes */ +}; + +struct fw_img { + struct fw_desc code; /* firmware code image */ + struct fw_desc data; /* firmware data image */ +}; + +/** + * struct iwl_fw - variables associated with the firmware + * + * @ucode_ver: ucode version from the ucode file + * @fw_version: firmware version string + * @ucode_rt: run time ucode image + * @ucode_init: init ucode image + * @ucode_wowlan: wake on wireless ucode image (optional) + * @ucode_capa: capabilities parsed from the ucode file. + * @enhance_sensitivity_table: device can do enhanced sensitivity. + */ +struct iwl_fw { + + u32 ucode_ver; + + char fw_version[ETHTOOL_BUSINFO_LEN]; + + /* ucode images */ + struct fw_img ucode_rt; + struct fw_img ucode_init; + struct fw_img ucode_wowlan; + + struct iwl_ucode_capabilities ucode_capa; + bool enhance_sensitivity_table; +}; + +#endif /* __iwl_ucode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index 1850110..d5cba07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2011 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,6 +64,43 @@ #define __iwl_wifi_h__ #include "iwl-shared.h" +#include "iwl-ucode.h" + +#define UCODE_EXPERIMENTAL_INDEX 100 + +/** + * struct iwl_nic - nic common data + * @fw: the iwl_fw structure + * @shrd: pointer to common shared structure + * @op_mode: the running op_mode + * @fw_index: firmware revision to try loading + * @firmware_name: composite filename of ucode file to load + * @init_evtlog_ptr: event log offset for init ucode. + * @init_evtlog_size: event log size for init ucode. + * @init_errlog_ptr: error log offfset for init ucode. + * @inst_evtlog_ptr: event log offset for runtime ucode. + * @inst_evtlog_size: event log size for runtime ucode. + * @inst_errlog_ptr: error log offfset for runtime ucode. + * @request_firmware_complete: the firmware has been obtained from user space + */ +struct iwl_nic { + struct iwl_fw fw; + + struct iwl_shared *shrd; + struct iwl_op_mode *op_mode; + + int fw_index; /* firmware we're trying to load */ + char firmware_name[25]; /* name of firmware file to load */ + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + struct completion request_firmware_complete; +}; + + +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first); +void iwl_dealloc_ucode(struct iwl_nic *nic); int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); void iwl_send_prio_tbl(struct iwl_trans *trans); |