Commit 623c4387 authored by John W. Linville's avatar John W. Linville
parents 204e35a9 cf4ef654
...@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) ...@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue); flush_workqueue(priv->workqueue);
/* User space software may expect getting rfkill changes
* even if interface is down, trans->down will leave the RF
* kill interrupt enabled
*/
iwl_trans_stop_hw(priv->trans, false);
IWL_DEBUG_MAC80211(priv, "leave\n"); IWL_DEBUG_MAC80211(priv, "leave\n");
} }
......
...@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ...@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
} }
/* Reset chip to save power until we load uCode during "up". */ /* Reset chip to save power until we load uCode during "up". */
iwl_trans_stop_hw(priv->trans, false); iwl_trans_stop_device(priv->trans);
priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg, priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
priv->eeprom_blob, priv->eeprom_blob,
...@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) ...@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
dev_kfree_skb(priv->beacon_skb); dev_kfree_skb(priv->beacon_skb);
iwl_trans_stop_hw(priv->trans, true); iwl_trans_op_mode_leave(priv->trans);
ieee80211_free_hw(priv->hw); ieee80211_free_hw(priv->hw);
} }
......
...@@ -108,7 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = { ...@@ -108,7 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = {
}; };
static const struct iwl_ht_params iwl7000_ht_params = { static const struct iwl_ht_params iwl7000_ht_params = {
.use_rts_for_aggregation = true, /* use rts/cts protection */ .stbc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
}; };
......
...@@ -162,12 +162,14 @@ struct iwl_base_params { ...@@ -162,12 +162,14 @@ struct iwl_base_params {
}; };
/* /*
* @stbc: support Tx STBC and 1*SS Rx STBC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic * @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/ */
struct iwl_ht_params { struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode; enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */ const bool ht_greenfield_support; /* if used set to true */
const bool stbc;
bool use_rts_for_aggregation; bool use_rts_for_aggregation;
u8 ht40_bands; u8 ht40_bands;
}; };
......
...@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces, ...@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
pieces->img[type].sec[sec].offset = offset; pieces->img[type].sec[sec].offset = offset;
} }
static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
{
int i, j;
struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
struct iwl_fw_cipher_scheme *fwcs;
struct ieee80211_cipher_scheme *cs;
u32 cipher;
if (len < sizeof(*l) ||
len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
return -EINVAL;
for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
fwcs = &l->cs[j];
cipher = le32_to_cpu(fwcs->cipher);
/* we skip schemes with zero cipher suite selector */
if (!cipher)
continue;
cs = &fw->cs[j++];
cs->cipher = cipher;
cs->iftype = BIT(NL80211_IFTYPE_STATION);
cs->hdr_len = fwcs->hdr_len;
cs->pn_len = fwcs->pn_len;
cs->pn_off = fwcs->pn_off;
cs->key_idx_off = fwcs->key_idx_off;
cs->key_idx_mask = fwcs->key_idx_mask;
cs->key_idx_shift = fwcs->key_idx_shift;
cs->mic_len = fwcs->mic_len;
}
return 0;
}
/* /*
* Gets uCode section from tlv. * Gets uCode section from tlv.
*/ */
...@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, ...@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return -EINVAL; return -EINVAL;
} }
break; break;
case IWL_UCODE_TLV_CSCHEME:
if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
goto invalid_tlv_len;
break;
default: default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break; break;
......
...@@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ...@@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->ht_supported = true; ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40; ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
if (cfg->ht_params->stbc) {
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
if (tx_chains > 1)
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
}
if (iwlwifi_mod_params.amsdu_size_8K) if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
......
...@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type { ...@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SECURE_SEC_INIT = 25, IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
IWL_UCODE_TLV_NUM_OF_CPU = 27, IWL_UCODE_TLV_NUM_OF_CPU = 27,
IWL_UCODE_TLV_CSCHEME = 28,
}; };
struct iwl_ucode_tlv { struct iwl_ucode_tlv {
......
...@@ -92,6 +92,9 @@ ...@@ -92,6 +92,9 @@
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
* containing CAM (Continuous Active Mode) indication. * containing CAM (Continuous Active Mode) indication.
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
* single bound interface).
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
*/ */
enum iwl_ucode_tlv_flag { enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0), IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
...@@ -113,7 +116,9 @@ enum iwl_ucode_tlv_flag { ...@@ -113,7 +116,9 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20), IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
}; };
/* The default calibrate table size if not specified by firmware file */ /* The default calibrate table size if not specified by firmware file */
...@@ -209,6 +214,44 @@ enum iwl_fw_phy_cfg { ...@@ -209,6 +214,44 @@ enum iwl_fw_phy_cfg {
FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
}; };
#define IWL_UCODE_MAX_CS 1
/**
* struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
* @cipher: a cipher suite selector
* @flags: cipher scheme flags (currently reserved for a future use)
* @hdr_len: a size of MPDU security header
* @pn_len: a size of PN
* @pn_off: an offset of pn from the beginning of the security header
* @key_idx_off: an offset of key index byte in the security header
* @key_idx_mask: a bit mask of key_idx bits
* @key_idx_shift: bit shift needed to get key_idx
* @mic_len: mic length in bytes
* @hw_cipher: a HW cipher index used in host commands
*/
struct iwl_fw_cipher_scheme {
__le32 cipher;
u8 flags;
u8 hdr_len;
u8 pn_len;
u8 pn_off;
u8 key_idx_off;
u8 key_idx_mask;
u8 key_idx_shift;
u8 mic_len;
u8 hw_cipher;
} __packed;
/**
* struct iwl_fw_cscheme_list - a cipher scheme list
* @size: a number of entries
* @cs: cipher scheme entries
*/
struct iwl_fw_cscheme_list {
u8 size;
struct iwl_fw_cipher_scheme cs[];
} __packed;
/** /**
* struct iwl_fw - variables associated with the firmware * struct iwl_fw - variables associated with the firmware
* *
...@@ -224,6 +267,7 @@ enum iwl_fw_phy_cfg { ...@@ -224,6 +267,7 @@ enum iwl_fw_phy_cfg {
* @inst_evtlog_size: event log size for runtime ucode. * @inst_evtlog_size: event log size for runtime ucode.
* @inst_errlog_ptr: error log offfset for runtime ucode. * @inst_errlog_ptr: error log offfset for runtime ucode.
* @mvm_fw: indicates this is MVM firmware * @mvm_fw: indicates this is MVM firmware
* @cipher_scheme: optional external cipher scheme.
*/ */
struct iwl_fw { struct iwl_fw {
u32 ucode_ver; u32 ucode_ver;
...@@ -243,6 +287,8 @@ struct iwl_fw { ...@@ -243,6 +287,8 @@ struct iwl_fw {
u32 phy_config; u32 phy_config;
bool mvm_fw; bool mvm_fw;
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
}; };
static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
......
...@@ -263,13 +263,20 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, ...@@ -263,13 +263,20 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap) struct ieee80211_sta_vht_cap *vht_cap)
{ {
int num_ants = num_of_ant(data->valid_rx_ant);
int bf_sts_cap = num_ants - 1;
vht_cap->vht_supported = true; vht_cap->vht_supported = true;
vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 | vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (num_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
if (iwlwifi_mod_params.amsdu_size_8K) if (iwlwifi_mod_params.amsdu_size_8K)
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
...@@ -283,16 +290,22 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, ...@@ -283,16 +290,22 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
if (num_of_ant(data->valid_rx_ant) == 1 || /* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
vht_cap->vht_mcs.rx_highest = cpu_to_le16(780);
if (num_ants == 1 ||
cfg->rx_with_siso_diversity) { cfg->rx_with_siso_diversity) {
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
/* this works because NOT_SUPPORTED == 3 */ /* this works because NOT_SUPPORTED == 3 */
vht_cap->vht_mcs.rx_mcs_map |= vht_cap->vht_mcs.rx_mcs_map |=
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
/* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
vht_cap->vht_mcs.rx_highest = cpu_to_le16(390);
} }
vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
} }
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
......
...@@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name); ...@@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name);
/** /**
* struct iwl_op_mode - operational mode * struct iwl_op_mode - operational mode
* @ops - pointer to its own ops
* *
* This holds an implementation of the mac80211 / fw API. * This holds an implementation of the mac80211 / fw API.
*
* @ops - pointer to its own ops
*/ */
struct iwl_op_mode { struct iwl_op_mode {
const struct iwl_op_mode_ops *ops; const struct iwl_op_mode_ops *ops;
const struct iwl_trans *trans;
char op_mode_specific[0] __aligned(sizeof(void *)); char op_mode_specific[0] __aligned(sizeof(void *));
}; };
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#include "iwl-debug.h" #include "iwl-debug.h"
#include "iwl-config.h" #include "iwl-config.h"
#include "iwl-fw.h" #include "iwl-fw.h"
#include "iwl-op-mode.h"
/** /**
* DOC: Transport layer - what is it ? * DOC: Transport layer - what is it ?
...@@ -100,8 +101,7 @@ ...@@ -100,8 +101,7 @@
* start_fw * start_fw
* *
* 5) Then when finished (or reset): * 5) Then when finished (or reset):
* stop_fw (a.k.a. stop device for the moment) * stop_device
* stop_hw
* *
* 6) Eventually, the free function will be called. * 6) Eventually, the free function will be called.
*/ */
...@@ -317,6 +317,24 @@ enum iwl_d3_status { ...@@ -317,6 +317,24 @@ enum iwl_d3_status {
IWL_D3_STATUS_RESET, IWL_D3_STATUS_RESET,
}; };
/**
* enum iwl_trans_status: transport status flags
* @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
*/
enum iwl_trans_status {
STATUS_SYNC_HCMD_ACTIVE,
STATUS_DEVICE_ENABLED,
STATUS_TPOWER_PMI,
STATUS_INT_ENABLED,
STATUS_RFKILL,
STATUS_FW_ERROR,
};
/** /**
* struct iwl_trans_config - transport configuration * struct iwl_trans_config - transport configuration
* *
...@@ -361,9 +379,7 @@ struct iwl_trans; ...@@ -361,9 +379,7 @@ struct iwl_trans;
* *
* @start_hw: starts the HW- from that point on, the HW can send interrupts * @start_hw: starts the HW- from that point on, the HW can send interrupts
* May sleep * May sleep
* @stop_hw: stops the HW- from that point on, the HW will be in low power but * @op_mode_leave: Turn off the HW RF kill indication if on
* will still issue interrupt if the HW RF kill is triggered unless
* op_mode_leaving is true.
* May sleep * May sleep
* @start_fw: allocates and inits all the resources for the transport * @start_fw: allocates and inits all the resources for the transport
* layer. Also kick a fw image. * layer. Also kick a fw image.
...@@ -371,8 +387,11 @@ struct iwl_trans; ...@@ -371,8 +387,11 @@ struct iwl_trans;
* @fw_alive: called when the fw sends alive notification. If the fw provides * @fw_alive: called when the fw sends alive notification. If the fw provides
* the SCD base address in SRAM, then provide it here, or 0 otherwise. * the SCD base address in SRAM, then provide it here, or 0 otherwise.
* May sleep * May sleep
* @stop_device:stops the whole device (embedded CPU put to reset) * @stop_device: stops the whole device (embedded CPU put to reset) and stops
* May sleep * 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. This callback must do
* the right thing and not crash even if start_hw() was called but not
* start_fw(). May sleep
* @d3_suspend: put the device into the correct mode for WoWLAN during * @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be * suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep. * supported. This callback may sleep.
...@@ -418,7 +437,7 @@ struct iwl_trans; ...@@ -418,7 +437,7 @@ struct iwl_trans;
struct iwl_trans_ops { struct iwl_trans_ops {
int (*start_hw)(struct iwl_trans *iwl_trans); int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); void (*op_mode_leave)(struct iwl_trans *iwl_trans);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
bool run_in_rfkill); bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
...@@ -479,6 +498,7 @@ enum iwl_trans_state { ...@@ -479,6 +498,7 @@ enum iwl_trans_state {
* @ops - pointer to iwl_trans_ops * @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode * @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration * @cfg - pointer to the configuration
* @status: a bit-mask of transport status flags
* @dev - pointer to struct device * that represents the device * @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice. * @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation. * Set during transport allocation.
...@@ -499,6 +519,7 @@ struct iwl_trans { ...@@ -499,6 +519,7 @@ struct iwl_trans {
struct iwl_op_mode *op_mode; struct iwl_op_mode *op_mode;
const struct iwl_cfg *cfg; const struct iwl_cfg *cfg;
enum iwl_trans_state state; enum iwl_trans_state state;
unsigned long status;
struct device *dev; struct device *dev;
u32 hw_rev; u32 hw_rev;
...@@ -540,14 +561,13 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans) ...@@ -540,14 +561,13 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return trans->ops->start_hw(trans); return trans->ops->start_hw(trans);
} }
static inline void iwl_trans_stop_hw(struct iwl_trans *trans, static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
bool op_mode_leaving)
{ {
might_sleep(); might_sleep();
trans->ops->stop_hw(trans, op_mode_leaving); if (trans->ops->op_mode_leave)
trans->ops->op_mode_leave(trans);
if (op_mode_leaving)
trans->op_mode = NULL; trans->op_mode = NULL;
trans->state = IWL_TRANS_NO_FW; trans->state = IWL_TRANS_NO_FW;
...@@ -570,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans, ...@@ -570,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
WARN_ON_ONCE(!trans->rx_mpdu_cmd); WARN_ON_ONCE(!trans->rx_mpdu_cmd);
clear_bit(STATUS_FW_ERROR, &trans->status);
return trans->ops->start_fw(trans, fw, run_in_rfkill); return trans->ops->start_fw(trans, fw, run_in_rfkill);
} }
...@@ -601,6 +622,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans, ...@@ -601,6 +622,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
{ {
int ret; int ret;
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
return -EIO;
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) { if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
return -EIO; return -EIO;
...@@ -640,6 +664,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, ...@@ -640,6 +664,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, int queue) struct iwl_device_cmd *dev_cmd, int queue)
{ {
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
return -EIO;
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
...@@ -760,6 +787,7 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, ...@@ -760,6 +787,7 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{ {
if (trans->ops->set_pmi)
trans->ops->set_pmi(trans, state); trans->ops->set_pmi(trans, state);
} }
...@@ -780,6 +808,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) ...@@ -780,6 +808,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
__release(nic_access); __release(nic_access);
} }
static inline void iwl_trans_fw_error(struct iwl_trans *trans)
{
if (WARN_ON_ONCE(!trans->op_mode))
return;
/* prevent double restarts due to the same erroneous FW */
if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
iwl_op_mode_nic_error(trans->op_mode);
}
/***************************************************** /*****************************************************
* driver (transport) register/unregister functions * driver (transport) register/unregister functions
******************************************************/ ******************************************************/
......
obj-$(CONFIG_IWLMVM) += iwlmvm.o obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o power_legacy.o bt-coex.o iwlmvm-y += power.o power_legacy.o bt-coex.o
iwlmvm-y += led.o tt.o iwlmvm-y += led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
......
...@@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL; return -EINVAL;
/*
* Update SF - Disable if needed. if this fails, SF might still be on
* while many macs are bound, which is forbidden - so fail the binding.
*/
if (iwl_mvm_sf_update(mvm, vif, false))
return -EINVAL;
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true); return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
} }
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL; return -EINVAL;
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false); ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
if (!ret)
if (iwl_mvm_sf_update(mvm, vif, true))
IWL_ERR(mvm, "Failed to update SF state\n");
return ret;
} }
...@@ -85,6 +85,8 @@ ...@@ -85,6 +85,8 @@
* PBW Snoozing enabled * PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
* @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
* detection enablement
*/ */
enum iwl_power_flags { enum iwl_power_flags {
POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
...@@ -94,6 +96,7 @@ enum iwl_power_flags { ...@@ -94,6 +96,7 @@ enum iwl_power_flags {
POWER_FLAGS_BT_SCO_ENA = BIT(8), POWER_FLAGS_BT_SCO_ENA = BIT(8),
POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9),
POWER_FLAGS_LPRX_ENA_MSK = BIT(11), POWER_FLAGS_LPRX_ENA_MSK = BIT(11),
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK = BIT(12),
}; };
#define IWL_POWER_VEC_SIZE 5 #define IWL_POWER_VEC_SIZE 5
...@@ -228,6 +231,19 @@ struct iwl_mac_power_cmd { ...@@ -228,6 +231,19 @@ struct iwl_mac_power_cmd {
u8 reserved; u8 reserved;
} __packed; } __packed;
/*
* struct iwl_uapsd_misbehaving_ap_notif - FW sends this notification when
* associated AP is identified as improperly implementing uAPSD protocol.
* PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78
* @sta_id: index of station in uCode's station table - associated AP ID in
* this context.
*/
struct iwl_uapsd_misbehaving_ap_notif {
__le32 sta_id;
u8 mac_id;
u8 reserved[3];
} __packed;
/** /**
* struct iwl_beacon_filter_cmd * struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
......
...@@ -138,7 +138,14 @@ enum iwl_sta_flags { ...@@ -138,7 +138,14 @@ enum iwl_sta_flags {
/** /**
* enum iwl_sta_key_flag - key flags for the ADD_STA host command * enum iwl_sta_key_flag - key flags for the ADD_STA host command
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithm * @STA_KEY_FLG_NO_ENC: no encryption
* @STA_KEY_FLG_WEP: WEP encryption algorithm
* @STA_KEY_FLG_CCM: CCMP encryption algorithm
* @STA_KEY_FLG_TKIP: TKIP encryption algorithm
* @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
* @STA_KEY_FLG_CMAC: CMAC encryption algorithm
* @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
* @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
* station info array (1 - n 1X mode) * station info array (1 - n 1X mode)
* @STA_KEY_FLG_KEYID_MSK: the index of the key * @STA_KEY_FLG_KEYID_MSK: the index of the key
...@@ -152,6 +159,7 @@ enum iwl_sta_key_flag { ...@@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_WEP = (1 << 0), STA_KEY_FLG_WEP = (1 << 0),
STA_KEY_FLG_CCM = (2 << 0), STA_KEY_FLG_CCM = (2 << 0),
STA_KEY_FLG_TKIP = (3 << 0), STA_KEY_FLG_TKIP = (3 << 0),
STA_KEY_FLG_EXT = (4 << 0),
STA_KEY_FLG_CMAC = (6 << 0), STA_KEY_FLG_CMAC = (6 << 0),
STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
STA_KEY_FLG_EN_MSK = (7 << 0), STA_KEY_FLG_EN_MSK = (7 << 0),
......
...@@ -132,6 +132,7 @@ enum iwl_tx_flags { ...@@ -132,6 +132,7 @@ enum iwl_tx_flags {
#define TX_CMD_SEC_WEP 0x01 #define TX_CMD_SEC_WEP 0x01
#define TX_CMD_SEC_CCM 0x02 #define TX_CMD_SEC_CCM 0x02
#define TX_CMD_SEC_TKIP 0x03 #define TX_CMD_SEC_TKIP 0x03
#define TX_CMD_SEC_EXT 0x04
#define TX_CMD_SEC_MSK 0x07 #define TX_CMD_SEC_MSK 0x07
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define TX_CMD_SEC_WEP_KEY_IDX_POS 6
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
......
...@@ -141,6 +141,7 @@ enum { ...@@ -141,6 +141,7 @@ enum {
/* Power - legacy power table command */ /* Power - legacy power table command */
POWER_TABLE_CMD = 0x77, POWER_TABLE_CMD = 0x77,
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
/* Thermal Throttling*/ /* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e, REPLY_THERMAL_MNG_BACKOFF = 0x7e,
...@@ -183,6 +184,7 @@ enum { ...@@ -183,6 +184,7 @@ enum {
BT_PROFILE_NOTIFICATION = 0xce, BT_PROFILE_NOTIFICATION = 0xce,
BT_COEX_CI = 0x5d, BT_COEX_CI = 0x5d,
REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2, REPLY_BEACON_FILTERING_CMD = 0xd2,
REPLY_DEBUG_CMD = 0xf0, REPLY_DEBUG_CMD = 0xf0,
...@@ -1052,6 +1054,7 @@ enum iwl_mvm_rx_status { ...@@ -1052,6 +1054,7 @@ enum iwl_mvm_rx_status {
RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8), RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8), RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
...@@ -1131,6 +1134,7 @@ struct iwl_set_calib_default_cmd { ...@@ -1131,6 +1134,7 @@ struct iwl_set_calib_default_cmd {
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
#define MAX_PORT_ID_NUM 2 #define MAX_PORT_ID_NUM 2
#define MAX_MCAST_FILTERING_ADDRESSES 256
/** /**
* struct iwl_mcast_filter_cmd - configure multicast filter. * struct iwl_mcast_filter_cmd - configure multicast filter.
...@@ -1363,4 +1367,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */ ...@@ -1363,4 +1367,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
struct mvm_statistics_general general; struct mvm_statistics_general general;
} __packed; } __packed;
/***********************************
* Smart Fifo API
***********************************/
/* Smart Fifo state */
enum iwl_sf_state {
SF_LONG_DELAY_ON = 0, /* should never be called by driver */
SF_FULL_ON,
SF_UNINIT,
SF_INIT_OFF,
SF_HW_NUM_STATES
};
/* Smart Fifo possible scenario */
enum iwl_sf_scenario {
SF_SCENARIO_SINGLE_UNICAST,
SF_SCENARIO_AGG_UNICAST,
SF_SCENARIO_MULTICAST,
SF_SCENARIO_BA_RESP,
SF_SCENARIO_TX_RESP,
SF_NUM_SCENARIO
};
#define SF_TRANSIENT_STATES_NUMBER 2 /* SF_LONG_DELAY_ON and SF_FULL_ON */
#define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */
/* smart FIFO default values */
#define SF_W_MARK_SISO 4096
#define SF_W_MARK_MIMO2 8192
#define SF_W_MARK_MIMO3 6144
#define SF_W_MARK_LEGACY 4096
#define SF_W_MARK_SCAN 4096
/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */
#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */
#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */
#define SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */
#define SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */
#define SF_MCAST_AGING_TIMER 10016 /* 10 mSec */
#define SF_BA_IDLE_TIMER 320 /* 300 uSec */
#define SF_BA_AGING_TIMER 2016 /* 2 mSec */
#define SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */
#define SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */
#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
/**
* Smart Fifo configuration command.
* @state: smart fifo state, types listed in iwl_sf_sate.
* @watermark: Minimum allowed availabe free space in RXF for transient state.
* @long_delay_timeouts: aging and idle timer values for each scenario
* in long delay state.
* @full_on_timeouts: timer values for each scenario in full on state.
*/
struct iwl_sf_cfg_cmd {
enum iwl_sf_state state;
__le32 watermark[SF_TRANSIENT_STATES_NUMBER];
__le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
} __packed; /* SF_CFG_API_S_VER_2 */
#endif /* __fw_api_h__ */ #endif /* __fw_api_h__ */
...@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (mvm->init_ucode_complete) if (WARN_ON_ONCE(mvm->init_ucode_complete))
return 0; return 0;
iwl_init_notification_wait(&mvm->notif_wait, iwl_init_notification_wait(&mvm->notif_wait,
...@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_DEBUG_RF_KILL(mvm, IWL_DEBUG_RF_KILL(mvm,
"jump over all phy activities due to RF kill\n"); "jump over all phy activities due to RF kill\n");
iwl_remove_notification(&mvm->notif_wait, &calib_wait); iwl_remove_notification(&mvm->notif_wait, &calib_wait);
return 1; ret = 1;
goto out;
} }
/* Send TX valid antennas before triggering calibrations */ /* Send TX valid antennas before triggering calibrations */
...@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
error: error:
iwl_remove_notification(&mvm->notif_wait, &calib_wait); iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out: out:
if (!iwlmvm_mod_params.init_dbg) { if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
iwl_trans_stop_device(mvm->trans);
} else if (!mvm->nvm_data) {
/* we want to debug INIT and we have no NVM - fake */ /* we want to debug INIT and we have no NVM - fake */
mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
sizeof(struct ieee80211_channel) + sizeof(struct ieee80211_channel) +
...@@ -370,12 +369,17 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -370,12 +369,17 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = -ERFKILL; ret = -ERFKILL;
goto error; goto error;
} }
/* should stop & start HW since that INIT image just loaded */ if (!iwlmvm_mod_params.init_dbg) {
iwl_trans_stop_hw(mvm->trans, false); /*
* should stop and start HW since that INIT
* image just loaded
*/
iwl_trans_stop_device(mvm->trans);
ret = iwl_trans_start_hw(mvm->trans); ret = iwl_trans_start_hw(mvm->trans);
if (ret) if (ret)
return ret; return ret;
} }
}
if (iwlmvm_mod_params.init_dbg) if (iwlmvm_mod_params.init_dbg)
return 0; return 0;
...@@ -386,6 +390,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -386,6 +390,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error; goto error;
} }
ret = iwl_mvm_sf_update(mvm, NULL, false);
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret) if (ret)
goto error; goto error;
......
This diff is collapsed.
...@@ -163,6 +163,8 @@ struct iwl_mvm_power_ops { ...@@ -163,6 +163,8 @@ struct iwl_mvm_power_ops {
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
int (*power_update_device_mode)(struct iwl_mvm *mvm); int (*power_update_device_mode)(struct iwl_mvm *mvm);
int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void (*power_update_binding)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, bool assign);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz); char *buf, int bufsz);
...@@ -181,6 +183,7 @@ enum iwl_dbgfs_pm_mask { ...@@ -181,6 +183,7 @@ enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_LPRX_ENA = BIT(6), MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
}; };
struct iwl_dbgfs_pm { struct iwl_dbgfs_pm {
...@@ -193,6 +196,7 @@ struct iwl_dbgfs_pm { ...@@ -193,6 +196,7 @@ struct iwl_dbgfs_pm {
bool lprx_ena; bool lprx_ena;
u32 lprx_rssi_threshold; u32 lprx_rssi_threshold;
bool snooze_ena; bool snooze_ena;
bool uapsd_misbehaving;
int mask; int mask;
}; };
...@@ -269,8 +273,8 @@ struct iwl_mvm_vif_bf_data { ...@@ -269,8 +273,8 @@ struct iwl_mvm_vif_bf_data {
* @bcast_sta: station used for broadcast packets. Used by the following * @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP. * vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template * @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the requests of of differents parts of the driver, regard * @smps_requests: the SMPS requests of differents parts of the driver,
the desired smps mode. * combined on update to yield the overall request to mac80211.
*/ */
struct iwl_mvm_vif { struct iwl_mvm_vif {
u16 id; u16 id;
...@@ -331,6 +335,11 @@ struct iwl_mvm_vif { ...@@ -331,6 +335,11 @@ struct iwl_mvm_vif {
#endif #endif
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
/* FW identified misbehaving AP */
u8 uapsd_misbehaving_bssid[ETH_ALEN];
bool pm_prevented;
}; };
static inline struct iwl_mvm_vif * static inline struct iwl_mvm_vif *
...@@ -479,6 +488,7 @@ struct iwl_mvm { ...@@ -479,6 +488,7 @@ struct iwl_mvm {
/* Scan status, cmd (pre-allocated) and auxiliary station */ /* Scan status, cmd (pre-allocated) and auxiliary station */
enum iwl_scan_status scan_status; enum iwl_scan_status scan_status;
struct iwl_scan_cmd *scan_cmd; struct iwl_scan_cmd *scan_cmd;
struct iwl_mcast_filter_cmd *mcast_filter_cmd;
/* rx chain antennas set through debugfs for the scan command */ /* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant; u8 scan_rx_ant;
...@@ -489,6 +499,9 @@ struct iwl_mvm { ...@@ -489,6 +499,9 @@ struct iwl_mvm {
u8 scan_last_antenna_idx; /* to toggle TX between antennas */ u8 scan_last_antenna_idx; /* to toggle TX between antennas */
u8 mgmt_last_antenna_idx; u8 mgmt_last_antenna_idx;
/* last smart fifo state that was successfully sent to firmware */
enum iwl_sf_state sf_state;
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len; u32 dbgfs_sram_offset, dbgfs_sram_len;
...@@ -512,12 +525,6 @@ struct iwl_mvm { ...@@ -512,12 +525,6 @@ struct iwl_mvm {
*/ */
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
/*
* This counter of created interfaces is referenced only in conjunction
* with FW limitation related to power management. Currently PM is
* supported only on a single interface.
* IMPORTANT: this variable counts all interfaces except P2P device.
*/
u8 vif_count; u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */ /* -1 for always, 0 for never, >0 for that many times */
...@@ -560,6 +567,11 @@ struct iwl_mvm { ...@@ -560,6 +567,11 @@ struct iwl_mvm {
u8 aux_queue; u8 aux_queue;
u8 first_agg_queue; u8 first_agg_queue;
u8 last_agg_queue; u8 last_agg_queue;
u8 bound_vif_cnt;
/* Indicate if device power save is allowed */
bool ps_prevented;
}; };
/* Extract MVM priv from op_mode and _hw */ /* Extract MVM priv from op_mode and _hw */
...@@ -778,6 +790,19 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm) ...@@ -778,6 +790,19 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
return 0; return 0;
} }
static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool assign)
{
if (mvm->pm_ops->power_update_binding)
mvm->pm_ops->power_update_binding(mvm, vif, assign);
}
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -869,4 +894,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); ...@@ -869,4 +894,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
void iwl_mvm_tt_exit(struct iwl_mvm *mvm); void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
/* smart fifo */
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool added_vif);
#endif /* __IWL_MVM_H__ */ #endif /* __IWL_MVM_H__ */
...@@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { ...@@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
false), false),
RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
}; };
#undef RX_HANDLER #undef RX_HANDLER
#define CMD(x) [x] = #x #define CMD(x) [x] = #x
...@@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { ...@@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE), CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI), CMD(BT_COEX_CI),
CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
}; };
#undef CMD #undef CMD
...@@ -341,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -341,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
op_mode = hw->priv; op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops; op_mode->ops = &iwl_mvm_ops;
op_mode->trans = trans;
mvm = IWL_OP_MODE_GET_MVM(op_mode); mvm = IWL_OP_MODE_GET_MVM(op_mode);
mvm->dev = trans->dev; mvm->dev = trans->dev;
...@@ -359,6 +361,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -359,6 +361,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->aux_queue = 11; mvm->aux_queue = 11;
mvm->first_agg_queue = 12; mvm->first_agg_queue = 12;
} }
mvm->sf_state = SF_UNINIT;
mutex_init(&mvm->mutex); mutex_init(&mvm->mutex);
spin_lock_init(&mvm->async_handlers_lock); spin_lock_init(&mvm->async_handlers_lock);
...@@ -424,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -424,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
* there is no need to unnecessarily power up the NIC at driver load * there is no need to unnecessarily power up the NIC at driver load
*/ */
if (iwlwifi_mod_params.nvm_file) { if (iwlwifi_mod_params.nvm_file) {
iwl_nvm_init(mvm); err = iwl_nvm_init(mvm);
if (err)
goto out_free;
} else { } else {
err = iwl_trans_start_hw(mvm->trans); err = iwl_trans_start_hw(mvm->trans);
if (err) if (err)
...@@ -432,16 +437,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -432,16 +437,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true); err = iwl_run_init_mvm_ucode(mvm, true);
iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */ /* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) { if (err < 0 && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free; goto out_free;
} }
/* Stop the hw after the ALIVE and NVM has been read */
if (!iwlmvm_mod_params.init_dbg)
iwl_trans_stop_hw(mvm->trans, false);
} }
scan_size = sizeof(struct iwl_scan_cmd) + scan_size = sizeof(struct iwl_scan_cmd) +
...@@ -474,7 +476,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -474,7 +476,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_phy_db_free(mvm->phy_db); iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd); kfree(mvm->scan_cmd);
if (!iwlwifi_mod_params.nvm_file) if (!iwlwifi_mod_params.nvm_file)
iwl_trans_stop_hw(trans, true); iwl_trans_op_mode_leave(trans);
ieee80211_free_hw(mvm->hw); ieee80211_free_hw(mvm->hw);
return NULL; return NULL;
} }
...@@ -491,12 +493,14 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ...@@ -491,12 +493,14 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw); ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd); kfree(mvm->scan_cmd);
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram); kfree(mvm->d3_resume_sram);
#endif #endif
iwl_trans_stop_hw(mvm->trans, true); iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db); iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL; mvm->phy_db = NULL;
......
This diff is collapsed.
This diff is collapsed.
...@@ -278,7 +278,6 @@ struct iwl_scale_tbl_info { ...@@ -278,7 +278,6 @@ struct iwl_scale_tbl_info {
struct rs_rate rate; struct rs_rate rate;
enum rs_column column; enum rs_column column;
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
}; };
...@@ -315,7 +314,6 @@ struct iwl_lq_sta { ...@@ -315,7 +314,6 @@ struct iwl_lq_sta {
enum ieee80211_band band; enum ieee80211_band band;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
u32 supp_rates;
u16 active_legacy_rate; u16 active_legacy_rate;
u16 active_siso_rate; u16 active_siso_rate;
u16 active_mimo2_rate; u16 active_mimo2_rate;
......
...@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, ...@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
stats->flag |= RX_FLAG_DECRYPTED; stats->flag |= RX_FLAG_DECRYPTED;
return 0; return 0;
case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
return -1;
stats->flag |= RX_FLAG_DECRYPTED;
return 0;
default: default:
IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
} }
......
/******************************************************************************
*
* 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) 2013 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 COPYING.
*
* 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) 2013 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 "mvm.h"
/* For counting bound interfaces */
struct iwl_mvm_active_iface_iterator_data {
struct ieee80211_vif *ignore_vif;
u8 sta_vif_ap_sta_id;
enum iwl_sf_state sta_vif_state;
int num_active_macs;
};
/*
* Count bound interfaces which are not p2p, besides data->ignore_vif.
* data->station_vif will point to one bound vif of type station, if exists.
*/
static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_active_iface_iterator_data *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
vif->type == NL80211_IFTYPE_P2P_DEVICE)
return;
data->num_active_macs++;
if (vif->type == NL80211_IFTYPE_STATION) {
data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
if (vif->bss_conf.assoc)
data->sta_vif_state = SF_FULL_ON;
else
data->sta_vif_state = SF_INIT_OFF;
}
}
/*
* Aging and idle timeouts for the different possible scenarios
* in SF_FULL_ON state.
*/
static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
{
cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
},
{
cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
},
{
cpu_to_le32(SF_MCAST_AGING_TIMER),
cpu_to_le32(SF_MCAST_IDLE_TIMER)
},
{
cpu_to_le32(SF_BA_AGING_TIMER),
cpu_to_le32(SF_BA_IDLE_TIMER)
},
{
cpu_to_le32(SF_TX_RE_AGING_TIMER),
cpu_to_le32(SF_TX_RE_IDLE_TIMER)
},
};
static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
struct ieee80211_sta *sta)
{
int i, j, watermark;
sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
/*
* If we are in association flow - check antenna configuration
* capabilities of the AP station, and choose the watermark accordingly.
*/
if (sta) {
if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) {
switch (sta->rx_nss) {
case 1:
watermark = SF_W_MARK_SISO;
break;
case 2:
watermark = SF_W_MARK_MIMO2;
break;
default:
watermark = SF_W_MARK_MIMO3;
break;
}
} else {
watermark = SF_W_MARK_LEGACY;
}
/* default watermark value for unassociated mode. */
} else {
watermark = SF_W_MARK_MIMO2;
}
sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
for (i = 0; i < SF_NUM_SCENARIO; i++) {
for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
sf_cmd->long_delay_timeouts[i][j] =
cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
}
}
BUILD_BUG_ON(sizeof(sf_full_timeout) !=
sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES);
memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
sizeof(sf_full_timeout));
}
static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
enum iwl_sf_state new_state)
{
struct iwl_sf_cfg_cmd sf_cmd = {
.state = new_state,
};
struct ieee80211_sta *sta;
int ret = 0;
/*
* If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered.
*/
if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
return 0;
switch (new_state) {
case SF_UNINIT:
break;
case SF_FULL_ON:
if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_ERR(mvm,
"No station: Cannot switch SF to FULL_ON\n");
return -EINVAL;
}
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
if (IS_ERR_OR_NULL(sta)) {
IWL_ERR(mvm, "Invalid station id\n");
rcu_read_unlock();
return -EINVAL;
}
iwl_mvm_fill_sf_command(&sf_cmd, sta);
rcu_read_unlock();
break;
case SF_INIT_OFF:
iwl_mvm_fill_sf_command(&sf_cmd, NULL);
break;
default:
WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
new_state);
return -EINVAL;
}
ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
sizeof(sf_cmd), &sf_cmd);
if (!ret)
mvm->sf_state = new_state;
return ret;
}
/*
* Update Smart fifo:
* Count bound interfaces that are not to be removed, ignoring p2p devices,
* and set new state accordingly.
*/
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
bool remove_vif)
{
enum iwl_sf_state new_state;
u8 sta_id = IWL_MVM_STATION_COUNT;
struct iwl_mvm_vif *mvmvif = NULL;
struct iwl_mvm_active_iface_iterator_data data = {
.ignore_vif = changed_vif,
.sta_vif_state = SF_UNINIT,
.sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT,
};
if (IWL_UCODE_API(mvm->fw->ucode_ver) < 8)
return 0;
/*
* Ignore the call if we are in HW Restart flow, or if the handled
* vif is a p2p device.
*/
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
(changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
return 0;
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bound_iface_iterator,
&data);
/* If changed_vif exists and is not to be removed, add to the count */
if (changed_vif && !remove_vif)
data.num_active_macs++;
switch (data.num_active_macs) {
case 0:
/* If there are no active macs - change state to SF_INIT_OFF */
new_state = SF_INIT_OFF;
break;
case 1:
if (remove_vif) {
/* The one active mac left is of type station
* and we filled the relevant data during iteration
*/
new_state = data.sta_vif_state;
sta_id = data.sta_vif_ap_sta_id;
} else {
if (WARN_ON(!changed_vif))
return -EINVAL;
if (changed_vif->type != NL80211_IFTYPE_STATION) {
new_state = SF_UNINIT;
} else if (changed_vif->bss_conf.assoc) {
mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
sta_id = mvmvif->ap_sta_id;
new_state = SF_FULL_ON;
} else {
new_state = SF_INIT_OFF;
}
}
break;
default:
/* If there are multiple active macs - change to SF_UNINIT */
new_state = SF_UNINIT;
}
return iwl_mvm_sf_config(mvm, sta_id, new_state);
}
...@@ -939,19 +939,6 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -939,19 +939,6 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid); sta->addr, tid);
if (mvm->cfg->ht_params->use_rts_for_aggregation) {
/*
* switch to RTS/CTS if it is the prefer protection
* method for HT traffic
* this function also sends the LQ command
*/
return iwl_mvm_tx_protection(mvm, mvmsta, true);
/*
* TODO: remove the TLC_RTS flag when we tear down the last
* AGG session (agg_tids_count in DVM)
*/
}
return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false); return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false);
} }
...@@ -1130,8 +1117,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, ...@@ -1130,8 +1117,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
memcpy(cmd.key, keyconf->key, keyconf->keylen); memcpy(cmd.key, keyconf->key, keyconf->keylen);
break; break;
default: default:
WARN_ON(1); key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
return -EINVAL; memcpy(cmd.key, keyconf->key, keyconf->keylen);
} }
if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
...@@ -1295,8 +1282,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1295,8 +1282,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
0, NULL, CMD_SYNC); 0, NULL, CMD_SYNC);
break; break;
default: default:
IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher); ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
ret = -EINVAL; sta_id, 0, NULL, CMD_SYNC);
} }
if (ret) if (ret)
......
...@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work) ...@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work)
iwl_trans_start_hw(mvm->trans); iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm); temp = check_nic_temperature(mvm);
iwl_trans_stop_hw(mvm->trans, false); iwl_trans_stop_device(mvm->trans);
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
......
...@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, ...@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
break; break;
default: default:
IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher); tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
break;
} }
} }
......
...@@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int i; int i;
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1)
return;
mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request; mvmvif->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
......
...@@ -256,7 +256,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) ...@@ -256,7 +256,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @hw_base: pci hardware address support * @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied. * @ucode_write_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load * @ucode_write_waitq: wait queue for uCode load
* @status - transport specific status flags
* @cmd_queue - command queue number * @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size * @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
...@@ -296,7 +295,6 @@ struct iwl_trans_pcie { ...@@ -296,7 +295,6 @@ struct iwl_trans_pcie {
wait_queue_head_t ucode_write_waitq; wait_queue_head_t ucode_write_waitq;
wait_queue_head_t wait_command_queue; wait_queue_head_t wait_command_queue;
unsigned long status;
u8 cmd_queue; u8 cmd_queue;
u8 cmd_fifo; u8 cmd_fifo;
u8 n_no_reclaim_cmds; u8 n_no_reclaim_cmds;
...@@ -315,24 +313,6 @@ struct iwl_trans_pcie { ...@@ -315,24 +313,6 @@ struct iwl_trans_pcie {
spinlock_t reg_lock; spinlock_t reg_lock;
}; };
/**
* enum iwl_pcie_status: status of the PCIe transport
* @STATUS_HCMD_ACTIVE: a SYNC command is being processed
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
*/
enum iwl_pcie_status {
STATUS_HCMD_ACTIVE,
STATUS_DEVICE_ENABLED,
STATUS_TPOWER_PMI,
STATUS_INT_ENABLED,
STATUS_RFKILL,
STATUS_FW_ERROR,
};
#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
...@@ -399,8 +379,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans); ...@@ -399,8 +379,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
******************************************************/ ******************************************************/
static inline void iwl_disable_interrupts(struct iwl_trans *trans) static inline void iwl_disable_interrupts(struct iwl_trans *trans)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); clear_bit(STATUS_INT_ENABLED, &trans->status);
clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
/* disable interrupts from uCode/NIC to host */ /* disable interrupts from uCode/NIC to host */
iwl_write32(trans, CSR_INT_MASK, 0x00000000); iwl_write32(trans, CSR_INT_MASK, 0x00000000);
...@@ -417,7 +396,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) ...@@ -417,7 +396,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
set_bit(STATUS_INT_ENABLED, &trans_pcie->status); set_bit(STATUS_INT_ENABLED, &trans->status);
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
} }
...@@ -477,12 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) ...@@ -477,12 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
} }
static inline void iwl_nic_error(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
set_bit(STATUS_FW_ERROR, &trans_pcie->status);
iwl_op_mode_nic_error(trans->op_mode);
}
#endif /* __iwl_trans_int_pcie_h__ */ #endif /* __iwl_trans_int_pcie_h__ */
...@@ -162,11 +162,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, ...@@ -162,11 +162,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
rxq->write_actual = (rxq->write & ~0x7); rxq->write_actual = (rxq->write & ~0x7);
iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
} else { } else {
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);
/* If power-saving is in use, make sure device is awake */ /* If power-saving is in use, make sure device is awake */
if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) { if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
...@@ -222,7 +219,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) ...@@ -222,7 +219,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
* stopped, we cannot access the HW (in particular not prph). * stopped, we cannot access the HW (in particular not prph).
* So don't try to restock if the APM has been already stopped. * So don't try to restock if the APM has been already stopped.
*/ */
if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
return; return;
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
...@@ -791,7 +788,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) ...@@ -791,7 +788,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
APMS_CLK_VAL_MRB_FUNC_MODE) || APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) & (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
APMG_PS_CTRL_VAL_RESET_REQ))) { APMG_PS_CTRL_VAL_RESET_REQ))) {
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
iwl_op_mode_wimax_active(trans->op_mode); iwl_op_mode_wimax_active(trans->op_mode);
wake_up(&trans_pcie->wait_command_queue); wake_up(&trans_pcie->wait_command_queue);
return; return;
...@@ -800,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) ...@@ -800,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
iwl_pcie_dump_csr(trans); iwl_pcie_dump_csr(trans);
iwl_dump_fh(trans, NULL); iwl_dump_fh(trans, NULL);
/* set the ERROR bit before we wake up the caller */
set_bit(STATUS_FW_ERROR, &trans_pcie->status);
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
wake_up(&trans_pcie->wait_command_queue);
local_bh_disable(); local_bh_disable();
iwl_nic_error(trans); /* The STATUS_FW_ERROR bit is set in this function. This must happen
* before we wake up the command caller, to ensure a proper cleanup. */
iwl_trans_fw_error(trans);
local_bh_enable(); local_bh_enable();
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
wake_up(&trans_pcie->wait_command_queue);
} }
irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
...@@ -894,14 +891,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) ...@@ -894,14 +891,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill) { if (hw_rfkill) {
set_bit(STATUS_RFKILL, &trans_pcie->status); set_bit(STATUS_RFKILL, &trans->status);
if (test_and_clear_bit(STATUS_HCMD_ACTIVE, if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
&trans_pcie->status)) &trans->status))
IWL_DEBUG_RF_KILL(trans, IWL_DEBUG_RF_KILL(trans,
"Rfkill while SYNC HCMD in flight\n"); "Rfkill while SYNC HCMD in flight\n");
wake_up(&trans_pcie->wait_command_queue); wake_up(&trans_pcie->wait_command_queue);
} else { } else {
clear_bit(STATUS_RFKILL, &trans_pcie->status); clear_bit(STATUS_RFKILL, &trans->status);
} }
handled |= CSR_INT_BIT_RF_KILL; handled |= CSR_INT_BIT_RF_KILL;
...@@ -1005,7 +1002,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) ...@@ -1005,7 +1002,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
/* Re-enable all interrupts */ /* Re-enable all interrupts */
/* only Re-enable if disabled by irq */ /* only Re-enable if disabled by irq */
if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status)) if (test_bit(STATUS_INT_ENABLED, &trans->status))
iwl_enable_interrupts(trans); iwl_enable_interrupts(trans);
/* Re-enable RF_KILL if it occurred */ /* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL) else if (handled & CSR_INT_BIT_RF_KILL)
...@@ -1160,7 +1157,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) ...@@ -1160,7 +1157,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
* the handler can be scheduled because of a previous * the handler can be scheduled because of a previous
* interrupt. * interrupt.
*/ */
if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
!trans_pcie->inta) !trans_pcie->inta)
iwl_enable_interrupts(trans); iwl_enable_interrupts(trans);
return IRQ_NONE; return IRQ_NONE;
...@@ -1290,7 +1287,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) ...@@ -1290,7 +1287,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
/* re-enable interrupts here since we don't have anything to service. /* re-enable interrupts here since we don't have anything to service.
* only Re-enable if disabled by irq. * only Re-enable if disabled by irq.
*/ */
if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
!trans_pcie->inta) !trans_pcie->inta)
iwl_enable_interrupts(trans); iwl_enable_interrupts(trans);
......
...@@ -150,7 +150,6 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) ...@@ -150,7 +150,6 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
*/ */
static int iwl_pcie_apm_init(struct iwl_trans *trans) static int iwl_pcie_apm_init(struct iwl_trans *trans)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret = 0; int ret = 0;
IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
...@@ -223,7 +222,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) ...@@ -223,7 +222,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
/* Clear the interrupt in APMG if the NIC is in RFKILL */ /* Clear the interrupt in APMG if the NIC is in RFKILL */
iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL); iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL);
set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); set_bit(STATUS_DEVICE_ENABLED, &trans->status);
out: out:
return ret; return ret;
...@@ -249,10 +248,9 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) ...@@ -249,10 +248,9 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
static void iwl_pcie_apm_stop(struct iwl_trans *trans) static void iwl_pcie_apm_stop(struct iwl_trans *trans)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
/* Stop device's DMA activity */ /* Stop device's DMA activity */
iwl_pcie_apm_stop_master(trans); iwl_pcie_apm_stop_master(trans);
...@@ -582,7 +580,6 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, ...@@ -582,7 +580,6 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
const struct fw_img *fw, bool run_in_rfkill) const struct fw_img *fw, bool run_in_rfkill)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret; int ret;
bool hw_rfkill; bool hw_rfkill;
...@@ -592,16 +589,14 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, ...@@ -592,16 +589,14 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
return -EIO; return -EIO;
} }
clear_bit(STATUS_FW_ERROR, &trans_pcie->status);
iwl_enable_rfkill_int(trans); iwl_enable_rfkill_int(trans);
/* If platform's RF_KILL switch is NOT set to KILL */ /* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans); hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill) if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status); set_bit(STATUS_RFKILL, &trans->status);
else else
clear_bit(STATUS_RFKILL, &trans_pcie->status); clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill && !run_in_rfkill) if (hw_rfkill && !run_in_rfkill)
return -ERFKILL; return -ERFKILL;
...@@ -641,6 +636,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -641,6 +636,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long flags; unsigned long flags;
bool hw_rfkill;
/* tell the device to stop sending interrupts */ /* tell the device to stop sending interrupts */
spin_lock_irqsave(&trans_pcie->irq_lock, flags); spin_lock_irqsave(&trans_pcie->irq_lock, flags);
...@@ -657,7 +653,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -657,7 +653,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
* restart. So don't process again if the device is * restart. So don't process again if the device is
* already dead. * already dead.
*/ */
if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) { if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
iwl_pcie_tx_stop(trans); iwl_pcie_tx_stop(trans);
iwl_pcie_rx_stop(trans); iwl_pcie_rx_stop(trans);
...@@ -681,17 +677,34 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -681,17 +677,34 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_disable_interrupts(trans); iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
iwl_enable_rfkill_int(trans);
/* stop and reset the on-board processor */ /* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
/* clear all status bits */ /* clear all status bits */
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
clear_bit(STATUS_INT_ENABLED, &trans_pcie->status); clear_bit(STATUS_INT_ENABLED, &trans->status);
clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); clear_bit(STATUS_TPOWER_PMI, &trans->status);
clear_bit(STATUS_RFKILL, &trans_pcie->status); clear_bit(STATUS_RFKILL, &trans->status);
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int(trans);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans->status);
else
clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
} }
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
...@@ -776,7 +789,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, ...@@ -776,7 +789,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
static int iwl_trans_pcie_start_hw(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);
bool hw_rfkill; bool hw_rfkill;
int err; int err;
...@@ -798,21 +810,20 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) ...@@ -798,21 +810,20 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans); hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill) if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status); set_bit(STATUS_RFKILL, &trans->status);
else else
clear_bit(STATUS_RFKILL, &trans_pcie->status); clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
return 0; return 0;
} }
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
bool op_mode_leaving)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
unsigned long flags; unsigned long flags;
/* disable interrupts - don't enable HW RF kill interrupt */
spin_lock_irqsave(&trans_pcie->irq_lock, flags); spin_lock_irqsave(&trans_pcie->irq_lock, flags);
iwl_disable_interrupts(trans); iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
...@@ -824,27 +835,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, ...@@ -824,27 +835,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
iwl_pcie_disable_ict(trans); iwl_pcie_disable_ict(trans);
if (!op_mode_leaving) {
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int(trans);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}
} }
static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
...@@ -928,12 +918,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) ...@@ -928,12 +918,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state) static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (state) if (state)
set_bit(STATUS_TPOWER_PMI, &trans_pcie->status); set_bit(STATUS_TPOWER_PMI, &trans->status);
else else
clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); clear_bit(STATUS_TPOWER_PMI, &trans->status);
} }
static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
...@@ -1457,7 +1445,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, ...@@ -1457,7 +1445,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
static const struct iwl_trans_ops trans_ops_pcie = { static const struct iwl_trans_ops trans_ops_pcie = {
.start_hw = iwl_trans_pcie_start_hw, .start_hw = iwl_trans_pcie_start_hw,
.stop_hw = iwl_trans_pcie_stop_hw, .op_mode_leave = iwl_trans_pcie_op_mode_leave,
.fw_alive = iwl_trans_pcie_fw_alive, .fw_alive = iwl_trans_pcie_fw_alive,
.start_fw = iwl_trans_pcie_start_fw, .start_fw = iwl_trans_pcie_start_fw,
.stop_device = iwl_trans_pcie_stop_device, .stop_device = iwl_trans_pcie_stop_device,
......
...@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) ...@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "scratch %d = 0x%08x\n", i, IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
le32_to_cpu(txq->scratchbufs[i].scratch)); le32_to_cpu(txq->scratchbufs[i].scratch));
iwl_nic_error(trans); iwl_trans_fw_error(trans);
} }
/* /*
...@@ -300,10 +300,8 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) ...@@ -300,10 +300,8 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
iwl_write32(trans, HBUS_TARG_WRPTR, iwl_write32(trans, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8)); txq->q.write_ptr | (txq_id << 8));
} else { } else {
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);
/* if we're trying to save power */ /* if we're trying to save power */
if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) { if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
/* wake up nic if it's powered down ... /* wake up nic if it's powered down ...
* uCode will wake up, and interrupt us again, so next * uCode will wake up, and interrupt us again, so next
* time we'll skip this part. */ * time we'll skip this part. */
...@@ -1023,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) ...@@ -1023,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
if (nfreed++ > 0) { if (nfreed++ > 0) {
IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
idx, q->write_ptr, q->read_ptr); idx, q->write_ptr, q->read_ptr);
iwl_nic_error(trans); iwl_trans_fw_error(trans);
} }
} }
...@@ -1449,12 +1447,12 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, ...@@ -1449,12 +1447,12 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
iwl_pcie_cmdq_reclaim(trans, txq_id, index); iwl_pcie_cmdq_reclaim(trans, txq_id, index);
if (!(meta->flags & CMD_ASYNC)) { if (!(meta->flags & CMD_ASYNC)) {
if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { if (!test_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status)) {
IWL_WARN(trans, IWL_WARN(trans,
"HCMD_ACTIVE already clear for command %s\n", "HCMD_ACTIVE already clear for command %s\n",
get_cmd_string(trans_pcie, cmd->hdr.cmd)); get_cmd_string(trans_pcie, cmd->hdr.cmd));
} }
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(trans_pcie, cmd->hdr.cmd)); get_cmd_string(trans_pcie, cmd->hdr.cmd));
wake_up(&trans_pcie->wait_command_queue); wake_up(&trans_pcie->wait_command_queue);
...@@ -1499,8 +1497,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1499,8 +1497,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
get_cmd_string(trans_pcie, cmd->id)); get_cmd_string(trans_pcie, cmd->id));
if (WARN(test_and_set_bit(STATUS_HCMD_ACTIVE, if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE,
&trans_pcie->status), &trans->status),
"Command %s: a command is already active!\n", "Command %s: a command is already active!\n",
get_cmd_string(trans_pcie, cmd->id))) get_cmd_string(trans_pcie, cmd->id)))
return -EIO; return -EIO;
...@@ -1511,7 +1509,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1511,7 +1509,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd); cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
if (cmd_idx < 0) { if (cmd_idx < 0) {
ret = cmd_idx; ret = cmd_idx;
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_ERR(trans, IWL_ERR(trans,
"Error sending %s: enqueue_hcmd failed: %d\n", "Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(trans_pcie, cmd->id), ret); get_cmd_string(trans_pcie, cmd->id), ret);
...@@ -1523,8 +1521,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1523,8 +1521,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
timeout -= COMMAND_POKE_TIMEOUT; timeout -= COMMAND_POKE_TIMEOUT;
ret = wait_event_timeout(trans_pcie->wait_command_queue, ret = wait_event_timeout(trans_pcie->wait_command_queue,
!test_bit(STATUS_HCMD_ACTIVE, !test_bit(STATUS_SYNC_HCMD_ACTIVE,
&trans_pcie->status), &trans->status),
COMMAND_POKE_TIMEOUT); COMMAND_POKE_TIMEOUT);
if (ret) if (ret)
break; break;
...@@ -1552,17 +1550,17 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1552,17 +1550,17 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n",
q->read_ptr, q->write_ptr); q->read_ptr, q->write_ptr);
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(trans_pcie, cmd->id)); get_cmd_string(trans_pcie, cmd->id));
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
iwl_nic_error(trans); iwl_trans_fw_error(trans);
goto cancel; goto cancel;
} }
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { if (test_bit(STATUS_FW_ERROR, &trans->status)) {
IWL_ERR(trans, "FW error in SYNC CMD %s\n", IWL_ERR(trans, "FW error in SYNC CMD %s\n",
get_cmd_string(trans_pcie, cmd->id)); get_cmd_string(trans_pcie, cmd->id));
dump_stack(); dump_stack();
...@@ -1571,7 +1569,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1571,7 +1569,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
} }
if (!(cmd->flags & CMD_SEND_IN_RFKILL) && if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL, &trans_pcie->status)) { test_bit(STATUS_RFKILL, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
ret = -ERFKILL; ret = -ERFKILL;
goto cancel; goto cancel;
...@@ -1608,13 +1606,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, ...@@ -1608,13 +1606,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
return -EIO;
if (!(cmd->flags & CMD_SEND_IN_RFKILL) && if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL, &trans_pcie->status)) { test_bit(STATUS_RFKILL, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
cmd->id); cmd->id);
return -ERFKILL; return -ERFKILL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment