}
 }
 
+static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         struct iwl_mac_power_cmd *cmd)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       enum ieee80211_ac_numbers ac;
+       bool tid_found = false;
+
+       for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
+               if (!mvmvif->queue_params[ac].uapsd)
+                       continue;
+
+               if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
+                       cmd->flags |=
+                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+
+               cmd->uapsd_ac_flags |= BIT(ac);
+
+               /* QNDP TID - the highest TID with no admission control */
+               if (!tid_found && !mvmvif->queue_params[ac].acm) {
+                       tid_found = true;
+                       switch (ac) {
+                       case IEEE80211_AC_VO:
+                               cmd->qndp_tid = 6;
+                               break;
+                       case IEEE80211_AC_VI:
+                               cmd->qndp_tid = 5;
+                               break;
+                       case IEEE80211_AC_BE:
+                               cmd->qndp_tid = 0;
+                               break;
+                       case IEEE80211_AC_BK:
+                               cmd->qndp_tid = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+               return;
+
+       cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
+
+       if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
+                                   BIT(IEEE80211_AC_VI) |
+                                   BIT(IEEE80211_AC_BE) |
+                                   BIT(IEEE80211_AC_BK))) {
+               cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
+               cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
+               cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
+                       cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
+                       cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
+       }
+
+       cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
+
+       if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
+           cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+               cmd->rx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
+               cmd->tx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+       } else {
+               cmd->rx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
+               cmd->tx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
+       }
+
+       if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+               cmd->heavy_tx_thld_packets =
+                       IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
+               cmd->heavy_rx_thld_packets =
+                       IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
+       } else {
+               cmd->heavy_tx_thld_packets =
+                       IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
+               cmd->heavy_rx_thld_packets =
+                       IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
+       }
+       cmd->heavy_tx_thld_percentage =
+               IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
+       cmd->heavy_rx_thld_percentage =
+               IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
+}
+
 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif,
                                    struct iwl_mac_power_cmd *cmd)
        bool radar_detect = false;
        struct iwl_mvm_vif *mvmvif __maybe_unused =
                iwl_mvm_vif_from_mac80211(vif);
-       enum ieee80211_ac_numbers ac;
-       bool tid_found = false;
 
        cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
                                                            mvmvif->color));
                        cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
        }
 
-       for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
-               if (!mvmvif->queue_params[ac].uapsd)
-                       continue;
-
-               if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
-                       cmd->flags |=
-                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
-
-               cmd->uapsd_ac_flags |= BIT(ac);
-
-               /* QNDP TID - the highest TID with no admission control */
-               if (!tid_found && !mvmvif->queue_params[ac].acm) {
-                       tid_found = true;
-                       switch (ac) {
-                       case IEEE80211_AC_VO:
-                               cmd->qndp_tid = 6;
-                               break;
-                       case IEEE80211_AC_VI:
-                               cmd->qndp_tid = 5;
-                               break;
-                       case IEEE80211_AC_BE:
-                               cmd->qndp_tid = 0;
-                               break;
-                       case IEEE80211_AC_BK:
-                               cmd->qndp_tid = 1;
-                               break;
-                       }
-               }
-       }
-
-       if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
-               if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
-                                           BIT(IEEE80211_AC_VI) |
-                                           BIT(IEEE80211_AC_BE) |
-                                           BIT(IEEE80211_AC_BK))) {
-                       cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
-                       cmd->snooze_interval =
-                               cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
-                       cmd->snooze_window =
-                               (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
-                               cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
-                               cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
-               }
-
-               cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
-
-               if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
-                   cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       cmd->rx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
-                       cmd->tx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
-               } else {
-                       cmd->rx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
-                       cmd->tx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
-               }
-
-               if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       cmd->heavy_tx_thld_packets =
-                               IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
-                       cmd->heavy_rx_thld_packets =
-                               IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
-               } else {
-                       cmd->heavy_tx_thld_packets =
-                               IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
-                       cmd->heavy_rx_thld_packets =
-                               IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
-               }
-               cmd->heavy_tx_thld_percentage =
-                       IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
-               cmd->heavy_rx_thld_percentage =
-                       IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
-       }
+       if (memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+                  ETH_ALEN))
+               iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
                                    &cmd);
 }
 
