|
@@ -186,6 +186,92 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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)
|
|
@@ -198,8 +284,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
|
|
|
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));
|
|
@@ -269,81 +353,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
|
|
|
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)
|
|
@@ -472,6 +484,44 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
|
|
|
&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,
|
|
@@ -494,70 +544,58 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
|
|
|
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;
|
|
|
}
|
|
|
|