1 /* 2 * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: offload lmac interface APIs definitions for scan 21 */ 22 23 #include <qdf_mem.h> 24 #include <qdf_status.h> 25 #include <target_if_scan.h> 26 #include <wmi_unified_priv.h> 27 #include <wmi_unified_param.h> 28 #include <wlan_objmgr_psoc_obj.h> 29 #include <wlan_scan_tgt_api.h> 30 #include <target_if.h> 31 32 33 static inline struct wlan_lmac_if_scan_rx_ops * 34 target_if_scan_get_rx_ops(struct wlan_objmgr_psoc *psoc) 35 { 36 return &psoc->soc_cb.rx_ops.scan; 37 } 38 39 static int 40 target_if_scan_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) 41 { 42 struct scan_event_info *event_info; 43 struct wlan_objmgr_psoc *psoc; 44 struct wmi_unified *wmi_handle; 45 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 46 QDF_STATUS status; 47 48 if (!scn || !data) { 49 target_if_err("scn: 0x%pK, data: 0x%pK\n", scn, data); 50 return -EINVAL; 51 } 52 psoc = target_if_get_psoc_from_scn_hdl(scn); 53 if (!psoc) { 54 target_if_err("null psoc\n"); 55 return -EINVAL; 56 } 57 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 58 59 if (!wmi_handle) { 60 target_if_err("wmi_handle is NULL"); 61 return -EINVAL; 62 } 63 64 event_info = qdf_mem_malloc(sizeof(*event_info)); 65 66 if (!event_info) { 67 target_if_err("unable to allocate scan_event"); 68 return -ENOMEM; 69 } 70 71 if (wmi_extract_vdev_scan_ev_param(wmi_handle, data, 72 &(event_info->event))) { 73 target_if_err("Failed to extract wmi scan event"); 74 qdf_mem_free(event_info); 75 return -EINVAL; 76 } 77 78 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 79 if (scan_rx_ops->scan_ev_handler) { 80 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 81 if (status != QDF_STATUS_SUCCESS) { 82 qdf_mem_free(event_info); 83 return -EINVAL; 84 } 85 } else { 86 qdf_mem_free(event_info); 87 return -EINVAL; 88 } 89 90 return 0; 91 } 92 93 #ifdef FEATURE_WLAN_SCAN_PNO 94 95 int target_if_nlo_complete_handler(ol_scn_t scn, uint8_t *data, 96 uint32_t len) 97 { 98 wmi_nlo_event *nlo_event; 99 struct scan_event_info *event_info; 100 struct wlan_objmgr_psoc *psoc; 101 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 102 WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = 103 (WMI_NLO_MATCH_EVENTID_param_tlvs *) data; 104 QDF_STATUS status; 105 106 if (!scn || !data) { 107 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 108 return -EINVAL; 109 } 110 111 psoc = target_if_get_psoc_from_scn_hdl(scn); 112 if (!psoc) { 113 target_if_err("null psoc"); 114 return -EINVAL; 115 } 116 117 event_info = qdf_mem_malloc(sizeof(*event_info)); 118 if (!event_info) { 119 target_if_err("unable to allocate scan_event"); 120 return -ENOMEM; 121 } 122 123 nlo_event = param_buf->fixed_param; 124 target_if_debug("PNO complete event received for vdev %d", 125 nlo_event->vdev_id); 126 127 event_info->event.type = SCAN_EVENT_TYPE_NLO_COMPLETE; 128 event_info->event.vdev_id = nlo_event->vdev_id; 129 130 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 131 if (scan_rx_ops->scan_ev_handler) { 132 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 133 if (status != QDF_STATUS_SUCCESS) { 134 qdf_mem_free(event_info); 135 return -EINVAL; 136 } 137 } else { 138 qdf_mem_free(event_info); 139 return -EINVAL; 140 } 141 142 return 0; 143 } 144 145 int target_if_nlo_match_event_handler(ol_scn_t scn, uint8_t *data, 146 uint32_t len) 147 { 148 wmi_nlo_event *nlo_event; 149 struct scan_event_info *event_info; 150 struct wlan_objmgr_psoc *psoc; 151 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 152 WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = 153 (WMI_NLO_MATCH_EVENTID_param_tlvs *) data; 154 QDF_STATUS status; 155 156 if (!scn || !data) { 157 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 158 return -EINVAL; 159 } 160 161 psoc = target_if_get_psoc_from_scn_hdl(scn); 162 if (!psoc) { 163 target_if_err("null psoc"); 164 return -EINVAL; 165 } 166 167 event_info = qdf_mem_malloc(sizeof(*event_info)); 168 if (!event_info) { 169 target_if_err("unable to allocate scan_event"); 170 return -ENOMEM; 171 } 172 173 nlo_event = param_buf->fixed_param; 174 target_if_debug("PNO match event received for vdev %d", 175 nlo_event->vdev_id); 176 177 event_info->event.type = SCAN_EVENT_TYPE_NLO_MATCH; 178 event_info->event.vdev_id = nlo_event->vdev_id; 179 180 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 181 if (scan_rx_ops->scan_ev_handler) { 182 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 183 if (status != QDF_STATUS_SUCCESS) { 184 qdf_mem_free(event_info); 185 return -EINVAL; 186 } 187 } else { 188 qdf_mem_free(event_info); 189 return -EINVAL; 190 } 191 192 return 0; 193 } 194 195 static QDF_STATUS 196 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 197 void *arg) 198 { 199 QDF_STATUS status; 200 struct wmi_unified *wmi_handle; 201 202 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 203 if (!wmi_handle) { 204 target_if_err("Invalid WMI handle"); 205 return QDF_STATUS_E_FAILURE; 206 } 207 208 status = wmi_unified_register_event( 209 wmi_handle, 210 wmi_nlo_match_event_id, 211 target_if_nlo_match_event_handler); 212 if (status) { 213 target_if_err("Failed to register nlo match event cb"); 214 return QDF_STATUS_E_FAILURE; 215 } 216 217 status = wmi_unified_register_event( 218 wmi_handle, 219 wmi_nlo_scan_complete_event_id, 220 target_if_nlo_complete_handler); 221 if (status) { 222 target_if_err("Failed to register nlo scan comp event cb"); 223 return QDF_STATUS_E_FAILURE; 224 } 225 226 return QDF_STATUS_SUCCESS; 227 } 228 229 static QDF_STATUS 230 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 231 void *arg) 232 { 233 QDF_STATUS status; 234 struct wmi_unified *wmi_handle; 235 236 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 237 if (!wmi_handle) { 238 target_if_err("Invalid WMI handle"); 239 return QDF_STATUS_E_FAILURE; 240 } 241 242 status = wmi_unified_unregister_event( 243 wmi_handle, 244 wmi_nlo_match_event_id); 245 if (status) { 246 target_if_err("Failed to unregister nlo match event cb"); 247 return QDF_STATUS_E_FAILURE; 248 } 249 250 status = wmi_unified_unregister_event( 251 wmi_handle, 252 wmi_nlo_scan_complete_event_id); 253 if (status) { 254 target_if_err("Failed to unregister nlo scan comp event cb"); 255 return QDF_STATUS_E_FAILURE; 256 } 257 258 return QDF_STATUS_SUCCESS; 259 } 260 261 static QDF_STATUS 262 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 263 struct pno_scan_req_params *req) 264 { 265 QDF_STATUS status; 266 struct wmi_unified *wmi_handle; 267 268 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 269 if (!wmi_handle) { 270 target_if_err("Invalid WMI handle"); 271 return QDF_STATUS_E_FAILURE; 272 } 273 274 status = wmi_unified_pno_start_cmd(wmi_handle, req); 275 if (status == QDF_STATUS_SUCCESS) { 276 if (req->mawc_params.enable) 277 status = wmi_unified_nlo_mawc_cmd(wmi_handle, 278 &req->mawc_params); 279 } 280 281 return status; 282 } 283 284 static QDF_STATUS 285 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 286 uint8_t vdev_id) 287 { 288 struct wmi_unified *wmi_handle; 289 290 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 291 if (!wmi_handle) { 292 target_if_err("Invalid WMI handle"); 293 return QDF_STATUS_E_FAILURE; 294 } 295 296 return wmi_unified_pno_stop_cmd(wmi_handle, vdev_id); 297 } 298 299 #else 300 301 static inline QDF_STATUS 302 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 303 void *arg) 304 { 305 return QDF_STATUS_SUCCESS; 306 } 307 308 static inline QDF_STATUS 309 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 310 void *arg) 311 { 312 return QDF_STATUS_SUCCESS; 313 } 314 315 static inline QDF_STATUS 316 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 317 struct pno_scan_req_params *req) 318 { 319 return QDF_STATUS_SUCCESS; 320 } 321 322 static inline QDF_STATUS 323 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 324 uint8_t vdev_id) 325 { 326 return QDF_STATUS_SUCCESS; 327 } 328 #endif 329 330 331 QDF_STATUS 332 target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg) 333 { 334 QDF_STATUS status; 335 struct wmi_unified *wmi_handle; 336 337 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 338 if (!wmi_handle) { 339 target_if_err("Invalid WMI handle"); 340 return QDF_STATUS_E_FAILURE; 341 } 342 343 status = wmi_unified_register_event( 344 wmi_handle, 345 wmi_scan_event_id, 346 target_if_scan_event_handler); 347 if (status) { 348 target_if_err("Failed to register Scan match event cb"); 349 return QDF_STATUS_E_FAILURE; 350 } 351 352 status = target_if_scan_register_pno_event_handler(psoc, arg); 353 354 return status; 355 } 356 357 QDF_STATUS 358 target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc, 359 void *arg) 360 { 361 QDF_STATUS status; 362 struct wmi_unified *wmi_handle; 363 364 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 365 if (!wmi_handle) { 366 target_if_err("Invalid WMI handle"); 367 return QDF_STATUS_E_FAILURE; 368 } 369 370 status = wmi_unified_unregister_event( 371 wmi_handle, 372 wmi_scan_event_id); 373 if (status) { 374 target_if_err("Failed to unregister Scan match event cb"); 375 return QDF_STATUS_E_FAILURE; 376 } 377 378 status = target_if_scan_unregister_pno_event_handler(psoc, arg); 379 380 return status; 381 } 382 383 QDF_STATUS 384 target_if_scan_start(struct wlan_objmgr_pdev *pdev, 385 struct scan_start_request *req) 386 { 387 void *pdev_wmi_handle; 388 389 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 390 if (!pdev_wmi_handle) { 391 target_if_err("Invalid PDEV WMI handle"); 392 return QDF_STATUS_E_FAILURE; 393 } 394 return wmi_unified_scan_start_cmd_send(pdev_wmi_handle, &req->scan_req); 395 } 396 397 QDF_STATUS 398 target_if_scan_cancel(struct wlan_objmgr_pdev *pdev, 399 struct scan_cancel_param *req) 400 { 401 void *pdev_wmi_handle; 402 403 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 404 if (!pdev_wmi_handle) { 405 target_if_err("Invalid PDEV WMI handle"); 406 return QDF_STATUS_E_NULL_VALUE; 407 } 408 return wmi_unified_scan_stop_cmd_send(pdev_wmi_handle, req); 409 } 410 411 QDF_STATUS 412 target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) 413 { 414 struct wlan_lmac_if_scan_tx_ops *scan; 415 416 scan = &tx_ops->scan; 417 if (!scan) { 418 target_if_err("Scan txops NULL"); 419 return QDF_STATUS_E_FAILURE; 420 } 421 422 scan->scan_start = target_if_scan_start; 423 scan->scan_cancel = target_if_scan_cancel; 424 scan->pno_start = target_if_pno_start; 425 scan->pno_stop = target_if_pno_stop; 426 scan->scan_reg_ev_handler = target_if_scan_register_event_handler; 427 scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler; 428 429 return QDF_STATUS_SUCCESS; 430 } 431 432 QDF_STATUS 433 target_if_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc, 434 uint32_t max_active_scans) 435 { 436 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 437 QDF_STATUS status; 438 439 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 440 if (scan_rx_ops->scan_set_max_active_scans) { 441 status = scan_rx_ops->scan_set_max_active_scans(psoc, 442 max_active_scans); 443 } else { 444 target_if_err("scan_set_max_active_scans uninitialized"); 445 status = QDF_STATUS_E_FAULT; 446 } 447 448 return status; 449 } 450