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