1 /*
2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: offload lmac interface APIs definitions for Green ap
22 */
23
24 #include <target_if_green_ap.h>
25 #include <wlan_green_ap_api.h>
26 #include <../../core/src/wlan_green_ap_main_i.h>
27 #include <target_if.h>
28 #include <wmi_unified_api.h>
29
30 #ifdef WLAN_SUPPORT_GAP_LL_PS_MODE
31 /**
32 * target_if_green_ap_ll_ps_cmd() - Green AP low latency power save mode
33 * cmd api
34 * @vdev: vdev object
35 * @ll_ps_params: low latency power save command parameter
36 *
37 * Return: QDF_STATUS_SUCCESS for success, otherwise appropriate failure reason
38 */
39 static QDF_STATUS
target_if_green_ap_ll_ps_cmd(struct wlan_objmgr_vdev * vdev,struct green_ap_ll_ps_cmd_param * ll_ps_params)40 target_if_green_ap_ll_ps_cmd(struct wlan_objmgr_vdev *vdev,
41 struct green_ap_ll_ps_cmd_param *ll_ps_params)
42 {
43 struct wlan_objmgr_pdev *pdev;
44 wmi_unified_t wmi_hdl;
45
46 pdev = wlan_vdev_get_pdev(vdev);
47 if (!pdev) {
48 green_ap_err("pdev context passed is NULL");
49 return QDF_STATUS_E_INVAL;
50 }
51
52 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
53 if (!wmi_hdl) {
54 green_ap_err("null wmi_hdl");
55 return QDF_STATUS_E_FAILURE;
56 }
57
58 return wmi_unified_green_ap_ll_ps_send(wmi_hdl, ll_ps_params);
59 }
60
target_if_register_ll_ps_tx_ops(struct wlan_lmac_if_green_ap_tx_ops * tx_ops)61 static inline void target_if_register_ll_ps_tx_ops(
62 struct wlan_lmac_if_green_ap_tx_ops *tx_ops)
63 {
64 tx_ops->ll_ps = target_if_green_ap_ll_ps_cmd;
65 }
66 #else
target_if_register_ll_ps_tx_ops(struct wlan_lmac_if_green_ap_tx_ops * tx_ops)67 static inline void target_if_register_ll_ps_tx_ops(
68 struct wlan_lmac_if_green_ap_tx_ops *tx_ops)
69 {
70 }
71 #endif
72
target_if_register_green_ap_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)73 QDF_STATUS target_if_register_green_ap_tx_ops(
74 struct wlan_lmac_if_tx_ops *tx_ops)
75 {
76 struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops;
77
78 if (!tx_ops) {
79 target_if_err("invalid tx_ops");
80 return QDF_STATUS_E_FAILURE;
81 }
82
83 green_ap_tx_ops = &tx_ops->green_ap_tx_ops;
84
85 green_ap_tx_ops->enable_egap = target_if_green_ap_enable_egap;
86 green_ap_tx_ops->ps_on_off_send = target_if_green_ap_set_ps_on_off;
87 green_ap_tx_ops->reset_dev = NULL;
88 green_ap_tx_ops->get_current_channel = NULL;
89 green_ap_tx_ops->get_current_channel_flags = NULL;
90 green_ap_tx_ops->get_capab = NULL;
91
92 target_if_register_ll_ps_tx_ops(green_ap_tx_ops);
93
94 return QDF_STATUS_SUCCESS;
95 }
96
97 #ifdef WLAN_SUPPORT_GAP_LL_PS_MODE
98 /**
99 * target_if_green_ap_ll_ps_event() - Green AP low latency
100 * Power save event handler
101 * @scn: pointer to scn handle
102 * @evt_buf: pointer to event buffer
103 * @data_len: data len of the event buffer
104 *
105 * Return: 0 for success, otherwise appropriate error code
106 */
target_if_green_ap_ll_ps_event(ol_scn_t scn,uint8_t * evt_buf,uint32_t data_len)107 static int target_if_green_ap_ll_ps_event(ol_scn_t scn, uint8_t *evt_buf,
108 uint32_t data_len)
109 {
110 QDF_STATUS status;
111 int err = 0;
112 struct wlan_objmgr_pdev *pdev;
113 struct wlan_green_ap_ll_ps_event_param *ll_ps_param;
114 void *wmi_hdl;
115 struct wlan_objmgr_psoc *psoc;
116 struct wlan_pdev_green_ap_ctx *green_ap_ctx;
117
118 psoc = target_if_get_psoc_from_scn_hdl(scn);
119 if (!psoc) {
120 green_ap_err("psoc is null");
121 return -ENOMEM;
122 }
123
124 pdev = target_if_get_pdev_from_scn_hdl(scn);
125 if (!pdev) {
126 green_ap_err("pdev is null");
127 return -ENOMEM;
128 }
129
130 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
131 pdev, WLAN_UMAC_COMP_GREEN_AP);
132 if (!green_ap_ctx) {
133 green_ap_err("green_ap_ctx not found");
134 return -ENOMEM;
135 }
136
137 ll_ps_param = qdf_mem_malloc(sizeof(*ll_ps_param));
138 if (!ll_ps_param) {
139 green_ap_err("Unable to allocate memory");
140 return -ENOMEM;
141 }
142
143 qdf_mem_zero(ll_ps_param, sizeof(*ll_ps_param));
144
145 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
146 if (!wmi_hdl) {
147 green_ap_err("null wmi_hdl");
148 err = -EINVAL;
149 goto free_event_param;
150 }
151
152 if (wmi_unified_extract_green_ap_ll_ps_param(wmi_hdl,
153 evt_buf,
154 ll_ps_param)) {
155 green_ap_err("unable to extract green ap ll ps event params");
156 err = -EINVAL;
157 goto free_event_param;
158 }
159
160 if ((ll_ps_param->dialog_token % 2))
161 ll_ps_param->bcn_mult = green_ap_ctx->bcn_mult;
162 else
163 ll_ps_param->bcn_mult = 1;
164
165 green_ap_debug("Next TSF: %llu Dialog Token: %u bcn_mult: %u",
166 ll_ps_param->next_tsf,
167 ll_ps_param->dialog_token,
168 ll_ps_param->bcn_mult);
169
170 status = wlan_green_ap_send_ll_ps_event_params(pdev,
171 ll_ps_param);
172 if (status != QDF_STATUS_SUCCESS) {
173 wmi_err("wlan_green_ap_send_ll_ps_event failed");
174 err = -EINVAL;
175 goto free_event_param;
176 }
177
178 free_event_param:
179 qdf_mem_free(ll_ps_param);
180 return err;
181 }
182
target_if_green_ap_register_ll_ps_event_handler(struct wlan_objmgr_pdev * pdev)183 QDF_STATUS target_if_green_ap_register_ll_ps_event_handler(
184 struct wlan_objmgr_pdev *pdev)
185 {
186 struct wlan_pdev_green_ap_ctx *green_ap_ctx;
187 QDF_STATUS ret;
188 wmi_unified_t wmi_hdl;
189
190 if (!pdev) {
191 green_ap_err("pdev is null");
192 return QDF_STATUS_E_INVAL;
193 }
194
195 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
196 if (!wmi_hdl) {
197 green_ap_err("null wmi_hdl");
198 return QDF_STATUS_E_FAILURE;
199 }
200
201 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
202 pdev, WLAN_UMAC_COMP_GREEN_AP);
203 if (!green_ap_ctx) {
204 green_ap_err("green ap context obtained is NULL");
205 return QDF_STATUS_E_FAILURE;
206 }
207
208 ret = wmi_unified_register_event_handler(
209 wmi_hdl,
210 wmi_xgap_enable_complete_eventid,
211 target_if_green_ap_ll_ps_event,
212 WMI_RX_UMAC_CTX);
213
214 if (QDF_IS_STATUS_ERROR(ret))
215 green_ap_err("Failed to register Enhance Green AP event");
216 else
217 green_ap_debug("Set the Enhance Green AP event handler");
218
219 return QDF_STATUS_SUCCESS;
220 }
221 #endif
222
223 /**
224 * target_if_green_ap_egap_status_info_event() - egap status info event
225 * @scn: pointer to scn handle
226 * @evt_buf: pointer to event buffer
227 * @data_len: data len of the event buffer
228 *
229 * Return: 0 for success, otherwise appropriate error code
230 */
target_if_green_ap_egap_status_info_event(ol_scn_t scn,uint8_t * evt_buf,uint32_t data_len)231 static int target_if_green_ap_egap_status_info_event(
232 ol_scn_t scn, uint8_t *evt_buf, uint32_t data_len)
233 {
234 struct wlan_objmgr_pdev *pdev;
235 struct wlan_green_ap_egap_status_info egap_status_info_params;
236 void *wmi_hdl;
237
238 pdev = target_if_get_pdev_from_scn_hdl(scn);
239 if (!pdev) {
240 green_ap_err("pdev is null");
241 return QDF_STATUS_E_FAILURE;
242 }
243
244 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
245 if (!wmi_hdl) {
246 green_ap_err("null wmi_hdl");
247 return QDF_STATUS_E_FAILURE;
248 }
249
250 if (wmi_extract_green_ap_egap_status_info(wmi_hdl,
251 evt_buf,
252 &egap_status_info_params) !=
253 QDF_STATUS_SUCCESS) {
254 green_ap_err("unable to extract green ap egap status info");
255 return QDF_STATUS_E_FAILURE;
256 }
257
258 green_ap_debug("mac_id: %d, status: %d, tx_mask: %x, rx_mask: %d",
259 egap_status_info_params.mac_id,
260 egap_status_info_params.status,
261 egap_status_info_params.tx_chainmask,
262 egap_status_info_params.rx_chainmask);
263
264 return 0;
265 }
266
target_if_green_ap_register_egap_event_handler(struct wlan_objmgr_pdev * pdev)267 QDF_STATUS target_if_green_ap_register_egap_event_handler(
268 struct wlan_objmgr_pdev *pdev)
269 {
270 struct wlan_pdev_green_ap_ctx *green_ap_ctx;
271 struct wlan_green_ap_egap_params *egap_params;
272 QDF_STATUS ret;
273 wmi_unified_t wmi_hdl;
274
275 if (!pdev) {
276 green_ap_err("pdev is null");
277 return QDF_STATUS_E_INVAL;
278 }
279
280 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
281 if (!wmi_hdl) {
282 green_ap_err("null wmi_hdl");
283 return QDF_STATUS_E_FAILURE;
284 }
285
286 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
287 pdev, WLAN_UMAC_COMP_GREEN_AP);
288 if (!green_ap_ctx) {
289 green_ap_err("green ap context obtained is NULL");
290 return QDF_STATUS_E_FAILURE;
291 }
292 egap_params = &green_ap_ctx->egap_params;
293
294 ret = wmi_unified_register_event_handler(
295 wmi_hdl,
296 wmi_ap_ps_egap_info_event_id,
297 target_if_green_ap_egap_status_info_event,
298 WMI_RX_UMAC_CTX);
299 if (QDF_IS_STATUS_ERROR(ret)) {
300 green_ap_err("Failed to register Enhance Green AP event");
301 egap_params->fw_egap_support = false;
302 } else {
303 green_ap_info("Set the Enhance Green AP event handler");
304 egap_params->fw_egap_support = true;
305 }
306
307 return QDF_STATUS_SUCCESS;
308 }
309
target_if_green_ap_enable_egap(struct wlan_objmgr_pdev * pdev,struct wlan_green_ap_egap_params * egap_params)310 QDF_STATUS target_if_green_ap_enable_egap(
311 struct wlan_objmgr_pdev *pdev,
312 struct wlan_green_ap_egap_params *egap_params)
313 {
314 struct wlan_pdev_green_ap_ctx *green_ap_ctx;
315 wmi_unified_t wmi_hdl;
316
317 if (!pdev) {
318 green_ap_err("pdev context passed is NULL");
319 return QDF_STATUS_E_INVAL;
320 }
321
322 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
323 if (!wmi_hdl) {
324 green_ap_err("null wmi_hdl");
325 return QDF_STATUS_E_FAILURE;
326 }
327
328 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
329 pdev, WLAN_UMAC_COMP_GREEN_AP);
330 if (!green_ap_ctx) {
331 green_ap_err("green ap context obtained is NULL");
332 return QDF_STATUS_E_FAILURE;
333 }
334
335 qdf_spin_lock_bh(&green_ap_ctx->lock);
336 if (!wlan_is_egap_enabled(green_ap_ctx)) {
337 green_ap_info("enhanced green ap support is not present");
338 qdf_spin_unlock_bh(&green_ap_ctx->lock);
339 return QDF_STATUS_SUCCESS;
340 }
341 qdf_spin_unlock_bh(&green_ap_ctx->lock);
342
343 return wmi_unified_egap_conf_params_cmd(wmi_hdl,
344 egap_params);
345 }
346
target_if_green_ap_set_ps_on_off(struct wlan_objmgr_pdev * pdev,bool value,uint8_t pdev_id)347 QDF_STATUS target_if_green_ap_set_ps_on_off(struct wlan_objmgr_pdev *pdev,
348 bool value, uint8_t pdev_id)
349 {
350 wmi_unified_t wmi_hdl;
351
352 if (!pdev) {
353 green_ap_err("pdev context passed is NULL");
354 return QDF_STATUS_E_INVAL;
355 }
356
357 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
358 if (!wmi_hdl) {
359 green_ap_err("null wmi_hdl");
360 return QDF_STATUS_E_FAILURE;
361 }
362
363 return wmi_unified_green_ap_ps_send(wmi_hdl,
364 value, pdev_id);
365 }
366