+void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
+                  ETH_ALEN))
+               memset(mvmvif->uapsd_misbehaving_bssid, 0, ETH_ALEN);
+}
+
+static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
+                                                    struct ieee80211_vif *vif)
+{
+       u8 *ap_sta_id = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       /* The ap_sta_id is not expected to change during current association
+        * so no explicit protection is needed
+        */
+       if (mvmvif->ap_sta_id == *ap_sta_id)
+               memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+                      ETH_ALEN);
+}
+
+int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
+                                            struct iwl_rx_cmd_buffer *rxb,
+                                            struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
+       u8 ap_sta_id = le32_to_cpu(notif->sta_id);
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
+
+       return 0;
+}
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif, char *buf,
        pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
                         le16_to_cpu(cmd.keep_alive_seconds));
 
-       if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
-               pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
-                                (cmd.flags &
-                                cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
-                                1 : 0);
-               pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
-                                cmd.skip_dtim_periods);
-               if (!(cmd.flags &
-                     cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "rx_data_timeout = %d\n",
-                                        le32_to_cpu(cmd.rx_data_timeout));
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "tx_data_timeout = %d\n",
-                                        le32_to_cpu(cmd.tx_data_timeout));
-               }
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "lprx_rssi_threshold = %d\n",
-                                        cmd.lprx_rssi_threshold);
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos,
-                                 "rx_data_timeout_uapsd = %d\n",
-                                 le32_to_cpu(cmd.rx_data_timeout_uapsd));
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos,
-                                 "tx_data_timeout_uapsd = %d\n",
-                                 le32_to_cpu(cmd.tx_data_timeout_uapsd));
-                       pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n",
-                                        cmd.qndp_tid);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "uapsd_ac_flags = 0x%x\n",
-                                        cmd.uapsd_ac_flags);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "uapsd_max_sp = %d\n",
-                                        cmd.uapsd_max_sp);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_tx_thld_packets = %d\n",
-                                        cmd.heavy_tx_thld_packets);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_rx_thld_packets = %d\n",
-                                        cmd.heavy_rx_thld_packets);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_tx_thld_percentage = %d\n",
-                                        cmd.heavy_tx_thld_percentage);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_rx_thld_percentage = %d\n",
-                                        cmd.heavy_rx_thld_percentage);
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n",
-                                 (cmd.flags &
-                                  cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ?
-                                 1 : 0);
-               }
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "snooze_interval = %d\n",
-                                        cmd.snooze_interval);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "snooze_window = %d\n",
-                                        cmd.snooze_window);
-               }
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
+                        (cmd.flags &
+                        cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
+       pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
+                        cmd.skip_dtim_periods);
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+               pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
+                                le32_to_cpu(cmd.rx_data_timeout));
+               pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
+                                le32_to_cpu(cmd.tx_data_timeout));
        }
+       if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
+               pos += scnprintf(buf+pos, bufsz-pos,
+                                "lprx_rssi_threshold = %d\n",
+                                cmd.lprx_rssi_threshold);
+
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
+                        le32_to_cpu(cmd.rx_data_timeout_uapsd));
+       pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
+                        le32_to_cpu(cmd.tx_data_timeout_uapsd));
+       pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
+                        cmd.uapsd_ac_flags);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
+                        cmd.uapsd_max_sp);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
+                        cmd.heavy_tx_thld_packets);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
+                        cmd.heavy_rx_thld_packets);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
+                        cmd.heavy_tx_thld_percentage);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
+                        cmd.heavy_rx_thld_percentage);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
+                        (cmd.flags &
+                         cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
+                        1 : 0);
+
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
+                        cmd.snooze_interval);
+       pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
+                        cmd.snooze_window);
+
        return pos;
 }