0001
0002
0003
0004
0005
0006 #include "mvm.h"
0007
0008
0009 struct iwl_mvm_active_iface_iterator_data {
0010 struct ieee80211_vif *ignore_vif;
0011 u8 sta_vif_ap_sta_id;
0012 enum iwl_sf_state sta_vif_state;
0013 u32 num_active_macs;
0014 };
0015
0016
0017
0018
0019
0020 static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
0021 struct ieee80211_vif *vif)
0022 {
0023 struct iwl_mvm_active_iface_iterator_data *data = _data;
0024 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0025
0026 if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
0027 vif->type == NL80211_IFTYPE_P2P_DEVICE)
0028 return;
0029
0030 data->num_active_macs++;
0031
0032 if (vif->type == NL80211_IFTYPE_STATION) {
0033 data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
0034 if (vif->cfg.assoc)
0035 data->sta_vif_state = SF_FULL_ON;
0036 else
0037 data->sta_vif_state = SF_INIT_OFF;
0038 }
0039 }
0040
0041
0042
0043
0044
0045 static const
0046 __le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
0047 {
0048 cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
0049 cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
0050 },
0051 {
0052 cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
0053 cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
0054 },
0055 {
0056 cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
0057 cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
0058 },
0059 {
0060 cpu_to_le32(SF_BA_AGING_TIMER_DEF),
0061 cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
0062 },
0063 {
0064 cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
0065 cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
0066 },
0067 };
0068
0069
0070
0071
0072
0073 static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
0074 {
0075 cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
0076 cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
0077 },
0078 {
0079 cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
0080 cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
0081 },
0082 {
0083 cpu_to_le32(SF_MCAST_AGING_TIMER),
0084 cpu_to_le32(SF_MCAST_IDLE_TIMER)
0085 },
0086 {
0087 cpu_to_le32(SF_BA_AGING_TIMER),
0088 cpu_to_le32(SF_BA_IDLE_TIMER)
0089 },
0090 {
0091 cpu_to_le32(SF_TX_RE_AGING_TIMER),
0092 cpu_to_le32(SF_TX_RE_IDLE_TIMER)
0093 },
0094 };
0095
0096 static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
0097 struct iwl_sf_cfg_cmd *sf_cmd,
0098 struct ieee80211_sta *sta)
0099 {
0100 int i, j, watermark;
0101
0102 sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
0103
0104
0105
0106
0107
0108 if (sta) {
0109 if (sta->deflink.ht_cap.ht_supported ||
0110 sta->deflink.vht_cap.vht_supported ||
0111 sta->deflink.he_cap.has_he) {
0112 switch (sta->deflink.rx_nss) {
0113 case 1:
0114 watermark = SF_W_MARK_SISO;
0115 break;
0116 case 2:
0117 watermark = SF_W_MARK_MIMO2;
0118 break;
0119 default:
0120 watermark = SF_W_MARK_MIMO3;
0121 break;
0122 }
0123 } else {
0124 watermark = SF_W_MARK_LEGACY;
0125 }
0126
0127 } else {
0128 watermark = SF_W_MARK_MIMO2;
0129 }
0130 sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
0131
0132 for (i = 0; i < SF_NUM_SCENARIO; i++) {
0133 for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
0134 sf_cmd->long_delay_timeouts[i][j] =
0135 cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
0136 }
0137 }
0138
0139 if (sta) {
0140 BUILD_BUG_ON(sizeof(sf_full_timeout) !=
0141 sizeof(__le32) * SF_NUM_SCENARIO *
0142 SF_NUM_TIMEOUT_TYPES);
0143
0144 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
0145 sizeof(sf_full_timeout));
0146 } else {
0147 BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
0148 sizeof(__le32) * SF_NUM_SCENARIO *
0149 SF_NUM_TIMEOUT_TYPES);
0150
0151 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
0152 sizeof(sf_full_timeout_def));
0153 }
0154
0155 }
0156
0157 static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
0158 enum iwl_sf_state new_state)
0159 {
0160 struct iwl_sf_cfg_cmd sf_cmd = {
0161 .state = cpu_to_le32(new_state),
0162 };
0163 struct ieee80211_sta *sta;
0164 int ret = 0;
0165
0166 if (mvm->cfg->disable_dummy_notification)
0167 sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
0168
0169
0170
0171
0172
0173 if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
0174 return 0;
0175
0176 switch (new_state) {
0177 case SF_UNINIT:
0178 iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
0179 break;
0180 case SF_FULL_ON:
0181 if (sta_id == IWL_MVM_INVALID_STA) {
0182 IWL_ERR(mvm,
0183 "No station: Cannot switch SF to FULL_ON\n");
0184 return -EINVAL;
0185 }
0186 rcu_read_lock();
0187 sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
0188 if (IS_ERR_OR_NULL(sta)) {
0189 IWL_ERR(mvm, "Invalid station id\n");
0190 rcu_read_unlock();
0191 return -EINVAL;
0192 }
0193 iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
0194 rcu_read_unlock();
0195 break;
0196 case SF_INIT_OFF:
0197 iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
0198 break;
0199 default:
0200 WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
0201 new_state);
0202 return -EINVAL;
0203 }
0204
0205 ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
0206 sizeof(sf_cmd), &sf_cmd);
0207 if (!ret)
0208 mvm->sf_state = new_state;
0209
0210 return ret;
0211 }
0212
0213
0214
0215
0216
0217
0218 int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
0219 bool remove_vif)
0220 {
0221 enum iwl_sf_state new_state;
0222 u8 sta_id = IWL_MVM_INVALID_STA;
0223 struct iwl_mvm_vif *mvmvif = NULL;
0224 struct iwl_mvm_active_iface_iterator_data data = {
0225 .ignore_vif = changed_vif,
0226 .sta_vif_state = SF_UNINIT,
0227 .sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
0228 };
0229
0230
0231
0232
0233
0234 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
0235 (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
0236 return 0;
0237
0238 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0239 IEEE80211_IFACE_ITER_NORMAL,
0240 iwl_mvm_bound_iface_iterator,
0241 &data);
0242
0243
0244 if (changed_vif && !remove_vif)
0245 data.num_active_macs++;
0246
0247 switch (data.num_active_macs) {
0248 case 0:
0249
0250 new_state = SF_INIT_OFF;
0251 break;
0252 case 1:
0253 if (remove_vif) {
0254
0255
0256
0257 new_state = data.sta_vif_state;
0258 sta_id = data.sta_vif_ap_sta_id;
0259 } else {
0260 if (WARN_ON(!changed_vif))
0261 return -EINVAL;
0262 if (changed_vif->type != NL80211_IFTYPE_STATION) {
0263 new_state = SF_UNINIT;
0264 } else if (changed_vif->cfg.assoc &&
0265 changed_vif->bss_conf.dtim_period) {
0266 mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
0267 sta_id = mvmvif->ap_sta_id;
0268 new_state = SF_FULL_ON;
0269 } else {
0270 new_state = SF_INIT_OFF;
0271 }
0272 }
0273 break;
0274 default:
0275
0276 new_state = SF_UNINIT;
0277 }
0278 return iwl_mvm_sf_config(mvm, sta_id, new_state);
0279 }