diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/rx.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rx.c | 113 | 
1 files changed, 61 insertions, 52 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 2a8cb5a6053..cf7276967ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -5,7 +5,7 @@   *   * GPL LICENSE SUMMARY   * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@   *   * BSD LICENSE   * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -60,7 +60,6 @@   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   *****************************************************************************/  #include "iwl-trans.h" -  #include "mvm.h"  #include "fw-api.h" @@ -77,6 +76,15 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));  	mvm->ampdu_ref++; + +#ifdef CONFIG_IWLWIFI_DEBUGFS +	if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { +		spin_lock(&mvm->drv_stats_lock); +		mvm->drv_rx_stats.ampdu_count++; +		spin_unlock(&mvm->drv_stats_lock); +	} +#endif +  	return 0;  } @@ -121,48 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); -	ieee80211_rx_ni(mvm->hw, skb); -} - -static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, -			      struct iwl_rx_phy_info *phy_info, -			      struct ieee80211_rx_status *rx_status) -{ -	int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; -	int rssi_all_band_a, rssi_all_band_b; -	u32 agc_a, agc_b, max_agc; -	u32 val; - -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); -	agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; -	agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; -	max_agc = max_t(u32, agc_a, agc_b); - -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); -	rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; -	rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; -	rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> -				IWL_OFDM_RSSI_ALLBAND_A_POS; -	rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> -				IWL_OFDM_RSSI_ALLBAND_B_POS; - -	/* -	 * dBm = rssi dB - agc dB - constant. -	 * Higher AGC (higher radio gain) means lower signal. -	 */ -	rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; -	rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; -	max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); - -	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", -			rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); - -	rx_status->signal = max_rssi_dbm; -	rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & -				RX_RES_PHY_FLAGS_ANTENNA) -					>> RX_RES_PHY_FLAGS_ANTENNA_POS; -	rx_status->chain_signal[0] = rssi_a_dbm; -	rx_status->chain_signal[1] = rssi_b_dbm; +	ieee80211_rx(mvm->hw, skb);  }  /* @@ -251,6 +218,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,  		stats->flag |= RX_FLAG_DECRYPTED;  		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:  		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);  	} @@ -300,10 +273,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		return 0;  	} +	/* +	 * Keep packets with CRC errors (and with overrun) for monitor mode +	 * (otherwise the firmware discards them) but mark them as bad. +	 */  	if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||  	    !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {  		IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); -		return 0; +		rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;  	}  	/* This will be used in several places later */ @@ -324,10 +301,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	 */  	/*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ -	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API) -		iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); -	else -		iwl_mvm_calc_rssi(mvm, phy_info, &rx_status); +	iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status);  	IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,  			      (unsigned long long)rx_status.mactime); @@ -354,31 +328,45 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		rx_status.flag |= RX_FLAG_40MHZ;  		break;  	case RATE_MCS_CHAN_WIDTH_80: -		rx_status.flag |= RX_FLAG_80MHZ; +		rx_status.vht_flag |= RX_VHT_FLAG_80MHZ;  		break;  	case RATE_MCS_CHAN_WIDTH_160: -		rx_status.flag |= RX_FLAG_160MHZ; +		rx_status.vht_flag |= RX_VHT_FLAG_160MHZ;  		break;  	}  	if (rate_n_flags & RATE_MCS_SGI_MSK)  		rx_status.flag |= RX_FLAG_SHORT_GI;  	if (rate_n_flags & RATE_HT_MCS_GF_MSK)  		rx_status.flag |= RX_FLAG_HT_GF; +	if (rate_n_flags & RATE_MCS_LDPC_MSK) +		rx_status.flag |= RX_FLAG_LDPC;  	if (rate_n_flags & RATE_MCS_HT_MSK) { +		u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> +				RATE_MCS_STBC_POS;  		rx_status.flag |= RX_FLAG_HT;  		rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; +		rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;  	} else if (rate_n_flags & RATE_MCS_VHT_MSK) { +		u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> +				RATE_MCS_STBC_POS;  		rx_status.vht_nss =  			((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>  						RATE_VHT_MCS_NSS_POS) + 1;  		rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;  		rx_status.flag |= RX_FLAG_VHT; +		rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; +		if (rate_n_flags & RATE_MCS_BF_MSK) +			rx_status.vht_flag |= RX_VHT_FLAG_BF;  	} else {  		rx_status.rate_idx =  			iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,  							    rx_status.band);  	} +#ifdef CONFIG_IWLWIFI_DEBUGFS +	iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, +				   rx_status.flag & RX_FLAG_AMPDU_DETAILS); +#endif  	iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status,  					rxb, &rx_status);  	return 0; @@ -422,6 +410,27 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,  	mvmvif->bf_data.ave_beacon_signal = sig; +	/* BT Coex */ +	if (mvmvif->bf_data.bt_coex_min_thold != +	    mvmvif->bf_data.bt_coex_max_thold) { +		last_event = mvmvif->bf_data.last_bt_coex_event; +		if (sig > mvmvif->bf_data.bt_coex_max_thold && +		    (last_event <= mvmvif->bf_data.bt_coex_min_thold || +		     last_event == 0)) { +			mvmvif->bf_data.last_bt_coex_event = sig; +			IWL_DEBUG_RX(mvm, "cqm_iterator bt coex high %d\n", +				     sig); +			iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_HIGH); +		} else if (sig < mvmvif->bf_data.bt_coex_min_thold && +			   (last_event >= mvmvif->bf_data.bt_coex_max_thold || +			    last_event == 0)) { +			mvmvif->bf_data.last_bt_coex_event = sig; +			IWL_DEBUG_RX(mvm, "cqm_iterator bt coex low %d\n", +				     sig); +			iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_LOW); +		} +	} +  	if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))  		return;  | 
