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 P2P 22 */ 23 24 #include <wmi_unified_api.h> 25 #include <wlan_p2p_public_struct.h> 26 #include "target_if.h" 27 #include "target_if_p2p.h" 28 #include "target_if_p2p_mcc_quota.h" 29 #include "init_deinit_lmac.h" 30 31 static inline struct wlan_lmac_if_p2p_rx_ops * target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc * psoc)32 target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc *psoc) 33 { 34 return &(psoc->soc_cb.rx_ops->p2p); 35 } 36 37 #ifdef FEATURE_P2P_LISTEN_OFFLOAD 38 static inline void target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops * p2p_tx_ops)39 target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops) 40 { 41 p2p_tx_ops->lo_start = target_if_p2p_lo_start; 42 p2p_tx_ops->lo_stop = target_if_p2p_lo_stop; 43 p2p_tx_ops->reg_lo_ev_handler = 44 target_if_p2p_register_lo_event_handler; 45 p2p_tx_ops->unreg_lo_ev_handler = 46 target_if_p2p_unregister_lo_event_handler; 47 } 48 49 /** 50 * target_p2p_lo_event_handler() - WMI callback for lo stop event 51 * @scn: pointer to scn 52 * @data: event buffer 53 * @datalen: buffer length 54 * 55 * This function gets called from WMI when triggered wmi event 56 * wmi_p2p_lo_stop_event_id. 57 * 58 * Return: 0 - success 59 * others - failure 60 */ target_p2p_lo_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)61 static int target_p2p_lo_event_handler(ol_scn_t scn, uint8_t *data, 62 uint32_t datalen) 63 { 64 struct wlan_objmgr_psoc *psoc; 65 struct wmi_unified *wmi_handle; 66 struct p2p_lo_event *event_info; 67 struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; 68 QDF_STATUS status = QDF_STATUS_E_FAILURE; 69 70 target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen); 71 72 if (!scn || !data) { 73 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 74 return -EINVAL; 75 } 76 77 psoc = target_if_get_psoc_from_scn_hdl(scn); 78 if (!psoc) { 79 target_if_err("null psoc"); 80 return -EINVAL; 81 } 82 83 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 84 if (!wmi_handle) { 85 target_if_err("null wmi handle"); 86 return -EINVAL; 87 } 88 89 event_info = qdf_mem_malloc(sizeof(*event_info)); 90 if (!event_info) 91 return -ENOMEM; 92 93 if (wmi_extract_p2p_lo_stop_ev_param(wmi_handle, data, 94 event_info)) { 95 target_if_err("Failed to extract wmi p2p lo stop event"); 96 qdf_mem_free(event_info); 97 return -EINVAL; 98 } 99 100 p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); 101 if (p2p_rx_ops->lo_ev_handler) { 102 status = p2p_rx_ops->lo_ev_handler(psoc, event_info); 103 target_if_debug("call lo event handler, status:%d", 104 status); 105 } else { 106 qdf_mem_free(event_info); 107 target_if_debug("no valid lo event handler"); 108 } 109 110 return qdf_status_to_os_return(status); 111 } 112 target_if_p2p_register_lo_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)113 QDF_STATUS target_if_p2p_register_lo_event_handler( 114 struct wlan_objmgr_psoc *psoc, void *arg) 115 { 116 QDF_STATUS status; 117 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 118 119 target_if_debug("psoc:%pK, arg:%pK", psoc, arg); 120 121 if (!wmi_handle) { 122 target_if_err("Invalid wmi handle"); 123 return QDF_STATUS_E_INVAL; 124 } 125 126 status = wmi_unified_register_event(wmi_handle, 127 wmi_p2p_lo_stop_event_id, 128 target_p2p_lo_event_handler); 129 130 target_if_debug("wmi register lo event handle, status:%d", status); 131 132 if (QDF_IS_STATUS_ERROR(status)) 133 return QDF_STATUS_E_FAILURE; 134 else 135 return QDF_STATUS_SUCCESS; 136 } 137 target_if_p2p_unregister_lo_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)138 QDF_STATUS target_if_p2p_unregister_lo_event_handler( 139 struct wlan_objmgr_psoc *psoc, void *arg) 140 { 141 QDF_STATUS status; 142 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 143 144 target_if_debug("psoc:%pK, arg:%pK", psoc, arg); 145 146 if (!wmi_handle) { 147 target_if_err("Invalid wmi handle"); 148 return QDF_STATUS_E_INVAL; 149 } 150 151 status = wmi_unified_unregister_event(wmi_handle, 152 wmi_p2p_lo_stop_event_id); 153 154 target_if_debug("wmi unregister lo event handle, status:%d", status); 155 156 if (QDF_IS_STATUS_ERROR(status)) 157 return QDF_STATUS_E_FAILURE; 158 else 159 return QDF_STATUS_SUCCESS; 160 } 161 target_if_p2p_lo_start(struct wlan_objmgr_psoc * psoc,struct p2p_lo_start * lo_start)162 QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc, 163 struct p2p_lo_start *lo_start) 164 { 165 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 166 167 if (!wmi_handle) { 168 target_if_err("Invalid wmi handle"); 169 return QDF_STATUS_E_INVAL; 170 } 171 172 if (!lo_start) { 173 target_if_err("lo start parameters is null"); 174 return QDF_STATUS_E_INVAL; 175 } 176 target_if_debug("psoc:%pK, vdev_id:%d", psoc, lo_start->vdev_id); 177 178 return wmi_unified_p2p_lo_start_cmd(wmi_handle, lo_start); 179 } 180 target_if_p2p_lo_stop(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id)181 QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc, 182 uint32_t vdev_id) 183 { 184 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 185 186 target_if_debug("psoc:%pK, vdev_id:%d", psoc, vdev_id); 187 188 if (!wmi_handle) { 189 target_if_err("Invalid wmi handle"); 190 return QDF_STATUS_E_INVAL; 191 } 192 193 return wmi_unified_p2p_lo_stop_cmd(wmi_handle, 194 (uint8_t)vdev_id); 195 } 196 #else 197 static inline void target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops * p2p_tx_ops)198 target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops) 199 { 200 } 201 #endif /* FEATURE_P2P_LISTEN_OFFLOAD */ 202 203 /** 204 * target_p2p_noa_event_handler() - WMI callback for noa event 205 * @scn: pointer to scn 206 * @data: event buffer 207 * @datalen: buffer length 208 * 209 * This function gets called from WMI when triggered WMI event 210 * wmi_p2p_noa_event_id. 211 * 212 * Return: 0 - success 213 * others - failure 214 */ target_p2p_noa_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)215 static int target_p2p_noa_event_handler(ol_scn_t scn, uint8_t *data, 216 uint32_t datalen) 217 { 218 struct wlan_objmgr_psoc *psoc; 219 struct wmi_unified *wmi_handle; 220 struct p2p_noa_info *event_info; 221 struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; 222 QDF_STATUS status = QDF_STATUS_E_FAILURE; 223 224 target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen); 225 226 if (!scn || !data) { 227 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 228 return -EINVAL; 229 } 230 231 psoc = target_if_get_psoc_from_scn_hdl(scn); 232 if (!psoc) { 233 target_if_err("null psoc"); 234 return -EINVAL; 235 } 236 237 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 238 if (!wmi_handle) { 239 target_if_err("null wmi handle"); 240 return -EINVAL; 241 } 242 243 event_info = qdf_mem_malloc(sizeof(*event_info)); 244 if (!event_info) 245 return -ENOMEM; 246 247 if (wmi_extract_p2p_noa_ev_param(wmi_handle, data, 248 event_info)) { 249 target_if_err("failed to extract wmi p2p noa event"); 250 qdf_mem_free(event_info); 251 return -EINVAL; 252 } 253 254 p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); 255 if (p2p_rx_ops->noa_ev_handler) { 256 status = p2p_rx_ops->noa_ev_handler(psoc, event_info); 257 target_if_debug("call noa event handler, status:%d", 258 status); 259 } else { 260 qdf_mem_free(event_info); 261 target_if_debug("no valid noa event handler"); 262 } 263 264 return qdf_status_to_os_return(status); 265 } 266 target_if_p2p_register_noa_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)267 QDF_STATUS target_if_p2p_register_noa_event_handler( 268 struct wlan_objmgr_psoc *psoc, void *arg) 269 { 270 int status; 271 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 272 273 target_if_debug("psoc:%pK, arg:%pK", psoc, arg); 274 275 if (!wmi_handle) { 276 target_if_err("Invalid wmi handle"); 277 return QDF_STATUS_E_INVAL; 278 } 279 280 status = wmi_unified_register_event(wmi_handle, 281 wmi_p2p_noa_event_id, 282 target_p2p_noa_event_handler); 283 284 target_if_debug("wmi register noa event handle, status:%d", 285 status); 286 287 return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; 288 } 289 target_if_p2p_unregister_noa_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)290 QDF_STATUS target_if_p2p_unregister_noa_event_handler( 291 struct wlan_objmgr_psoc *psoc, void *arg) 292 { 293 QDF_STATUS status; 294 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 295 296 target_if_debug("psoc:%pK, arg:%pK", psoc, arg); 297 298 if (!wmi_handle) { 299 target_if_err("Invalid wmi handle"); 300 return QDF_STATUS_E_INVAL; 301 } 302 303 status = wmi_unified_unregister_event(wmi_handle, 304 wmi_p2p_noa_event_id); 305 306 target_if_debug("wmi unregister noa event handle, status:%d", 307 status); 308 309 if (QDF_IS_STATUS_ERROR(status)) 310 return QDF_STATUS_E_FAILURE; 311 else 312 return QDF_STATUS_SUCCESS; 313 } 314 target_if_p2p_set_ps(struct wlan_objmgr_psoc * psoc,struct p2p_ps_config * ps_config)315 QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc, 316 struct p2p_ps_config *ps_config) 317 { 318 struct p2p_ps_params cmd; 319 QDF_STATUS status; 320 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 321 322 if (!wmi_handle) { 323 target_if_err("Invalid wmi handle"); 324 return QDF_STATUS_E_INVAL; 325 } 326 327 if (!ps_config) { 328 target_if_err("ps config parameters is null"); 329 return QDF_STATUS_E_INVAL; 330 } 331 332 target_if_debug("psoc:%pK, vdev_id:%d, opp_ps:%d", psoc, 333 ps_config->vdev_id, ps_config->opp_ps); 334 335 cmd.opp_ps = ps_config->opp_ps; 336 cmd.ctwindow = ps_config->ct_window; 337 cmd.count = ps_config->count; 338 cmd.duration = ps_config->duration; 339 cmd.interval = ps_config->interval; 340 cmd.single_noa_duration = ps_config->single_noa_duration; 341 cmd.ps_selection = ps_config->ps_selection; 342 cmd.session_id = ps_config->vdev_id; 343 cmd.start = ps_config->start; 344 345 if (ps_config->opp_ps) 346 status = wmi_unified_set_p2pgo_oppps_req(wmi_handle, 347 &cmd); 348 else 349 status = wmi_unified_set_p2pgo_noa_req_cmd(wmi_handle, 350 &cmd); 351 352 if (status != QDF_STATUS_SUCCESS) 353 target_if_err("Failed to send set uapsd param, %d", 354 status); 355 356 return status; 357 } 358 target_if_p2p_set_noa(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id,bool disable_noa)359 QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, 360 uint32_t vdev_id, bool disable_noa) 361 { 362 struct vdev_set_params param; 363 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 364 365 if (!wmi_handle) { 366 target_if_err("Invalid wmi handle"); 367 return QDF_STATUS_E_INVAL; 368 } 369 370 target_if_debug("psoc:%pK, vdev_id:%d disable_noa:%d", 371 psoc, vdev_id, disable_noa); 372 param.vdev_id = vdev_id; 373 param.param_id = wmi_vdev_param_disable_noa_p2p_go; 374 param.param_value = (uint32_t)disable_noa; 375 376 return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); 377 } 378 target_p2p_mac_rx_filter_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)379 static int target_p2p_mac_rx_filter_event_handler(ol_scn_t scn, uint8_t *data, 380 uint32_t datalen) 381 { 382 struct wlan_objmgr_psoc *psoc; 383 struct wmi_unified *wmi_handle; 384 struct p2p_set_mac_filter_evt event_info; 385 struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; 386 QDF_STATUS status = QDF_STATUS_E_FAILURE; 387 388 if (!scn || !data) { 389 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 390 return -EINVAL; 391 } 392 393 psoc = target_if_get_psoc_from_scn_hdl(scn); 394 if (!psoc) { 395 target_if_err("null psoc"); 396 return -EINVAL; 397 } 398 399 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 400 if (!wmi_handle) { 401 target_if_err("null wmi handle"); 402 return -EINVAL; 403 } 404 405 if (wmi_extract_mac_addr_rx_filter_evt_param(wmi_handle, data, 406 &event_info)) { 407 target_if_err("failed to extract wmi p2p noa event"); 408 return -EINVAL; 409 } 410 target_if_debug("vdev_id %d status %d", event_info.vdev_id, 411 event_info.status); 412 p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); 413 if (p2p_rx_ops && p2p_rx_ops->add_mac_addr_filter_evt_handler) 414 status = p2p_rx_ops->add_mac_addr_filter_evt_handler( 415 psoc, &event_info); 416 else 417 target_if_debug("no add mac addr filter event handler"); 418 419 return qdf_status_to_os_return(status); 420 } 421 target_if_p2p_register_macaddr_rx_filter_evt_handler(struct wlan_objmgr_psoc * psoc,bool reg)422 static QDF_STATUS target_if_p2p_register_macaddr_rx_filter_evt_handler( 423 struct wlan_objmgr_psoc *psoc, bool reg) 424 { 425 int status; 426 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 427 428 target_if_debug("psoc:%pK, register %d mac addr rx evt", psoc, reg); 429 430 if (!wmi_handle) { 431 target_if_err("Invalid wmi handle"); 432 return QDF_STATUS_E_INVAL; 433 } 434 if (reg) 435 status = wmi_unified_register_event( 436 wmi_handle, 437 wmi_vdev_add_macaddr_rx_filter_event_id, 438 target_p2p_mac_rx_filter_event_handler); 439 else 440 status = wmi_unified_unregister_event( 441 wmi_handle, 442 wmi_vdev_add_macaddr_rx_filter_event_id); 443 444 return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; 445 } 446 target_if_p2p_set_mac_addr_rx_filter_cmd(struct wlan_objmgr_psoc * psoc,struct set_rx_mac_filter * param)447 static QDF_STATUS target_if_p2p_set_mac_addr_rx_filter_cmd( 448 struct wlan_objmgr_psoc *psoc, struct set_rx_mac_filter *param) 449 { 450 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); 451 452 if (!wmi_handle) { 453 target_if_err("Invalid wmi handle"); 454 return QDF_STATUS_E_INVAL; 455 } 456 457 return wmi_unified_set_mac_addr_rx_filter(wmi_handle, param); 458 } 459 target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)460 void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 461 { 462 struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops; 463 464 if (!tx_ops) { 465 target_if_err("lmac tx_ops is null"); 466 return; 467 } 468 469 p2p_tx_ops = &tx_ops->p2p; 470 p2p_tx_ops->set_ps = target_if_p2p_set_ps; 471 p2p_tx_ops->set_noa = target_if_p2p_set_noa; 472 p2p_tx_ops->reg_noa_ev_handler = 473 target_if_p2p_register_noa_event_handler; 474 p2p_tx_ops->unreg_noa_ev_handler = 475 target_if_p2p_unregister_noa_event_handler; 476 p2p_tx_ops->reg_mac_addr_rx_filter_handler = 477 target_if_p2p_register_macaddr_rx_filter_evt_handler; 478 p2p_tx_ops->set_mac_addr_rx_filter_cmd = 479 target_if_p2p_set_mac_addr_rx_filter_cmd; 480 target_if_mcc_quota_register_tx_ops(tx_ops); 481 482 /* register P2P listen offload callbacks */ 483 target_if_p2p_lo_register_tx_ops(p2p_tx_ops); 484 } 485