1 /* 2 * Copyright (c) 2012-2020 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: wifi_pos_main.c 21 * This file defines the important functions pertinent to 22 * wifi positioning to initialize and de-initialize the component. 23 */ 24 #include "target_if_wifi_pos.h" 25 #include "wifi_pos_oem_interface_i.h" 26 #include "wifi_pos_utils_i.h" 27 #include "wifi_pos_api.h" 28 #include "wifi_pos_main_i.h" 29 #include "wifi_pos_ucfg_i.h" 30 #include "wlan_objmgr_cmn.h" 31 #include "wlan_objmgr_global_obj.h" 32 #include "wlan_objmgr_psoc_obj.h" 33 #include "wlan_objmgr_pdev_obj.h" 34 #include "wlan_objmgr_vdev_obj.h" 35 #include "wlan_ptt_sock_svc.h" 36 37 #include "wlan_reg_services_api.h" 38 /* forward declartion */ 39 struct regulatory_channel; 40 41 #define REG_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \ 42 reg_info_1 &= 0xff00ffff; \ 43 reg_info_1 |= ((val & 0xff) << 16); \ 44 } while (0) 45 46 /* max tx power is in 1 dBm units */ 47 #define REG_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \ 48 reg_info_2 &= 0xffff00ff; \ 49 reg_info_2 |= ((val & 0xff) << 8); \ 50 } while (0) 51 52 /* channel info consists of 6 bits of channel mode */ 53 54 #define REG_SET_CHANNEL_MODE(reg_channel, val) do { \ 55 (reg_channel)->info &= 0xffffffc0; \ 56 (reg_channel)->info |= (val); \ 57 } while (0) 58 59 /* 60 * obj mgr api to iterate over vdevs does not provide a direct array or vdevs, 61 * rather takes a callback that is called for every vdev. wifi pos needs to 62 * store device mode and vdev id of all active vdevs and provide this info to 63 * user space as part of APP registration response. due to this, vdev_idx is 64 * used to identify how many vdevs have been populated by obj manager API. 65 */ 66 static uint32_t vdev_idx; 67 68 /** 69 * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg 70 * @psoc: psoc object 71 * 72 * Return: status of operation 73 */ 74 static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc) 75 { 76 /* this is TBD */ 77 return true; 78 } 79 80 struct wlan_lmac_if_wifi_pos_tx_ops * 81 wifi_pos_get_tx_ops(struct wlan_objmgr_psoc *psoc) 82 { 83 struct wlan_lmac_if_tx_ops *tx_ops; 84 85 if (!psoc) { 86 wifi_pos_err("psoc is null"); 87 return NULL; 88 } 89 90 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 91 if (!tx_ops) { 92 wifi_pos_err("tx_ops is NULL"); 93 return NULL; 94 } 95 96 return &tx_ops->wifi_pos_tx_ops; 97 } 98 99 #ifdef CNSS_GENL 100 static uint8_t * 101 wifi_pos_prepare_reg_resp(uint32_t *rsp_len, 102 struct app_reg_rsp_vdev_info *vdevs_info) 103 { 104 uint32_t *nl_sign; 105 uint8_t *resp_buf; 106 struct wifi_app_reg_rsp *app_reg_rsp; 107 108 /* 109 * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp 110 * to indicate NLA type response is supported for OEM request 111 * commands. 112 */ 113 *rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx) 114 + sizeof(uint8_t) + ENHNC_FLAGS_LEN; 115 resp_buf = qdf_mem_malloc(*rsp_len); 116 if (!resp_buf) 117 return NULL; 118 119 app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf; 120 app_reg_rsp->num_inf = vdev_idx; 121 qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info, 122 sizeof(struct app_reg_rsp_vdev_info) * vdev_idx); 123 124 nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx]; 125 *nl_sign |= NL_ENABLE_OEM_REQ_RSP; 126 127 return resp_buf; 128 } 129 #else 130 static uint8_t * 131 wifi_pos_prepare_reg_resp(uint32_t *rsp_len, 132 struct app_reg_rsp_vdev_info *vdevs_info) 133 { 134 uint8_t *resp_buf; 135 struct wifi_app_reg_rsp *app_reg_rsp; 136 137 *rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx) 138 + sizeof(uint8_t); 139 resp_buf = qdf_mem_malloc(*rsp_len); 140 if (!resp_buf) 141 return NULL; 142 143 app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf; 144 app_reg_rsp->num_inf = vdev_idx; 145 qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info, 146 sizeof(struct app_reg_rsp_vdev_info) * vdev_idx); 147 148 return resp_buf; 149 } 150 #endif 151 152 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc, 153 struct wifi_pos_req_msg *req) 154 { 155 uint8_t idx; 156 uint32_t sub_type = 0; 157 uint32_t channel_mhz = 0; 158 uint32_t pdev_id = 0; 159 uint32_t offset; 160 struct oem_data_req data_req; 161 struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops; 162 struct wlan_objmgr_pdev *pdev; 163 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 164 wifi_pos_get_psoc_priv_obj(psoc); 165 166 if (!wifi_pos_obj) { 167 wifi_pos_err("wifi_pos priv obj is null"); 168 return QDF_STATUS_E_INVAL; 169 } 170 171 wifi_pos_debug("Received data req pid(%d), len(%d)", 172 req->pid, req->buf_len); 173 174 /* look for fields */ 175 if (req->field_info_buf) 176 for (idx = 0; idx < req->field_info_buf->count; idx++) { 177 offset = req->field_info_buf->fields[idx].offset; 178 /* 179 * replace following reads with read_api based on 180 * length 181 */ 182 if (req->field_info_buf->fields[idx].id == 183 WMIRTT_FIELD_ID_oem_data_sub_type) { 184 sub_type = *((uint32_t *)&req->buf[offset]); 185 continue; 186 } 187 188 if (req->field_info_buf->fields[idx].id == 189 WMIRTT_FIELD_ID_channel_mhz) { 190 channel_mhz = *((uint32_t *)&req->buf[offset]); 191 continue; 192 } 193 194 if (req->field_info_buf->fields[idx].id == 195 WMIRTT_FIELD_ID_pdev) { 196 pdev_id = *((uint32_t *)&req->buf[offset]); 197 /* pdev_id in FW starts from 1. So convert it to 198 * host id by decrementing it. 199 * zero has special meaning due to backward 200 * compatibility. Dont change it. 201 */ 202 if (pdev_id) 203 pdev_id -= 1; 204 continue; 205 } 206 } 207 208 switch (sub_type) { 209 case TARGET_OEM_CAPABILITY_REQ: 210 /* TBD */ 211 break; 212 case TARGET_OEM_CONFIGURE_LCR: 213 /* TBD */ 214 break; 215 case TARGET_OEM_CONFIGURE_LCI: 216 /* TBD */ 217 break; 218 case TARGET_OEM_MEASUREMENT_REQ: 219 /* TBD */ 220 break; 221 case TARGET_OEM_CONFIGURE_FTMRR: 222 wifi_pos_debug("FTMRR request"); 223 if (wifi_pos_obj->wifi_pos_send_action) 224 wifi_pos_obj->wifi_pos_send_action(psoc, sub_type, 225 req->buf, 226 req->buf_len); 227 break; 228 case TARGET_OEM_CONFIGURE_WRU: 229 wifi_pos_debug("WRU request"); 230 if (wifi_pos_obj->wifi_pos_send_action) 231 wifi_pos_obj->wifi_pos_send_action(psoc, sub_type, 232 req->buf, 233 req->buf_len); 234 break; 235 default: 236 wifi_pos_debug("invalid sub type or not passed"); 237 238 tx_ops = wifi_pos_get_tx_ops(psoc); 239 if (!tx_ops) { 240 wifi_pos_err("tx ops null"); 241 return QDF_STATUS_E_INVAL; 242 } 243 244 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, 245 WLAN_WIFI_POS_CORE_ID); 246 if (!pdev) { 247 wifi_pos_err("pdev null"); 248 return QDF_STATUS_E_INVAL; 249 } 250 data_req.data_len = req->buf_len; 251 data_req.data = req->buf; 252 tx_ops->data_req_tx(pdev, &data_req); 253 wlan_objmgr_pdev_release_ref(pdev, 254 WLAN_WIFI_POS_CORE_ID); 255 break; 256 } 257 258 return QDF_STATUS_SUCCESS; 259 } 260 261 static QDF_STATUS wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc, 262 struct wifi_pos_req_msg *req) 263 { 264 int error_code; 265 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 266 wifi_pos_get_psoc_priv_obj(psoc); 267 struct wifi_pos_user_defined_caps *caps = 268 (struct wifi_pos_user_defined_caps *)req->buf; 269 270 if (!wifi_pos_obj) { 271 wifi_pos_err("wifi_pos priv obj is null"); 272 return QDF_STATUS_E_INVAL; 273 } 274 275 wifi_pos_debug("Received set cap req pid(%d), len(%d)", 276 req->pid, req->buf_len); 277 278 wifi_pos_obj->ftm_rr = caps->ftm_rr; 279 wifi_pos_obj->lci_capability = caps->lci_capability; 280 error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS); 281 wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, 282 WIFI_POS_CMD_SET_CAPS, 283 sizeof(error_code), 284 (uint8_t *)&error_code); 285 286 return QDF_STATUS_SUCCESS; 287 } 288 289 static QDF_STATUS wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc, 290 struct wifi_pos_req_msg *req) 291 { 292 struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } }; 293 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 294 wifi_pos_get_psoc_priv_obj(psoc); 295 296 if (!wifi_pos_obj) { 297 wifi_pos_err("wifi_pos priv obj is null"); 298 return QDF_STATUS_E_INVAL; 299 } 300 301 wifi_pos_debug("Received get cap req pid(%d), len(%d)", 302 req->pid, req->buf_len); 303 304 wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap); 305 cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr; 306 cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability; 307 308 wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, 309 WIFI_POS_CMD_GET_CAPS, 310 sizeof(cap_rsp), 311 (uint8_t *)&cap_rsp); 312 313 return QDF_STATUS_SUCCESS; 314 } 315 316 QDF_STATUS wifi_pos_send_report_resp(struct wlan_objmgr_psoc *psoc, 317 int req_id, uint8_t *dest_mac, 318 int err_code) 319 { 320 struct wifi_pos_err_msg_report err_report = {0}; 321 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 322 wifi_pos_get_psoc_priv_obj(psoc); 323 324 if (!wifi_pos_obj) { 325 wifi_pos_err("wifi_pos priv obj is null"); 326 return QDF_STATUS_E_INVAL; 327 } 328 329 err_report.msg_tag_len = OEM_MSG_RSP_HEAD_TAG_ID << 16; 330 err_report.msg_tag_len |= (sizeof(err_report) - 331 sizeof(err_report.err_rpt)) & 0x0000FFFF; 332 err_report.msg_subtype = TARGET_OEM_ERROR_REPORT_RSP; 333 err_report.req_id = req_id & 0xFFFF; 334 err_report.req_id |= ((err_code & 0xFF) << 16); 335 err_report.req_id |= (0x1 << 24); 336 err_report.time_left = 0xFFFFFFFF; 337 err_report.err_rpt.tag_len = OEM_MEAS_RSP_HEAD_TAG_ID << 16; 338 err_report.err_rpt.tag_len |= 339 (sizeof(struct wifi_pos_err_rpt)) & 0x0000FFFF; 340 memcpy(&err_report.err_rpt.dest_mac, dest_mac, QDF_MAC_ADDR_SIZE); 341 342 wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, 343 WIFI_POS_CMD_OEM_DATA, 344 sizeof(err_report), 345 (uint8_t *)&err_report); 346 347 return QDF_STATUS_SUCCESS; 348 } 349 350 static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc, 351 struct wlan_objmgr_pdev *pdev, 352 uint16_t freq, 353 struct wifi_pos_ch_info_rsp *chan_info) 354 { 355 struct ch_params ch_params = {0}; 356 uint16_t sec_ch_2g = 0; 357 struct wifi_pos_psoc_priv_obj *wifi_pos_psoc = 358 wifi_pos_get_psoc_priv_obj(psoc); 359 uint32_t phy_mode; 360 361 if (!wifi_pos_psoc) { 362 wifi_pos_err("wifi_pos priv obj is null"); 363 return; 364 } 365 366 /* Passing CH_WIDTH_MAX will give the max bandwidth supported */ 367 ch_params.ch_width = CH_WIDTH_MAX; 368 wlan_reg_set_channel_params_for_freq(pdev, freq, 369 sec_ch_2g, &ch_params); 370 chan_info->band_center_freq1 = ch_params.mhz_freq_seg0; 371 wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq(freq, 372 ch_params.ch_width, 373 &phy_mode); 374 REG_SET_CHANNEL_MODE(chan_info, phy_mode); 375 } 376 377 static void wifi_pos_get_reg_info(struct wlan_objmgr_pdev *pdev, 378 uint16_t freq, uint32_t *reg_info_1, 379 uint32_t *reg_info_2) 380 { 381 uint32_t reg_power = wlan_reg_get_channel_reg_power_for_freq(pdev, 382 freq); 383 384 *reg_info_1 = 0; 385 *reg_info_2 = 0; 386 387 REG_SET_CHANNEL_REG_POWER(*reg_info_1, reg_power); 388 REG_SET_CHANNEL_MAX_TX_POWER(*reg_info_2, reg_power); 389 } 390 391 /** 392 * wifi_pos_get_valid_channels: Get the list of valid channels from the 393 * given channel list 394 * @channels: Channel list to be validated 395 * @num_ch: NUmber of channels in the channel list to be validated 396 * @valid_channel_list: Pointer to valid channel list 397 * 398 * Return: Number of valid channels in the given list 399 */ 400 401 static uint32_t wifi_pos_get_valid_channels(uint8_t *channels, uint32_t num_ch, 402 uint8_t *valid_channel_list) { 403 uint32_t i, num_valid_channels = 0; 404 405 for (i = 0; i < num_ch; i++) { 406 if (wlan_reg_get_chan_enum(channels[i]) == INVALID_CHANNEL) 407 continue; 408 valid_channel_list[num_valid_channels++] = channels[i]; 409 } 410 return num_valid_channels; 411 } 412 413 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc, 414 void *obj, void *arg) 415 { 416 QDF_STATUS status; 417 uint8_t num_channels; 418 struct wlan_objmgr_pdev *pdev = obj; 419 struct wifi_pos_channel_list *chan_list = arg; 420 struct channel_power *ch_info = NULL; 421 422 if (!chan_list) { 423 wifi_pos_err("wifi_pos priv arg is null"); 424 return; 425 } 426 ch_info = (struct channel_power *)chan_list->chan_info; 427 status = wlan_reg_get_channel_list_with_power(pdev, ch_info, 428 &num_channels); 429 430 if (QDF_IS_STATUS_ERROR(status)) { 431 wifi_pos_err("Failed to get valid channel list"); 432 return; 433 } 434 chan_list->num_channels = num_channels; 435 } 436 437 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc, 438 struct wifi_pos_channel_list *chan_list) 439 { 440 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 441 wifi_pos_pdev_iterator, 442 chan_list, true, WLAN_WIFI_POS_CORE_ID); 443 wifi_pos_notice("num channels: %d", chan_list->num_channels); 444 } 445 446 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc, 447 struct wifi_pos_req_msg *req) 448 { 449 uint8_t idx, band_mask; 450 uint8_t *buf; 451 uint32_t len, i, freq; 452 uint32_t reg_info_1; 453 uint32_t reg_info_2; 454 bool oem_6g_support_disable; 455 uint8_t *channels = req->buf; 456 struct wlan_objmgr_pdev *pdev; 457 uint32_t num_ch = req->buf_len; 458 uint8_t valid_channel_list[NUM_CHANNELS]; 459 uint32_t num_valid_channels = 0; 460 struct wifi_pos_ch_info_rsp *ch_info; 461 struct wifi_pos_channel_list *ch_list; 462 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 463 wifi_pos_get_psoc_priv_obj(psoc); 464 465 if (!wifi_pos_obj) { 466 wifi_pos_err("wifi_pos priv obj is null"); 467 return QDF_STATUS_E_INVAL; 468 } 469 470 wifi_pos_debug("Received ch info req pid(%d), len(%d)", 471 req->pid, req->buf_len); 472 473 /* get first pdev since we need that only for freq and dfs state */ 474 pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_WIFI_POS_CORE_ID); 475 if (!pdev) { 476 wifi_pos_err("pdev get API failed"); 477 return QDF_STATUS_E_INVAL; 478 } 479 if (num_ch > NUM_CHANNELS) { 480 wifi_pos_err("Invalid number of channels"); 481 return QDF_STATUS_E_INVAL; 482 } 483 484 ch_list = qdf_mem_malloc(sizeof(*ch_list)); 485 if (!ch_list) 486 return QDF_STATUS_E_NOMEM; 487 488 if (num_ch == 0 && req->rsp_version == WIFI_POS_RSP_V2_NL) { 489 wifi_pos_get_ch_info(psoc, ch_list); 490 qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock); 491 oem_6g_support_disable = wifi_pos_obj->oem_6g_support_disable; 492 qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock); 493 494 /* ch_list has the frequencies in order of 2.4g, 5g & 6g */ 495 for (i = 0; i < ch_list->num_channels; i++) { 496 freq = ch_list->chan_info[i].center_freq; 497 if (oem_6g_support_disable && 498 WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) 499 continue; 500 num_valid_channels++; 501 } 502 } else { 503 /* v1 has ch_list with frequencies in order of 2.4g, 5g only */ 504 num_valid_channels = wifi_pos_get_valid_channels( 505 channels, num_ch, 506 valid_channel_list); 507 band_mask = BIT(REG_BAND_5G) | BIT(REG_BAND_2G); 508 for (i = 0; i < num_valid_channels; i++) { 509 ch_list->chan_info[i].chan_num = valid_channel_list[i]; 510 ch_list->chan_info[i].center_freq = 511 wlan_reg_chan_band_to_freq( 512 pdev, 513 ch_list->chan_info[i].chan_num, 514 band_mask); 515 } 516 } 517 518 len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) * 519 num_valid_channels; 520 buf = qdf_mem_malloc(len); 521 if (!buf) { 522 wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID); 523 qdf_mem_free(ch_list); 524 return QDF_STATUS_E_NOMEM; 525 } 526 527 /* First byte of message body will have num of channels */ 528 buf[0] = num_valid_channels; 529 ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1]; 530 for (idx = 0; idx < num_valid_channels; idx++) { 531 ch_info[idx].reserved0 = 0; 532 ch_info[idx].chan_id = ch_list->chan_info[idx].chan_num; 533 ch_info[idx].mhz = ch_list->chan_info[idx].center_freq; 534 ch_info[idx].band_center_freq1 = ch_info[idx].mhz; 535 ch_info[idx].band_center_freq2 = 0; 536 ch_info[idx].info = 0; 537 wifi_pos_get_reg_info(pdev, ch_info[idx].mhz, 538 ®_info_1, ®_info_2); 539 540 if (wlan_reg_is_dfs_for_freq(pdev, ch_info[idx].mhz)) 541 WIFI_POS_SET_DFS(ch_info[idx].info); 542 543 wifi_update_channel_bw_info(psoc, pdev, 544 ch_info[idx].mhz, 545 &ch_info[idx]); 546 547 ch_info[idx].reg_info_1 = reg_info_1; 548 ch_info[idx].reg_info_2 = reg_info_2; 549 } 550 551 wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, 552 WIFI_POS_CMD_GET_CH_INFO, 553 len, buf); 554 555 qdf_mem_free(buf); 556 qdf_mem_free(ch_list); 557 wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID); 558 559 return QDF_STATUS_SUCCESS; 560 } 561 562 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc, 563 void *vdev, void *arg) 564 { 565 struct app_reg_rsp_vdev_info *vdev_info = arg; 566 567 vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev); 568 vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev); 569 vdev_idx++; 570 } 571 572 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc, 573 struct wifi_pos_req_msg *req) 574 { 575 QDF_STATUS ret = QDF_STATUS_SUCCESS; 576 uint8_t err = 0, *app_reg_rsp; 577 uint32_t rsp_len; 578 char *sign_str = NULL; 579 struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS] 580 = { { 0 } }; 581 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 582 wifi_pos_get_psoc_priv_obj(psoc); 583 584 if (!wifi_pos_obj) { 585 wifi_pos_err("wifi_pos priv obj is null"); 586 return QDF_STATUS_E_INVAL; 587 } 588 589 wifi_pos_err("Received App Req Req pid(%d), len(%d)", 590 req->pid, req->buf_len); 591 592 sign_str = (char *)req->buf; 593 /* Registration request is only allowed for QTI Application */ 594 if ((OEM_APP_SIGNATURE_LEN != req->buf_len) || 595 (strncmp(sign_str, OEM_APP_SIGNATURE_STR, 596 OEM_APP_SIGNATURE_LEN))) { 597 wifi_pos_err("Invalid signature pid(%d)", req->pid); 598 ret = QDF_STATUS_E_PERM; 599 err = OEM_ERR_INVALID_SIGNATURE; 600 goto app_reg_failed; 601 } 602 603 wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid); 604 qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock); 605 wifi_pos_obj->is_app_registered = true; 606 wifi_pos_obj->app_pid = req->pid; 607 qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock); 608 609 vdev_idx = 0; 610 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, 611 wifi_pos_vdev_iterator, 612 vdevs_info, true, WLAN_WIFI_POS_CORE_ID); 613 614 app_reg_rsp = wifi_pos_prepare_reg_resp(&rsp_len, vdevs_info); 615 if (!app_reg_rsp) { 616 ret = QDF_STATUS_E_NOMEM; 617 err = OEM_ERR_NULL_CONTEXT; 618 goto app_reg_failed; 619 } 620 621 if (!vdev_idx) 622 wifi_pos_debug("no active vdev"); 623 624 vdev_idx = 0; 625 wifi_pos_obj->wifi_pos_send_rsp(req->pid, WIFI_POS_CMD_REGISTRATION, 626 rsp_len, (uint8_t *)app_reg_rsp); 627 628 qdf_mem_free(app_reg_rsp); 629 return ret; 630 631 app_reg_failed: 632 633 wifi_pos_obj->wifi_pos_send_rsp(req->pid, WIFI_POS_CMD_ERROR, 634 sizeof(err), &err); 635 return ret; 636 } 637 638 /** 639 * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req 640 * @wmi_msg: wmi type request msg 641 * 642 * Return: status of operation 643 */ 644 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc, 645 struct wifi_pos_req_msg *req) 646 { 647 wifi_pos_debug("enter: msg_type: %d", req->msg_type); 648 switch (req->msg_type) { 649 case WIFI_POS_CMD_REGISTRATION: 650 return wifi_pos_process_app_reg_req(psoc, req); 651 case WIFI_POS_CMD_OEM_DATA: 652 return wifi_pos_process_data_req(psoc, req); 653 case WIFI_POS_CMD_GET_CH_INFO: 654 return wifi_pos_process_ch_info_req(psoc, req); 655 case WIFI_POS_CMD_SET_CAPS: 656 return wifi_pos_process_set_cap_req(psoc, req); 657 case WIFI_POS_CMD_GET_CAPS: 658 return wifi_pos_process_get_cap_req(psoc, req); 659 default: 660 wifi_pos_err("invalid request type"); 661 break; 662 } 663 return 0; 664 } 665 666 /** 667 * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV 668 * type req 669 * @wmi_msg: wmi type request msg 670 * 671 * Return: status of operation 672 */ 673 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc, 674 struct wifi_pos_req_msg *req) 675 { 676 return QDF_STATUS_SUCCESS; 677 } 678 679 QDF_STATUS wifi_pos_psoc_obj_created_notification( 680 struct wlan_objmgr_psoc *psoc, void *arg_list) 681 { 682 QDF_STATUS status; 683 struct wifi_pos_psoc_priv_obj *wifi_pos_obj; 684 685 /* 686 * this is for WIN, if they have multiple psoc, we dont want to create 687 * multiple priv object. Since there is just one LOWI app registered to 688 * one driver, avoid 2nd private object with another psoc. 689 */ 690 if (wifi_pos_get_psoc()) { 691 wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object"); 692 return QDF_STATUS_SUCCESS; 693 } else { 694 wifi_pos_debug("setting global pos object"); 695 wifi_pos_set_psoc(psoc); 696 } 697 698 /* initialize wifi-pos psoc priv object */ 699 wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj)); 700 if (!wifi_pos_obj) { 701 wifi_pos_clear_psoc(); 702 return QDF_STATUS_E_NOMEM; 703 } 704 705 qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock); 706 /* Register TLV or non-TLV callbacks depending on target fw version */ 707 if (wifi_pos_get_tlv_support(psoc)) 708 wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback; 709 else 710 wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback; 711 712 /* 713 * MGMT Rx is not handled in this phase since wifi pos only uses few 714 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are 715 * used for 80211k. That part is not yet converged and still follows 716 * legacy MGMT Rx to work. Action frame in new TXRX can be registered 717 * at per ACTION Frame type granularity only. 718 */ 719 720 status = wlan_objmgr_psoc_component_obj_attach(psoc, 721 WLAN_UMAC_COMP_WIFI_POS, 722 wifi_pos_obj, 723 QDF_STATUS_SUCCESS); 724 725 if (QDF_IS_STATUS_ERROR(status)) { 726 wifi_pos_err("obj attach with psoc failed with status: %d", 727 status); 728 qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock); 729 qdf_mem_free(wifi_pos_obj); 730 wifi_pos_clear_psoc(); 731 } 732 733 return status; 734 } 735 736 QDF_STATUS wifi_pos_psoc_obj_destroyed_notification( 737 struct wlan_objmgr_psoc *psoc, void *arg_list) 738 { 739 QDF_STATUS status; 740 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL; 741 742 if (wifi_pos_get_psoc() == psoc) { 743 wifi_pos_debug("deregistering wifi_pos_psoc object"); 744 wifi_pos_clear_psoc(); 745 } else { 746 wifi_pos_warn("un-related PSOC closed. do nothing"); 747 return QDF_STATUS_SUCCESS; 748 } 749 750 wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc); 751 if (!wifi_pos_obj) { 752 wifi_pos_err("wifi_pos_obj is NULL"); 753 return QDF_STATUS_E_FAULT; 754 } 755 756 target_if_wifi_pos_deinit_dma_rings(psoc); 757 758 status = wlan_objmgr_psoc_component_obj_detach(psoc, 759 WLAN_UMAC_COMP_WIFI_POS, 760 wifi_pos_obj); 761 if (status != QDF_STATUS_SUCCESS) 762 wifi_pos_err("wifi_pos_obj detach failed"); 763 764 wifi_pos_debug("wifi_pos_obj deleted with status %d", status); 765 qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock); 766 qdf_mem_free(wifi_pos_obj); 767 768 return status; 769 } 770 771 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc, 772 struct oem_data_rsp *oem_rsp) 773 { 774 uint32_t len; 775 uint8_t *data; 776 uint32_t app_pid; 777 struct wifi_pos_psoc_priv_obj *priv = 778 wifi_pos_get_psoc_priv_obj(psoc); 779 wifi_pos_send_rsp_handler wifi_pos_send_rsp; 780 781 if (!priv) { 782 wifi_pos_err("private object is NULL"); 783 return -EINVAL; 784 } 785 786 qdf_spin_lock_bh(&priv->wifi_pos_lock); 787 app_pid = priv->app_pid; 788 wifi_pos_send_rsp = priv->wifi_pos_send_rsp; 789 qdf_spin_unlock_bh(&priv->wifi_pos_lock); 790 791 len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len; 792 if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE || 793 oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) { 794 wifi_pos_err("invalid length of Oem Data response"); 795 return -EINVAL; 796 } 797 798 if (!wifi_pos_send_rsp) { 799 wifi_pos_err("invalid response handler"); 800 return -EINVAL; 801 } 802 803 wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid); 804 805 if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) { 806 /* stitch togther the msg data_1 + CIR/CFR + data_2 */ 807 data = qdf_mem_malloc(len); 808 if (!data) 809 return -ENOMEM; 810 811 qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1); 812 qdf_mem_copy(&data[oem_rsp->rsp_len_1], 813 oem_rsp->vaddr, oem_rsp->dma_len); 814 qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len], 815 oem_rsp->data_2, oem_rsp->rsp_len_2); 816 817 wifi_pos_send_rsp(app_pid, WIFI_POS_CMD_OEM_DATA, len, data); 818 qdf_mem_free(data); 819 } else { 820 wifi_pos_send_rsp(app_pid, WIFI_POS_CMD_OEM_DATA, 821 oem_rsp->rsp_len_1, oem_rsp->data_1); 822 } 823 824 return 0; 825 } 826 827 void wifi_pos_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) 828 { 829 struct wlan_lmac_if_wifi_pos_rx_ops *wifi_pos_rx_ops; 830 831 wifi_pos_rx_ops = &rx_ops->wifi_pos_rx_ops; 832 wifi_pos_rx_ops->oem_rsp_event_rx = wifi_pos_oem_rsp_handler; 833 } 834 835 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc, 836 struct wifi_pos_driver_caps *caps) 837 { 838 uint16_t i, count = 0; 839 uint32_t freq; 840 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 841 wifi_pos_get_psoc_priv_obj(psoc); 842 struct wifi_pos_channel_list *ch_list = NULL; 843 844 wifi_pos_debug("Enter"); 845 if (!wifi_pos_obj) { 846 wifi_pos_err("wifi_pos_obj is null"); 847 return QDF_STATUS_E_NULL_VALUE; 848 } 849 850 ch_list = qdf_mem_malloc(sizeof(*ch_list)); 851 if (!ch_list) 852 return QDF_STATUS_E_NOMEM; 853 854 strlcpy(caps->oem_target_signature, 855 OEM_TARGET_SIGNATURE, 856 OEM_TARGET_SIGNATURE_LEN); 857 caps->oem_target_type = wifi_pos_obj->oem_target_type; 858 caps->oem_fw_version = wifi_pos_obj->oem_fw_version; 859 caps->driver_version.major = wifi_pos_obj->driver_version.major; 860 caps->driver_version.minor = wifi_pos_obj->driver_version.minor; 861 caps->driver_version.patch = wifi_pos_obj->driver_version.patch; 862 caps->driver_version.build = wifi_pos_obj->driver_version.build; 863 caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min; 864 caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max; 865 caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min; 866 caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max; 867 caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc); 868 wifi_pos_get_ch_info(psoc, ch_list); 869 870 /* copy valid channels list to caps */ 871 for (i = 0; i < ch_list->num_channels; i++) { 872 freq = ch_list->chan_info[i].center_freq; 873 if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) 874 continue; 875 caps->channel_list[count++] = ch_list->chan_info[i].chan_num; 876 } 877 caps->num_channels = count; 878 qdf_mem_free(ch_list); 879 return QDF_STATUS_SUCCESS; 880 } 881