static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; bool ba_enable; struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; /* * TODO: The following vif_count verification is temporary condition. * Avoid power mode update if more than one interface is currently * active. Remove this condition when FW will support power management * on multiple MACs. */ IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", mvm->vif_count); if (mvm->vif_count > 1) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); if (ret) return ret; ba_enable = !!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); }
static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; bool ba_enable; struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION) return 0; if (vif->p2p && !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); if (ret) return ret; ba_enable = !!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); }
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable, u32 flags) { int ret; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; if (!vif->bss_conf.assoc) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { /* configure skip over dtim up to 306TU - 314 msec */ int dtimper = vif->bss_conf.dtim_period ?: 1; int dtimper_tu = dtimper * vif->bss_conf.beacon_int; bool radar_detect = iwl_mvm_power_is_radar(vif); if (WARN_ON(!dtimper_tu)) return 0; /* Check skip over DTIM conditions */ /* TODO: check that multicast wake lock is off */ if (!radar_detect && (dtimper < 10)) { cmd.skip_dtim_periods = 306 / dtimper_tu; if (cmd.skip_dtim_periods) cmd.flags |= cpu_to_le16( POWER_FLAGS_SKIP_OVER_DTIM_MSK); } } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, sizeof(cmd), &cmd); if (ret) return ret; /* configure beacon filtering */ if (mvmvif != mvm->bf_allowed_vif) return 0; if (enable) { struct iwl_beacon_filter_cmd cmd_bf = { IWL_BF_CMD_CONFIG_D0I3, .bf_enable_beacon_filter = cpu_to_le32(1), }; ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, flags, true); } else { if (mvmvif->bf_data.bf_enabled)
static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0, sizeof(cmd), &cmd); }
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable, u32 flags) { int ret; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; if (!vif->bss_conf.assoc) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { /* configure skip over dtim up to 300 msec */ int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; int dtimper_msec = dtimper * vif->bss_conf.beacon_int; if (WARN_ON(!dtimper_msec)) return 0; cmd.skip_dtim_periods = 300 / dtimper_msec; if (cmd.skip_dtim_periods) cmd.flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, sizeof(cmd), &cmd); if (ret) return ret; /* configure beacon filtering */ if (mvmvif != mvm->bf_allowed_vif) return 0; if (enable) { struct iwl_beacon_filter_cmd cmd_bf = { IWL_BF_CMD_CONFIG_D0I3, .bf_enable_beacon_filter = cpu_to_le32(1), }; ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, flags, true); } else { if (mvmvif->bf_data.bf_enabled)
static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, char *buf, int bufsz) { struct iwl_mac_power_cmd cmd = {}; int pos = 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? 0 : 1); pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", iwlmvm_mod_params.power_scheme); pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", le16_to_cpu(cmd.flags)); 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); } } return pos; }