wifi: ath12k: enable 802.11 power save mode in station mode
authorBaochen Qiang <quic_bqiang@quicinc.com>
Thu, 1 Feb 2024 03:58:30 +0000 (11:58 +0800)
committerKalle Valo <quic_kvalo@quicinc.com>
Mon, 5 Feb 2024 16:59:48 +0000 (18:59 +0200)
To reduce power consumption enable 802.11 power save mode in
station mode. This allows both radio and CPU to sleep more.

Only enable the mode on WCN7850, other chips don't support it
for now.

To test that power save mode is running, run below command and
check there is no NULL Data frame seen by a sniffer:
        iw dev <inf> set power_save off

And run below command, then check there is a NULL Data frame
in sniffer:
        iw dev <inf> set power_save on

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240201035830.2534-1-quic_bqiang@quicinc.com
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/hw.c
drivers/net/wireless/ath/ath12k/hw.h
drivers/net/wireless/ath/ath12k/mac.c

index a984171e4a087ac0f800eb84e94bd8a097de824f..97e5a0ccd2338f018b7e9a2aa485666db0a36e57 100644 (file)
@@ -266,6 +266,7 @@ struct ath12k_vif {
        u8 tx_encap_type;
        u8 vdev_stats_id;
        u32 punct_bitmap;
+       bool ps;
 };
 
 struct ath12k_vif_iter {
index a9adb547c83d25a6b6c0494851e9d9ba4d67617c..6e2242a79a2f17554caa9e1b4b4fb457099041fd 100644 (file)
@@ -918,6 +918,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .max_mlo_peer = 256,
 
                .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
+
+               .supports_sta_ps = false,
        },
        {
                .name = "wcn7850 hw2.0",
@@ -986,6 +988,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .max_mlo_peer = 32,
 
                .otp_board_id_register = 0,
+
+               .supports_sta_ps = true,
        },
        {
                .name = "qcn9274 hw2.0",
@@ -1052,6 +1056,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .max_mlo_peer = 256,
 
                .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
+
+               .supports_sta_ps = false,
        },
 };
 
index 2e9c3b05d75ac53d8e803c9845c582d21b8ced28..87965980b938c5867c562cbe0c6512fa4ccb912a 100644 (file)
@@ -209,6 +209,8 @@ struct ath12k_hw_params {
        u16 max_mlo_peer;
 
        u32 otp_board_id_register;
+
+       bool supports_sta_ps;
 };
 
 struct ath12k_hw_ops {
index 6ef55876e7dfae80dffa9ef569160f62c30c1e32..fb5bf500ed8726647b1991bc09c1a12ecc108624 100644 (file)
@@ -2510,12 +2510,60 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
        return ret;
 }
 
+static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
+{
+       struct ath12k *ar = arvif->ar;
+       struct ieee80211_vif *vif = arvif->vif;
+       struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf;
+       enum wmi_sta_powersave_param param;
+       enum wmi_sta_ps_mode psmode;
+       int ret;
+       int timeout;
+       bool enable_ps;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       enable_ps = arvif->ps;
+       if (enable_ps) {
+               psmode = WMI_STA_PS_MODE_ENABLED;
+               param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
+
+               timeout = conf->dynamic_ps_timeout;
+               if (timeout == 0) {
+                       /* firmware doesn't like 0 */
+                       timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000;
+               }
+
+               ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
+                                                 timeout);
+               if (ret) {
+                       ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n",
+                                   arvif->vdev_id, ret);
+                       return;
+               }
+       } else {
+               psmode = WMI_STA_PS_MODE_DISABLED;
+       }
+
+       ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n",
+                  arvif->vdev_id, psmode ? "enable" : "disable");
+
+       ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode);
+       if (ret)
+               ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n",
+                           psmode, arvif->vdev_id, ret);
+}
+
 static void ath12k_mac_bss_info_changed(struct ath12k *ar,
                                        struct ath12k_vif *arvif,
                                        struct ieee80211_bss_conf *info,
                                        u64 changed)
 {
        struct ieee80211_vif *vif = arvif->vif;
+       struct ieee80211_vif_cfg *vif_cfg = &vif->cfg;
        struct cfg80211_chan_def def;
        u32 param_id, param_value;
        enum nl80211_band band;
@@ -2788,6 +2836,12 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
 
        if (changed & BSS_CHANGED_EHT_PUNCTURING)
                arvif->punct_bitmap = info->eht_puncturing;
+
+       if (changed & BSS_CHANGED_PS &&
+           ar->ab->hw_params->supports_sta_ps) {
+               arvif->ps = vif_cfg->ps;
+               ath12k_mac_vif_setup_ps(arvif);
+       }
 }
 
 static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,