cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sf.c (7232B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/*
      3 * Copyright (C) 2013-2014, 2018-2019 Intel Corporation
      4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
      5 */
      6#include "mvm.h"
      7
      8/* For counting bound interfaces */
      9struct iwl_mvm_active_iface_iterator_data {
     10	struct ieee80211_vif *ignore_vif;
     11	u8 sta_vif_ap_sta_id;
     12	enum iwl_sf_state sta_vif_state;
     13	u32 num_active_macs;
     14};
     15
     16/*
     17 * Count bound interfaces which are not p2p, besides data->ignore_vif.
     18 * data->station_vif will point to one bound vif of type station, if exists.
     19 */
     20static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
     21					 struct ieee80211_vif *vif)
     22{
     23	struct iwl_mvm_active_iface_iterator_data *data = _data;
     24	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
     25
     26	if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
     27	    vif->type == NL80211_IFTYPE_P2P_DEVICE)
     28		return;
     29
     30	data->num_active_macs++;
     31
     32	if (vif->type == NL80211_IFTYPE_STATION) {
     33		data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
     34		if (vif->bss_conf.assoc)
     35			data->sta_vif_state = SF_FULL_ON;
     36		else
     37			data->sta_vif_state = SF_INIT_OFF;
     38	}
     39}
     40
     41/*
     42 * Aging and idle timeouts for the different possible scenarios
     43 * in default configuration
     44 */
     45static const
     46__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
     47	{
     48		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
     49		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
     50	},
     51	{
     52		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
     53		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
     54	},
     55	{
     56		cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
     57		cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
     58	},
     59	{
     60		cpu_to_le32(SF_BA_AGING_TIMER_DEF),
     61		cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
     62	},
     63	{
     64		cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
     65		cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
     66	},
     67};
     68
     69/*
     70 * Aging and idle timeouts for the different possible scenarios
     71 * in single BSS MAC configuration.
     72 */
     73static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
     74	{
     75		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
     76		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
     77	},
     78	{
     79		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
     80		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
     81	},
     82	{
     83		cpu_to_le32(SF_MCAST_AGING_TIMER),
     84		cpu_to_le32(SF_MCAST_IDLE_TIMER)
     85	},
     86	{
     87		cpu_to_le32(SF_BA_AGING_TIMER),
     88		cpu_to_le32(SF_BA_IDLE_TIMER)
     89	},
     90	{
     91		cpu_to_le32(SF_TX_RE_AGING_TIMER),
     92		cpu_to_le32(SF_TX_RE_IDLE_TIMER)
     93	},
     94};
     95
     96static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
     97				    struct iwl_sf_cfg_cmd *sf_cmd,
     98				    struct ieee80211_sta *sta)
     99{
    100	int i, j, watermark;
    101
    102	sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
    103
    104	/*
    105	 * If we are in association flow - check antenna configuration
    106	 * capabilities of the AP station, and choose the watermark accordingly.
    107	 */
    108	if (sta) {
    109		if (sta->deflink.ht_cap.ht_supported ||
    110		    sta->deflink.vht_cap.vht_supported ||
    111		    sta->deflink.he_cap.has_he) {
    112			switch (sta->deflink.rx_nss) {
    113			case 1:
    114				watermark = SF_W_MARK_SISO;
    115				break;
    116			case 2:
    117				watermark = SF_W_MARK_MIMO2;
    118				break;
    119			default:
    120				watermark = SF_W_MARK_MIMO3;
    121				break;
    122			}
    123		} else {
    124			watermark = SF_W_MARK_LEGACY;
    125		}
    126	/* default watermark value for unassociated mode. */
    127	} else {
    128		watermark = SF_W_MARK_MIMO2;
    129	}
    130	sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
    131
    132	for (i = 0; i < SF_NUM_SCENARIO; i++) {
    133		for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
    134			sf_cmd->long_delay_timeouts[i][j] =
    135					cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
    136		}
    137	}
    138
    139	if (sta) {
    140		BUILD_BUG_ON(sizeof(sf_full_timeout) !=
    141			     sizeof(__le32) * SF_NUM_SCENARIO *
    142			     SF_NUM_TIMEOUT_TYPES);
    143
    144		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
    145		       sizeof(sf_full_timeout));
    146	} else {
    147		BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
    148			     sizeof(__le32) * SF_NUM_SCENARIO *
    149			     SF_NUM_TIMEOUT_TYPES);
    150
    151		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
    152		       sizeof(sf_full_timeout_def));
    153	}
    154
    155}
    156
    157static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
    158			     enum iwl_sf_state new_state)
    159{
    160	struct iwl_sf_cfg_cmd sf_cmd = {
    161		.state = cpu_to_le32(new_state),
    162	};
    163	struct ieee80211_sta *sta;
    164	int ret = 0;
    165
    166	if (mvm->cfg->disable_dummy_notification)
    167		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
    168
    169	/*
    170	 * If an associated AP sta changed its antenna configuration, the state
    171	 * will remain FULL_ON but SF parameters need to be reconsidered.
    172	 */
    173	if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
    174		return 0;
    175
    176	switch (new_state) {
    177	case SF_UNINIT:
    178		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
    179		break;
    180	case SF_FULL_ON:
    181		if (sta_id == IWL_MVM_INVALID_STA) {
    182			IWL_ERR(mvm,
    183				"No station: Cannot switch SF to FULL_ON\n");
    184			return -EINVAL;
    185		}
    186		rcu_read_lock();
    187		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
    188		if (IS_ERR_OR_NULL(sta)) {
    189			IWL_ERR(mvm, "Invalid station id\n");
    190			rcu_read_unlock();
    191			return -EINVAL;
    192		}
    193		iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
    194		rcu_read_unlock();
    195		break;
    196	case SF_INIT_OFF:
    197		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
    198		break;
    199	default:
    200		WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
    201			  new_state);
    202		return -EINVAL;
    203	}
    204
    205	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
    206				   sizeof(sf_cmd), &sf_cmd);
    207	if (!ret)
    208		mvm->sf_state = new_state;
    209
    210	return ret;
    211}
    212
    213/*
    214 * Update Smart fifo:
    215 * Count bound interfaces that are not to be removed, ignoring p2p devices,
    216 * and set new state accordingly.
    217 */
    218int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
    219		      bool remove_vif)
    220{
    221	enum iwl_sf_state new_state;
    222	u8 sta_id = IWL_MVM_INVALID_STA;
    223	struct iwl_mvm_vif *mvmvif = NULL;
    224	struct iwl_mvm_active_iface_iterator_data data = {
    225		.ignore_vif = changed_vif,
    226		.sta_vif_state = SF_UNINIT,
    227		.sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
    228	};
    229
    230	/*
    231	 * Ignore the call if we are in HW Restart flow, or if the handled
    232	 * vif is a p2p device.
    233	 */
    234	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
    235	    (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
    236		return 0;
    237
    238	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
    239						   IEEE80211_IFACE_ITER_NORMAL,
    240						   iwl_mvm_bound_iface_iterator,
    241						   &data);
    242
    243	/* If changed_vif exists and is not to be removed, add to the count */
    244	if (changed_vif && !remove_vif)
    245		data.num_active_macs++;
    246
    247	switch (data.num_active_macs) {
    248	case 0:
    249		/* If there are no active macs - change state to SF_INIT_OFF */
    250		new_state = SF_INIT_OFF;
    251		break;
    252	case 1:
    253		if (remove_vif) {
    254			/* The one active mac left is of type station
    255			 * and we filled the relevant data during iteration
    256			 */
    257			new_state = data.sta_vif_state;
    258			sta_id = data.sta_vif_ap_sta_id;
    259		} else {
    260			if (WARN_ON(!changed_vif))
    261				return -EINVAL;
    262			if (changed_vif->type != NL80211_IFTYPE_STATION) {
    263				new_state = SF_UNINIT;
    264			} else if (changed_vif->bss_conf.assoc &&
    265				   changed_vif->bss_conf.dtim_period) {
    266				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
    267				sta_id = mvmvif->ap_sta_id;
    268				new_state = SF_FULL_ON;
    269			} else {
    270				new_state = SF_INIT_OFF;
    271			}
    272		}
    273		break;
    274	default:
    275		/* If there are multiple active macs - change to SF_UNINIT */
    276		new_state = SF_UNINIT;
    277	}
    278	return iwl_mvm_sf_config(mvm, sta_id, new_state);
    279}