diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 4c086d04809765be7fbffe81ad9361ec5a854241..ade170bd8683fa7e3d66a0ee3ef58875aa78e3b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -437,9 +437,11 @@ struct iwl_rxq_sync_notification { /** * Internal message identifier * +* @IWL_MVM_RXQ_SYNC: sync RSS queues * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA */ enum iwl_mvm_rxq_notif_type { + IWL_MVM_RXQ_SYNC, IWL_MVM_RXQ_NOTIF_DEL_BA, }; @@ -448,10 +450,12 @@ enum iwl_mvm_rxq_notif_type { * in &iwl_rxq_sync_cmd. Should be DWORD aligned. * * @type: value from &iwl_mvm_rxq_notif_type +* @cookie: internal cookie to identify old notifications * @data: payload */ struct iwl_mvm_internal_rxq_notif { u32 type; + u32 cookie; u8 data[]; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5ace468070cbe4721ecb2fd3a3c2a0e9bc48e8c6..d6ad77a2c767115b4aa3fc702b47b71a27acb0b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4037,6 +4037,47 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, } } +static void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm) +{ + struct iwl_mvm_internal_rxq_notif data = { + .type = IWL_MVM_RXQ_SYNC, + .cookie = mvm->queue_sync_cookie, + }; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq); + u32 qmask = BIT(mvm->trans->num_rx_queues) - 1; + int ret; + + lockdep_assert_held(&mvm->mutex); + + if (!iwl_mvm_has_new_rx_api(mvm)) + return; + + atomic_set(&mvm->queue_sync_counter, mvm->trans->num_rx_queues); + + ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)&data, sizeof(data)); + if (ret) { + IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret); + goto out; + } + ret = wait_event_timeout(notif_waitq, + atomic_read(&mvm->queue_sync_counter) == 0, + HZ); + WARN_ON_ONCE(!ret); + +out: + atomic_set(&mvm->queue_sync_counter, 0); + mvm->queue_sync_cookie++; +} + +static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + mutex_lock(&mvm->mutex); + iwl_mvm_sync_rx_queues_internal(mvm); + mutex_unlock(&mvm->mutex); +} + const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, .ampdu_action = iwl_mvm_mac_ampdu_action, @@ -4093,6 +4134,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .event_callback = iwl_mvm_mac_event_callback, + .sync_rx_queues = iwl_mvm_sync_rx_queues, + CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 85800ba0c667d39969aa7efab620fb13fd67d1db..c7c8a6205eaae78ebe379701cf3dc04df4febaab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -633,6 +633,8 @@ struct iwl_mvm { unsigned long status; + u32 queue_sync_cookie; + atomic_t queue_sync_counter; /* * for beacon filtering - * currently only one interface can be supported diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 8bfb8e06a90c4dd24765ca56aaf7a16abaa0f25b..7c6a5984105f2cea68fcd7ed25d2b23382fd4216 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -586,6 +586,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, skb_queue_head_init(&mvm->d0i3_tx); init_waitqueue_head(&mvm->d0i3_exit_waitq); + atomic_set(&mvm->queue_sync_counter, 0); + SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 651604d18a3252af432d396bff7e923bd1439c2c..b4d9c42d411afd53a869e5f393f7f1a703d912a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -406,6 +406,13 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, internal_notif = (void *)notif->payload; switch (internal_notif->type) { + case IWL_MVM_RXQ_SYNC: + if (mvm->queue_sync_cookie == internal_notif->cookie) + atomic_dec(&mvm->queue_sync_counter); + else + WARN_ONCE(1, + "Received expired RX queue sync message\n"); + break; case IWL_MVM_RXQ_NOTIF_DEL_BA: /* TODO */ break;