1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2018-2019 Realtek Corporation 3 */ 4 5 #include "main.h" 6 #include "fw.h" 7 #include "ps.h" 8 #include "mac.h" 9 #include "debug.h" 10 11 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) 12 { 13 int ret; 14 15 ret = rtw_core_start(rtwdev); 16 if (ret) 17 rtw_err(rtwdev, "leave idle state failed\n"); 18 19 rtw_set_channel(rtwdev); 20 rtw_flag_clear(rtwdev, RTW_FLAG_INACTIVE_PS); 21 22 return ret; 23 } 24 25 int rtw_enter_ips(struct rtw_dev *rtwdev) 26 { 27 rtw_flag_set(rtwdev, RTW_FLAG_INACTIVE_PS); 28 29 rtw_core_stop(rtwdev); 30 31 return 0; 32 } 33 34 static void rtw_restore_port_cfg_iter(void *data, u8 *mac, 35 struct ieee80211_vif *vif) 36 { 37 struct rtw_dev *rtwdev = data; 38 struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 39 u32 config = ~0; 40 41 rtw_vif_port_config(rtwdev, rtwvif, config); 42 } 43 44 int rtw_leave_ips(struct rtw_dev *rtwdev) 45 { 46 int ret; 47 48 ret = rtw_ips_pwr_up(rtwdev); 49 if (ret) { 50 rtw_err(rtwdev, "failed to leave ips state\n"); 51 return ret; 52 } 53 54 rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev); 55 56 return 0; 57 } 58 59 static void rtw_leave_lps_core(struct rtw_dev *rtwdev) 60 { 61 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 62 63 conf->state = RTW_ALL_ON; 64 conf->awake_interval = 1; 65 conf->rlbm = 0; 66 conf->smart_ps = 0; 67 68 rtw_fw_set_pwr_mode(rtwdev); 69 rtw_flag_clear(rtwdev, RTW_FLAG_LEISURE_PS); 70 } 71 72 static void rtw_enter_lps_core(struct rtw_dev *rtwdev) 73 { 74 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 75 76 conf->state = RTW_RF_OFF; 77 conf->awake_interval = 1; 78 conf->rlbm = 1; 79 conf->smart_ps = 2; 80 81 rtw_fw_set_pwr_mode(rtwdev); 82 rtw_flag_set(rtwdev, RTW_FLAG_LEISURE_PS); 83 } 84 85 void rtw_lps_work(struct work_struct *work) 86 { 87 struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, 88 lps_work.work); 89 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 90 struct rtw_vif *rtwvif = conf->rtwvif; 91 92 if (WARN_ON(!rtwvif)) 93 return; 94 95 if (conf->mode == RTW_MODE_LPS) 96 rtw_enter_lps_core(rtwdev); 97 else 98 rtw_leave_lps_core(rtwdev); 99 } 100 101 void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 102 { 103 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 104 105 if (rtwvif->in_lps) 106 return; 107 108 conf->mode = RTW_MODE_LPS; 109 conf->rtwvif = rtwvif; 110 rtwvif->in_lps = true; 111 112 ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); 113 } 114 115 void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 116 { 117 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 118 119 if (!rtwvif->in_lps) 120 return; 121 122 conf->mode = RTW_MODE_ACTIVE; 123 conf->rtwvif = rtwvif; 124 rtwvif->in_lps = false; 125 126 ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); 127 } 128 129 bool rtw_in_lps(struct rtw_dev *rtwdev) 130 { 131 return rtw_flag_check(rtwdev, RTW_FLAG_LEISURE_PS); 132 } 133 134 void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 135 { 136 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 137 138 if (WARN_ON(!rtwvif)) 139 return; 140 141 if (rtwvif->in_lps) 142 return; 143 144 conf->mode = RTW_MODE_LPS; 145 conf->rtwvif = rtwvif; 146 rtwvif->in_lps = true; 147 148 rtw_enter_lps_core(rtwdev); 149 } 150 151 void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 152 { 153 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 154 155 if (WARN_ON(!rtwvif)) 156 return; 157 158 if (!rtwvif->in_lps) 159 return; 160 161 conf->mode = RTW_MODE_ACTIVE; 162 conf->rtwvif = rtwvif; 163 rtwvif->in_lps = false; 164 165 rtw_leave_lps_core(rtwdev); 166 } 167