1 /* 2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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 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 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 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 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 */ 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: %llu 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 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 */ 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 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 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 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