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 event_info = qdf_mem_malloc(sizeof(*event_info)); 60 61 if (!event_info) { 62 target_if_err("unable to allocate scan_event"); 63 return -ENOMEM; 64 } 65 66 if (wmi_extract_vdev_scan_ev_param(wmi_handle, data, 67 &(event_info->event))) { 68 target_if_err("Failed to extract wmi scan event"); 69 qdf_mem_free(event_info); 70 return -EINVAL; 71 } 72 73 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 74 if (scan_rx_ops->scan_ev_handler) { 75 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 76 if (status != QDF_STATUS_SUCCESS) { 77 qdf_mem_free(event_info); 78 return -EINVAL; 79 } 80 } else { 81 qdf_mem_free(event_info); 82 return -EINVAL; 83 } 84 85 return 0; 86 } 87 88 #ifdef FEATURE_WLAN_SCAN_PNO 89 90 int target_if_nlo_complete_handler(ol_scn_t scn, uint8_t *data, 91 uint32_t len) 92 { 93 wmi_nlo_event *nlo_event; 94 struct scan_event_info *event_info; 95 struct wlan_objmgr_psoc *psoc; 96 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 97 WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = 98 (WMI_NLO_MATCH_EVENTID_param_tlvs *) data; 99 QDF_STATUS status; 100 101 if (!scn || !data) { 102 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 103 return -EINVAL; 104 } 105 106 psoc = target_if_get_psoc_from_scn_hdl(scn); 107 if (!psoc) { 108 target_if_err("null psoc"); 109 return -EINVAL; 110 } 111 112 event_info = qdf_mem_malloc(sizeof(*event_info)); 113 if (!event_info) { 114 target_if_err("unable to allocate scan_event"); 115 return -ENOMEM; 116 } 117 118 nlo_event = param_buf->fixed_param; 119 target_if_info("PNO complete event received for vdev %d", 120 nlo_event->vdev_id); 121 122 event_info->event.type = SCAN_EVENT_TYPE_NLO_COMPLETE; 123 event_info->event.vdev_id = nlo_event->vdev_id; 124 125 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 126 if (scan_rx_ops->scan_ev_handler) { 127 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 128 if (status != QDF_STATUS_SUCCESS) { 129 qdf_mem_free(event_info); 130 return -EINVAL; 131 } 132 } else { 133 qdf_mem_free(event_info); 134 return -EINVAL; 135 } 136 137 return 0; 138 } 139 140 int target_if_nlo_match_event_handler(ol_scn_t scn, uint8_t *data, 141 uint32_t len) 142 { 143 wmi_nlo_event *nlo_event; 144 struct scan_event_info *event_info; 145 struct wlan_objmgr_psoc *psoc; 146 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 147 WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = 148 (WMI_NLO_MATCH_EVENTID_param_tlvs *) data; 149 QDF_STATUS status; 150 151 if (!scn || !data) { 152 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 153 return -EINVAL; 154 } 155 156 psoc = target_if_get_psoc_from_scn_hdl(scn); 157 if (!psoc) { 158 target_if_err("null psoc"); 159 return -EINVAL; 160 } 161 162 event_info = qdf_mem_malloc(sizeof(*event_info)); 163 if (!event_info) { 164 target_if_err("unable to allocate scan_event"); 165 return -ENOMEM; 166 } 167 168 nlo_event = param_buf->fixed_param; 169 target_if_info("PNO match event received for vdev %d", 170 nlo_event->vdev_id); 171 172 event_info->event.type = SCAN_EVENT_TYPE_NLO_MATCH; 173 event_info->event.vdev_id = nlo_event->vdev_id; 174 175 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 176 if (scan_rx_ops->scan_ev_handler) { 177 status = scan_rx_ops->scan_ev_handler(psoc, event_info); 178 if (status != QDF_STATUS_SUCCESS) { 179 qdf_mem_free(event_info); 180 return -EINVAL; 181 } 182 } else { 183 qdf_mem_free(event_info); 184 return -EINVAL; 185 } 186 187 return 0; 188 } 189 190 static QDF_STATUS 191 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 192 void *arg) 193 { 194 QDF_STATUS status; 195 196 status = wmi_unified_register_event( 197 get_wmi_unified_hdl_from_psoc(psoc), 198 wmi_nlo_match_event_id, 199 target_if_nlo_match_event_handler); 200 if (status) { 201 target_if_err("Failed to register nlo match event cb"); 202 return QDF_STATUS_E_FAILURE; 203 } 204 205 status = wmi_unified_register_event( 206 get_wmi_unified_hdl_from_psoc(psoc), 207 wmi_nlo_scan_complete_event_id, 208 target_if_nlo_complete_handler); 209 if (status) { 210 target_if_err("Failed to register nlo scan comp event cb"); 211 return QDF_STATUS_E_FAILURE; 212 } 213 214 return QDF_STATUS_SUCCESS; 215 } 216 217 static QDF_STATUS 218 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 219 void *arg) 220 { 221 QDF_STATUS status; 222 223 status = wmi_unified_unregister_event( 224 get_wmi_unified_hdl_from_psoc(psoc), 225 wmi_nlo_match_event_id); 226 if (status) { 227 target_if_err("Failed to unregister nlo match event cb"); 228 return QDF_STATUS_E_FAILURE; 229 } 230 231 status = wmi_unified_unregister_event( 232 get_wmi_unified_hdl_from_psoc(psoc), 233 wmi_nlo_scan_complete_event_id); 234 if (status) { 235 target_if_err("Failed to unregister nlo scan comp event cb"); 236 return QDF_STATUS_E_FAILURE; 237 } 238 239 return QDF_STATUS_SUCCESS; 240 } 241 242 static QDF_STATUS 243 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 244 struct pno_scan_req_params *req) 245 { 246 QDF_STATUS status; 247 248 status = wmi_unified_pno_start_cmd(GET_WMI_HDL_FROM_PSOC(psoc), req); 249 if (status == QDF_STATUS_SUCCESS) { 250 if (req->mawc_params.enable) 251 status = wmi_unified_nlo_mawc_cmd( 252 GET_WMI_HDL_FROM_PSOC(psoc), 253 &req->mawc_params); 254 } 255 256 return status; 257 } 258 259 static QDF_STATUS 260 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 261 uint8_t vdev_id) 262 { 263 return wmi_unified_pno_stop_cmd(GET_WMI_HDL_FROM_PSOC(psoc), vdev_id); 264 } 265 266 #else 267 268 static inline QDF_STATUS 269 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc, 270 void *arg) 271 { 272 return QDF_STATUS_SUCCESS; 273 } 274 275 static inline QDF_STATUS 276 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc, 277 void *arg) 278 { 279 return QDF_STATUS_SUCCESS; 280 } 281 282 static inline QDF_STATUS 283 target_if_pno_start(struct wlan_objmgr_psoc *psoc, 284 struct pno_scan_req_params *req) 285 { 286 return QDF_STATUS_SUCCESS; 287 } 288 289 static inline QDF_STATUS 290 target_if_pno_stop(struct wlan_objmgr_psoc *psoc, 291 uint8_t vdev_id) 292 { 293 return QDF_STATUS_SUCCESS; 294 } 295 #endif 296 297 298 QDF_STATUS 299 target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg) 300 { 301 QDF_STATUS status; 302 303 status = wmi_unified_register_event( 304 get_wmi_unified_hdl_from_psoc(psoc), 305 wmi_scan_event_id, 306 target_if_scan_event_handler); 307 if (status) { 308 target_if_err("Failed to register Scan match event cb"); 309 return QDF_STATUS_E_FAILURE; 310 } 311 312 status = target_if_scan_register_pno_event_handler(psoc, arg); 313 314 return status; 315 } 316 317 QDF_STATUS 318 target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc, 319 void *arg) 320 { 321 QDF_STATUS status; 322 323 status = wmi_unified_unregister_event( 324 get_wmi_unified_hdl_from_psoc(psoc), 325 wmi_scan_event_id); 326 if (status) { 327 target_if_err("Failed to unregister Scan match event cb"); 328 return QDF_STATUS_E_FAILURE; 329 } 330 331 status = target_if_scan_unregister_pno_event_handler(psoc, arg); 332 333 return status; 334 } 335 336 QDF_STATUS 337 target_if_scan_start(struct wlan_objmgr_pdev *pdev, 338 struct scan_start_request *req) 339 { 340 void *pdev_wmi_handle; 341 342 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 343 if (!pdev_wmi_handle) { 344 target_if_err("Invalid PDEV WMI handle"); 345 return QDF_STATUS_E_FAILURE; 346 } 347 return wmi_unified_scan_start_cmd_send(pdev_wmi_handle, &req->scan_req); 348 } 349 350 QDF_STATUS 351 target_if_scan_cancel(struct wlan_objmgr_pdev *pdev, 352 struct scan_cancel_param *req) 353 { 354 void *pdev_wmi_handle; 355 356 pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 357 if (!pdev_wmi_handle) { 358 target_if_err("Invalid PDEV WMI handle"); 359 return QDF_STATUS_E_NULL_VALUE; 360 } 361 return wmi_unified_scan_stop_cmd_send(pdev_wmi_handle, req); 362 } 363 364 QDF_STATUS 365 target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) 366 { 367 struct wlan_lmac_if_scan_tx_ops *scan; 368 369 scan = &tx_ops->scan; 370 if (!scan) { 371 target_if_err("Scan txops NULL"); 372 return QDF_STATUS_E_FAILURE; 373 } 374 375 scan->scan_start = target_if_scan_start; 376 scan->scan_cancel = target_if_scan_cancel; 377 scan->pno_start = target_if_pno_start; 378 scan->pno_stop = target_if_pno_stop; 379 scan->scan_reg_ev_handler = target_if_scan_register_event_handler; 380 scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler; 381 382 return QDF_STATUS_SUCCESS; 383 } 384 385 QDF_STATUS 386 target_if_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc, 387 uint32_t max_active_scans) 388 { 389 struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; 390 QDF_STATUS status; 391 392 scan_rx_ops = target_if_scan_get_rx_ops(psoc); 393 if (scan_rx_ops->scan_set_max_active_scans) { 394 status = scan_rx_ops->scan_set_max_active_scans(psoc, 395 max_active_scans); 396 } else { 397 target_if_err("scan_set_max_active_scans uninitialized"); 398 status = QDF_STATUS_E_FAULT; 399 } 400 401 return status; 402 } 403