diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 89 |
1 files changed, 83 insertions, 6 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 318efd814037..45122dafe922 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -445,6 +445,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); if (iwl_mvm_has_new_rx_api(mvm)) ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF)) + ieee80211_hw_set(hw, AP_LINK_PS); if (mvm->trans->num_rx_queues > 1) ieee80211_hw_set(hw, USES_RSS); @@ -2097,6 +2099,22 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_unbind; + /* enable the multicast queue, now that we have a station for it */ + if (iwl_mvm_is_dqa_supported(mvm)) { + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = IWL_MVM_TX_FIFO_MCAST, + .sta_id = mvmvif->bcast_sta.sta_id, + .tid = IWL_MAX_TID_COUNT, + .aggregate = false, + .frame_limit = IWL_FRAME_LIMIT, + }; + + iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, + &cfg, wdg_timeout); + } + /* must be set before quota calculations */ mvmvif->ap_ibss_active = true; @@ -2318,10 +2336,9 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, tids, more_data, true); } -static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) +static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -2374,6 +2391,67 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, spin_unlock_bh(&mvmsta->lock); } +static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + __iwl_mvm_mac_sta_notify(hw, cmd, sta); +} + +void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mvm_pm_state_notification *notif = (void *)pkt->data; + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + bool sleeping = (notif->type != IWL_MVM_PM_EVENT_AWAKE); + + if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) + return; + + rcu_read_lock(); + sta = mvm->fw_id_to_mac_id[notif->sta_id]; + if (WARN_ON(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return; + } + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + if (!mvmsta->vif || + mvmsta->vif->type != NL80211_IFTYPE_AP) { + rcu_read_unlock(); + return; + } + + if (mvmsta->sleeping != sleeping) { + mvmsta->sleeping = sleeping; + __iwl_mvm_mac_sta_notify(mvm->hw, + sleeping ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, + sta); + ieee80211_sta_ps_transition(sta, sleeping); + } + + if (sleeping) { + switch (notif->type) { + case IWL_MVM_PM_EVENT_AWAKE: + case IWL_MVM_PM_EVENT_ASLEEP: + break; + case IWL_MVM_PM_EVENT_UAPSD: + ieee80211_sta_uapsd_trigger(sta, IEEE80211_NUM_TIDS); + break; + case IWL_MVM_PM_EVENT_PS_POLL: + ieee80211_sta_pspoll(sta); + break; + default: + break; + } + } + + rcu_read_unlock(); +} + static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -4121,7 +4199,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, struct iwl_mvm_internal_rxq_notif *notif, u32 size) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq); u32 qmask = BIT(mvm->trans->num_rx_queues) - 1; int ret; @@ -4143,7 +4220,7 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, } if (notif->sync) - ret = wait_event_timeout(notif_waitq, + ret = wait_event_timeout(mvm->rx_sync_waitq, atomic_read(&mvm->queue_sync_counter) == 0, HZ); WARN_ON_ONCE(!ret); |