mirror of https://gitee.com/openkylin/linux.git
iwlwifi: mvm: support CHANNEL_SWITCH_TIME_EVENT_CMD command
When we do channel switch, we used to schedule time events ourselves. This was offloaded to FW. Support the new command and flow. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
parent
b2c1bf597f
commit
74a1025212
|
@ -73,6 +73,10 @@ enum iwl_mac_conf_subcmd_ids {
|
|||
* @LOW_LATENCY_CMD: &struct iwl_mac_low_latency_cmd
|
||||
*/
|
||||
LOW_LATENCY_CMD = 0x3,
|
||||
/**
|
||||
* @CHANNEL_SWITCH_TIME_EVENT_CMD: &struct iwl_chan_switch_te_cmd
|
||||
*/
|
||||
CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4,
|
||||
/**
|
||||
* @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif
|
||||
*/
|
||||
|
@ -135,6 +139,29 @@ struct iwl_channel_switch_noa_notif {
|
|||
__le32 id_and_color;
|
||||
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_chan_switch_te_cmd - Channel Switch Time Event command
|
||||
*
|
||||
* @mac_id: MAC ID for channel switch
|
||||
* @action: action to perform, one of FW_CTXT_ACTION_*
|
||||
* @tsf: beacon tsf
|
||||
* @cs_count: channel switch count from CSA/eCSA IE
|
||||
* @cs_delayed_bcn_count: if set to N (!= 0) GO/AP can delay N beacon intervals
|
||||
* at the new channel after the channel switch, otherwise (N == 0) expect
|
||||
* beacon right after the channel switch.
|
||||
* @cs_mode: 1 - quiet, 0 - otherwise
|
||||
* @reserved: reserved for alignment purposes
|
||||
*/
|
||||
struct iwl_chan_switch_te_cmd {
|
||||
__le32 mac_id;
|
||||
__le32 action;
|
||||
__le32 tsf;
|
||||
u8 cs_count;
|
||||
u8 cs_delayed_bcn_count;
|
||||
u8 cs_mode;
|
||||
u8 reserved;
|
||||
} __packed; /* MAC_CHANNEL_SWITCH_TIME_EVENT_S_VER_2 */
|
||||
|
||||
/**
|
||||
* struct iwl_mac_low_latency_cmd - set/clear mac to 'low-latency mode'
|
||||
*
|
||||
|
|
|
@ -333,6 +333,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
|
|||
* @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm
|
||||
* @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related
|
||||
* @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2
|
||||
* IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command
|
||||
* @IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band
|
||||
* (6 GHz).
|
||||
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
|
||||
|
@ -397,6 +398,7 @@ enum iwl_ucode_tlv_capa {
|
|||
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD = (__force iwl_ucode_tlv_capa_t)43,
|
||||
IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA = (__force iwl_ucode_tlv_capa_t)44,
|
||||
IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2 = (__force iwl_ucode_tlv_capa_t)45,
|
||||
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD = (__force iwl_ucode_tlv_capa_t)46,
|
||||
IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS = (__force iwl_ucode_tlv_capa_t)48,
|
||||
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
|
||||
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
|
||||
|
|
|
@ -1539,42 +1539,58 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
|
||||
struct ieee80211_vif *csa_vif;
|
||||
struct ieee80211_vif *csa_vif, *vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
int len = iwl_rx_packet_payload_len(pkt);
|
||||
u32 id_n_color;
|
||||
u32 id_n_color, csa_id, mac_id;
|
||||
|
||||
if (WARN_ON_ONCE(len < sizeof(*notif)))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
csa_vif = rcu_dereference(mvm->csa_vif);
|
||||
if (WARN_ON(!csa_vif || !csa_vif->csa_active))
|
||||
goto out_unlock;
|
||||
|
||||
id_n_color = le32_to_cpu(notif->id_and_color);
|
||||
mac_id = id_n_color & FW_CTXT_ID_MSK;
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
|
||||
if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color,
|
||||
"channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
|
||||
FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color))
|
||||
goto out_unlock;
|
||||
if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
|
||||
rcu_read_lock();
|
||||
vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]);
|
||||
|
||||
schedule_delayed_work(&mvm->cs_tx_unblock_dwork,
|
||||
msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
|
||||
csa_vif->bss_conf.beacon_int));
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
csa_vif = rcu_dereference(mvm->csa_vif);
|
||||
if (WARN_ON(!csa_vif || !csa_vif->csa_active ||
|
||||
csa_vif != vif))
|
||||
goto out_unlock;
|
||||
|
||||
ieee80211_csa_finish(csa_vif);
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
|
||||
csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
|
||||
if (WARN(csa_id != id_n_color,
|
||||
"channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
|
||||
csa_id, id_n_color))
|
||||
goto out_unlock;
|
||||
|
||||
rcu_read_unlock();
|
||||
IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
|
||||
|
||||
RCU_INIT_POINTER(mvm->csa_vif, NULL);
|
||||
schedule_delayed_work(&mvm->cs_tx_unblock_dwork,
|
||||
msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
|
||||
csa_vif->bss_conf.beacon_int));
|
||||
|
||||
return;
|
||||
ieee80211_csa_finish(csa_vif);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
RCU_INIT_POINTER(mvm->csa_vif, NULL);
|
||||
return;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
iwl_mvm_csa_client_absent(mvm, vif);
|
||||
ieee80211_chswitch_done(vif, true);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -3953,25 +3953,30 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
|
||||
u32 duration = 3 * vif->bss_conf.beacon_int;
|
||||
|
||||
/* iwl_mvm_protect_session() reads directly from the
|
||||
* device (the system time), so make sure it is
|
||||
* available.
|
||||
*/
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA);
|
||||
if (ret)
|
||||
goto out_remove_binding;
|
||||
|
||||
/* Protect the session to make sure we hear the first
|
||||
* beacon on the new channel.
|
||||
*/
|
||||
mvmvif->csa_bcn_pending = true;
|
||||
iwl_mvm_protect_session(mvm, vif, duration, duration,
|
||||
vif->bss_conf.beacon_int / 2,
|
||||
true);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {
|
||||
u32 duration = 3 * vif->bss_conf.beacon_int;
|
||||
|
||||
|
||||
/* iwl_mvm_protect_session() reads directly from the
|
||||
* device (the system time), so make sure it is
|
||||
* available.
|
||||
*/
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA);
|
||||
if (ret)
|
||||
goto out_remove_binding;
|
||||
|
||||
/* Protect the session to make sure we hear the first
|
||||
* beacon on the new channel.
|
||||
*/
|
||||
iwl_mvm_protect_session(mvm, vif, duration, duration,
|
||||
vif->bss_conf.beacon_int / 2,
|
||||
true);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
|
||||
}
|
||||
|
||||
iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
}
|
||||
|
@ -4041,7 +4046,9 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
|
||||
disabled_vif = vif;
|
||||
|
||||
iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
|
||||
iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -4292,6 +4299,27 @@ static void iwl_mvm_channel_switch(struct ieee80211_hw *hw,
|
|||
"dummy channel switch op\n");
|
||||
}
|
||||
|
||||
static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel_switch *chsw)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_chan_switch_te_cmd cmd = {
|
||||
.mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
|
||||
mvmvif->color)),
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
||||
.tsf = cpu_to_le32(chsw->timestamp),
|
||||
.cs_count = chsw->count,
|
||||
};
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm,
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
CHANNEL_SWITCH_TIME_EVENT_CMD),
|
||||
0, sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel_switch *chsw)
|
||||
|
@ -4359,14 +4387,19 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
if (chsw->block_tx)
|
||||
iwl_mvm_csa_client_absent(mvm, vif);
|
||||
|
||||
iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int,
|
||||
apply_time);
|
||||
if (mvmvif->bf_data.bf_enabled) {
|
||||
ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
|
||||
iwl_mvm_schedule_client_csa(mvm, vif, chsw);
|
||||
else
|
||||
iwl_mvm_schedule_csa_period(mvm, vif,
|
||||
vif->bss_conf.beacon_int,
|
||||
apply_time);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -421,6 +421,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
|
|||
* Access is done through binary search
|
||||
*/
|
||||
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
|
||||
HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
|
||||
HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue