1 /* 2 * Copyright (c) 2017-2019 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 #ifdef FEATURE_WLAN_SCAN_PNO 32 #include "wmi.h" 33 #endif 34 35 static inline struct wlan_lmac_if_scan_rx_ops * 36 target_if_scan_get_rx_ops(struct wlan_objmgr_psoc *psoc) 37 { 38 return &psoc->soc_cb.rx_ops.scan; 39 } 40 41 static int 42 target_if_scan_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) 43 { 44 struct scan_event_info *event_info; 45 struct wlan_objmgr_psoc *psoc; 46 struct wmi_unified *wmi_handle; 47 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 48 QDF_STATUS status; 49 50 if (!scn || !data) { 51 target_if_err("scn: 0x%pK, data: 0x%pK\n", scn, data); 52 return -EINVAL; 53 } 54 psoc = target_if_get_psoc_from_scn_hdl(scn); 55 if (!psoc) { 56 target_if_err("null psoc\n"); 57 return -EINVAL; 58 } 59 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 60 61 if (!wmi_handle) { 62 target_if_err("wmi_handle is NULL"); 63 return -EINVAL; 64 } 65 66 event_info = qdf_mem_malloc(sizeof(*event_info)); 67 68 if (!event_info) 69 return -ENOMEM; 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 return -ENOMEM; 120 121 nlo_event = param_buf->fixed_param; 122 target_if_debug("PNO complete event received for vdev %d", 123 nlo_event->vdev_id); 124 125 event_info->event.type = SCAN_EVENT_TYPE_NLO_COMPLETE; 126 event_info->event.vdev_id = nlo_event->vdev_id; 127 128 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 129 if (scan_rx_ops->scan_ev_handler) { 130 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 131 if (status != QDF_STATUS_SUCCESS) { 132 qdf_mem_free(event_info); 133 return -EINVAL; 134 } 135 } else { 136 qdf_mem_free(event_info); 137 return -EINVAL; 138 } 139 140 return 0; 141 } 142 143 int target_if_nlo_match_event_handler(ol_scn_t scn, uint8_t *data, 144 uint32_t len) 145 { 146 wmi_nlo_event *nlo_event; 147 struct scan_event_info *event_info; 148 struct wlan_objmgr_psoc *psoc; 149 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 150 WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = 151 (WMI_NLO_MATCH_EVENTID_param_tlvs *) data; 152 QDF_STATUS status; 153 154 if (!scn || !data) { 155 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 156 return -EINVAL; 157 } 158 159 psoc = target_if_get_psoc_from_scn_hdl(scn); 160 if (!psoc) { 161 target_if_err("null psoc"); 162 return -EINVAL; 163 } 164 165 event_info = qdf_mem_malloc(sizeof(*event_info)); 166 if (!event_info) 167 return -ENOMEM; 168 169 nlo_event = param_buf->fixed_param; 170 target_if_debug("PNO match event received for vdev %d", 171 nlo_event->vdev_id); 172 173 event_info->event.type = SCAN_EVENT_TYPE_NLO_MATCH; 174 event_info->event.vdev_id = nlo_event->vdev_id; 175 176 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 177 if (scan_rx_ops->scan_ev_handler) { 178 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 179 if (status != QDF_STATUS_SUCCESS) { 180 qdf_mem_free(event_info); 181 return -EINVAL; 182 } 183 } else { 184 qdf_mem_free(event_info); 185 return -EINVAL; 186 } 187 188 return 0; 189 } 190 191 static QDF_STATUS 192 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 193 void *arg) 194 { 195 QDF_STATUS status; 196 struct wmi_unified *wmi_handle; 197 198 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 199 if (!wmi_handle) { 200 target_if_err("Invalid WMI handle"); 201 return QDF_STATUS_E_FAILURE; 202 } 203 204 status = wmi_unified_register_event( 205 wmi_handle, 206 wmi_nlo_match_event_id, 207 target_if_nlo_match_event_handler); 208 if (status) { 209 target_if_err("Failed to register nlo match event cb"); 210 return QDF_STATUS_E_FAILURE; 211 } 212 213 status = wmi_unified_register_event( 214 wmi_handle, 215 wmi_nlo_scan_complete_event_id, 216 target_if_nlo_complete_handler); 217 if (status) { 218 target_if_err("Failed to register nlo scan comp event cb"); 219 return QDF_STATUS_E_FAILURE; 220 } 221 222 return QDF_STATUS_SUCCESS; 223 } 224 225 static QDF_STATUS 226 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 227 void *arg) 228 { 229 QDF_STATUS status; 230 struct wmi_unified *wmi_handle; 231 232 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 233 if (!wmi_handle) { 234 target_if_err("Invalid WMI handle"); 235 return QDF_STATUS_E_FAILURE; 236 } 237 238 status = wmi_unified_unregister_event( 239 wmi_handle, 240 wmi_nlo_match_event_id); 241 if (status) { 242 target_if_err("Failed to unregister nlo match event cb"); 243 return QDF_STATUS_E_FAILURE; 244 } 245 246 status = wmi_unified_unregister_event( 247 wmi_handle, 248 wmi_nlo_scan_complete_event_id); 249 if (status) { 250 target_if_err("Failed to unregister nlo scan comp event cb"); 251 return QDF_STATUS_E_FAILURE; 252 } 253 254 return QDF_STATUS_SUCCESS; 255 } 256 257 static QDF_STATUS 258 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 259 struct pno_scan_req_params *req) 260 { 261 QDF_STATUS status; 262 struct wmi_unified *wmi_handle; 263 264 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 265 if (!wmi_handle) { 266 target_if_err("Invalid WMI handle"); 267 return QDF_STATUS_E_FAILURE; 268 } 269 270 status = wmi_unified_pno_start_cmd(wmi_handle, req); 271 if (status == QDF_STATUS_SUCCESS) { 272 if (req->mawc_params.enable) 273 status = wmi_unified_nlo_mawc_cmd(wmi_handle, 274 &req->mawc_params); 275 } 276 277 return status; 278 } 279 280 static QDF_STATUS 281 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 282 uint8_t vdev_id) 283 { 284 struct wmi_unified *wmi_handle; 285 286 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 287 if (!wmi_handle) { 288 target_if_err("Invalid WMI handle"); 289 return QDF_STATUS_E_FAILURE; 290 } 291 292 return wmi_unified_pno_stop_cmd(wmi_handle, vdev_id); 293 } 294 295 #else 296 297 static inline QDF_STATUS 298 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 299 void *arg) 300 { 301 return QDF_STATUS_SUCCESS; 302 } 303 304 static inline QDF_STATUS 305 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 306 void *arg) 307 { 308 return QDF_STATUS_SUCCESS; 309 } 310 311 static inline QDF_STATUS 312 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 313 struct pno_scan_req_params *req) 314 { 315 return QDF_STATUS_SUCCESS; 316 } 317 318 static inline QDF_STATUS 319 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 320 uint8_t vdev_id) 321 { 322 return QDF_STATUS_SUCCESS; 323 } 324 #endif 325 326 327 QDF_STATUS 328 target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg) 329 { 330 QDF_STATUS status; 331 struct wmi_unified *wmi_handle; 332 333 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 334 if (!wmi_handle) { 335 target_if_err("Invalid WMI handle"); 336 return QDF_STATUS_E_FAILURE; 337 } 338 339 status = wmi_unified_register_event( 340 wmi_handle, 341 wmi_scan_event_id, 342 target_if_scan_event_handler); 343 if (status) { 344 target_if_err("Failed to register Scan match event cb"); 345 return QDF_STATUS_E_FAILURE; 346 } 347 348 status = target_if_scan_register_pno_event_handler(psoc, arg); 349 350 return status; 351 } 352 353 QDF_STATUS 354 target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc, 355 void *arg) 356 { 357 QDF_STATUS status; 358 struct wmi_unified *wmi_handle; 359 360 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 361 if (!wmi_handle) { 362 target_if_err("Invalid WMI handle"); 363 return QDF_STATUS_E_FAILURE; 364 } 365 366 status = wmi_unified_unregister_event( 367 wmi_handle, 368 wmi_scan_event_id); 369 if (status) { 370 target_if_err("Failed to unregister Scan match event cb"); 371 return QDF_STATUS_E_FAILURE; 372 } 373 374 status = target_if_scan_unregister_pno_event_handler(psoc, arg); 375 376 return status; 377 } 378 379 QDF_STATUS 380 target_if_scan_start(struct wlan_objmgr_pdev *pdev, 381 struct scan_start_request *req) 382 { 383 wmi_unified_t pdev_wmi_handle; 384 385 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 386 if (!pdev_wmi_handle) { 387 target_if_err("Invalid PDEV WMI handle"); 388 return QDF_STATUS_E_FAILURE; 389 } 390 return wmi_unified_scan_start_cmd_send(pdev_wmi_handle, &req->scan_req); 391 } 392 393 QDF_STATUS 394 target_if_scan_cancel(struct wlan_objmgr_pdev *pdev, 395 struct scan_cancel_param *req) 396 { 397 wmi_unified_t pdev_wmi_handle; 398 399 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 400 if (!pdev_wmi_handle) { 401 target_if_err("Invalid PDEV WMI handle"); 402 return QDF_STATUS_E_NULL_VALUE; 403 } 404 return wmi_unified_scan_stop_cmd_send(pdev_wmi_handle, req); 405 } 406 407 QDF_STATUS 408 target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) 409 { 410 struct wlan_lmac_if_scan_tx_ops *scan; 411 412 scan = &tx_ops->scan; 413 if (!scan) { 414 target_if_err("Scan txops NULL"); 415 return QDF_STATUS_E_FAILURE; 416 } 417 418 scan->scan_start = target_if_scan_start; 419 scan->scan_cancel = target_if_scan_cancel; 420 scan->pno_start = target_if_pno_start; 421 scan->pno_stop = target_if_pno_stop; 422 scan->scan_reg_ev_handler = target_if_scan_register_event_handler; 423 scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler; 424 425 return QDF_STATUS_SUCCESS; 426 } 427 428 QDF_STATUS 429 target_if_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc, 430 uint32_t max_active_scans) 431 { 432 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 433 QDF_STATUS status; 434 435 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 436 if (scan_rx_ops->scan_set_max_active_scans) { 437 status = scan_rx_ops->scan_set_max_active_scans(psoc, 438 max_active_scans); 439 } else { 440 target_if_err("scan_set_max_active_scans uninitialized"); 441 status = QDF_STATUS_E_FAULT; 442 } 443 444 return status; 445 } 446