Commit ad12b231 authored by Nathan Errera's avatar Nathan Errera Committed by Luca Coelho

iwlwifi: mvm: offload channel switch timing to FW

Since FW is now in charge of timing the channel switch, there is no need
to send the add/modify/remove time event command to fw with every (e)CSA
element.
However, the driver needs to cancel the channel switch if the CS start
notification arrives and it does not know about an ongoing channel switch.
Signed-off-by: default avatarNathan Errera <nathan.errera@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20220128153013.ac3af0ff22c7.Ie87c62047b71b93b12aa80b5dc5391b4798dbe97@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 30d17c12
......@@ -27,6 +27,10 @@ enum iwl_mac_conf_subcmd_ids {
* @SESSION_PROTECTION_CMD: &struct iwl_mvm_session_prot_cmd
*/
SESSION_PROTECTION_CMD = 0x5,
/**
* @CANCEL_CHANNEL_SWITCH_CMD: &struct iwl_cancel_channel_switch_cmd
*/
CANCEL_CHANNEL_SWITCH_CMD = 0x6,
/**
* @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif
......@@ -42,6 +46,11 @@ enum iwl_mac_conf_subcmd_ids {
* @CHANNEL_SWITCH_START_NOTIF: &struct iwl_channel_switch_start_notif
*/
CHANNEL_SWITCH_START_NOTIF = 0xFF,
/**
*@CHANNEL_SWITCH_ERROR_NOTIF: &struct iwl_channel_switch_error_notif
*/
CHANNEL_SWITCH_ERROR_NOTIF = 0xF9,
};
#define IWL_P2P_NOA_DESC_COUNT (2)
......@@ -110,6 +119,31 @@ struct iwl_channel_switch_start_notif {
__le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
#define CS_ERR_COUNT_ERROR BIT(0)
#define CS_ERR_LONG_DELAY_AFTER_CS BIT(1)
#define CS_ERR_LONG_TX_BLOCK BIT(2)
#define CS_ERR_TX_BLOCK_TIMER_EXPIRED BIT(3)
/**
* struct iwl_channel_switch_error_notif - Channel switch error notification
*
* @mac_id: the mac for which the ucode sends the notification for
* @csa_err_mask: mask of channel switch error that can occur
*/
struct iwl_channel_switch_error_notif {
__le32 mac_id;
__le32 csa_err_mask;
} __packed; /* CHANNEL_SWITCH_ERROR_NTFY_API_S_VER_1 */
/**
* struct iwl_cancel_channel_switch_cmd - Cancel Channel Switch command
*
* @mac_id: the mac that should cancel the channel switch
*/
struct iwl_cancel_channel_switch_cmd {
__le32 mac_id;
} __packed; /* MAC_CANCEL_CHANNEL_SWITCH_S_VER_1 */
/**
* struct iwl_chan_switch_te_cmd - Channel Switch Time Event command
*
......
......@@ -1602,6 +1602,18 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
RCU_INIT_POINTER(mvm->csa_vif, NULL);
return;
case NL80211_IFTYPE_STATION:
/*
* if we don't know about an ongoing channel switch,
* make sure FW cancels it
*/
if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
CHANNEL_SWITCH_ERROR_NOTIF,
0) && !vif->csa_active) {
IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n");
iwl_mvm_cancel_channel_switch(mvm, vif, mac_id);
break;
}
iwl_mvm_csa_client_absent(mvm, vif);
cancel_delayed_work(&mvmvif->csa_work);
ieee80211_chswitch_done(vif, true);
......@@ -1615,6 +1627,31 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
rcu_read_unlock();
}
void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_channel_switch_error_notif *notif = (void *)pkt->data;
struct ieee80211_vif *vif;
u32 id = le32_to_cpu(notif->mac_id);
u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask);
rcu_read_lock();
vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true);
if (!vif) {
rcu_read_unlock();
return;
}
IWL_DEBUG_INFO(mvm, "FW reports CSA error: mac_id=%u, csa_err_mask=%u\n",
id, csa_err_mask);
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
CS_ERR_LONG_DELAY_AFTER_CS |
CS_ERR_TX_BLOCK_TIMER_EXPIRED))
ieee80211_channel_switch_disconnect(vif, true);
rcu_read_unlock();
}
void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
......
......@@ -1414,6 +1414,15 @@ static void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
};
/*
* In the new flow since FW is in charge of the timing,
* if driver has canceled the channel switch he will receive the
* CHANNEL_SWITCH_START_NOTIF notification from FW and then cancel it
*/
if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
CHANNEL_SWITCH_ERROR_NOTIF, 0))
return;
IWL_DEBUG_MAC80211(mvm, "Abort CSA on mac %d\n", mvmvif->id);
mutex_lock(&mvm->mutex);
......@@ -4846,6 +4855,15 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
break;
case NL80211_IFTYPE_STATION:
/*
* In the new flow FW is in charge of timing the switch so there
* is no need for all of this
*/
if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
CHANNEL_SWITCH_ERROR_NOTIF,
0))
break;
/*
* We haven't configured the firmware to be associated yet since
* we don't know the dtim period. In this case, the firmware can't
......@@ -4917,6 +4935,14 @@ static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
.cs_mode = chsw->block_tx,
};
/*
* In the new flow FW is in charge of timing the switch so there is no
* need for all of this
*/
if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
CHANNEL_SWITCH_ERROR_NOTIF, 0))
return;
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CS_MODIFY))
return;
......
......@@ -1684,6 +1684,8 @@ void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
......
......@@ -382,6 +382,10 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF,
iwl_mvm_channel_switch_start_notif,
RX_HANDLER_SYNC, struct iwl_channel_switch_start_notif),
RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF,
iwl_mvm_channel_switch_error_notif,
RX_HANDLER_ASYNC_UNLOCKED,
struct iwl_channel_switch_error_notif),
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,
iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED,
struct iwl_datapath_monitor_notif),
......
......@@ -3940,7 +3940,7 @@ void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
if (!WARN_ON(!mvmsta))
if (mvmsta)
iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
rcu_read_unlock();
......@@ -3999,3 +3999,21 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_dealloc_int_sta(mvm, sta);
return ret;
}
void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 mac_id)
{
struct iwl_cancel_channel_switch_cmd cancel_channel_switch_cmd = {
.mac_id = cpu_to_le32(mac_id),
};
int ret;
ret = iwl_mvm_send_cmd_pdu(mvm,
iwl_cmd_id(CANCEL_CHANNEL_SWITCH_CMD, MAC_CONF_GROUP, 0),
CMD_ASYNC,
sizeof(cancel_channel_switch_cmd),
&cancel_channel_switch_cmd);
if (ret)
IWL_ERR(mvm, "Failed to cancel the channel switch\n");
}
......@@ -548,4 +548,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher,
u8 *key, u32 key_len);
void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 mac_id);
#endif /* __sta_h__ */
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