1 /* 2 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <dp_internal.h> 17 #include <wlan_cfg.h> 18 #include <hif.h> 19 #include <dp_htt.h> 20 21 /** 22 * dp_get_umac_reset_intr_ctx() - Get the interrupt context to be used by 23 * UMAC reset feature 24 * @soc: DP soc object 25 * @intr_ctx: Interrupt context variable to be populated by this API 26 * 27 * Return: QDF_STATUS of operation 28 */ 29 static QDF_STATUS dp_get_umac_reset_intr_ctx(struct dp_soc *soc, int *intr_ctx) 30 { 31 int umac_reset_mask, i; 32 33 /** 34 * Go over all the contexts and check which interrupt context has 35 * the UMAC reset mask set. 36 */ 37 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { 38 umac_reset_mask = wlan_cfg_get_umac_reset_intr_mask( 39 soc->wlan_cfg_ctx, i); 40 41 if (umac_reset_mask) { 42 *intr_ctx = i; 43 return QDF_STATUS_SUCCESS; 44 } 45 } 46 47 *intr_ctx = -1; 48 return QDF_STATUS_E_FAILURE; 49 } 50 51 /** 52 * dp_umac_reset_send_setup_cmd(): Send the UMAC reset setup command 53 * @soc: dp soc object 54 * 55 * Return: QDF_STATUS of operation 56 */ 57 static QDF_STATUS 58 dp_umac_reset_send_setup_cmd(struct dp_soc *soc) 59 { 60 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 61 int msi_vector_count, ret; 62 uint32_t msi_base_data, msi_vector_start; 63 struct dp_htt_umac_reset_setup_cmd_params params; 64 65 umac_reset_ctx = &soc->umac_reset_ctx; 66 qdf_mem_zero(¶ms, sizeof(params)); 67 ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP", 68 &msi_vector_count, &msi_base_data, 69 &msi_vector_start); 70 if (ret) { 71 params.msi_data = UMAC_RESET_IPC; 72 } else { 73 params.msi_data = (umac_reset_ctx->intr_offset % 74 msi_vector_count) + msi_base_data; 75 } 76 77 params.shmem_addr_low = 78 qdf_get_lower_32_bits(umac_reset_ctx->shmem_paddr_aligned); 79 params.shmem_addr_high = 80 qdf_get_upper_32_bits(umac_reset_ctx->shmem_paddr_aligned); 81 82 return dp_htt_umac_reset_send_setup_cmd(soc, ¶ms); 83 } 84 85 QDF_STATUS dp_soc_umac_reset_init(struct cdp_soc_t *txrx_soc) 86 { 87 struct dp_soc *soc = (struct dp_soc *)txrx_soc; 88 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 89 size_t alloc_size; 90 QDF_STATUS status; 91 92 if (!soc) { 93 dp_umac_reset_err("DP SOC is null"); 94 return QDF_STATUS_E_NULL_VALUE; 95 } 96 97 if (!soc->features.umac_hw_reset_support) { 98 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 99 return QDF_STATUS_E_NOSUPPORT; 100 } 101 102 umac_reset_ctx = &soc->umac_reset_ctx; 103 qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx)); 104 105 umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; 106 umac_reset_ctx->shmem_exp_magic_num = DP_UMAC_RESET_SHMEM_MAGIC_NUM; 107 108 status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset); 109 if (QDF_IS_STATUS_ERROR(status)) { 110 dp_umac_reset_err("No interrupt assignment"); 111 return status; 112 } 113 114 alloc_size = sizeof(htt_umac_hang_recovery_msg_shmem_t) + 115 DP_UMAC_RESET_SHMEM_ALIGN - 1; 116 umac_reset_ctx->shmem_vaddr_unaligned = 117 qdf_mem_alloc_consistent(soc->osdev, soc->osdev->dev, 118 alloc_size, 119 &umac_reset_ctx->shmem_paddr_unaligned); 120 if (!umac_reset_ctx->shmem_vaddr_unaligned) { 121 dp_umac_reset_err("shmem allocation failed"); 122 return QDF_STATUS_E_NOMEM; 123 } 124 125 umac_reset_ctx->shmem_vaddr_aligned = (void *)(uintptr_t)qdf_roundup( 126 (uint64_t)(uintptr_t)umac_reset_ctx->shmem_vaddr_unaligned, 127 DP_UMAC_RESET_SHMEM_ALIGN); 128 umac_reset_ctx->shmem_paddr_aligned = qdf_roundup( 129 (uint64_t)umac_reset_ctx->shmem_paddr_unaligned, 130 DP_UMAC_RESET_SHMEM_ALIGN); 131 umac_reset_ctx->shmem_size = alloc_size; 132 133 /* Write the magic number to the shared memory */ 134 umac_reset_ctx->shmem_vaddr_aligned->magic_num = 135 DP_UMAC_RESET_SHMEM_MAGIC_NUM; 136 137 /* Attach the interrupts */ 138 status = dp_umac_reset_interrupt_attach(soc); 139 if (QDF_IS_STATUS_ERROR(status)) { 140 dp_umac_reset_err("Interrupt attach failed"); 141 qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, 142 umac_reset_ctx->shmem_size, 143 umac_reset_ctx->shmem_vaddr_unaligned, 144 umac_reset_ctx->shmem_paddr_unaligned, 145 0); 146 return status; 147 } 148 149 /* Send the setup cmd to the target */ 150 return dp_umac_reset_send_setup_cmd(soc); 151 } 152 153 /** 154 * dp_umac_reset_get_rx_event_from_shmem() - Extract the Rx event from the 155 * shared memory 156 * @umac_reset_ctx: UMAC reset context 157 * 158 * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event 159 */ 160 static enum umac_reset_rx_event 161 dp_umac_reset_get_rx_event_from_shmem( 162 struct dp_soc_umac_reset_ctx *umac_reset_ctx) 163 { 164 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 165 uint32_t t2h_msg; 166 uint8_t num_events = 0; 167 enum umac_reset_rx_event rx_event; 168 169 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 170 if (!shmem_vaddr) { 171 dp_umac_reset_err("Shared memory address is NULL"); 172 goto err; 173 } 174 175 if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) { 176 dp_umac_reset_err("Shared memory got corrupted"); 177 goto err; 178 } 179 180 /* Read the shared memory into a local variable */ 181 t2h_msg = shmem_vaddr->t2h_msg; 182 183 /* Clear the shared memory right away */ 184 shmem_vaddr->t2h_msg = 0; 185 186 dp_umac_reset_debug("shmem value - t2h_msg: 0x%x", t2h_msg); 187 188 rx_event = UMAC_RESET_RX_EVENT_NONE; 189 190 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_UMAC_RECOVERY_GET(t2h_msg)) { 191 rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY; 192 num_events++; 193 } 194 195 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_TARGET_RECOVERY_SYNC_USING_UMAC_GET(t2h_msg)) { 196 rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC; 197 num_events++; 198 } 199 200 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) { 201 rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET; 202 num_events++; 203 } 204 205 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_START_GET(t2h_msg)) { 206 rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_START; 207 num_events++; 208 } 209 210 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_COMPLETE_GET(t2h_msg)) { 211 rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE; 212 num_events++; 213 } 214 215 dp_umac_reset_debug("deduced rx event: 0x%x", rx_event); 216 /* There should not be more than 1 event */ 217 if (num_events > 1) { 218 dp_umac_reset_err("Multiple events(0x%x) got posted", rx_event); 219 goto err; 220 } 221 222 return rx_event; 223 err: 224 qdf_assert_always(0); 225 return UMAC_RESET_RX_EVENT_ERROR; 226 } 227 228 /** 229 * dp_umac_reset_peek_rx_event_from_shmem() - Peek the Rx event from the 230 * shared memory without clearing the bit 231 * @umac_reset_ctx: UMAC reset context 232 * 233 * Return: true if the shared memory has any valid bits set 234 */ 235 static inline bool dp_umac_reset_peek_rx_event_from_shmem( 236 struct dp_soc_umac_reset_ctx *umac_reset_ctx) 237 { 238 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 239 240 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 241 if (!shmem_vaddr) { 242 dp_umac_reset_debug("Shared memory address is NULL"); 243 goto err; 244 } 245 246 if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) { 247 dp_umac_reset_debug("Shared memory got corrupted"); 248 goto err; 249 } 250 251 /* Read the shared memory into a local variable */ 252 return !!shmem_vaddr->t2h_msg; 253 254 err: 255 return false; 256 } 257 258 /** 259 * dp_umac_reset_get_rx_event() - Extract the Rx event 260 * @umac_reset_ctx: UMAC reset context 261 * 262 * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event 263 */ 264 static inline enum umac_reset_rx_event 265 dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx *umac_reset_ctx) 266 { 267 return dp_umac_reset_get_rx_event_from_shmem(umac_reset_ctx); 268 } 269 270 /** 271 * dp_umac_reset_validate_n_update_state_machine_on_rx() - Validate the state 272 * machine for a given rx event and update the state machine 273 * @umac_reset_ctx: UMAC reset context 274 * @rx_event: Rx event 275 * @current_exp_state: Expected state 276 * @next_state: The state to which the state machine needs to be updated 277 * 278 * Return: QDF_STATUS of operation 279 */ 280 QDF_STATUS 281 dp_umac_reset_validate_n_update_state_machine_on_rx( 282 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 283 enum umac_reset_rx_event rx_event, 284 enum umac_reset_state current_exp_state, 285 enum umac_reset_state next_state) 286 { 287 if (umac_reset_ctx->current_state != current_exp_state) { 288 dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d", 289 rx_event, 290 umac_reset_ctx->current_state); 291 292 if ((rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY) && 293 (rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC)) 294 qdf_assert_always(0); 295 296 return QDF_STATUS_E_FAILURE; 297 } 298 299 /* Update the state */ 300 umac_reset_ctx->current_state = next_state; 301 return QDF_STATUS_SUCCESS; 302 } 303 304 static bool dp_umac_reset_peek_rx_event(void *dp_ctx) 305 { 306 struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx; 307 struct dp_soc *soc = int_ctx->soc; 308 struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx; 309 310 return dp_umac_reset_peek_rx_event_from_shmem(umac_reset_ctx); 311 } 312 313 /** 314 * dp_check_umac_reset_in_progress() - Check if Umac reset is in progress 315 * @soc: dp soc handle 316 * 317 * Return: true if Umac reset is in progress or false otherwise 318 */ 319 bool dp_check_umac_reset_in_progress(struct dp_soc *soc) 320 { 321 return !!soc->umac_reset_ctx.intr_ctx_bkp; 322 } 323 324 #if !defined(WLAN_FEATURE_11BE_MLO) || !defined(WLAN_MLO_MULTI_CHIP) 325 /** 326 * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session 327 * @soc: dp soc handle 328 * @umac_reset_ctx: Umac reset context 329 * @rx_event: Rx event received 330 * @is_target_recovery: Flag to indicate if it is triggered for target recovery 331 * 332 * Return: status 333 */ 334 static QDF_STATUS dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc, 335 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 336 enum umac_reset_rx_event rx_event, 337 bool is_target_recovery) 338 { 339 return dp_umac_reset_validate_n_update_state_machine_on_rx( 340 umac_reset_ctx, rx_event, 341 UMAC_RESET_STATE_WAIT_FOR_TRIGGER, 342 UMAC_RESET_STATE_DO_TRIGGER_RECEIVED); 343 } 344 345 /** 346 * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session 347 * @soc: dp soc handle 348 * 349 * Return: void 350 */ 351 static void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc) 352 { 353 dp_umac_reset_alert("Umac reset was handled successfully on soc %pK", 354 soc); 355 } 356 357 /** 358 * dp_umac_reset_handle_action_cb() - Function to call action callback 359 * @soc: dp soc handle 360 * @umac_reset_ctx: Umac reset context 361 * @action: Action to call the callback for 362 * 363 * Return: QDF_STATUS status 364 */ 365 static QDF_STATUS dp_umac_reset_handle_action_cb(struct dp_soc *soc, 366 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 367 enum umac_reset_action action) 368 { 369 QDF_STATUS status = QDF_STATUS_SUCCESS; 370 371 if (!umac_reset_ctx->rx_actions.cb[action]) { 372 dp_umac_reset_err("rx callback is NULL"); 373 return QDF_STATUS_E_FAILURE; 374 } 375 376 status = umac_reset_ctx->rx_actions.cb[action](soc); 377 378 return QDF_STATUS_SUCCESS; 379 } 380 381 /** 382 * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command 383 * @umac_reset_ctx: UMAC reset context 384 * @tx_cmd: Tx command to be posted 385 * 386 * Return: QDF status of operation 387 */ 388 static QDF_STATUS 389 dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx, 390 enum umac_reset_tx_cmd tx_cmd) 391 { 392 struct dp_soc *soc = container_of(umac_reset_ctx, struct dp_soc, 393 umac_reset_ctx); 394 395 dp_umac_reset_post_tx_cmd_via_shmem(soc, &tx_cmd, 0); 396 return QDF_STATUS_SUCCESS; 397 } 398 399 /** 400 * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator 401 * @soc: dp soc handle 402 * 403 * Return: true if the soc is initiator or false otherwise 404 */ 405 static bool dp_umac_reset_initiator_check(struct dp_soc *soc) 406 { 407 return true; 408 } 409 410 /** 411 * dp_umac_reset_target_recovery_check() - Check if this is for target recovery 412 * @soc: dp soc handle 413 * 414 * Return: true if the session is for target recovery or false otherwise 415 */ 416 static bool dp_umac_reset_target_recovery_check(struct dp_soc *soc) 417 { 418 return false; 419 } 420 421 /** 422 * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored 423 * @soc: dp soc handle 424 * 425 * Return: true if the soc is ignored or false otherwise 426 */ 427 static bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc) 428 { 429 return false; 430 } 431 #endif 432 433 /** 434 * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset 435 * @dp_ctx: Interrupt context corresponding to UMAC reset 436 * 437 * Return: 0 incase of success, else failure 438 */ 439 static int dp_umac_reset_rx_event_handler(void *dp_ctx) 440 { 441 struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx; 442 struct dp_soc *soc = int_ctx->soc; 443 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 444 enum umac_reset_rx_event rx_event; 445 QDF_STATUS status = QDF_STATUS_E_INVAL; 446 enum umac_reset_action action = UMAC_RESET_ACTION_NONE; 447 bool target_recovery = false; 448 449 if (!soc) { 450 dp_umac_reset_err("DP SOC is null"); 451 goto exit; 452 } 453 454 umac_reset_ctx = &soc->umac_reset_ctx; 455 456 dp_umac_reset_debug("enter"); 457 rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx); 458 459 if (umac_reset_ctx->pending_action) { 460 if (rx_event != UMAC_RESET_RX_EVENT_NONE) { 461 dp_umac_reset_err("Invalid value(%u) for Rx event when " 462 "action %u is pending\n", rx_event, 463 umac_reset_ctx->pending_action); 464 qdf_assert_always(0); 465 } 466 } 467 468 switch (rx_event) { 469 case UMAC_RESET_RX_EVENT_NONE: 470 if (umac_reset_ctx->pending_action) 471 action = umac_reset_ctx->pending_action; 472 else 473 dp_umac_reset_err("Not a UMAC reset event!!"); 474 475 status = QDF_STATUS_SUCCESS; 476 break; 477 478 case UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC: 479 target_recovery = true; 480 /* Fall through */ 481 case UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY: 482 status = 483 dp_umac_reset_initiate_umac_recovery(soc, umac_reset_ctx, 484 rx_event, target_recovery); 485 486 if (status != QDF_STATUS_SUCCESS) 487 break; 488 489 umac_reset_ctx->ts.trigger_start = 490 qdf_get_log_timestamp_usecs(); 491 492 action = UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY; 493 494 break; 495 496 case UMAC_RESET_RX_EVENT_DO_PRE_RESET: 497 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 498 umac_reset_ctx, rx_event, 499 UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, 500 UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED); 501 502 umac_reset_ctx->ts.pre_reset_start = 503 qdf_get_log_timestamp_usecs(); 504 505 action = UMAC_RESET_ACTION_DO_PRE_RESET; 506 break; 507 508 case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: 509 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 510 umac_reset_ctx, rx_event, 511 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, 512 UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED); 513 514 umac_reset_ctx->ts.post_reset_start = 515 qdf_get_log_timestamp_usecs(); 516 517 action = UMAC_RESET_ACTION_DO_POST_RESET_START; 518 break; 519 520 case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: 521 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 522 umac_reset_ctx, rx_event, 523 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, 524 UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED); 525 526 umac_reset_ctx->ts.post_reset_complete_start = 527 qdf_get_log_timestamp_usecs(); 528 529 action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE; 530 break; 531 532 case UMAC_RESET_RX_EVENT_ERROR: 533 dp_umac_reset_err("Error Rx event"); 534 goto exit; 535 536 default: 537 dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event); 538 goto exit; 539 } 540 541 /* Call the handler for this event */ 542 if (QDF_IS_STATUS_SUCCESS(status)) { 543 dp_umac_reset_handle_action_cb(soc, umac_reset_ctx, action); 544 } 545 546 exit: 547 return qdf_status_to_os_return(status); 548 } 549 550 QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc) 551 { 552 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 553 int msi_vector_count, ret; 554 uint32_t msi_base_data, msi_vector_start; 555 uint32_t umac_reset_vector, umac_reset_irq; 556 QDF_STATUS status; 557 558 if (!soc) { 559 dp_umac_reset_err("DP SOC is null"); 560 return QDF_STATUS_E_NULL_VALUE; 561 } 562 563 if (!soc->features.umac_hw_reset_support) { 564 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 565 return QDF_STATUS_SUCCESS; 566 } 567 568 umac_reset_ctx = &soc->umac_reset_ctx; 569 570 if (pld_get_enable_intx(soc->osdev->dev)) { 571 dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode"); 572 return QDF_STATUS_E_FAILURE; 573 } 574 575 ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP", 576 &msi_vector_count, &msi_base_data, 577 &msi_vector_start); 578 if (ret) { 579 /* UMAC reset uses IPC interrupt for AHB devices */ 580 status = hif_get_umac_reset_irq(soc->hif_handle, 581 &umac_reset_irq); 582 if (status) { 583 dp_umac_reset_err("get_umac_reset_irq failed status %d", 584 status); 585 return QDF_STATUS_E_FAILURE; 586 } 587 } else { 588 if (umac_reset_ctx->intr_offset < 0 || 589 umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) { 590 dp_umac_reset_err("Invalid interrupt offset: %d", 591 umac_reset_ctx->intr_offset); 592 return QDF_STATUS_E_FAILURE; 593 } 594 595 umac_reset_vector = msi_vector_start + 596 (umac_reset_ctx->intr_offset % msi_vector_count); 597 598 /* Get IRQ number */ 599 umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, 600 umac_reset_vector); 601 } 602 603 /* Finally register to this IRQ from HIF layer */ 604 return hif_register_umac_reset_handler( 605 soc->hif_handle, 606 dp_umac_reset_peek_rx_event, 607 dp_umac_reset_rx_event_handler, 608 &soc->intr_ctx[umac_reset_ctx->intr_offset], 609 umac_reset_irq); 610 } 611 612 QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc) 613 { 614 if (!soc) { 615 dp_umac_reset_err("DP SOC is null"); 616 return QDF_STATUS_E_NULL_VALUE; 617 } 618 619 if (!soc->features.umac_hw_reset_support) { 620 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 621 return QDF_STATUS_SUCCESS; 622 } 623 624 return hif_unregister_umac_reset_handler(soc->hif_handle); 625 } 626 627 QDF_STATUS dp_umac_reset_register_rx_action_callback( 628 struct dp_soc *soc, 629 QDF_STATUS (*handler)(struct dp_soc *soc), 630 enum umac_reset_action action) 631 { 632 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 633 634 if (!soc) { 635 dp_umac_reset_err("DP SOC is null"); 636 return QDF_STATUS_E_NULL_VALUE; 637 } 638 639 if (!soc->features.umac_hw_reset_support) { 640 dp_umac_reset_info("Target doesn't support UMAC HW reset"); 641 return QDF_STATUS_E_NOSUPPORT; 642 } 643 644 if (action >= UMAC_RESET_ACTION_MAX) { 645 dp_umac_reset_err("invalid action: %d", action); 646 return QDF_STATUS_E_INVAL; 647 } 648 649 umac_reset_ctx = &soc->umac_reset_ctx; 650 651 umac_reset_ctx->rx_actions.cb[action] = handler; 652 653 return QDF_STATUS_SUCCESS; 654 } 655 656 /** 657 * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory 658 * @soc: DP soc object 659 * @ctxt: Tx command to be posted 660 * @chip_id: Chip id of the mlo soc 661 * 662 * Return: None 663 */ 664 void 665 dp_umac_reset_post_tx_cmd_via_shmem(struct dp_soc *soc, void *ctxt, int chip_id) 666 { 667 enum umac_reset_tx_cmd tx_cmd = *((enum umac_reset_tx_cmd *)ctxt); 668 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 669 struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx; 670 bool initiator; 671 QDF_STATUS status; 672 673 if (dp_umac_reset_is_soc_ignored(soc)) { 674 dp_umac_reset_debug("Skipping soc (chip id %d)", chip_id); 675 return; 676 } 677 678 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 679 if (!shmem_vaddr) { 680 dp_umac_reset_err("Shared memory address is NULL"); 681 return; 682 } 683 684 dp_umac_reset_debug("Sending txcmd %u for chip id %u", tx_cmd, chip_id); 685 686 switch (tx_cmd) { 687 case UMAC_RESET_TX_CMD_TRIGGER_DONE: 688 /* Send htt message to the partner soc */ 689 initiator = dp_umac_reset_initiator_check(soc); 690 if (!initiator) 691 umac_reset_ctx->current_state = 692 UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; 693 694 status = dp_htt_umac_reset_send_start_pre_reset_cmd(soc, 695 initiator, 696 !dp_umac_reset_target_recovery_check(soc)); 697 698 if (status != QDF_STATUS_SUCCESS) { 699 dp_umac_reset_err("Unable to send Umac trigger"); 700 qdf_assert_always(0); 701 } else { 702 dp_umac_reset_debug("Sent trigger for soc (chip_id %d)", 703 chip_id); 704 } 705 706 umac_reset_ctx->ts.trigger_done = qdf_get_log_timestamp_usecs(); 707 break; 708 709 case UMAC_RESET_TX_CMD_PRE_RESET_DONE: 710 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET( 711 shmem_vaddr->h2t_msg, 1); 712 713 umac_reset_ctx->ts.pre_reset_done = 714 qdf_get_log_timestamp_usecs(); 715 break; 716 717 case UMAC_RESET_TX_CMD_POST_RESET_START_DONE: 718 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET( 719 shmem_vaddr->h2t_msg, 1); 720 721 umac_reset_ctx->ts.post_reset_done = 722 qdf_get_log_timestamp_usecs(); 723 break; 724 725 case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE: 726 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET( 727 shmem_vaddr->h2t_msg, 1); 728 729 umac_reset_ctx->ts.post_reset_complete_done = 730 qdf_get_log_timestamp_usecs(); 731 break; 732 733 default: 734 dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd); 735 return; 736 } 737 738 return; 739 } 740 741 /** 742 * dp_umac_reset_notify_target() - Notify the target about completion of action. 743 * @umac_reset_ctx: UMAC reset context 744 * 745 * This API figures out the Tx command that needs to be posted based on the 746 * current state in the state machine. Also, updates the state machine once the 747 * Tx command has been posted. 748 * 749 * Return: QDF status of operation 750 */ 751 static QDF_STATUS 752 dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) 753 { 754 enum umac_reset_state next_state; 755 enum umac_reset_tx_cmd tx_cmd; 756 QDF_STATUS status; 757 758 switch (umac_reset_ctx->current_state) { 759 case UMAC_RESET_STATE_HOST_TRIGGER_DONE: 760 tx_cmd = UMAC_RESET_TX_CMD_TRIGGER_DONE; 761 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; 762 break; 763 764 case UMAC_RESET_STATE_HOST_PRE_RESET_DONE: 765 tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE; 766 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START; 767 break; 768 769 case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE: 770 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE; 771 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE; 772 break; 773 774 case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: 775 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE; 776 next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; 777 break; 778 779 default: 780 dp_umac_reset_err("Invalid state(%d) during Tx", 781 umac_reset_ctx->current_state); 782 qdf_assert_always(0); 783 return QDF_STATUS_E_FAILURE; 784 } 785 786 /* 787 * Update the state machine before sending the command to firmware 788 * as we might get the response from firmware even before the state 789 * is updated. 790 */ 791 umac_reset_ctx->current_state = next_state; 792 793 status = dp_umac_reset_post_tx_cmd(umac_reset_ctx, tx_cmd); 794 if (QDF_IS_STATUS_ERROR(status)) { 795 dp_umac_reset_err("Couldn't post Tx cmd"); 796 qdf_assert_always(0); 797 return status; 798 } 799 800 return status; 801 } 802 803 /** 804 * dp_umac_reset_notify_completion() - Notify that a given action has been 805 * completed 806 * @soc: DP soc object 807 * @next_state: The state to which the state machine needs to be updated due to 808 * this completion 809 * 810 * Return: QDF status of operation 811 */ 812 static QDF_STATUS dp_umac_reset_notify_completion( 813 struct dp_soc *soc, 814 enum umac_reset_state next_state) 815 { 816 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 817 818 if (!soc) { 819 dp_umac_reset_err("DP SOC is null"); 820 return QDF_STATUS_E_NULL_VALUE; 821 } 822 823 umac_reset_ctx = &soc->umac_reset_ctx; 824 825 /* Update the state first */ 826 umac_reset_ctx->current_state = next_state; 827 828 return dp_umac_reset_notify_target(umac_reset_ctx); 829 } 830 831 static void dp_umac_wait_for_quiescent_state(struct dp_soc *soc) 832 { 833 enum umac_reset_state current_state; 834 835 do { 836 msleep(10); 837 barrier(); 838 current_state = soc->umac_reset_ctx.current_state; 839 840 } while ((current_state == UMAC_RESET_STATE_DO_TRIGGER_RECEIVED) || 841 (current_state == UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED) || 842 (current_state == UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED) || 843 (current_state == UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED)); 844 } 845 846 QDF_STATUS dp_umac_reset_notify_action_completion( 847 struct dp_soc *soc, 848 enum umac_reset_action action) 849 { 850 enum umac_reset_state next_state; 851 852 if (!soc) { 853 dp_umac_reset_err("DP SOC is null"); 854 return QDF_STATUS_E_NULL_VALUE; 855 } 856 857 if (!soc->features.umac_hw_reset_support) { 858 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 859 return QDF_STATUS_E_NOSUPPORT; 860 } 861 862 switch (action) { 863 case UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY: 864 next_state = UMAC_RESET_STATE_HOST_TRIGGER_DONE; 865 break; 866 867 case UMAC_RESET_ACTION_DO_PRE_RESET: 868 next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE; 869 break; 870 871 case UMAC_RESET_ACTION_DO_POST_RESET_START: 872 next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE; 873 break; 874 875 case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE: 876 next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE; 877 break; 878 879 case UMAC_RESET_ACTION_ABORT: 880 next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; 881 break; 882 883 default: 884 dp_umac_reset_err("Invalid action: %u", action); 885 return QDF_STATUS_E_FAILURE; 886 } 887 888 return dp_umac_reset_notify_completion(soc, next_state); 889 } 890 891 /** 892 * dp_soc_umac_reset_deinit() - Deinitialize the umac reset module 893 * @txrx_soc: DP soc object 894 * 895 * Return: QDF status of operation 896 */ 897 QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc) 898 { 899 struct dp_soc *soc = (struct dp_soc *)txrx_soc; 900 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 901 qdf_nbuf_t nbuf_list; 902 903 if (!soc) { 904 dp_umac_reset_err("DP SOC is null"); 905 return QDF_STATUS_E_NULL_VALUE; 906 } 907 908 if (!soc->features.umac_hw_reset_support) { 909 dp_umac_reset_info("No target support for UMAC reset feature"); 910 return QDF_STATUS_E_NOSUPPORT; 911 } 912 913 if (dp_check_umac_reset_in_progress(soc)) { 914 dp_umac_reset_info("Cleaning up Umac reset context"); 915 dp_umac_wait_for_quiescent_state(soc); 916 dp_resume_reo_send_cmd(soc); 917 dp_umac_reset_notify_action_completion(soc, 918 UMAC_RESET_ACTION_ABORT); 919 } 920 921 nbuf_list = soc->umac_reset_ctx.nbuf_list; 922 soc->umac_reset_ctx.nbuf_list = NULL; 923 924 while (nbuf_list) { 925 qdf_nbuf_t nbuf = nbuf_list->next; 926 927 qdf_nbuf_free(nbuf_list); 928 nbuf_list = nbuf; 929 } 930 931 dp_umac_reset_interrupt_detach(soc); 932 933 umac_reset_ctx = &soc->umac_reset_ctx; 934 qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, 935 umac_reset_ctx->shmem_size, 936 umac_reset_ctx->shmem_vaddr_unaligned, 937 umac_reset_ctx->shmem_paddr_unaligned, 938 0); 939 940 return QDF_STATUS_SUCCESS; 941 } 942 943 static inline const char *dp_umac_reset_current_state_to_str( 944 enum umac_reset_state current_state) 945 { 946 switch (current_state) { 947 case UMAC_RESET_STATE_WAIT_FOR_TRIGGER: 948 return "UMAC_RESET_STATE_WAIT_FOR_TRIGGER"; 949 case UMAC_RESET_STATE_DO_TRIGGER_RECEIVED: 950 return "UMAC_RESET_STATE_DO_TRIGGER_RECEIVED"; 951 case UMAC_RESET_STATE_HOST_TRIGGER_DONE: 952 return "UMAC_RESET_STATE_HOST_TRIGGER_DONE"; 953 case UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET: 954 return "UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET"; 955 case UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED: 956 return "UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED"; 957 case UMAC_RESET_STATE_HOST_PRE_RESET_DONE: 958 return "UMAC_RESET_STATE_HOST_PRE_RESET_DONE"; 959 case UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START: 960 return "UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START"; 961 case UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED: 962 return "UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED"; 963 case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE: 964 return "UMAC_RESET_STATE_HOST_POST_RESET_START_DONE"; 965 case UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE: 966 return "UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE"; 967 case UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED: 968 return "UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED"; 969 case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: 970 return "UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE"; 971 default: 972 return "Invalid UMAC Reset state"; 973 } 974 } 975 976 static inline const char *dp_umac_reset_pending_action_to_str( 977 enum umac_reset_rx_event pending_action) 978 { 979 switch (pending_action) { 980 case UMAC_RESET_RX_EVENT_NONE: 981 return "UMAC_RESET_RX_EVENT_NONE"; 982 case UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY: 983 return "UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY"; 984 case UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC: 985 return "UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC"; 986 case UMAC_RESET_RX_EVENT_DO_PRE_RESET: 987 return "UMAC_RESET_RX_EVENT_DO_PRE_RESET"; 988 case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: 989 return "UMAC_RESET_RX_EVENT_DO_POST_RESET_START"; 990 case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: 991 return "UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE"; 992 default: 993 return "Invalid pending action"; 994 } 995 } 996 997 QDF_STATUS dp_umac_reset_stats_print(struct dp_soc *soc) 998 { 999 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 1000 1001 umac_reset_ctx = &soc->umac_reset_ctx; 1002 1003 DP_UMAC_RESET_PRINT_STATS("UMAC reset stats for soc:%pK\n" 1004 "\t\ttrigger time :%llu us\n" 1005 "\t\tPre_reset time :%llu us\n" 1006 "\t\tPost_reset time :%llu us\n" 1007 "\t\tPost_reset_complete time :%llu us\n" 1008 "\t\tCurrent state :%s\n" 1009 "\t\tPending action :%s", 1010 soc, 1011 umac_reset_ctx->ts.trigger_done - 1012 umac_reset_ctx->ts.trigger_start, 1013 umac_reset_ctx->ts.pre_reset_done - 1014 umac_reset_ctx->ts.pre_reset_start, 1015 umac_reset_ctx->ts.post_reset_done - 1016 umac_reset_ctx->ts.post_reset_start, 1017 umac_reset_ctx->ts.post_reset_complete_done - 1018 umac_reset_ctx->ts.post_reset_complete_start, 1019 dp_umac_reset_current_state_to_str( 1020 umac_reset_ctx->current_state), 1021 dp_umac_reset_pending_action_to_str( 1022 umac_reset_ctx->pending_action)); 1023 1024 return dp_mlo_umac_reset_stats_print(soc); 1025 } 1026