1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 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 * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation 22 */ 23 24 #include "osif_sync.h" 25 #include "wlan_hdd_main.h" 26 #include "wlan_hdd_tsf.h" 27 #include "wma_api.h" 28 #include "wlan_fwol_ucfg_api.h" 29 #include <qca_vendor.h> 30 #include <linux/errqueue.h> 31 #if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \ 32 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) 33 #include <linux/gpio.h> 34 #endif 35 36 #include "ol_txrx_api.h" 37 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY 38 #include <cdp_txrx_ctrl.h> 39 #endif 40 41 #ifdef WLAN_FEATURE_TSF_PLUS 42 #if !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \ 43 !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \ 44 !defined(WLAN_FEATURE_TSF_TIMER_SYNC) 45 static int tsf_gpio_irq_num = -1; 46 #endif 47 #endif 48 static qdf_event_t tsf_sync_get_completion_evt; 49 #define WLAN_TSF_SYNC_GET_TIMEOUT 2000 50 #define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500 51 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100 52 #ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC 53 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 1 54 #else 55 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 100 56 #endif 57 #define OUTPUT_HIGH 1 58 #define OUTPUT_LOW 0 59 60 #ifdef WLAN_FEATURE_TSF_PLUS 61 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \ 62 defined(WLAN_FEATURE_TSF_TIMER_SYNC) 63 static void hdd_update_timestamp(struct hdd_adapter *adapter); 64 #else 65 static void 66 hdd_update_timestamp(struct hdd_adapter *adapter, 67 uint64_t target_time, uint64_t host_time); 68 #endif 69 #endif 70 71 #ifdef QCA_GET_TSF_VIA_REG 72 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf); 73 74 /** 75 * struct hdd_tsf_report - TSF report filled in by DP layer 76 * @vdev_id: vdev id for which TSF values is to be read 77 * @tsf_id: tsf if used to read TSF report 78 * @mac_id: lmac_id for which TSF values are read 79 * @tsf: 64 bit tsf value as read from scratch registers 80 * @tsf_sync_soc_time: host qtimer time when scratch registers are read 81 * 82 * The structure is used by the upper layers to pass vdev_id, tsf_id and mac_id 83 * information to DP layer and get tsf time and host time when TSF was read. 84 */ 85 struct hdd_tsf_report { 86 uint32_t vdev_id; 87 uint32_t tsf_id; 88 uint32_t mac_id; 89 uint64_t tsf; 90 uint64_t tsf_sync_soc_time; 91 }; 92 #endif 93 94 /** 95 * enum hdd_tsf_op_result - result of tsf operation 96 * 97 * HDD_TSF_OP_SUCC: succeed 98 * HDD_TSF_OP_FAIL: fail 99 */ 100 enum hdd_tsf_op_result { 101 HDD_TSF_OP_SUCC, 102 HDD_TSF_OP_FAIL 103 }; 104 105 #ifdef WLAN_FEATURE_TSF_PLUS 106 #ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC 107 #define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 1 108 #else 109 #define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 9 110 #endif 111 static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter, 112 bool initialized) 113 { 114 qdf_atomic_set(&adapter->tsf_sync_ready_flag, 115 (initialized ? 1 : 0)); 116 } 117 118 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter) 119 { 120 return qdf_atomic_read(&adapter->tsf_sync_ready_flag) != 0; 121 } 122 123 #else 124 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter) 125 { 126 return true; 127 } 128 #endif 129 130 static 131 enum hdd_tsf_get_state hdd_tsf_check_conn_state(struct hdd_adapter *adapter) 132 { 133 enum hdd_tsf_get_state ret = TSF_RETURN; 134 135 if (adapter->device_mode == QDF_STA_MODE || 136 adapter->device_mode == QDF_P2P_CLIENT_MODE) { 137 if (!hdd_cm_is_vdev_associated(adapter)) { 138 hdd_err("failed to cap tsf, not connect with ap"); 139 ret = TSF_STA_NOT_CONNECTED_NO_TSF; 140 } 141 } else if ((adapter->device_mode == QDF_SAP_MODE || 142 adapter->device_mode == QDF_P2P_GO_MODE) && 143 !(test_bit(SOFTAP_BSS_STARTED, 144 &adapter->event_flags))) { 145 hdd_err("Soft AP / P2p GO not beaconing"); 146 ret = TSF_SAP_NOT_STARTED_NO_TSF; 147 } 148 return ret; 149 } 150 151 static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter) 152 { 153 struct hdd_context *hddctx; 154 155 if (!adapter) { 156 hdd_err("invalid adapter"); 157 return false; 158 } 159 160 hddctx = WLAN_HDD_GET_CTX(adapter); 161 if (!hddctx) { 162 hdd_err("invalid hdd context"); 163 return false; 164 } 165 166 if (!qdf_atomic_read(&hddctx->tsf_ready_flag) || 167 !hdd_get_th_sync_status(adapter)) { 168 hdd_err("TSF is not initialized"); 169 return false; 170 } 171 172 return true; 173 } 174 175 #if (defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \ 176 defined(WLAN_FEATURE_TSF_PLUS)) || \ 177 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) || \ 178 defined(WLAN_FEATURE_TSF_TIMER_SYNC) 179 /** 180 * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync 181 * @adapter: pointer to adapter 182 * 183 * This function send WMI command to reset GPIO configured in FW after 184 * TSF get operation. 185 * 186 * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure 187 */ 188 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) 189 { 190 /* No GPIO Host timer sync for integrated WIFI Device */ 191 return TSF_RETURN; 192 } 193 194 /** 195 * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync 196 * @hdd_ctx: pointer to hdd context 197 * 198 * This function is a dummy function for adrastea arch 199 * 200 * Return: QDF_STATUS_SUCCESS on Success 201 */ 202 203 static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) 204 { 205 return QDF_STATUS_SUCCESS; 206 } 207 #else 208 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) 209 { 210 int ret; 211 212 ret = wma_cli_set_command((int)adapter->vdev_id, 213 (int)GEN_PARAM_RESET_TSF_GPIO, 214 adapter->vdev_id, 215 GEN_CMD); 216 217 if (ret != 0) { 218 hdd_err("tsf reset GPIO fail "); 219 ret = TSF_RESET_GPIO_FAIL; 220 } else { 221 ret = TSF_RETURN; 222 } 223 return ret; 224 } 225 226 /** 227 * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync 228 * @hdd_ctx: pointer to hdd context 229 * 230 * This function check GPIO and set GPIO as IRQ to FW side on 231 * none Adrastea arch 232 * 233 * Return: QDF_STATUS_SUCCESS on Success, others on Failure. 234 */ 235 static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) 236 { 237 QDF_STATUS status; 238 uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID; 239 240 status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin); 241 if (QDF_IS_STATUS_ERROR(status)) 242 return QDF_STATUS_E_INVAL; 243 244 if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID) 245 return QDF_STATUS_E_INVAL; 246 247 status = sme_set_tsf_gpio(hdd_ctx->mac_handle, 248 tsf_gpio_pin); 249 250 return status; 251 } 252 #endif 253 254 #ifdef WLAN_FEATURE_TSF_PLUS 255 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) 256 { 257 uint32_t tsf_ptp_options; 258 259 if (hdd && QDF_IS_STATUS_SUCCESS( 260 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 261 return !!tsf_ptp_options; 262 else 263 return false; 264 } 265 266 bool hdd_tsf_is_tx_set(struct hdd_context *hdd) 267 { 268 uint32_t tsf_ptp_options; 269 270 if (hdd && QDF_IS_STATUS_SUCCESS( 271 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 272 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TX; 273 else 274 return false; 275 } 276 277 bool hdd_tsf_is_rx_set(struct hdd_context *hdd) 278 { 279 uint32_t tsf_ptp_options; 280 281 if (hdd && QDF_IS_STATUS_SUCCESS( 282 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 283 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RX; 284 else 285 return false; 286 } 287 288 bool hdd_tsf_is_raw_set(struct hdd_context *hdd) 289 { 290 uint32_t tsf_ptp_options; 291 292 if (hdd && QDF_IS_STATUS_SUCCESS( 293 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 294 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RAW; 295 else 296 return false; 297 } 298 299 bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd) 300 { 301 uint32_t tsf_ptp_options; 302 303 if (hdd && QDF_IS_STATUS_SUCCESS( 304 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 305 return tsf_ptp_options & CFG_SET_TSF_DBG_FS; 306 else 307 return false; 308 } 309 310 bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd) 311 { 312 uint32_t tsf_ptp_options; 313 314 if (hdd && QDF_IS_STATUS_SUCCESS( 315 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) 316 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TSF64_TX; 317 else 318 return false; 319 } 320 321 static bool hdd_is_tsf_sync_enabled(struct hdd_context *hdd) 322 { 323 bool is_tsf_sync_enable; 324 325 if (hdd && QDF_IS_STATUS_SUCCESS( 326 ucfg_fwol_get_tsf_sync_enable(hdd->psoc, &is_tsf_sync_enable))) 327 return is_tsf_sync_enable; 328 else 329 return false; 330 } 331 332 void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter) 333 { 334 adapter->enable_dynamic_tsf_sync = 335 hdd_is_tsf_sync_enabled(adapter->hdd_ctx); 336 } 337 #else 338 339 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) 340 { 341 return false; 342 } 343 #endif 344 345 #ifdef WLAN_FEATURE_TSF_PLUS 346 static inline 347 uint64_t hdd_get_monotonic_host_time(struct hdd_context *hdd_ctx) 348 { 349 return hdd_tsf_is_raw_set(hdd_ctx) ? 350 ktime_get_ns() : ktime_get_real_ns(); 351 } 352 #endif 353 354 #if defined(WLAN_FEATURE_TSF_PLUS) && \ 355 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) 356 #define MAX_CONTINUOUS_RETRY_CNT 10 357 static uint32_t 358 hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter) 359 { 360 struct hdd_context *hddctx; 361 int count = adapter->continuous_cap_retry_count; 362 363 hddctx = WLAN_HDD_GET_CTX(adapter); 364 if (count == MAX_CONTINUOUS_RETRY_CNT) { 365 hdd_debug("Max retry count reached"); 366 return 0; 367 } 368 qdf_atomic_set(&hddctx->cap_tsf_flag, 0); 369 count++; 370 adapter->continuous_cap_retry_count = count; 371 return (count * WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS); 372 } 373 374 static void 375 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter) 376 { 377 struct hdd_context *hddctx; 378 int count = adapter->continuous_cap_retry_count; 379 380 hddctx = WLAN_HDD_GET_CTX(adapter); 381 if (count == MAX_CONTINUOUS_RETRY_CNT) { 382 hdd_debug("Restart TSF CAP"); 383 qdf_atomic_set(&hddctx->cap_tsf_flag, 0); 384 adapter->continuous_cap_retry_count = 0; 385 qdf_mc_timer_start(&adapter->host_target_sync_timer, 386 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS); 387 } 388 } 389 390 static void 391 hdd_update_host_time(struct hdd_adapter *adapter) 392 { 393 struct hdd_context *hdd_ctx; 394 u64 host_time; 395 char *name = NULL; 396 397 hdd_ctx = adapter->hdd_ctx; 398 399 if (!hdd_tsf_is_initialized(adapter)) { 400 hdd_err("tsf is not init, exit"); 401 return; 402 } 403 404 host_time = hdd_get_monotonic_host_time(hdd_ctx); 405 hdd_update_timestamp(adapter, 0, host_time); 406 name = adapter->dev->name; 407 408 hdd_debug("iface: %s - host_time: %llu", 409 (!name ? "none" : name), host_time); 410 } 411 412 static 413 void hdd_tsf_ext_gpio_sync_work(void *data) 414 { 415 QDF_STATUS status; 416 struct hdd_adapter *adapter; 417 struct hdd_context *hdd_ctx; 418 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; 419 420 adapter = data; 421 hdd_ctx = adapter->hdd_ctx; 422 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, 423 &tsf_sync_gpio_pin); 424 if (QDF_IS_STATUS_ERROR(status)) { 425 hdd_err("tsf sync gpio host pin error"); 426 return; 427 } 428 gpio_set_value(tsf_sync_gpio_pin, OUTPUT_HIGH); 429 hdd_update_host_time(adapter); 430 usleep_range(50, 100); 431 gpio_set_value(tsf_sync_gpio_pin, OUTPUT_LOW); 432 433 status = wma_cli_set_command((int)adapter->vdev_id, 434 (int)GEN_PARAM_CAPTURE_TSF, 435 adapter->vdev_id, GEN_CMD); 436 if (status != QDF_STATUS_SUCCESS) { 437 hdd_err("cap tsf fail"); 438 qdf_mc_timer_stop(&adapter->host_capture_req_timer); 439 qdf_mc_timer_destroy(&adapter->host_capture_req_timer); 440 } 441 } 442 443 static void 444 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter) 445 { 446 qdf_create_work(0, &adapter->gpio_tsf_sync_work, 447 hdd_tsf_ext_gpio_sync_work, adapter); 448 } 449 450 static void 451 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter) 452 { 453 qdf_destroy_work(0, &adapter->gpio_tsf_sync_work); 454 } 455 456 static void 457 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter) 458 { 459 qdf_cancel_work(&adapter->gpio_tsf_sync_work); 460 } 461 462 static void 463 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter) 464 { 465 qdf_sched_work(0, &adapter->gpio_tsf_sync_work); 466 } 467 468 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) 469 { 470 hdd_tsf_start_ext_gpio_sync(adapter); 471 return true; 472 } 473 #elif defined(WLAN_FEATURE_TSF_PLUS) && \ 474 !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) 475 static void 476 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter) 477 { 478 } 479 480 static void 481 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter) 482 { 483 } 484 485 static void 486 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter) 487 { 488 } 489 490 static void 491 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter) 492 { 493 } 494 495 static void 496 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter) 497 { 498 } 499 500 static bool 501 hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) 502 { 503 hdd_tsf_start_ext_gpio_sync(adapter); 504 return false; 505 } 506 507 #else 508 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) 509 { 510 return false; 511 } 512 #endif 513 514 #ifdef WLAN_FEATURE_TSF_TIMER_SYNC 515 /** 516 * hdd_convert_qtime_to_us() - convert qtime to us 517 * @time: QTIMER ticks for adrastea and us for Lithium 518 * 519 * This function converts qtime to us. 520 * 521 * Return: Time in microseconds 522 */ 523 static inline uint64_t 524 hdd_convert_qtime_to_us(uint64_t time) 525 { 526 return time; 527 } 528 529 #else 530 static inline uint64_t 531 hdd_convert_qtime_to_us(uint64_t time) 532 { 533 return qdf_log_timestamp_to_usecs(time); 534 } 535 #endif 536 537 /** 538 * hdd_capture_tsf_internal_via_wmi() - convert qtime to us 539 * @adapter: pointer to adapter 540 * @buf: in case of failure update with fail 541 * @len: buffer length 542 * 543 * Return: result of tsf operation 544 */ 545 static enum hdd_tsf_op_result 546 hdd_capture_tsf_internal_via_wmi(struct hdd_adapter *adapter, uint32_t *buf, 547 int len) 548 { 549 int ret; 550 struct hdd_context *hddctx = adapter->hdd_ctx; 551 552 ret = wma_cli_set_command((int)adapter->vdev_id, 553 (int)GEN_PARAM_CAPTURE_TSF, 554 adapter->vdev_id, GEN_CMD); 555 if (ret != QDF_STATUS_SUCCESS) { 556 hdd_err("cap tsf fail"); 557 buf[0] = TSF_CAPTURE_FAIL; 558 hddctx->cap_tsf_context = NULL; 559 qdf_atomic_set(&hddctx->cap_tsf_flag, 0); 560 qdf_mc_timer_stop(&adapter->host_capture_req_timer); 561 qdf_mc_timer_destroy(&adapter->host_capture_req_timer); 562 } 563 return HDD_TSF_OP_SUCC; 564 } 565 566 #ifndef QCA_GET_TSF_VIA_REG 567 static inline 568 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter, 569 uint32_t *buf, int len) 570 { 571 return hdd_capture_tsf_internal_via_wmi(adapter, buf, len); 572 } 573 574 static inline void wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, 575 struct stsf *ptsf) 576 { 577 } 578 #else 579 580 static inline int hdd_tsf_reg_is_details_valid(struct hdd_adapter *adapter) 581 { 582 return qdf_atomic_read(&adapter->tsf_details_valid); 583 } 584 585 static inline void 586 wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, struct stsf *ptsf) 587 { 588 if (!qdf_atomic_read(&adapter->tsf_details_valid)) { 589 if (ptsf->tsf_id_valid) { 590 adapter->tsf_id = ptsf->tsf_id; 591 adapter->tsf_mac_id = ptsf->mac_id; 592 qdf_atomic_set(&adapter->tsf_details_valid, 1); 593 } 594 } 595 hdd_info("tsf_id %u tsf_id_valid %u mac_id %u mac_id_valid %u", 596 ptsf->tsf_id, ptsf->tsf_id_valid, ptsf->mac_id, 597 ptsf->mac_id_valid); 598 } 599 600 static inline 601 QDF_STATUS wlan_hdd_tsf_reg_get(struct hdd_adapter *adapter, 602 struct hdd_tsf_report *tsf_report) 603 { 604 ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); 605 uint64_t tsf_time = 0; 606 uint64_t tsf_sync_soc_time = 0; 607 608 if (qdf_unlikely(!soc)) 609 return QDF_STATUS_E_INVAL; 610 611 cdp_get_tsf_time(soc, tsf_report->tsf_id, tsf_report->mac_id, 612 &tsf_time, &tsf_sync_soc_time); 613 614 /* fill in the report */ 615 tsf_report->tsf = tsf_time; 616 tsf_report->tsf_sync_soc_time = tsf_sync_soc_time; 617 return QDF_STATUS_SUCCESS; 618 } 619 620 /** 621 * wlan_hdd_tsf_reg_process_report() - Process tsf report 622 * @adapter: pointer to the adapter 623 * @tsf_report: pointer to tsf report 624 * 625 * This function process the tsf report received and update tsf 626 * value received via scratch register read to adapter 627 * 628 * Return: 0 for success or 1 in case of failure 629 */ 630 static enum hdd_tsf_op_result 631 wlan_hdd_tsf_reg_process_report(struct hdd_adapter *adapter, 632 struct hdd_tsf_report *tsf_report) 633 { 634 QDF_STATUS status; 635 QDF_TIMER_STATE capture_req_timer_status; 636 qdf_mc_timer_t *capture_timer; 637 638 if (!tsf_report->tsf && !tsf_report->tsf_sync_soc_time) { 639 hdd_err("Invalid TSF report"); 640 return HDD_TSF_OP_FAIL; 641 } 642 643 if (!hdd_tsf_is_initialized(adapter)) { 644 hdd_err("tsf is not init, ignore tsf event"); 645 return HDD_TSF_OP_FAIL; 646 } 647 648 hdd_info("device_mode is %d", adapter->device_mode); 649 650 capture_timer = &adapter->host_capture_req_timer; 651 capture_req_timer_status = 652 qdf_mc_timer_get_current_state(capture_timer); 653 if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { 654 hdd_warn("invalid timer status"); 655 return HDD_TSF_OP_FAIL; 656 } 657 658 qdf_mc_timer_stop(capture_timer); 659 status = qdf_mc_timer_destroy(capture_timer); 660 if (status != QDF_STATUS_SUCCESS) 661 hdd_warn("destroy cap req timer fail, ret: %d", status); 662 663 adapter->cur_target_time = tsf_report->tsf; 664 adapter->cur_tsf_sync_soc_time = tsf_report->tsf_sync_soc_time * 665 NSEC_PER_USEC; 666 667 qdf_event_set(&tsf_sync_get_completion_evt); 668 hdd_update_tsf(adapter, adapter->cur_target_time); 669 hdd_info("vdev id=%u, tsf=%llu", adapter->vdev_id, tsf_report->tsf); 670 return HDD_TSF_OP_SUCC; 671 } 672 673 static enum hdd_tsf_op_result 674 hdd_capture_tsf_internal_via_reg(struct hdd_adapter *adapter, uint32_t *buf, 675 int len) 676 { 677 struct hdd_tsf_report tsf_report; 678 679 if (!hdd_tsf_reg_is_details_valid(adapter)) { 680 hdd_warn("TSF reg details are not valid!"); 681 return HDD_TSF_OP_FAIL; 682 } 683 684 qdf_mem_zero(&tsf_report, sizeof(tsf_report)); 685 tsf_report.vdev_id = adapter->vdev_id; 686 tsf_report.tsf_id = adapter->tsf_id; 687 tsf_report.mac_id = adapter->tsf_mac_id; 688 689 if (wlan_hdd_tsf_reg_get(adapter, &tsf_report)) { 690 hdd_warn("Unable to get tsf report"); 691 return HDD_TSF_OP_FAIL; 692 } 693 694 return wlan_hdd_tsf_reg_process_report(adapter, &tsf_report); 695 } 696 697 static inline 698 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter, 699 uint32_t *buf, int len) 700 { 701 if (!qdf_atomic_read(&adapter->tsf_details_valid)) 702 return hdd_capture_tsf_internal_via_wmi(adapter, buf, len); 703 else 704 return hdd_capture_tsf_internal_via_reg(adapter, buf, len); 705 } 706 707 #endif /* QCA_GET_TSF_VIA_REG */ 708 709 static enum hdd_tsf_op_result hdd_capture_tsf_internal( 710 struct hdd_adapter *adapter, uint32_t *buf, int len) 711 { 712 enum hdd_tsf_op_result ret; 713 struct hdd_context *hddctx; 714 qdf_mc_timer_t *cap_timer; 715 716 if (!adapter || !buf) { 717 hdd_err("invalid pointer"); 718 return HDD_TSF_OP_FAIL; 719 } 720 721 if (len != 1) 722 return HDD_TSF_OP_FAIL; 723 724 hddctx = WLAN_HDD_GET_CTX(adapter); 725 if (!hddctx) { 726 hdd_err("invalid hdd context"); 727 return HDD_TSF_OP_FAIL; 728 } 729 730 if (wlan_hdd_validate_context(hddctx)) { 731 hdd_err("hdd context validation failed"); 732 return HDD_TSF_OP_FAIL; 733 } 734 735 if (!hdd_tsf_is_initialized(adapter)) { 736 buf[0] = TSF_NOT_READY; 737 return HDD_TSF_OP_SUCC; 738 } 739 740 buf[0] = hdd_tsf_check_conn_state(adapter); 741 if (buf[0] != TSF_RETURN) 742 return HDD_TSF_OP_SUCC; 743 744 if (qdf_atomic_inc_return(&hddctx->cap_tsf_flag) > 1) { 745 hdd_err("current in capture state"); 746 buf[0] = TSF_CURRENT_IN_CAP_STATE; 747 return HDD_TSF_OP_SUCC; 748 } 749 750 /* record adapter for cap_tsf_irq_handler */ 751 hddctx->cap_tsf_context = adapter; 752 753 hdd_info("+ioctl issue cap tsf cmd"); 754 cap_timer = &adapter->host_capture_req_timer; 755 qdf_mc_timer_init(cap_timer, QDF_TIMER_TYPE_SW, 756 hdd_capture_req_timer_expired_handler, 757 (void *)adapter); 758 qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS); 759 760 /* Reset TSF value for new capture */ 761 adapter->cur_target_time = 0; 762 763 buf[0] = TSF_RETURN; 764 765 if (hdd_tsf_cap_sync_send(adapter)) 766 return HDD_TSF_OP_SUCC; 767 768 ret = _hdd_capture_tsf_internal(adapter, buf, len); 769 hdd_info("-ioctl return cap tsf cmd"); 770 771 return ret; 772 } 773 774 static enum hdd_tsf_op_result hdd_indicate_tsf_internal( 775 struct hdd_adapter *adapter, struct hdd_tsf_op_response *tsf_op_resp) 776 { 777 int ret; 778 struct hdd_context *hddctx; 779 780 if (!adapter || !tsf_op_resp) { 781 hdd_err("invalid pointer"); 782 return HDD_TSF_OP_FAIL; 783 } 784 785 hddctx = WLAN_HDD_GET_CTX(adapter); 786 if (!hddctx) { 787 hdd_err("invalid hdd context"); 788 return HDD_TSF_OP_FAIL; 789 } 790 791 memset(tsf_op_resp, 0, sizeof(*tsf_op_resp)); 792 if (!hdd_tsf_is_initialized(adapter)) { 793 tsf_op_resp->status = TSF_NOT_READY; 794 return HDD_TSF_OP_SUCC; 795 } 796 797 tsf_op_resp->status = hdd_tsf_check_conn_state(adapter); 798 if (tsf_op_resp->status != TSF_RETURN) 799 return HDD_TSF_OP_SUCC; 800 801 if (adapter->cur_target_time == 0) { 802 hdd_info("TSF value not received"); 803 tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW; 804 return HDD_TSF_OP_SUCC; 805 } 806 807 tsf_op_resp->status = TSF_RETURN; 808 tsf_op_resp->time = adapter->cur_target_time; 809 tsf_op_resp->soc_time = adapter->cur_tsf_sync_soc_time; 810 811 if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) { 812 hdd_info("old: status=%u, tsf_time=%llu, tsf_soc_time=%llu", 813 tsf_op_resp->status, 814 tsf_op_resp->time, 815 tsf_op_resp->soc_time); 816 return HDD_TSF_OP_SUCC; 817 } 818 819 ret = hdd_tsf_reset_gpio(adapter); 820 if (0 != ret) { 821 hdd_err("reset tsf gpio fail"); 822 tsf_op_resp->status = TSF_RESET_GPIO_FAIL; 823 return HDD_TSF_OP_SUCC; 824 } 825 hddctx->cap_tsf_context = NULL; 826 qdf_atomic_set(&hddctx->cap_tsf_flag, 0); 827 hdd_info("get tsf cmd,status=%u, tsf_time=%llu, tsf_soc_time=%llu", 828 tsf_op_resp->status, 829 tsf_op_resp->time, 830 tsf_op_resp->soc_time); 831 832 return HDD_TSF_OP_SUCC; 833 } 834 835 #ifdef WLAN_FEATURE_TSF_PLUS 836 /* unit for target time: us; host time: ns */ 837 #define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC 838 #define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC) 839 #define MAX_CONTINUOUS_ERROR_CNT 3 840 841 /* to distinguish 32-bit overflow case, this interval should: 842 * equal or less than (1/2 * OVERFLOW_INDICATOR32 us) 843 */ 844 #if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \ 845 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) 846 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2 847 #else 848 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 4 849 #endif 850 #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32) 851 #define CAP_TSF_TIMER_FIX_SEC 1 852 853 /** 854 * TS_STATUS - timestamp status 855 * 856 * HDD_TS_STATUS_WAITING: one of the stamp-pair 857 * is not updated 858 * HDD_TS_STATUS_READY: valid tstamp-pair 859 * HDD_TS_STATUS_INVALID: invalid tstamp-pair 860 */ 861 enum hdd_ts_status { 862 HDD_TS_STATUS_WAITING, 863 HDD_TS_STATUS_READY, 864 HDD_TS_STATUS_INVALID 865 }; 866 867 static 868 enum hdd_tsf_op_result __hdd_start_tsf_sync(struct hdd_adapter *adapter) 869 { 870 QDF_STATUS ret; 871 872 if (!hdd_get_th_sync_status(adapter)) { 873 hdd_err("Host Target sync has not initialized"); 874 return HDD_TSF_OP_FAIL; 875 } 876 877 hdd_tsf_gpio_sync_work_init(adapter); 878 ret = qdf_mc_timer_start(&adapter->host_target_sync_timer, 879 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS); 880 if (ret != QDF_STATUS_SUCCESS && ret != QDF_STATUS_E_ALREADY) { 881 hdd_err("Failed to start timer, ret: %d", ret); 882 return HDD_TSF_OP_FAIL; 883 } 884 return HDD_TSF_OP_SUCC; 885 } 886 887 static 888 enum hdd_tsf_op_result __hdd_stop_tsf_sync(struct hdd_adapter *adapter) 889 { 890 QDF_STATUS ret; 891 struct hdd_context *hdd_ctx; 892 893 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 894 if (!hdd_ctx) { 895 hdd_err("invalid hdd context"); 896 return HDD_TSF_OP_FAIL; 897 } 898 899 if (!hdd_get_th_sync_status(adapter)) { 900 hdd_err("Host Target sync has not initialized"); 901 return HDD_TSF_OP_SUCC; 902 } 903 904 ret = qdf_mc_timer_stop(&adapter->host_target_sync_timer); 905 if (ret != QDF_STATUS_SUCCESS) { 906 hdd_err("Failed to stop timer, ret: %d", ret); 907 return HDD_TSF_OP_FAIL; 908 } 909 hdd_tsf_stop_ext_gpio_sync(adapter); 910 hdd_tsf_gpio_sync_work_deinit(adapter); 911 return HDD_TSF_OP_SUCC; 912 } 913 914 static inline void hdd_reset_timestamps(struct hdd_adapter *adapter) 915 { 916 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 917 adapter->cur_host_time = 0; 918 adapter->cur_target_time = 0; 919 adapter->last_host_time = 0; 920 adapter->last_target_time = 0; 921 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 922 } 923 924 /** 925 * hdd_check_timestamp_status() - return the tstamp status 926 * 927 * @last_target_time: the last saved target time 928 * @last_sync_time: the last saved sync time 929 * @cur_target_time : new target time 930 * @cur_sync_time : new sync time 931 * 932 * This function check the new timstamp-pair(cur_host_time/cur_target_time)or 933 * (cur_qtime_time/cur_target_time) 934 * Return: 935 * HDD_TS_STATUS_WAITING: cur_sync_time or cur_sync_time is 0 936 * HDD_TS_STATUS_READY: cur_target_time/cur_host_time is a valid pair, 937 * and can be saved 938 * HDD_TS_STATUS_INVALID: cur_target_time/cur_sync_time is a invalid pair, 939 * should be discard 940 */ 941 static 942 enum hdd_ts_status hdd_check_timestamp_status( 943 uint64_t last_target_time, 944 uint64_t last_sync_time, 945 uint64_t cur_target_time, 946 uint64_t cur_sync_time) 947 { 948 uint64_t delta_ns, delta_target_time, delta_sync_time; 949 950 /* one or more are not updated, need to wait */ 951 if (cur_target_time == 0 || cur_sync_time == 0) 952 return HDD_TS_STATUS_WAITING; 953 954 /* init value, it's the first time to update the pair */ 955 if (last_target_time == 0 && last_sync_time == 0) 956 return HDD_TS_STATUS_READY; 957 958 /* the new values should be greater than the saved values */ 959 if ((cur_target_time <= last_target_time) || 960 (cur_sync_time <= last_sync_time)) { 961 hdd_err("Invalid timestamps!last_target_time: %llu;" 962 "last_sync_time: %llu; cur_target_time: %llu;" 963 "cur_sync_time: %llu", 964 last_target_time, last_sync_time, 965 cur_target_time, cur_sync_time); 966 return HDD_TS_STATUS_INVALID; 967 } 968 969 delta_target_time = (cur_target_time - last_target_time) * 970 NSEC_PER_USEC; 971 delta_sync_time = cur_sync_time - last_sync_time; 972 973 /* 974 * DO NOT use abs64() , a big uint64 value might be turned to 975 * a small int64 value 976 */ 977 delta_ns = ((delta_target_time > delta_sync_time) ? 978 (delta_target_time - delta_sync_time) : 979 (delta_sync_time - delta_target_time)); 980 hdd_warn("timestamps deviation - delta: %llu ns", delta_ns); 981 /* the deviation should be smaller than a threshold */ 982 if (delta_ns > MAX_ALLOWED_DEVIATION_NS) { 983 hdd_warn("Invalid timestamps - delta: %llu ns", delta_ns); 984 return HDD_TS_STATUS_INVALID; 985 } 986 return HDD_TS_STATUS_READY; 987 } 988 989 static inline bool hdd_tsf_is_in_cap(struct hdd_adapter *adapter) 990 { 991 struct hdd_context *hddctx; 992 993 hddctx = WLAN_HDD_GET_CTX(adapter); 994 if (!hddctx) 995 return false; 996 997 return qdf_atomic_read(&hddctx->cap_tsf_flag) > 0; 998 } 999 1000 /* define 64bit plus/minus to deal with overflow */ 1001 static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret) 1002 { 1003 if ((y < 0 && (-y) > x) || 1004 (y > 0 && (y > U64_MAX - x))) { 1005 *ret = 0; 1006 return -EINVAL; 1007 } 1008 1009 *ret = x + y; 1010 return 0; 1011 } 1012 1013 static inline int hdd_uint64_plus(uint64_t x, uint64_t y, uint64_t *ret) 1014 { 1015 if (!ret) 1016 return -EINVAL; 1017 1018 if (x > (U64_MAX - y)) { 1019 *ret = 0; 1020 return -EINVAL; 1021 } 1022 1023 *ret = x + y; 1024 return 0; 1025 } 1026 1027 static inline int hdd_uint64_minus(uint64_t x, uint64_t y, uint64_t *ret) 1028 { 1029 if (!ret) 1030 return -EINVAL; 1031 1032 if (x < y) { 1033 *ret = 0; 1034 return -EINVAL; 1035 } 1036 1037 *ret = x - y; 1038 return 0; 1039 } 1040 1041 static inline int32_t hdd_get_hosttime_from_targettime( 1042 struct hdd_adapter *adapter, uint64_t target_time, 1043 uint64_t *host_time) 1044 { 1045 int32_t ret = -EINVAL; 1046 int64_t delta32_target; 1047 bool in_cap_state; 1048 int64_t normal_interval_target; 1049 1050 in_cap_state = hdd_tsf_is_in_cap(adapter); 1051 1052 /* 1053 * To avoid check the lock when it's not capturing tsf 1054 * (the tstamp-pair won't be changed) 1055 */ 1056 if (in_cap_state) 1057 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1058 1059 hdd_wlan_restart_tsf_cap(adapter); 1060 /* at present, target_time is only 32bit in fact */ 1061 delta32_target = (int64_t)((target_time & U32_MAX) - 1062 (adapter->last_target_time & U32_MAX)); 1063 1064 normal_interval_target = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC * 1065 qdf_do_div(NSEC_PER_SEC, HOST_TO_TARGET_TIME_RATIO); 1066 1067 if (delta32_target < 1068 (normal_interval_target - OVERFLOW_INDICATOR32)) 1069 delta32_target += OVERFLOW_INDICATOR32; 1070 else if (delta32_target > 1071 (OVERFLOW_INDICATOR32 - normal_interval_target)) 1072 delta32_target -= OVERFLOW_INDICATOR32; 1073 1074 ret = hdd_64bit_plus(adapter->last_host_time, 1075 HOST_TO_TARGET_TIME_RATIO * delta32_target, 1076 host_time); 1077 1078 if (in_cap_state) 1079 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1080 1081 return ret; 1082 } 1083 1084 static inline int32_t hdd_get_targettime_from_hosttime( 1085 struct hdd_adapter *adapter, uint64_t host_time, 1086 uint64_t *target_time) 1087 { 1088 int32_t ret = -EINVAL; 1089 bool in_cap_state; 1090 1091 if (!adapter || host_time == 0) 1092 return ret; 1093 1094 in_cap_state = hdd_tsf_is_in_cap(adapter); 1095 if (in_cap_state) 1096 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1097 1098 if (host_time < adapter->last_host_time) 1099 ret = hdd_uint64_minus(adapter->last_target_time, 1100 qdf_do_div(adapter->last_host_time - 1101 host_time, 1102 HOST_TO_TARGET_TIME_RATIO), 1103 target_time); 1104 else 1105 ret = hdd_uint64_plus(adapter->last_target_time, 1106 qdf_do_div(host_time - 1107 adapter->last_host_time, 1108 HOST_TO_TARGET_TIME_RATIO), 1109 target_time); 1110 1111 if (in_cap_state) 1112 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1113 1114 return ret; 1115 } 1116 1117 /** 1118 * hdd_get_soctime_from_tsf64time() - return get status 1119 * 1120 * @adapter: Adapter pointer 1121 * @tsf64_time: current tsf64time, us 1122 * @soc_time: current soc time(qtime), ns 1123 * 1124 * This function get current soc time from current tsf64 time 1125 * Returun int32_t value to tell get success or fail. 1126 * 1127 * Return: 1128 * 0: success 1129 * other: fail 1130 * 1131 */ 1132 static inline int32_t hdd_get_soctime_from_tsf64time( 1133 struct hdd_adapter *adapter, uint64_t tsf64_time, 1134 uint64_t *soc_time) 1135 { 1136 int32_t ret = -EINVAL; 1137 uint64_t delta64_tsf64time; 1138 uint64_t delta64_soctime; 1139 bool in_cap_state; 1140 1141 in_cap_state = hdd_tsf_is_in_cap(adapter); 1142 1143 /* 1144 * To avoid check the lock when it's not capturing tsf 1145 * (the tstamp-pair won't be changed) 1146 */ 1147 if (in_cap_state) 1148 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1149 1150 /* at present, target_time is 64bit (g_tsf64), us*/ 1151 if (tsf64_time > adapter->last_target_global_tsf_time) { 1152 delta64_tsf64time = tsf64_time - 1153 adapter->last_target_global_tsf_time; 1154 delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; 1155 1156 /* soc_time (ns)*/ 1157 ret = hdd_uint64_plus(adapter->last_tsf_sync_soc_time, 1158 delta64_soctime, soc_time); 1159 } else { 1160 delta64_tsf64time = adapter->last_target_global_tsf_time - 1161 tsf64_time; 1162 delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; 1163 1164 /* soc_time (ns)*/ 1165 ret = hdd_uint64_minus(adapter->last_tsf_sync_soc_time, 1166 delta64_soctime, soc_time); 1167 } 1168 1169 if (in_cap_state) 1170 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1171 1172 return ret; 1173 } 1174 1175 /** 1176 * hdd_get_tsftime_from_qtime() 1177 * 1178 * @adapter: Adapter pointer 1179 * @qtime: current qtime, us 1180 * @tsf_sync_qtime: qtime of the tsf, us 1181 * @tsf_time: current tsf time(qtime), us 1182 * 1183 * This function determines current tsf time 1184 * using current qtime 1185 * 1186 * Return: 0 for success or non-zero negative failure code 1187 */ 1188 static inline int32_t 1189 hdd_get_tsftime_from_qtime(struct hdd_adapter *adapter, uint64_t qtime, 1190 uint64_t tsf_sync_qtime, uint64_t *tsf_time) 1191 { 1192 int32_t ret = -EINVAL; 1193 uint64_t delta64_tsf64time; 1194 bool in_cap_state; 1195 1196 in_cap_state = hdd_tsf_is_in_cap(adapter); 1197 1198 /* 1199 * To avoid check the lock when it's not capturing tsf 1200 * (the tstamp-pair won't be changed) 1201 */ 1202 if (in_cap_state) 1203 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1204 1205 if (qtime > tsf_sync_qtime) { 1206 delta64_tsf64time = qtime - tsf_sync_qtime; 1207 ret = hdd_uint64_plus(adapter->last_target_time, 1208 delta64_tsf64time, tsf_time); 1209 } else { 1210 delta64_tsf64time = tsf_sync_qtime - qtime; 1211 ret = hdd_uint64_minus(adapter->last_target_time, 1212 delta64_tsf64time, tsf_time); 1213 } 1214 1215 if (in_cap_state) 1216 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1217 1218 return ret; 1219 } 1220 1221 QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time, 1222 uint64_t *tsf_time) 1223 { 1224 struct hdd_adapter *adapter; 1225 uint64_t tsf_sync_qtime, qtime; 1226 1227 /* Sanity check on inputs */ 1228 if (unlikely((!adapter_ctx) || (!input_time))) { 1229 hdd_err("Invalid param passed"); 1230 return QDF_STATUS_E_FAILURE; 1231 } 1232 1233 adapter = (struct hdd_adapter *)adapter_ctx; 1234 if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { 1235 hdd_err("Magic cookie(%x) for adapter sanity verification is invalid", 1236 adapter->magic); 1237 return QDF_STATUS_E_FAILURE; 1238 } 1239 1240 tsf_sync_qtime = adapter->last_tsf_sync_soc_time; 1241 tsf_sync_qtime = qdf_do_div(tsf_sync_qtime, NSEC_PER_USEC); 1242 1243 qtime = qdf_log_timestamp_to_usecs(input_time); 1244 hdd_get_tsftime_from_qtime(adapter, qtime, tsf_sync_qtime, tsf_time); 1245 return QDF_STATUS_SUCCESS; 1246 } 1247 1248 static void hdd_capture_tsf_timer_expired_handler(void *arg) 1249 { 1250 uint32_t tsf_op_resp; 1251 struct hdd_adapter *adapter; 1252 1253 if (!arg) 1254 return; 1255 1256 adapter = (struct hdd_adapter *)arg; 1257 hdd_capture_tsf_internal(adapter, &tsf_op_resp, 1); 1258 } 1259 1260 #ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ 1261 #if !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \ 1262 !defined(WLAN_FEATURE_TSF_TIMER_SYNC) 1263 1264 static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg) 1265 { 1266 struct hdd_adapter *adapter; 1267 struct hdd_context *hdd_ctx; 1268 uint64_t host_time; 1269 char *name = NULL; 1270 1271 if (!arg) 1272 return IRQ_NONE; 1273 1274 if (irq != tsf_gpio_irq_num) 1275 return IRQ_NONE; 1276 1277 hdd_ctx = (struct hdd_context *)arg; 1278 host_time = hdd_get_monotonic_host_time(hdd_ctx); 1279 1280 adapter = hdd_ctx->cap_tsf_context; 1281 if (!adapter) 1282 return IRQ_HANDLED; 1283 1284 if (!hdd_tsf_is_initialized(adapter)) { 1285 hdd_err("tsf is not init, ignore irq"); 1286 return IRQ_HANDLED; 1287 } 1288 1289 hdd_update_timestamp(adapter, 0, host_time); 1290 if (adapter->dev) 1291 name = adapter->dev->name; 1292 1293 hdd_info("irq: %d - iface: %s - host_time: %llu", 1294 irq, (!name ? "none" : name), host_time); 1295 1296 return IRQ_HANDLED; 1297 } 1298 #endif 1299 #endif 1300 1301 void hdd_capture_req_timer_expired_handler(void *arg) 1302 { 1303 struct hdd_adapter *adapter; 1304 struct hdd_context *hdd_ctx; 1305 QDF_TIMER_STATE capture_req_timer_status; 1306 qdf_mc_timer_t *sync_timer; 1307 int interval; 1308 int ret; 1309 1310 if (!arg) 1311 return; 1312 adapter = (struct hdd_adapter *)arg; 1313 1314 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1315 if (!hdd_ctx) { 1316 hdd_warn("invalid hdd context"); 1317 return; 1318 } 1319 1320 if (!hdd_tsf_is_initialized(adapter)) { 1321 qdf_mc_timer_destroy(&adapter->host_capture_req_timer); 1322 hdd_warn("tsf not init"); 1323 return; 1324 } 1325 1326 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1327 adapter->cur_host_time = 0; 1328 adapter->cur_target_time = 0; 1329 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1330 1331 ret = hdd_tsf_reset_gpio(adapter); 1332 if (0 != ret) 1333 hdd_info("reset tsf gpio fail"); 1334 1335 hdd_ctx->cap_tsf_context = NULL; 1336 qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0); 1337 qdf_mc_timer_destroy(&adapter->host_capture_req_timer); 1338 1339 sync_timer = &adapter->host_target_sync_timer; 1340 capture_req_timer_status = 1341 qdf_mc_timer_get_current_state(sync_timer); 1342 1343 if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { 1344 hdd_warn("invalid timer status"); 1345 return; 1346 } 1347 1348 interval = WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL * MSEC_PER_SEC; 1349 qdf_mc_timer_start(sync_timer, interval); 1350 } 1351 1352 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \ 1353 defined(WLAN_FEATURE_TSF_TIMER_SYNC) 1354 static void hdd_update_timestamp(struct hdd_adapter *adapter) 1355 { 1356 int interval = 0; 1357 enum hdd_ts_status sync_status; 1358 1359 if (!adapter) 1360 return; 1361 1362 /* on ADREASTEA ach, Qtime is used to sync host and tsf time as a 1363 * intermedia there is no IRQ to sync up TSF-HOST, so host time in ns 1364 * and target in us will be updated at the same time in WMI command 1365 * callback 1366 */ 1367 1368 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1369 sync_status = 1370 hdd_check_timestamp_status(adapter->last_target_time, 1371 adapter->last_tsf_sync_soc_time, 1372 adapter->cur_target_time, 1373 adapter->cur_tsf_sync_soc_time); 1374 hdd_info("sync_status %d", sync_status); 1375 switch (sync_status) { 1376 case HDD_TS_STATUS_INVALID: 1377 if (++adapter->continuous_error_count < 1378 MAX_CONTINUOUS_ERROR_CNT) { 1379 interval = 1380 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; 1381 adapter->cur_target_time = 0; 1382 adapter->cur_tsf_sync_soc_time = 0; 1383 break; 1384 } 1385 hdd_warn("Reach the max continuous error count"); 1386 1387 /* If reach MAX_CONTINUOUS_ERROR_CNT, treat it as valid pair */ 1388 fallthrough; 1389 case HDD_TS_STATUS_READY: 1390 adapter->last_target_time = adapter->cur_target_time; 1391 adapter->last_target_global_tsf_time = 1392 adapter->cur_target_global_tsf_time; 1393 adapter->last_tsf_sync_soc_time = 1394 adapter->cur_tsf_sync_soc_time; 1395 adapter->cur_target_time = 0; 1396 adapter->cur_target_global_tsf_time = 0; 1397 adapter->cur_tsf_sync_soc_time = 0; 1398 hdd_info("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu", 1399 adapter->last_target_time, 1400 adapter->last_target_global_tsf_time, 1401 adapter->last_tsf_sync_soc_time); 1402 1403 /* 1404 * TSF-HOST need to be updated in at most 1405 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved 1406 * if the timer interval is also 1407 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or 1408 * schedule delay. So deduct several seconds from 1409 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC. 1410 * Without this change, hdd_get_hosttime_from_targettime() will 1411 * get wrong host time when it's longer than 1412 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last 1413 * TSF-HOST update. 1414 */ 1415 1416 if (adapter->dynamic_tsf_sync_interval) 1417 interval = adapter->dynamic_tsf_sync_interval; 1418 else 1419 interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC - 1420 CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC; 1421 1422 adapter->continuous_error_count = 0; 1423 adapter->continuous_cap_retry_count = 0; 1424 hdd_debug("ts-pair updated: interval: %d", 1425 interval); 1426 break; 1427 case HDD_TS_STATUS_WAITING: 1428 interval = 0; 1429 hdd_warn("TS status is waiting due to one or more pair not updated"); 1430 break; 1431 } 1432 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1433 1434 if (interval > 0) 1435 qdf_mc_timer_start(&adapter->host_target_sync_timer, interval); 1436 } 1437 1438 static ssize_t __hdd_wlan_tsf_show(struct device *dev, 1439 struct device_attribute *attr, char *buf) 1440 { 1441 struct hdd_station_ctx *hdd_sta_ctx; 1442 struct hdd_adapter *adapter; 1443 struct hdd_context *hdd_ctx; 1444 uint64_t tsf_sync_qtime, host_time, reg_qtime, qtime, target_time; 1445 ssize_t size; 1446 1447 struct net_device *net_dev = container_of(dev, struct net_device, dev); 1448 1449 adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); 1450 if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) 1451 return scnprintf(buf, PAGE_SIZE, "Invalid device\n"); 1452 1453 if (!hdd_get_th_sync_status(adapter)) 1454 return scnprintf(buf, PAGE_SIZE, 1455 "TSF sync is not initialized\n"); 1456 1457 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); 1458 if (!hdd_cm_is_vdev_associated(adapter) && 1459 (adapter->device_mode == QDF_STA_MODE || 1460 adapter->device_mode == QDF_P2P_CLIENT_MODE)) 1461 return scnprintf(buf, PAGE_SIZE, "NOT connected\n"); 1462 1463 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1464 1465 if (!hdd_ctx) 1466 return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n"); 1467 1468 tsf_sync_qtime = adapter->last_tsf_sync_soc_time; 1469 do_div(tsf_sync_qtime, NSEC_PER_USEC); 1470 1471 reg_qtime = qdf_get_log_timestamp(); 1472 host_time = hdd_get_monotonic_host_time(hdd_ctx); 1473 1474 qtime = qdf_log_timestamp_to_usecs(reg_qtime); 1475 do_div(host_time, NSEC_PER_USEC); 1476 hdd_get_tsftime_from_qtime(adapter, qtime, tsf_sync_qtime, 1477 &target_time); 1478 1479 if (adapter->device_mode == QDF_STA_MODE || 1480 adapter->device_mode == QDF_P2P_CLIENT_MODE) { 1481 size = scnprintf(buf, PAGE_SIZE, 1482 "%s%llu %llu %pM %llu %llu %llu\n", 1483 buf, adapter->last_target_time, 1484 tsf_sync_qtime, 1485 hdd_sta_ctx->conn_info.bssid.bytes, 1486 qtime, host_time, target_time); 1487 } else { 1488 size = scnprintf(buf, PAGE_SIZE, 1489 "%s%llu %llu %pM %llu %llu %llu\n", 1490 buf, adapter->last_target_time, 1491 tsf_sync_qtime, 1492 adapter->mac_addr.bytes, 1493 qtime, host_time, target_time); 1494 } 1495 1496 return size; 1497 } 1498 1499 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) 1500 { 1501 struct hdd_tsf_op_response tsf_op_resp; 1502 1503 hdd_indicate_tsf_internal(adapter, &tsf_op_resp); 1504 hdd_update_timestamp(adapter); 1505 } 1506 #else 1507 static void hdd_update_timestamp(struct hdd_adapter *adapter, 1508 uint64_t target_time, uint64_t host_time) 1509 { 1510 int interval = 0; 1511 enum hdd_ts_status sync_status; 1512 1513 if (!adapter) 1514 return; 1515 1516 /* host time is updated in IRQ context, it's always before target time, 1517 * and so no need to try update last_host_time at present; 1518 * since the interval of capturing TSF 1519 * (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC) is long enough, host and target 1520 * time are updated in pairs, and one by one, we can return here to 1521 * avoid requiring spin lock, and to speed up the IRQ processing. 1522 */ 1523 if (host_time > 0) 1524 adapter->cur_host_time = host_time; 1525 1526 qdf_spin_lock_bh(&adapter->host_target_sync_lock); 1527 if (target_time > 0) 1528 adapter->cur_target_time = target_time; 1529 1530 sync_status = hdd_check_timestamp_status(adapter->last_target_time, 1531 adapter->last_host_time, 1532 adapter->cur_target_time, 1533 adapter->cur_host_time); 1534 hdd_info("sync_status %d", sync_status); 1535 switch (sync_status) { 1536 case HDD_TS_STATUS_INVALID: 1537 if (++adapter->continuous_error_count < 1538 MAX_CONTINUOUS_ERROR_CNT) { 1539 interval = 1540 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; 1541 adapter->cur_target_time = 0; 1542 adapter->cur_host_time = 0; 1543 break; 1544 } 1545 hdd_warn("Reach the max continuous error count"); 1546 /* 1547 * fall through: 1548 * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a 1549 * valid pair 1550 */ 1551 case HDD_TS_STATUS_READY: 1552 adapter->last_target_time = adapter->cur_target_time; 1553 adapter->last_host_time = adapter->cur_host_time; 1554 adapter->cur_target_time = 0; 1555 adapter->cur_host_time = 0; 1556 hdd_info("ts-pair updated: target: %llu; host: %llu", 1557 adapter->last_target_time, 1558 adapter->last_host_time); 1559 1560 /* 1561 * TSF-HOST need to be updated in at most 1562 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved 1563 * if the timer interval is also 1564 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or 1565 * schedule delay. So deduct several seconds from 1566 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC. 1567 * Without this change, hdd_get_hosttime_from_targettime() will 1568 * get wrong host time when it's longer than 1569 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last 1570 * TSF-HOST update. 1571 */ 1572 interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC - 1573 CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC; 1574 if (adapter->device_mode == QDF_SAP_MODE || 1575 adapter->device_mode == QDF_P2P_GO_MODE) { 1576 interval *= WLAN_HDD_SOFTAP_INTERVAL_TIMES; 1577 } 1578 1579 adapter->continuous_error_count = 0; 1580 adapter->continuous_cap_retry_count = 0; 1581 hdd_debug("ts-pair updated: interval: %d", 1582 interval); 1583 break; 1584 case HDD_TS_STATUS_WAITING: 1585 interval = 0; 1586 hdd_warn("TS status is waiting due to one or more pair not updated"); 1587 1588 if (!target_time && !host_time) 1589 interval = hdd_wlan_retry_tsf_cap(adapter); 1590 break; 1591 } 1592 qdf_spin_unlock_bh(&adapter->host_target_sync_lock); 1593 1594 if (interval > 0) 1595 qdf_mc_timer_start(&adapter->host_target_sync_timer, interval); 1596 } 1597 1598 static ssize_t __hdd_wlan_tsf_show(struct device *dev, 1599 struct device_attribute *attr, char *buf) 1600 { 1601 struct hdd_station_ctx *hdd_sta_ctx; 1602 struct hdd_adapter *adapter; 1603 struct hdd_context *hdd_ctx; 1604 ssize_t size; 1605 uint64_t host_time, target_time; 1606 1607 struct net_device *net_dev = container_of(dev, struct net_device, dev); 1608 1609 adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); 1610 if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) 1611 return scnprintf(buf, PAGE_SIZE, "Invalid device\n"); 1612 1613 if (!hdd_get_th_sync_status(adapter)) 1614 return scnprintf(buf, PAGE_SIZE, 1615 "TSF sync is not initialized\n"); 1616 1617 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); 1618 if (!hdd_cm_is_vdev_associated(adapter) && 1619 (adapter->device_mode == QDF_STA_MODE || 1620 adapter->device_mode == QDF_P2P_CLIENT_MODE)) 1621 return scnprintf(buf, PAGE_SIZE, "NOT connected\n"); 1622 1623 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1624 if (!hdd_ctx) 1625 return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n"); 1626 1627 host_time = hdd_get_monotonic_host_time(hdd_ctx); 1628 1629 if (hdd_get_targettime_from_hosttime(adapter, host_time, 1630 &target_time)) { 1631 size = scnprintf(buf, PAGE_SIZE, "Invalid timestamp\n"); 1632 } else { 1633 if (adapter->device_mode == QDF_STA_MODE || 1634 adapter->device_mode == QDF_P2P_CLIENT_MODE) { 1635 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n", 1636 buf, target_time, host_time, 1637 hdd_sta_ctx->conn_info.bssid.bytes); 1638 } else { 1639 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n", 1640 buf, target_time, host_time, 1641 adapter->mac_addr.bytes); 1642 } 1643 } 1644 1645 return size; 1646 } 1647 1648 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) 1649 { 1650 struct hdd_tsf_op_response tsf_op_resp; 1651 1652 hdd_indicate_tsf_internal(adapter, &tsf_op_resp); 1653 hdd_update_timestamp(adapter, tsf, 0); 1654 } 1655 #endif 1656 1657 static ssize_t hdd_wlan_tsf_show(struct device *dev, 1658 struct device_attribute *attr, char *buf) 1659 { 1660 struct net_device *net_dev = container_of(dev, struct net_device, dev); 1661 struct osif_vdev_sync *vdev_sync; 1662 ssize_t err_size; 1663 1664 err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); 1665 if (err_size) 1666 return err_size; 1667 1668 err_size = __hdd_wlan_tsf_show(dev, attr, buf); 1669 1670 osif_vdev_sync_op_stop(vdev_sync); 1671 1672 return err_size; 1673 } 1674 1675 static DEVICE_ATTR(tsf, 0444, hdd_wlan_tsf_show, NULL); 1676 1677 static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter) 1678 { 1679 QDF_STATUS ret; 1680 struct hdd_context *hddctx; 1681 struct net_device *net_dev; 1682 uint64_t host_time, qtime; 1683 1684 if (!adapter) 1685 return HDD_TSF_OP_FAIL; 1686 1687 hddctx = WLAN_HDD_GET_CTX(adapter); 1688 if (!hddctx) { 1689 hdd_err("invalid hdd context"); 1690 return HDD_TSF_OP_FAIL; 1691 } 1692 1693 if (!qdf_atomic_read(&hddctx->tsf_ready_flag)) { 1694 hdd_err("TSF feature has NOT been initialized"); 1695 return HDD_TSF_OP_FAIL; 1696 } 1697 1698 if (!adapter->enable_dynamic_tsf_sync) { 1699 hdd_debug("TSF sync feature not enabled"); 1700 return HDD_TSF_OP_FAIL; 1701 } 1702 1703 if (hdd_get_th_sync_status(adapter)) { 1704 hdd_err("Host Target sync has been initialized!!"); 1705 return HDD_TSF_OP_SUCC; 1706 } 1707 1708 qdf_spinlock_create(&adapter->host_target_sync_lock); 1709 1710 hdd_reset_timestamps(adapter); 1711 1712 ret = qdf_mc_timer_init(&adapter->host_target_sync_timer, 1713 QDF_TIMER_TYPE_SW, 1714 hdd_capture_tsf_timer_expired_handler, 1715 (void *)adapter); 1716 if (ret != QDF_STATUS_SUCCESS) { 1717 hdd_err("Failed to init timer, ret: %d", ret); 1718 goto fail; 1719 } 1720 1721 net_dev = adapter->dev; 1722 if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) 1723 device_create_file(&net_dev->dev, &dev_attr_tsf); 1724 hdd_set_th_sync_status(adapter, true); 1725 1726 qtime = qdf_get_log_timestamp(); 1727 host_time = hdd_get_monotonic_host_time(hddctx); 1728 1729 qtime = qdf_log_timestamp_to_usecs(qtime); 1730 do_div(host_time, NSEC_PER_USEC); 1731 1732 adapter->delta_qtime = (qtime - host_time) * NSEC_PER_USEC; 1733 1734 return HDD_TSF_OP_SUCC; 1735 fail: 1736 hdd_set_th_sync_status(adapter, false); 1737 return HDD_TSF_OP_FAIL; 1738 } 1739 1740 static enum hdd_tsf_op_result hdd_tsf_sync_deinit(struct hdd_adapter *adapter) 1741 { 1742 QDF_STATUS ret; 1743 struct hdd_context *hddctx; 1744 struct net_device *net_dev; 1745 1746 if (!adapter) 1747 return HDD_TSF_OP_FAIL; 1748 1749 if (!hdd_get_th_sync_status(adapter)) 1750 return HDD_TSF_OP_SUCC; 1751 1752 hdd_set_th_sync_status(adapter, false); 1753 ret = qdf_mc_timer_destroy(&adapter->host_target_sync_timer); 1754 if (ret != QDF_STATUS_SUCCESS) 1755 hdd_err("Failed to destroy timer, ret: %d", ret); 1756 1757 hddctx = WLAN_HDD_GET_CTX(adapter); 1758 1759 /* reset the cap_tsf flag and gpio if needed */ 1760 if (hddctx && qdf_atomic_read(&hddctx->cap_tsf_flag) && 1761 hddctx->cap_tsf_context == adapter) { 1762 int reset_ret = hdd_tsf_reset_gpio(adapter); 1763 1764 if (reset_ret) 1765 hdd_err("Failed to reset tsf gpio, ret:%d", 1766 reset_ret); 1767 hddctx->cap_tsf_context = NULL; 1768 qdf_atomic_set(&hddctx->cap_tsf_flag, 0); 1769 } 1770 1771 hdd_reset_timestamps(adapter); 1772 1773 net_dev = adapter->dev; 1774 if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) { 1775 struct device *dev = &net_dev->dev; 1776 1777 device_remove_file(dev, &dev_attr_tsf); 1778 } 1779 return HDD_TSF_OP_SUCC; 1780 } 1781 1782 int hdd_start_tsf_sync(struct hdd_adapter *adapter) 1783 { 1784 enum hdd_tsf_op_result ret; 1785 1786 if (!adapter) 1787 return -EINVAL; 1788 1789 ret = hdd_tsf_sync_init(adapter); 1790 if (ret != HDD_TSF_OP_SUCC) 1791 return -EINVAL; 1792 1793 return (__hdd_start_tsf_sync(adapter) == 1794 HDD_TSF_OP_SUCC) ? 0 : -EINVAL; 1795 } 1796 1797 int hdd_stop_tsf_sync(struct hdd_adapter *adapter) 1798 { 1799 enum hdd_tsf_op_result ret; 1800 1801 if (!adapter) 1802 return -EINVAL; 1803 1804 ret = __hdd_stop_tsf_sync(adapter); 1805 if (ret != HDD_TSF_OP_SUCC) 1806 return -EINVAL; 1807 1808 ret = hdd_tsf_sync_deinit(adapter); 1809 if (ret != HDD_TSF_OP_SUCC) { 1810 hdd_err("Failed to deinit tsf sync, ret: %d", ret); 1811 return -EINVAL; 1812 } 1813 return 0; 1814 } 1815 1816 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter, 1817 uint32_t *buf, int len) 1818 { 1819 if (!adapter || !buf) { 1820 hdd_err("invalid pointer"); 1821 return -EINVAL; 1822 } 1823 1824 if (len != 1) 1825 return -EINVAL; 1826 1827 buf[0] = TSF_DISABLED_BY_TSFPLUS; 1828 1829 return 0; 1830 } 1831 1832 /** 1833 * hdd_handle_tsf_dynamic_start() 1834 * @adapter: Adapter pointer 1835 * @attr: TSF sync interval from NL interface 1836 * 1837 * This function enables TSF sync if capture mode is Dynamic set from ini 1838 * 1839 * Return: 0 for success or non-zero negative failure code 1840 */ 1841 static int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter, 1842 struct nlattr *attr) 1843 { 1844 struct hdd_context *hdd_ctx; 1845 uint32_t dynamic_tsf_sync_interval = 0; 1846 1847 if (!adapter) 1848 return -EINVAL; 1849 1850 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1851 if (wlan_hdd_validate_context(hdd_ctx)) 1852 return -EINVAL; 1853 1854 if (attr) 1855 dynamic_tsf_sync_interval = nla_get_u32(attr); 1856 1857 if (adapter->enable_dynamic_tsf_sync) { 1858 if (dynamic_tsf_sync_interval == 1859 adapter->dynamic_tsf_sync_interval) { 1860 return -EALREADY; 1861 } 1862 adapter->dynamic_tsf_sync_interval = 1863 dynamic_tsf_sync_interval; 1864 return 0; 1865 } 1866 1867 adapter->dynamic_tsf_sync_interval = dynamic_tsf_sync_interval; 1868 adapter->enable_dynamic_tsf_sync = true; 1869 1870 return hdd_start_tsf_sync(adapter); 1871 } 1872 1873 /** 1874 * hdd_handle_tsf_dynamic_stop() 1875 * @adapter: Adapter pointer 1876 * 1877 * This function disable TSF sync if capture mode is Dynamic set from ini 1878 * 1879 * Return: 0 for success or non-zero negative failure code 1880 */ 1881 static int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter) 1882 { 1883 struct hdd_context *hdd_ctx; 1884 1885 if (!adapter) 1886 return -EINVAL; 1887 1888 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1889 if (wlan_hdd_validate_context(hdd_ctx)) 1890 return -EINVAL; 1891 1892 if (!adapter->enable_dynamic_tsf_sync) 1893 return -EALREADY; 1894 1895 adapter->enable_dynamic_tsf_sync = false; 1896 adapter->dynamic_tsf_sync_interval = 0; 1897 return hdd_stop_tsf_sync(adapter); 1898 } 1899 1900 #if defined(WLAN_FEATURE_TSF_TIMER_SYNC) 1901 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, 1902 struct hdd_tsf_op_response 1903 *tsf_op_resp) 1904 { 1905 if (!adapter || !tsf_op_resp) { 1906 hdd_err("invalid pointer"); 1907 return HDD_TSF_OP_FAIL; 1908 } 1909 1910 memset(tsf_op_resp, 0, sizeof(*tsf_op_resp)); 1911 if (!hdd_tsf_is_initialized(adapter)) { 1912 tsf_op_resp->status = TSF_NOT_READY; 1913 return HDD_TSF_OP_SUCC; 1914 } 1915 1916 tsf_op_resp->status = hdd_tsf_check_conn_state(adapter); 1917 if (tsf_op_resp->status != TSF_RETURN) 1918 return HDD_TSF_OP_SUCC; 1919 1920 if (adapter->last_target_time == 0) { 1921 hdd_info("TSF value not received"); 1922 tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW; 1923 return HDD_TSF_OP_SUCC; 1924 } 1925 1926 tsf_op_resp->time = adapter->last_target_time; 1927 tsf_op_resp->soc_time = adapter->last_tsf_sync_soc_time; 1928 1929 return HDD_TSF_OP_SUCC; 1930 } 1931 1932 #else 1933 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, 1934 struct hdd_tsf_op_response 1935 *tsf_op_resp) 1936 { 1937 if (!adapter || !tsf_op_resp) { 1938 hdd_err("invalid pointer"); 1939 return HDD_TSF_OP_FAIL; 1940 } 1941 1942 tsf_op_resp->status = TSF_DISABLED_BY_TSFPLUS; 1943 tsf_op_resp->time = 0; 1944 tsf_op_resp->soc_time = 0; 1945 1946 return HDD_TSF_OP_SUCC; 1947 } 1948 #endif 1949 1950 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS 1951 #ifdef CONFIG_HL_SUPPORT 1952 static inline 1953 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf, 1954 uint64_t target_time) 1955 { 1956 struct hdd_adapter *adapter; 1957 struct net_device *net_dev = netbuf->dev; 1958 1959 if (!net_dev) 1960 return HDD_TSF_OP_FAIL; 1961 1962 adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); 1963 if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC && 1964 hdd_get_th_sync_status(adapter)) { 1965 uint64_t host_time; 1966 int32_t ret = hdd_get_hosttime_from_targettime(adapter, 1967 target_time, &host_time); 1968 if (!ret) { 1969 netbuf->tstamp = ns_to_ktime(host_time); 1970 return HDD_TSF_OP_SUCC; 1971 } 1972 } 1973 1974 return HDD_TSF_OP_FAIL; 1975 } 1976 1977 #else 1978 static inline 1979 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf, 1980 uint64_t target_time) 1981 { 1982 struct hdd_adapter *adapter; 1983 struct net_device *net_dev = netbuf->dev; 1984 struct skb_shared_hwtstamps hwtstamps; 1985 1986 if (!net_dev) 1987 return HDD_TSF_OP_FAIL; 1988 1989 adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); 1990 if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC && 1991 hdd_get_th_sync_status(adapter)) { 1992 uint64_t tsf64_time = target_time; 1993 uint64_t soc_time = 0;/*ns*/ 1994 int32_t ret = hdd_get_soctime_from_tsf64time(adapter, 1995 tsf64_time, &soc_time); 1996 if (!ret) { 1997 /* Adjust delta_qtime to soc_time(Qtime), so that 1998 * System Monotonic time and Qtime are in sync. 1999 */ 2000 if (soc_time > (adapter->delta_qtime)) { 2001 hwtstamps.hwtstamp = 2002 soc_time - (adapter->delta_qtime); 2003 *skb_hwtstamps(netbuf) = hwtstamps; 2004 netbuf->tstamp = ktime_set(0, 0); 2005 return HDD_TSF_OP_SUCC; 2006 } else { 2007 return HDD_TSF_OP_FAIL; 2008 } 2009 } 2010 } 2011 2012 return HDD_TSF_OP_FAIL; 2013 } 2014 #endif 2015 2016 /** 2017 * hdd_tx_timestamp() - time stamp TX netbuf 2018 * 2019 * @netbuf: pointer to a TX netbuf 2020 * @target_time: TX time for the netbuf 2021 * 2022 * This function get corresponding host time from target time, 2023 * and time stamp the TX netbuf with this time 2024 * 2025 * Return: Describe the execute result of this routine 2026 */ 2027 static int hdd_tx_timestamp(enum htt_tx_status status, 2028 qdf_nbuf_t netbuf, uint64_t target_time) 2029 { 2030 struct sock *sk = netbuf->sk; 2031 2032 if (!sk) 2033 return -EINVAL; 2034 2035 if ((skb_shinfo(netbuf)->tx_flags & SKBTX_HW_TSTAMP) && 2036 !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) { 2037 struct sock_exterr_skb *serr; 2038 qdf_nbuf_t new_netbuf; 2039 int err; 2040 2041 if (hdd_netbuf_timestamp(netbuf, target_time) != 2042 HDD_TSF_OP_SUCC) 2043 return -EINVAL; 2044 2045 new_netbuf = qdf_nbuf_clone(netbuf); 2046 if (!new_netbuf) 2047 return -ENOMEM; 2048 2049 serr = SKB_EXT_ERR(new_netbuf); 2050 memset(serr, 0, sizeof(*serr)); 2051 2052 switch (status) { 2053 case htt_tx_status_ok: 2054 serr->ee.ee_errno = ENOMSG; 2055 break; 2056 case htt_tx_status_discard: 2057 serr->ee.ee_errno = ENOBUFS; 2058 break; 2059 case htt_tx_status_no_ack: 2060 serr->ee.ee_errno = EREMOTEIO; 2061 break; 2062 default: 2063 serr->ee.ee_errno = ENOMSG; 2064 break; 2065 } 2066 2067 hdd_debug("packet status %d, sock ee_errno %d", 2068 status, serr->ee.ee_errno); 2069 2070 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; 2071 2072 err = sock_queue_err_skb(sk, new_netbuf); 2073 if (err) { 2074 qdf_nbuf_free(new_netbuf); 2075 return err; 2076 } 2077 2078 return 0; 2079 } 2080 return -EINVAL; 2081 } 2082 2083 int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time) 2084 { 2085 if (hdd_netbuf_timestamp(netbuf, target_time) == 2086 HDD_TSF_OP_SUCC) 2087 return 0; 2088 2089 /* reset tstamp when failed */ 2090 netbuf->tstamp = ktime_set(0, 0); 2091 return -EINVAL; 2092 } 2093 2094 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx) 2095 { 2096 if (hdd_tsf_is_tx_set(hdd_ctx)) 2097 ol_register_timestamp_callback(hdd_tx_timestamp); 2098 } 2099 2100 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx) 2101 { 2102 if (hdd_tsf_is_tx_set(hdd_ctx)) 2103 ol_deregister_timestamp_callback(); 2104 } 2105 #else 2106 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx) 2107 { 2108 } 2109 2110 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx) 2111 { 2112 } 2113 #endif /* WLAN_FEATURE_TSF_PLUS_SOCK_TS */ 2114 2115 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) 2116 static inline 2117 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2118 { 2119 2120 wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); 2121 return HDD_TSF_OP_SUCC; 2122 } 2123 2124 static inline 2125 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2126 { 2127 QDF_STATUS status; 2128 QDF_TIMER_STATE capture_req_timer_status; 2129 qdf_mc_timer_t *cap_timer; 2130 struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr; 2131 2132 wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); 2133 2134 status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr); 2135 2136 while (adapternode_ptr && QDF_STATUS_SUCCESS == status) { 2137 adapter = adapternode_ptr; 2138 status = 2139 hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr); 2140 adapternode_ptr = next_ptr; 2141 if (adapter->host_capture_req_timer.state == 0) 2142 continue; 2143 cap_timer = &adapter->host_capture_req_timer; 2144 capture_req_timer_status = 2145 qdf_mc_timer_get_current_state(cap_timer); 2146 2147 if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) { 2148 qdf_mc_timer_stop(cap_timer); 2149 status = 2150 qdf_mc_timer_destroy(cap_timer); 2151 if (status != QDF_STATUS_SUCCESS) 2152 hdd_err("remove timer failed: %d", status); 2153 } 2154 } 2155 2156 return HDD_TSF_OP_SUCC; 2157 } 2158 2159 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) 2160 static 2161 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2162 { 2163 int ret; 2164 QDF_STATUS status; 2165 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; 2166 2167 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, 2168 &tsf_sync_gpio_pin); 2169 if (QDF_IS_STATUS_ERROR(status)) { 2170 hdd_err("tsf gpio irq host pin error"); 2171 goto fail; 2172 } 2173 2174 if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) { 2175 hdd_err("gpio host pin is invalid"); 2176 goto fail; 2177 } 2178 2179 ret = gpio_request(tsf_sync_gpio_pin, "wlan_tsf"); 2180 if (ret) { 2181 hdd_err("gpio host pin is invalid"); 2182 goto fail; 2183 } 2184 2185 ret = gpio_direction_output(tsf_sync_gpio_pin, OUTPUT_LOW); 2186 if (ret) { 2187 hdd_err("gpio host pin is invalid"); 2188 goto fail_free_gpio; 2189 } 2190 2191 wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); 2192 2193 return HDD_TSF_OP_SUCC; 2194 2195 fail_free_gpio: 2196 gpio_free(tsf_sync_gpio_pin); 2197 fail: 2198 return HDD_TSF_OP_FAIL; 2199 } 2200 2201 static 2202 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2203 { 2204 QDF_STATUS status; 2205 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; 2206 2207 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, 2208 &tsf_sync_gpio_pin); 2209 if (QDF_IS_STATUS_ERROR(status)) 2210 return QDF_STATUS_E_INVAL; 2211 2212 if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) 2213 return QDF_STATUS_E_INVAL; 2214 2215 wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); 2216 2217 gpio_free(tsf_sync_gpio_pin); 2218 return HDD_TSF_OP_SUCC; 2219 } 2220 2221 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) 2222 static 2223 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2224 { 2225 int ret; 2226 QDF_STATUS status; 2227 uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; 2228 2229 status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, 2230 &tsf_irq_gpio_pin); 2231 if (QDF_IS_STATUS_ERROR(status)) { 2232 hdd_err("tsf gpio irq host pin error"); 2233 goto fail; 2234 } 2235 2236 if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) { 2237 hdd_err("gpio host pin is invalid"); 2238 goto fail; 2239 } 2240 2241 ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf"); 2242 if (ret) { 2243 hdd_err("gpio host pin is invalid"); 2244 goto fail; 2245 } 2246 2247 ret = gpio_direction_input(tsf_irq_gpio_pin); 2248 if (ret) { 2249 hdd_err("gpio host pin is invalid"); 2250 goto fail_free_gpio; 2251 } 2252 2253 tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin); 2254 if (tsf_gpio_irq_num < 0) { 2255 hdd_err("fail to get irq: %d", tsf_gpio_irq_num); 2256 goto fail_free_gpio; 2257 } 2258 2259 ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler, 2260 IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf", 2261 hdd_ctx); 2262 2263 if (ret) { 2264 hdd_err("Failed to register irq handler: %d", ret); 2265 goto fail_free_gpio; 2266 } 2267 2268 wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); 2269 2270 return HDD_TSF_OP_SUCC; 2271 2272 fail_free_gpio: 2273 gpio_free(tsf_irq_gpio_pin); 2274 fail: 2275 tsf_gpio_irq_num = -1; 2276 return HDD_TSF_OP_FAIL; 2277 } 2278 2279 static 2280 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2281 { 2282 QDF_STATUS status; 2283 uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; 2284 2285 status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, 2286 &tsf_irq_gpio_pin); 2287 if (QDF_IS_STATUS_ERROR(status)) 2288 return QDF_STATUS_E_INVAL; 2289 2290 if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) 2291 return QDF_STATUS_E_INVAL; 2292 2293 wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); 2294 2295 if (tsf_gpio_irq_num >= 0) { 2296 free_irq(tsf_gpio_irq_num, hdd_ctx); 2297 tsf_gpio_irq_num = -1; 2298 gpio_free(tsf_irq_gpio_pin); 2299 } 2300 2301 return HDD_TSF_OP_SUCC; 2302 } 2303 2304 #elif defined(WLAN_FEATURE_TSF_TIMER_SYNC) 2305 static inline 2306 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2307 { 2308 return HDD_TSF_OP_SUCC; 2309 } 2310 2311 static inline 2312 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2313 { 2314 QDF_STATUS status; 2315 QDF_TIMER_STATE capture_req_timer_status; 2316 qdf_mc_timer_t *cap_timer; 2317 struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr; 2318 2319 status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr); 2320 2321 while (adapternode_ptr && QDF_STATUS_SUCCESS == status) { 2322 adapter = adapternode_ptr; 2323 status = 2324 hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr); 2325 adapternode_ptr = next_ptr; 2326 if (adapter->host_capture_req_timer.state == 0) 2327 continue; 2328 cap_timer = &adapter->host_capture_req_timer; 2329 capture_req_timer_status = 2330 qdf_mc_timer_get_current_state(cap_timer); 2331 2332 if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) { 2333 qdf_mc_timer_stop(cap_timer); 2334 status = 2335 qdf_mc_timer_destroy(cap_timer); 2336 if (status != QDF_STATUS_SUCCESS) 2337 hdd_err_rl("remove timer failed: %d", status); 2338 } 2339 } 2340 2341 return HDD_TSF_OP_SUCC; 2342 } 2343 #else 2344 static inline 2345 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2346 { 2347 int ret; 2348 2349 ret = cnss_common_register_tsf_captured_handler( 2350 hdd_ctx->parent_dev, 2351 hdd_tsf_captured_irq_handler, 2352 (void *)hdd_ctx); 2353 if (ret != 0) { 2354 hdd_err("Failed to register irq handler: %d", ret); 2355 return HDD_TSF_OP_FAIL; 2356 } 2357 2358 wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); 2359 return HDD_TSF_OP_SUCC; 2360 } 2361 2362 static inline 2363 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2364 { 2365 int ret; 2366 2367 wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); 2368 2369 ret = cnss_common_unregister_tsf_captured_handler( 2370 hdd_ctx->parent_dev, 2371 (void *)hdd_ctx); 2372 if (ret != 0) { 2373 hdd_err("Failed to unregister irq handler, ret:%d", 2374 ret); 2375 ret = HDD_TSF_OP_FAIL; 2376 } 2377 2378 return HDD_TSF_OP_SUCC; 2379 } 2380 #endif 2381 #else 2382 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) 2383 { 2384 } 2385 2386 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, 2387 struct hdd_tsf_op_response 2388 *tsf_op_resp) 2389 { 2390 return hdd_indicate_tsf_internal(adapter, tsf_op_resp); 2391 } 2392 2393 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter, 2394 uint32_t *buf, int len) 2395 { 2396 return (hdd_capture_tsf_internal(adapter, buf, len) == 2397 HDD_TSF_OP_SUCC) ? 0 : -EINVAL; 2398 } 2399 2400 static inline 2401 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) 2402 { 2403 return HDD_TSF_OP_SUCC; 2404 } 2405 2406 static inline 2407 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) 2408 { 2409 return HDD_TSF_OP_SUCC; 2410 } 2411 2412 static inline int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter, 2413 struct nlattr *attr) 2414 { 2415 return -ENOTSUPP; 2416 } 2417 2418 static inline int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter) 2419 { 2420 return -ENOTSUPP; 2421 } 2422 #endif /* WLAN_FEATURE_TSF_PLUS */ 2423 2424 int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len) 2425 { 2426 return __hdd_capture_tsf(adapter, buf, len); 2427 } 2428 2429 int hdd_indicate_tsf(struct hdd_adapter *adapter, 2430 struct hdd_tsf_op_response *tsf_op_resp) 2431 { 2432 if (__hdd_indicate_tsf(adapter, tsf_op_resp) == HDD_TSF_OP_FAIL) 2433 return -EINVAL; 2434 2435 switch (tsf_op_resp->status) { 2436 case TSF_RETURN: 2437 return 0; 2438 case TSF_NOT_RETURNED_BY_FW: 2439 return -EINPROGRESS; 2440 case TSF_STA_NOT_CONNECTED_NO_TSF: 2441 case TSF_SAP_NOT_STARTED_NO_TSF: 2442 return -EPERM; 2443 default: 2444 return -EINVAL; 2445 } 2446 } 2447 2448 #ifdef WLAN_FEATURE_TSF_PTP 2449 int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) 2450 2451 { 2452 struct hdd_adapter *adapter = netdev_priv(dev); 2453 struct osif_vdev_sync *vdev_sync; 2454 struct hdd_context *hdd_ctx; 2455 int errno; 2456 2457 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 2458 errno = wlan_hdd_validate_context(hdd_ctx); 2459 if (errno) 2460 return -EINVAL; 2461 2462 errno = osif_vdev_sync_op_start(dev, &vdev_sync); 2463 if (errno) 2464 return -EAGAIN; 2465 2466 info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | 2467 SOF_TIMESTAMPING_RX_HARDWARE | 2468 SOF_TIMESTAMPING_RAW_HARDWARE; 2469 if (hdd_ctx->ptp_clock) 2470 info->phc_index = ptp_clock_index(hdd_ctx->ptp_clock); 2471 else 2472 info->phc_index = -1; 2473 2474 osif_vdev_sync_op_stop(vdev_sync); 2475 return 0; 2476 } 2477 2478 #if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE) 2479 /** 2480 * wlan_ptp_gettime() - return fw ts info to uplayer 2481 * @ptp: pointer to ptp_clock_info. 2482 * @ts: pointer to timespec. 2483 * 2484 * Return: Describe the execute result of this routine 2485 */ 2486 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 2487 { 2488 uint64_t host_time, target_time = 0; 2489 struct hdd_context *hdd_ctx; 2490 struct hdd_adapter *adapter; 2491 uint32_t tsf_reg_read_enabled; 2492 struct osif_psoc_sync *psoc_sync; 2493 int errno, status = 0; 2494 2495 hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo); 2496 errno = wlan_hdd_validate_context(hdd_ctx); 2497 if (errno) 2498 return -EINVAL; 2499 2500 errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); 2501 if (errno) 2502 return -EAGAIN; 2503 2504 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); 2505 if (!adapter) { 2506 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); 2507 if (!adapter) { 2508 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); 2509 if (!adapter) 2510 adapter = hdd_get_adapter(hdd_ctx, 2511 QDF_STA_MODE); 2512 if (!adapter) { 2513 status = -EOPNOTSUPP; 2514 goto end; 2515 } 2516 } 2517 } 2518 2519 host_time = hdd_get_monotonic_host_time(hdd_ctx); 2520 if (hdd_get_targettime_from_hosttime(adapter, host_time, 2521 &target_time)) { 2522 hdd_err("get invalid target timestamp"); 2523 status = -EINVAL; 2524 goto end; 2525 } 2526 *ts = ns_to_timespec(target_time * NSEC_PER_USEC); 2527 2528 end: 2529 osif_psoc_sync_op_stop(psoc_sync); 2530 return status; 2531 } 2532 2533 /** 2534 * wlan_hdd_phc_init() - phc init 2535 * @hdd_ctx: pointer to the hdd_context. 2536 * 2537 * Return: NULL 2538 */ 2539 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) 2540 { 2541 hdd_ctx->ptp_cinfo.gettime = wlan_ptp_gettime; 2542 2543 hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo, 2544 hdd_ctx->parent_dev); 2545 } 2546 2547 /** 2548 * wlan_hdd_phc_deinit() - phc deinit 2549 * @hdd_ctx: pointer to the hdd_context. 2550 * 2551 * Return: NULL 2552 */ 2553 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) 2554 { 2555 hdd_ctx->ptp_cinfo.gettime = NULL; 2556 2557 if (hdd_ctx->ptp_clock) { 2558 ptp_clock_unregister(hdd_ctx->ptp_clock); 2559 hdd_ctx->ptp_clock = NULL; 2560 } 2561 } 2562 2563 #else 2564 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 2565 { 2566 uint64_t host_time, target_time = 0; 2567 struct hdd_context *hdd_ctx; 2568 struct hdd_adapter *adapter; 2569 struct osif_psoc_sync *psoc_sync; 2570 int errno, status = 0; 2571 2572 hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo); 2573 errno = wlan_hdd_validate_context(hdd_ctx); 2574 if (errno) 2575 return -EINVAL; 2576 2577 errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); 2578 if (errno) 2579 return -EAGAIN; 2580 2581 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); 2582 if (!adapter) { 2583 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); 2584 if (!adapter) { 2585 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); 2586 if (!adapter) 2587 adapter = hdd_get_adapter(hdd_ctx, 2588 QDF_STA_MODE); 2589 if (!adapter) { 2590 status = -EOPNOTSUPP; 2591 goto end; 2592 } 2593 } 2594 } 2595 2596 host_time = hdd_get_monotonic_host_time(hdd_ctx); 2597 if (hdd_get_targettime_from_hosttime(adapter, host_time, 2598 &target_time)) { 2599 hdd_err("get invalid target timestamp"); 2600 status = -EINVAL; 2601 goto end; 2602 } 2603 *ts = ns_to_timespec64(target_time * NSEC_PER_USEC); 2604 2605 end: 2606 osif_psoc_sync_op_stop(psoc_sync); 2607 return status; 2608 } 2609 2610 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) 2611 { 2612 hdd_ctx->ptp_cinfo.gettime64 = wlan_ptp_gettime; 2613 hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo, 2614 hdd_ctx->parent_dev); 2615 } 2616 2617 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) 2618 { 2619 hdd_ctx->ptp_cinfo.gettime64 = NULL; 2620 2621 if (hdd_ctx->ptp_clock) { 2622 ptp_clock_unregister(hdd_ctx->ptp_clock); 2623 hdd_ctx->ptp_clock = NULL; 2624 } 2625 } 2626 2627 #endif 2628 #else 2629 2630 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) 2631 { 2632 } 2633 2634 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) 2635 { 2636 } 2637 #endif /* WLAN_FEATURE_TSF_PTP */ 2638 2639 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY 2640 static int hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena) 2641 { 2642 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 2643 int ret; 2644 2645 if (QDF_IS_STATUS_ERROR(cdp_set_tsf_ul_delay_report(soc, 2646 adapter->vdev_id, 2647 ena))) { 2648 hdd_err_rl("Set tsf report uplink delay failed"); 2649 return -EPERM; 2650 } 2651 2652 ret = wma_cli_set_command((int)adapter->vdev_id, 2653 ena ? (int)GEN_PARAM_TSF_AUTO_REPORT_ENABLE : 2654 (int)GEN_PARAM_TSF_AUTO_REPORT_DISABLE, 2655 ena, GEN_CMD); 2656 if (ret) { 2657 hdd_err_rl("tsf auto report %d failed", ena); 2658 return -EINPROGRESS; 2659 } 2660 2661 qdf_atomic_set(&adapter->tsf_auto_report, ena); 2662 2663 return 0; 2664 } 2665 2666 /** 2667 * hdd_handle_tsf_auto_report(): Handle TSF auto report enable or disable 2668 * @adapter: pointer of struct hdd_adapter 2669 * @tsf_cmd: TSF command from user space 2670 * 2671 * Return: 0 for success, -EINVAL to continue to handle other TSF commands and 2672 * else errors 2673 */ 2674 static int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter, 2675 uint32_t tsf_cmd) 2676 { 2677 bool ena; 2678 2679 if (tsf_cmd != QCA_TSF_AUTO_REPORT_ENABLE && 2680 tsf_cmd != QCA_TSF_AUTO_REPORT_DISABLE) { 2681 hdd_debug_rl("tsf_cmd %d not for uplink delay", tsf_cmd); 2682 return -EINVAL; 2683 } 2684 2685 /* uplink delay feature is only required for STA mode */ 2686 if (adapter->device_mode != QDF_STA_MODE) { 2687 hdd_debug_rl("tsf_cmd %d not allowed for device mode %d", 2688 tsf_cmd, adapter->device_mode); 2689 return -EPERM; 2690 } 2691 2692 ena = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) ? true : false; 2693 2694 return hdd_set_tsf_auto_report(adapter, ena); 2695 } 2696 2697 static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter, 2698 struct stsf *ptsf) 2699 { 2700 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 2701 uint32_t delta_tsf; 2702 2703 /* If TSF report is for uplink delay, mac_id_valid will be set to 2704 * 1 by target. If not, the report is not for uplink delay feature 2705 * and return failure here so that legacy BSS TSF logic can be 2706 * continued. 2707 */ 2708 if (!ptsf->mac_id_valid) { 2709 hdd_debug_rl("TSF report not for uplink delay"); 2710 return QDF_STATUS_E_FAILURE; 2711 } 2712 2713 /* For uplink delay feature, TSF auto report needs to be enabled 2714 * first. Otherwise TSF event will not be posted by target. 2715 */ 2716 if (!qdf_atomic_read(&adapter->tsf_auto_report)) { 2717 hdd_debug_rl("adapter %u tsf_auto_report disabled", 2718 adapter->vdev_id); 2719 goto exit_with_success; 2720 } 2721 2722 delta_tsf = ptsf->tsf_low - ptsf->soc_timer_low; 2723 hdd_debug("vdev %u tsf_low %u qtimer_low %u delta_tsf %u", 2724 ptsf->vdev_id, ptsf->tsf_low, ptsf->soc_timer_low, delta_tsf); 2725 2726 /* Pass delta_tsf to DP layer to report uplink delay 2727 * on a per vdev basis 2728 */ 2729 cdp_set_delta_tsf(soc, adapter->vdev_id, delta_tsf); 2730 2731 exit_with_success: 2732 return QDF_STATUS_SUCCESS; 2733 } 2734 #else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */ 2735 static inline int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter, 2736 uint32_t tsf_cmd) 2737 { 2738 return -EINVAL; 2739 } 2740 2741 static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter, 2742 struct stsf *ptsf) 2743 { 2744 return QDF_STATUS_E_FAILURE; 2745 } 2746 #endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ 2747 2748 /** 2749 * hdd_get_tsf_cb() - handle tsf callback 2750 * @pcb_cxt: pointer to the hdd_contex 2751 * @ptsf: pointer to struct stsf 2752 * 2753 * This function handle the event that reported by firmware at first. 2754 * The event contains the vdev_id, current tsf value of this vdev, 2755 * tsf value is 64bits, discripted in two variable tsf_low and tsf_high. 2756 * These two values each is uint32. 2757 * 2758 * Return: 0 for success or non-zero negative failure code 2759 */ 2760 int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) 2761 { 2762 struct hdd_context *hddctx; 2763 struct hdd_adapter *adapter; 2764 int ret; 2765 uint64_t tsf_sync_soc_time; 2766 QDF_STATUS status; 2767 QDF_TIMER_STATE capture_req_timer_status; 2768 qdf_mc_timer_t *capture_timer; 2769 2770 if (!pcb_cxt || !ptsf) { 2771 hdd_err("HDD context is not valid"); 2772 return -EINVAL; 2773 } 2774 2775 hddctx = (struct hdd_context *)pcb_cxt; 2776 ret = wlan_hdd_validate_context(hddctx); 2777 if (0 != ret) 2778 return -EINVAL; 2779 2780 adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id); 2781 2782 if (!adapter) { 2783 hdd_err("failed to find adapter"); 2784 return -EINVAL; 2785 } 2786 2787 /* Intercept tsf report and check if it is for uplink delay. 2788 * If yes, return in advance and skip the legacy BSS TSF 2789 * report. Otherwise continue on to the legacy BSS TSF 2790 * report logic. 2791 */ 2792 if (QDF_IS_STATUS_SUCCESS(hdd_set_delta_tsf(adapter, ptsf))) 2793 return 0; 2794 2795 if (!hdd_tsf_is_initialized(adapter)) { 2796 hdd_err("tsf is not init, ignore tsf event"); 2797 return -EINVAL; 2798 } 2799 2800 hdd_info("tsf cb handle event, device_mode is %d", 2801 adapter->device_mode); 2802 2803 capture_timer = &adapter->host_capture_req_timer; 2804 capture_req_timer_status = 2805 qdf_mc_timer_get_current_state(capture_timer); 2806 if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { 2807 hdd_warn("invalid timer status"); 2808 return -EINVAL; 2809 } 2810 2811 qdf_mc_timer_stop(capture_timer); 2812 status = qdf_mc_timer_destroy(capture_timer); 2813 if (status != QDF_STATUS_SUCCESS) 2814 hdd_warn("destroy cap req timer fail, ret: %d", status); 2815 2816 adapter->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 | 2817 ptsf->tsf_low); 2818 2819 adapter->cur_target_global_tsf_time = 2820 ((uint64_t)ptsf->global_tsf_high << 32 | 2821 ptsf->global_tsf_low); 2822 tsf_sync_soc_time = ((uint64_t)ptsf->soc_timer_high << 32 | 2823 ptsf->soc_timer_low); 2824 adapter->cur_tsf_sync_soc_time = 2825 hdd_convert_qtime_to_us(tsf_sync_soc_time) * NSEC_PER_USEC; 2826 2827 wlan_hdd_tsf_reg_update_details(adapter, ptsf); 2828 2829 qdf_event_set(&tsf_sync_get_completion_evt); 2830 hdd_update_tsf(adapter, adapter->cur_target_time); 2831 hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u", 2832 ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high, 2833 ptsf->soc_timer_low, ptsf->soc_timer_high); 2834 return 0; 2835 } 2836 2837 const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = { 2838 [QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32}, 2839 [QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL] = {.type = NLA_U32}, 2840 }; 2841 2842 /** 2843 * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations 2844 * @wiphy: Pointer to wireless phy 2845 * @wdev: Pointer to wireless device 2846 * @data: Pointer to data 2847 * @data_len: Data length 2848 * 2849 * Handle TSF SET / GET operation from userspace 2850 * 2851 * Return: 0 on success, negative errno on failure 2852 */ 2853 static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, 2854 struct wireless_dev *wdev, 2855 const void *data, 2856 int data_len) 2857 { 2858 struct net_device *dev = wdev->netdev; 2859 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 2860 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2861 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1]; 2862 struct hdd_tsf_op_response tsf_op_resp; 2863 struct nlattr *attr; 2864 enum hdd_tsf_get_state value; 2865 int status; 2866 QDF_STATUS ret; 2867 struct sk_buff *reply_skb; 2868 uint32_t tsf_cmd; 2869 2870 hdd_enter_dev(wdev->netdev); 2871 2872 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 2873 hdd_err("Command not allowed in FTM mode"); 2874 return -EPERM; 2875 } 2876 2877 status = wlan_hdd_validate_context(hdd_ctx); 2878 if (0 != status) 2879 return -EINVAL; 2880 2881 if (wlan_cfg80211_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX, 2882 data, data_len, tsf_policy)) { 2883 hdd_err("Invalid TSF cmd"); 2884 return -EINVAL; 2885 } 2886 2887 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) { 2888 hdd_err("Invalid TSF cmd"); 2889 return -EINVAL; 2890 } 2891 tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]); 2892 2893 /* Intercept tsf_cmd for TSF auto report enable or disable subcmds. 2894 * If status is -EINVAL, it means tsf_cmd is not for auto report and 2895 * need to continue to handle other tsf cmds. 2896 */ 2897 status = hdd_handle_tsf_auto_report(adapter, tsf_cmd); 2898 if (status != -EINVAL) 2899 goto end; 2900 ret = qdf_event_reset(&tsf_sync_get_completion_evt); 2901 if (QDF_IS_STATUS_ERROR(ret)) 2902 hdd_warn("failed to reset tsf_sync_get_completion_evt"); 2903 2904 if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) { 2905 hdd_capture_tsf(adapter, &value, 1); 2906 switch (value) { 2907 case TSF_RETURN: 2908 status = 0; 2909 break; 2910 case TSF_CURRENT_IN_CAP_STATE: 2911 status = -EALREADY; 2912 break; 2913 case TSF_STA_NOT_CONNECTED_NO_TSF: 2914 case TSF_SAP_NOT_STARTED_NO_TSF: 2915 status = -EPERM; 2916 break; 2917 default: 2918 case TSF_CAPTURE_FAIL: 2919 status = -EINVAL; 2920 break; 2921 } 2922 } else if (tsf_cmd == QCA_TSF_SYNC_START) { 2923 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL]; 2924 status = hdd_handle_tsf_dynamic_start(adapter, attr); 2925 } else if (tsf_cmd == QCA_TSF_SYNC_STOP) { 2926 status = hdd_handle_tsf_dynamic_stop(adapter); 2927 } 2928 2929 if (status < 0) 2930 goto end; 2931 2932 if (tsf_cmd == QCA_TSF_SYNC_GET) { 2933 ret = qdf_wait_single_event(&tsf_sync_get_completion_evt, 2934 WLAN_TSF_SYNC_GET_TIMEOUT); 2935 if (QDF_IS_STATUS_ERROR(ret)) { 2936 status = -ETIMEDOUT; 2937 goto end; 2938 } 2939 } 2940 2941 if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) { 2942 status = hdd_indicate_tsf(adapter, &tsf_op_resp); 2943 if (status != 0) 2944 goto end; 2945 2946 reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, 2947 sizeof(uint64_t) * 2 + NLMSG_HDRLEN, 2948 QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX, 2949 GFP_KERNEL); 2950 if (!reply_skb) { 2951 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); 2952 status = -ENOMEM; 2953 goto end; 2954 } 2955 if (hdd_wlan_nla_put_u64(reply_skb, 2956 QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, 2957 tsf_op_resp.time) || 2958 hdd_wlan_nla_put_u64(reply_skb, 2959 QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, 2960 tsf_op_resp.soc_time)) { 2961 hdd_err("nla put fail"); 2962 kfree_skb(reply_skb); 2963 status = -EINVAL; 2964 goto end; 2965 } 2966 status = cfg80211_vendor_cmd_reply(reply_skb); 2967 } 2968 2969 end: 2970 hdd_info("TSF operation %d status: %d", tsf_cmd, status); 2971 return status; 2972 } 2973 2974 int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, 2975 struct wireless_dev *wdev, 2976 const void *data, 2977 int data_len) 2978 { 2979 int errno; 2980 struct osif_vdev_sync *vdev_sync; 2981 2982 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 2983 if (errno) 2984 return errno; 2985 2986 errno = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len); 2987 2988 osif_vdev_sync_op_stop(vdev_sync); 2989 2990 return errno; 2991 } 2992 2993 /** 2994 * wlan_hdd_tsf_init() - set callback to handle tsf value. 2995 * @hdd_ctx: pointer to the struct hdd_context 2996 * 2997 * This function set the callback to sme module, the callback will be 2998 * called when a tsf event is reported by firmware 2999 * 3000 * Return: none 3001 */ 3002 void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx) 3003 { 3004 QDF_STATUS status; 3005 3006 if (!hdd_ctx) 3007 return; 3008 3009 if (qdf_atomic_inc_return(&hdd_ctx->tsf_ready_flag) > 1) 3010 return; 3011 3012 qdf_atomic_init(&hdd_ctx->cap_tsf_flag); 3013 3014 status = hdd_tsf_set_gpio(hdd_ctx); 3015 3016 if (QDF_STATUS_SUCCESS != status) { 3017 hdd_debug("set tsf GPIO failed, status: %d", status); 3018 goto fail; 3019 } 3020 3021 if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC) 3022 goto fail; 3023 3024 if (hdd_tsf_is_ptp_enabled(hdd_ctx)) 3025 wlan_hdd_phc_init(hdd_ctx); 3026 3027 status = qdf_event_create(&tsf_sync_get_completion_evt); 3028 if (QDF_IS_STATUS_ERROR(status)) { 3029 hdd_debug("failed to create tsf_sync_get_completion_evt"); 3030 goto fail; 3031 } 3032 3033 return; 3034 3035 fail: 3036 qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); 3037 } 3038 3039 void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx) 3040 { 3041 QDF_STATUS status; 3042 3043 if (!hdd_ctx) 3044 return; 3045 3046 if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag)) 3047 return; 3048 3049 status = qdf_event_destroy(&tsf_sync_get_completion_evt); 3050 if (QDF_IS_STATUS_ERROR(status)) 3051 hdd_debug("failed to destroy tsf_sync_get_completion_evt"); 3052 3053 if (hdd_tsf_is_ptp_enabled(hdd_ctx)) 3054 wlan_hdd_phc_deinit(hdd_ctx); 3055 wlan_hdd_tsf_plus_deinit(hdd_ctx); 3056 qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); 3057 qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0); 3058 } 3059