diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 136 | 
1 files changed, 90 insertions, 46 deletions
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9ffff6ed8133..4d1188b8736a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -7,6 +7,7 @@   *   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH   *   * 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 @@ -33,7 +34,7 @@   *   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -67,10 +68,10 @@  #include <linux/vmalloc.h>  #include <net/mac80211.h> -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h"  #include "iwl-trans.h"  #include "iwl-op-mode.h" -#include "iwl-fw.h" +#include "fw/img.h"  #include "iwl-debug.h"  #include "iwl-drv.h"  #include "iwl-modparams.h" @@ -172,13 +173,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  		 ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE);  	/* -	 * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and -	 * shouldn't be set to any non-zero value. The same is supposed to be -	 * true of the other HW, but unsetting them (such as the 7260) causes -	 * automatic tests to fail on seemingly unrelated errors. Need to -	 * further investigate this, but for now we'll separate cases. +	 * TODO: Bits 7-8 of CSR in 8000 HW family and higher set the ADC +	 * sampling, and shouldn't be set to any non-zero value. +	 * The same is supposed to be true of the other HW, but unsetting +	 * them (such as the 7260) causes automatic tests to fail on seemingly +	 * unrelated errors. Need to further investigate this, but for now +	 * we'll separate cases.  	 */ -	if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) +	if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)  		reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;  	iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, @@ -355,9 +357,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD),  	HCMD_NAME(HOT_SPOT_CMD),  	HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), -	HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), -	HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), -	HCMD_NAME(BT_COEX_UPDATE_SW_BOOST),  	HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT),  	HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP),  	HCMD_NAME(BT_COEX_CI), @@ -366,13 +365,11 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(PHY_DB_CMD),  	HCMD_NAME(SCAN_OFFLOAD_COMPLETE),  	HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), -	HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD),  	HCMD_NAME(POWER_TABLE_CMD),  	HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),  	HCMD_NAME(REPLY_THERMAL_MNG_BACKOFF),  	HCMD_NAME(DC2DC_CONFIG_CMD),  	HCMD_NAME(NVM_ACCESS_CMD), -	HCMD_NAME(SET_CALIB_DEFAULT_CMD),  	HCMD_NAME(BEACON_NOTIFICATION),  	HCMD_NAME(BEACON_TEMPLATE_CMD),  	HCMD_NAME(TX_ANT_CONFIGURATION_CMD), @@ -381,7 +378,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(STATISTICS_NOTIFICATION),  	HCMD_NAME(EOSP_NOTIFICATION),  	HCMD_NAME(REDUCE_TX_POWER_CMD), -	HCMD_NAME(CARD_STATE_CMD),  	HCMD_NAME(CARD_STATE_NOTIFICATION),  	HCMD_NAME(MISSED_BEACONS_NOTIFICATION),  	HCMD_NAME(TDLS_CONFIG_CMD), @@ -396,8 +392,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(MCC_UPDATE_CMD),  	HCMD_NAME(MCC_CHUB_UPDATE_CMD),  	HCMD_NAME(MARKER_CMD), -	HCMD_NAME(BT_COEX_PRIO_TABLE), -	HCMD_NAME(BT_COEX_PROT_ENV),  	HCMD_NAME(BT_PROFILE_NOTIFICATION),  	HCMD_NAME(BCAST_FILTER_CMD),  	HCMD_NAME(MCAST_FILTER_CMD), @@ -408,7 +402,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(OFFLOADS_QUERY_CMD),  	HCMD_NAME(REMOTE_WAKE_CONFIG_CMD),  	HCMD_NAME(MATCH_FOUND_NOTIFICATION), -	HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER),  	HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION),  	HCMD_NAME(WOWLAN_PATTERNS),  	HCMD_NAME(WOWLAN_CONFIGURATION), @@ -416,11 +409,9 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {  	HCMD_NAME(WOWLAN_TKIP_PARAM),  	HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL),  	HCMD_NAME(WOWLAN_GET_STATUSES), -	HCMD_NAME(WOWLAN_TX_POWER_PER_DB),  	HCMD_NAME(SCAN_ITERATION_COMPLETE),  	HCMD_NAME(D0I3_END_CMD),  	HCMD_NAME(LTR_CONFIG), -	HCMD_NAME(REPLY_DEBUG_CMD),  };  /* Please keep this array *SORTED* by hex value. @@ -483,6 +474,7 @@ static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {   */  static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = {  	HCMD_NAME(NVM_ACCESS_COMPLETE), +	HCMD_NAME(NVM_GET_INFO),  };  static const struct iwl_hcmd_arr iwl_mvm_groups[] = { @@ -588,6 +580,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	mvm->fw = fw;  	mvm->hw = hw; +	mvm->init_status = 0; +  	if (iwl_mvm_has_new_rx_api(mvm)) {  		op_mode->ops = &iwl_mvm_ops_mq;  		trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc); @@ -600,7 +594,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  			goto out_free;  	} -	mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; +	mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0;  	if (!iwl_mvm_is_dqa_supported(mvm)) {  		mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; @@ -608,9 +602,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  		if (mvm->cfg->base_params->num_of_queues == 16) {  			mvm->aux_queue = 11;  			mvm->first_agg_queue = 12; +			BUILD_BUG_ON(BITS_PER_BYTE * +				     sizeof(mvm->hw_queue_to_mac80211[0]) < 12);  		} else {  			mvm->aux_queue = 15;  			mvm->first_agg_queue = 16; +			BUILD_BUG_ON(BITS_PER_BYTE * +				     sizeof(mvm->hw_queue_to_mac80211[0]) < 16);  		}  	} else {  		mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; @@ -747,12 +745,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	mutex_lock(&mvm->mutex);  	iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);  	err = iwl_run_init_mvm_ucode(mvm, true); -	if (!err || !iwlmvm_mod_params.init_dbg) +	if (!iwlmvm_mod_params.init_dbg)  		iwl_mvm_stop_device(mvm);  	iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);  	mutex_unlock(&mvm->mutex);  	/* returns 0 if successful, 1 if success but in rfkill */ -	if (err < 0 && !iwlmvm_mod_params.init_dbg) { +	if (err < 0) {  		IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);  		goto out_free;  	} @@ -778,7 +776,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	if (err)  		goto out_unregister; -	memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); +	if (!iwl_mvm_has_new_rx_stats_api(mvm)) +		memset(&mvm->rx_stats_v3, 0, +		       sizeof(struct mvm_statistics_rx_v3)); +	else +		memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));  	/* The transport always starts with a taken reference, we can  	 * release it now if d0i3 is supported */ @@ -790,12 +792,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	return op_mode;   out_unregister: +	if (iwlmvm_mod_params.init_dbg) +		return op_mode; +  	ieee80211_unregister_hw(mvm->hw);  	mvm->hw_registered = false;  	iwl_mvm_leds_exit(mvm);  	iwl_mvm_thermal_exit(mvm);   out_free:  	flush_delayed_work(&mvm->fw_dump_wk); + +	if (iwlmvm_mod_params.init_dbg) +		return op_mode;  	iwl_phy_db_free(mvm->phy_db);  	kfree(mvm->scan_cmd);  	iwl_trans_op_mode_leave(trans); @@ -820,7 +828,10 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)  	iwl_mvm_thermal_exit(mvm); -	ieee80211_unregister_hw(mvm->hw); +	if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) { +		ieee80211_unregister_hw(mvm->hw); +		mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; +	}  	kfree(mvm->scan_cmd);  	kfree(mvm->mcast_filter_cmd); @@ -835,7 +846,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)  	iwl_phy_db_free(mvm->phy_db);  	mvm->phy_db = NULL; -	iwl_free_nvm_data(mvm->nvm_data); +	kfree(mvm->nvm_data);  	for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)  		kfree(mvm->nvm_sections[i].data); @@ -1080,6 +1091,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)  	iwl_mvm_start_mac_queues(mvm, mq);  } +static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) +{ +	bool state = iwl_mvm_is_radio_killed(mvm); + +	if (state) +		wake_up(&mvm->rx_sync_waitq); + +	wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); +} +  void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)  {  	if (state) @@ -1087,7 +1108,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)  	else  		clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); -	wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); +	iwl_mvm_set_rfkill_state(mvm);  }  static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) @@ -1100,7 +1121,7 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)  	else  		clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); -	wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); +	iwl_mvm_set_rfkill_state(mvm);  	/* iwl_run_init_mvm_ucode is waiting for results, abort it */  	if (calibrating) @@ -1149,21 +1170,41 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)  	mutex_lock(&mvm->mutex); -	/* stop recording */  	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { +		/* stop recording */  		iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + +		iwl_mvm_fw_error_dump(mvm); + +		/* start recording again if the firmware is not crashed */ +		if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && +		    mvm->fw->dbg_dest_tlv) { +			iwl_clear_bits_prph(mvm->trans, +					    MON_BUFF_SAMPLE_CTL, 0x100); +			iwl_clear_bits_prph(mvm->trans, +					    MON_BUFF_SAMPLE_CTL, 0x1); +			iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x1); +		}  	} else { +		u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE); +		u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL); + +		/* stop recording */  		iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); -		/* wait before we collect the data till the DBGC stop */  		udelay(100); -	} +		iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); +		/* wait before we collect the data till the DBGC stop */ +		udelay(500); -	iwl_mvm_fw_error_dump(mvm); +		iwl_mvm_fw_error_dump(mvm); -	/* start recording again if the firmware is not crashed */ -	WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && -		     mvm->fw->dbg_dest_tlv && -		     iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); +		/* start recording again if the firmware is not crashed */ +		if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && +		    mvm->fw->dbg_dest_tlv) { +			iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, in_sample); +			iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, out_ctrl); +		} +	}  	mutex_unlock(&mvm->mutex); @@ -1192,7 +1233,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)  	 * If WoWLAN fw asserted, don't restart either, mac80211  	 * can't recover this since we're already half suspended.  	 */ -	if (!mvm->restart_fw && fw_error) { +	if (!mvm->fw_restart && fw_error) {  		iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert,  					    NULL);  	} else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, @@ -1225,8 +1266,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)  		/* don't let the transport/FW power down */  		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); -		if (fw_error && mvm->restart_fw > 0) -			mvm->restart_fw--; +		if (fw_error && mvm->fw_restart > 0) +			mvm->fw_restart--;  		ieee80211_restart_hw(mvm->hw);  	}  } @@ -1283,7 +1324,7 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm,  		 * for offloading in order to prevent reuse of the same  		 * qos seq counters.  		 */ -		if (iwl_mvm_tid_queued(tid_data)) +		if (iwl_mvm_tid_queued(mvm, tid_data))  			continue;  		if (tid_data->state != IWL_AGG_OFF) @@ -1433,9 +1474,15 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)  	synchronize_net();  	/* Flush the hw queues, in case something got queued during entry */ -	ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), flags); -	if (ret) -		return ret; +	/* TODO new tx api */ +	if (iwl_mvm_has_new_tx_api(mvm)) { +		WARN_ONCE(1, "d0i3: Need to implement flush TX queue\n"); +	} else { +		ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), +					    flags); +		if (ret) +			return ret; +	}  	/* configure wowlan configuration only if needed */  	if (mvm->d0i3_ap_sta_id != IWL_MVM_INVALID_STA) { @@ -1581,9 +1628,6 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)  	if (ret)  		goto out; -	if (!get_status_cmd.resp_pkt) -		goto out; -  	status = (void *)get_status_cmd.resp_pkt->data;  	wakeup_reasons = le32_to_cpu(status->wakeup_reasons);  	qos_seq = status->qos_seq_ctr; | 
