diff options
author | Jakub Kicinski <kuba@kernel.org> | 2024-06-27 13:53:43 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-06-27 13:53:43 -0700 |
commit | 56bf02c26a362a270c7f12f1e36aeced95bc2287 (patch) | |
tree | 1f651324663249a83a033a880884489e698bbe68 /drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | |
parent | 193b9b200224dab4eaec407eb2955303a521f5b6 (diff) | |
parent | f3f942d6e5889ea9d46cecf8fc0b7893b5ba9792 (diff) |
Merge tag 'wireless-next-2024-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
Highlights this time are:
- cfg80211/nl80211:
* improvements for 6 GHz regulatory flexibility
- mac80211:
* use generic netdev stats
* multi-link improvements/fixes
- brcmfmac:
* MFP support (to enable WPA3)
- wilc1000:
* suspend/resume improvements
- iwlwifi:
* remove support for older FW for new devices
* fast resume (keeping the device configured)
- wl18xx:
* support newer firmware versions
* tag 'wireless-next-2024-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (100 commits)
wifi: brcmfmac: of: Support interrupts-extended
wifi: brcmsmac: advertise MFP_CAPABLE to enable WPA3
net: rfkill: Correct return value in invalid parameter case
wifi: mac80211: fix NULL dereference at band check in starting tx ba session
wifi: iwlwifi: mvm: fix rs.h kernel-doc
wifi: iwlwifi: fw: api: datapath: fix kernel-doc
wifi: iwlwifi: fix remaining mistagged kernel-doc comments
wifi: iwlwifi: fix prototype mismatch kernel-doc warnings
wifi: iwlwifi: fix kernel-doc in iwl-fh.h
wifi: iwlwifi: fix kernel-doc in iwl-trans.h
wifi: iwlwifi: pcie: fix kernel-doc
wifi: iwlwifi: dvm: fix kernel-doc warnings
wifi: iwlwifi: mvm: don't log error for failed UATS table read
wifi: iwlwifi: trans: make bad state warnings
wifi: iwlwifi: fw: api: fix some kernel-doc
wifi: iwlwifi: mvm: remove init_dbg module parameter
wifi: iwlwifi: update the BA notification API
wifi: iwlwifi: mvm: always unblock EMLSR on ROC end
wifi: iwlwifi: mvm: use IWL_FW_CHECK for link ID check
wifi: iwlwifi: mvm: don't flush BSSes on restart with MLD API
...
====================
Link: https://patch.msgid.link/20240627114135.28507-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/time-event.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 182 |
1 files changed, 119 insertions, 63 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 31bc80cdcb7d..2773dfa8baa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -47,12 +47,13 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) { + struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); struct ieee80211_vif *vif = mvm->p2p_device_vif; lockdep_assert_held(&mvm->mutex); /* - * Clear the ROC_RUNNING status bit. + * Clear the ROC_P2P_RUNNING status bit. * This will cause the TX path to drop offchannel transmissions. * That would also be done by mac80211, but it is racy, in particular * in the case that the time event actually completed in the firmware. @@ -62,7 +63,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) * won't get stuck on the queue and be transmitted in the next * time event. */ - if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) { + if (test_and_clear_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status)) { struct iwl_mvm_vif *mvmvif; synchronize_net(); @@ -99,7 +100,14 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) } } - /* Do the same for AUX ROC */ + /* + * P2P AUX ROC and HS2.0 ROC do not run simultaneously. + * Clear the ROC_AUX_RUNNING status bit. + * This will cause the TX path to drop offchannel transmissions. + * That would also be done by mac80211, but it is racy, in particular + * in the case that the time event actually completed in the firmware + * (which is handled in iwl_mvm_te_handle_notif). + */ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) { synchronize_net(); @@ -119,9 +127,9 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) iwl_mvm_rm_aux_sta(mvm); } + if (!IS_ERR_OR_NULL(bss_vif)) + iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_ROC); mutex_unlock(&mvm->mutex); - if (vif) - iwl_mvm_esr_non_bss_link(mvm, vif, 0, false); } void iwl_mvm_roc_done_wk(struct work_struct *wk) @@ -378,7 +386,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration); if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { - set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status); ieee80211_ready_on_channel(mvm->hw); } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) { iwl_mvm_te_handle_notify_csa(mvm, te_data, notif); @@ -388,14 +396,51 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, } } +struct iwl_mvm_rx_roc_iterator_data { + u32 activity; + bool end_activity; + bool found; +}; + +static void iwl_mvm_rx_roc_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_rx_roc_iterator_data *data = _data; + + if (mvmvif->roc_activity == data->activity) { + data->found = true; + if (data->end_activity) + mvmvif->roc_activity = ROC_NUM_ACTIVITIES; + } +} + void iwl_mvm_rx_roc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_roc_notif *notif = (void *)pkt->data; + u32 activity = le32_to_cpu(notif->activity); + bool started = le32_to_cpu(notif->success) && + le32_to_cpu(notif->started); + struct iwl_mvm_rx_roc_iterator_data data = { + .activity = activity, + .end_activity = !started, + }; + + /* Clear vif roc_activity if done (set to ROC_NUM_ACTIVITIES) */ + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_rx_roc_iterator, + &data); + /* + * It is possible that the ROC was canceled + * but the notification was already fired. + */ + if (!data.found) + return; - if (le32_to_cpu(notif->success) && le32_to_cpu(notif->started) && - le32_to_cpu(notif->activity) == ROC_ACTIVITY_HOTSPOT) { + if (started) { set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); ieee80211_ready_on_channel(mvm->hw); } else { @@ -724,6 +769,21 @@ static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); } +static void iwl_mvm_roc_rm_cmd(struct iwl_mvm *mvm, u32 activity) +{ + struct iwl_roc_req roc_cmd = { + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + .activity = cpu_to_le32(activity), + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0, + sizeof(roc_cmd), &roc_cmd); + if (ret) + IWL_ERR(mvm, "Couldn't send the ROC_CMD: %d\n", ret); +} + static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data, u32 *uid) @@ -733,6 +793,9 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif; enum nl80211_iftype iftype; s8 link_id; + bool p2p_aux = iwl_mvm_has_p2p_over_aux(mvm); + u8 roc_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); if (!vif) return false; @@ -757,14 +820,22 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); spin_unlock_bh(&mvm->time_event_lock); - /* When session protection is used, the te_data->id field - * is reused to save session protection's configuration. - * For AUX ROC, HOT_SPOT_CMD is used and the te_data->id field is set - * to HOT_SPOT_CMD. - */ - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD) && - id != HOT_SPOT_CMD) { + if ((p2p_aux && iftype == NL80211_IFTYPE_P2P_DEVICE) || + (roc_ver >= 3 && mvmvif->roc_activity == ROC_ACTIVITY_HOTSPOT)) { + if (mvmvif->roc_activity < ROC_NUM_ACTIVITIES) { + iwl_mvm_roc_rm_cmd(mvm, mvmvif->roc_activity); + mvmvif->roc_activity = ROC_NUM_ACTIVITIES; + iwl_mvm_roc_finished(mvm); + } + return false; + } else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD) && + id != HOT_SPOT_CMD) { + /* When session protection is used, the te_data->id field + * is reused to save session protection's configuration. + * For AUX ROC, HOT_SPOT_CMD is used and the te_data->id + * field is set to HOT_SPOT_CMD. + */ if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ iwl_mvm_cancel_session_protection(mvm, vif, id, @@ -965,7 +1036,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (WARN_ON(mvmvif->time_event_data.id != le32_to_cpu(notif->conf_id))) goto out_unlock; - set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status); ieee80211_ready_on_channel(mvm->hw); /* Start TE */ } @@ -1014,7 +1085,7 @@ void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, struct ieee80211_channel *channel, struct ieee80211_vif *vif, - int duration, u32 activity) + int duration, enum iwl_roc_activity activity) { int res; u32 duration_tu, delay; @@ -1023,9 +1094,13 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, .activity = cpu_to_le32(activity), .sta_id = cpu_to_le32(mvm->aux_sta.sta_id), }; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); lockdep_assert_held(&mvm->mutex); + if (WARN_ON(mvmvif->roc_activity != ROC_NUM_ACTIVITIES)) + return -EBUSY; + /* Set the channel info data */ iwl_mvm_set_chan_info(mvm, &roc_req.channel_info, channel->hw_value, @@ -1041,14 +1116,16 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, "\t(requested = %ums, max_delay = %ums)\n", duration, delay); IWL_DEBUG_TE(mvm, - "Requesting to remain on channel %u for %utu\n", - channel->hw_value, duration_tu); + "Requesting to remain on channel %u for %utu. activity %u\n", + channel->hw_value, duration_tu, activity); /* Set the node address */ memcpy(roc_req.node_addr, vif->addr, ETH_ALEN); res = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0, sizeof(roc_req), &roc_req); + if (!res) + mvmvif->roc_activity = activity; return res; } @@ -1191,62 +1268,40 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) __iwl_mvm_remove_time_event(mvm, te_data, &uid); } -static void iwl_mvm_roc_rm_cmd(struct iwl_mvm *mvm, u32 activity) -{ - int ret; - struct iwl_roc_req roc_cmd = { - .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), - .activity = cpu_to_le32(activity), - }; - - lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - 0, sizeof(roc_cmd), &roc_cmd); - WARN_ON(ret); -} - -static void iwl_mvm_roc_station_remove(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif) -{ - u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, ROC_CMD); - u8 fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - - if (fw_ver == IWL_FW_CMD_VER_UNKNOWN) - iwl_mvm_remove_aux_roc_te(mvm, mvmvif, - &mvmvif->hs_time_event_data); - else if (fw_ver == 3) - iwl_mvm_roc_rm_cmd(mvm, ROC_ACTIVITY_HOTSPOT); - else - IWL_ERR(mvm, "ROC command version %d mismatch!\n", fw_ver); -} - void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data; + bool p2p_aux = iwl_mvm_has_p2p_over_aux(mvm); + u8 roc_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); + int iftype = vif->type; mutex_lock(&mvm->mutex); - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { - mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (p2p_aux || (roc_ver >= 3 && iftype != NL80211_IFTYPE_P2P_DEVICE)) { + if (mvmvif->roc_activity < ROC_NUM_ACTIVITIES) { + iwl_mvm_roc_rm_cmd(mvm, mvmvif->roc_activity); + mvmvif->roc_activity = ROC_NUM_ACTIVITIES; + } + goto cleanup_roc; + } else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { te_data = &mvmvif->time_event_data; - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + if (iftype == NL80211_IFTYPE_P2P_DEVICE) { if (te_data->id >= SESSION_PROTECT_CONF_MAX_ID) { IWL_DEBUG_TE(mvm, "No remain on channel event\n"); mutex_unlock(&mvm->mutex); return; } - iwl_mvm_cancel_session_protection(mvm, vif, te_data->id, te_data->link_id); } else { - iwl_mvm_roc_station_remove(mvm, mvmvif); + iwl_mvm_remove_aux_roc_te(mvm, mvmvif, + &mvmvif->hs_time_event_data); } goto cleanup_roc; } @@ -1259,8 +1314,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) + iftype = te_data->vif->type; + if (iftype == NL80211_IFTYPE_P2P_DEVICE) iwl_mvm_remove_time_event(mvm, mvmvif, te_data); else iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); @@ -1271,9 +1326,10 @@ cleanup_roc: * (so the status bit isn't set) set it here so iwl_mvm_cleanup_roc will * cleanup things properly */ - set_bit(vif->type == NL80211_IFTYPE_P2P_DEVICE ? - IWL_MVM_STATUS_ROC_RUNNING : IWL_MVM_STATUS_ROC_AUX_RUNNING, - &mvm->status); + if (p2p_aux || iftype != NL80211_IFTYPE_P2P_DEVICE) + set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); + else + set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status); /* Mutex is released inside this function */ iwl_mvm_cleanup_roc(mvm); |