blob: 607bfa4317d926bbda3cef1c65cca6aefc1ae239 [file] [log] [blame]
Yan-Hsuan Chuange3037482019-04-26 15:17:37 +03001// 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
11static 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
25int 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
34static 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
44int 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
59static 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
72static 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
85void 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
101void 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
115void 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
129bool rtw_in_lps(struct rtw_dev *rtwdev)
130{
131 return rtw_flag_check(rtwdev, RTW_FLAG_LEISURE_PS);
132}
133
134void 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
151void 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}