1 /* 2 * Copyright (c) 2022 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_types.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 ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP", 67 &msi_vector_count, &msi_base_data, 68 &msi_vector_start); 69 if (ret) 70 return QDF_STATUS_E_FAILURE; 71 72 qdf_mem_zero(¶ms, sizeof(params)); 73 params.msi_data = (umac_reset_ctx->intr_offset % msi_vector_count) + 74 msi_base_data; 75 params.shmem_addr_low = 76 qdf_get_lower_32_bits(umac_reset_ctx->shmem_paddr_aligned); 77 params.shmem_addr_high = 78 qdf_get_upper_32_bits(umac_reset_ctx->shmem_paddr_aligned); 79 80 return dp_htt_umac_reset_send_setup_cmd(soc, ¶ms); 81 } 82 83 QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) 84 { 85 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 86 size_t alloc_size; 87 QDF_STATUS status; 88 89 if (!soc) { 90 dp_umac_reset_err("DP SOC is null"); 91 return QDF_STATUS_E_NULL_VALUE; 92 } 93 94 if (!soc->features.umac_hw_reset_support) { 95 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 96 return QDF_STATUS_E_NOSUPPORT; 97 } 98 99 umac_reset_ctx = &soc->umac_reset_ctx; 100 qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx)); 101 102 umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; 103 umac_reset_ctx->shmem_exp_magic_num = DP_UMAC_RESET_SHMEM_MAGIC_NUM; 104 105 status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset); 106 if (QDF_IS_STATUS_ERROR(status)) { 107 dp_umac_reset_err("No interrupt assignment"); 108 return status; 109 } 110 111 alloc_size = sizeof(htt_umac_hang_recovery_msg_shmem_t) + 112 DP_UMAC_RESET_SHMEM_ALIGN - 1; 113 umac_reset_ctx->shmem_vaddr_unaligned = 114 qdf_mem_alloc_consistent(soc->osdev, soc->osdev->dev, 115 alloc_size, 116 &umac_reset_ctx->shmem_paddr_unaligned); 117 if (!umac_reset_ctx->shmem_vaddr_unaligned) { 118 dp_umac_reset_err("shmem allocation failed"); 119 return QDF_STATUS_E_NOMEM; 120 } 121 122 umac_reset_ctx->shmem_vaddr_aligned = (void *)(uintptr_t)qdf_roundup( 123 (uint64_t)(uintptr_t)umac_reset_ctx->shmem_vaddr_unaligned, 124 DP_UMAC_RESET_SHMEM_ALIGN); 125 umac_reset_ctx->shmem_paddr_aligned = qdf_roundup( 126 (uint64_t)umac_reset_ctx->shmem_paddr_unaligned, 127 DP_UMAC_RESET_SHMEM_ALIGN); 128 umac_reset_ctx->shmem_size = alloc_size; 129 130 /* Write the magic number to the shared memory */ 131 umac_reset_ctx->shmem_vaddr_aligned->magic_num = 132 DP_UMAC_RESET_SHMEM_MAGIC_NUM; 133 134 /* Attach the interrupts */ 135 status = dp_umac_reset_interrupt_attach(soc); 136 if (QDF_IS_STATUS_ERROR(status)) { 137 dp_umac_reset_err("Interrupt attach failed"); 138 qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, 139 umac_reset_ctx->shmem_size, 140 umac_reset_ctx->shmem_vaddr_unaligned, 141 umac_reset_ctx->shmem_paddr_unaligned, 142 0); 143 return status; 144 } 145 146 /* Send the setup cmd to the target */ 147 return dp_umac_reset_send_setup_cmd(soc); 148 } 149 150 QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc) 151 { 152 struct dp_soc *soc = (struct dp_soc *)txrx_soc; 153 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 154 155 if (!soc) { 156 dp_umac_reset_err("DP SOC is null"); 157 return QDF_STATUS_E_NULL_VALUE; 158 } 159 160 if (!soc->features.umac_hw_reset_support) { 161 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 162 return QDF_STATUS_E_NOSUPPORT; 163 } 164 165 dp_umac_reset_interrupt_detach(soc); 166 167 umac_reset_ctx = &soc->umac_reset_ctx; 168 qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, 169 umac_reset_ctx->shmem_size, 170 umac_reset_ctx->shmem_vaddr_unaligned, 171 umac_reset_ctx->shmem_paddr_unaligned, 172 0); 173 174 return QDF_STATUS_SUCCESS; 175 } 176 177 /** 178 * dp_umac_reset_get_rx_event() - Extract the Rx event from the shared memory 179 * @umac_reset_ctx: UMAC reset context 180 * 181 * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event 182 */ 183 static enum umac_reset_rx_event 184 dp_umac_reset_get_rx_event_from_shmem( 185 struct dp_soc_umac_reset_ctx *umac_reset_ctx) 186 { 187 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 188 uint32_t t2h_msg; 189 uint8_t num_events = 0; 190 enum umac_reset_rx_event rx_event; 191 192 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 193 if (!shmem_vaddr) { 194 dp_umac_reset_err("Shared memory address is NULL"); 195 goto err; 196 } 197 198 if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) { 199 dp_umac_reset_err("Shared memory got corrupted"); 200 goto err; 201 } 202 203 /* Read the shared memory into a local variable */ 204 t2h_msg = shmem_vaddr->t2h_msg; 205 206 /* Clear the shared memory right away */ 207 shmem_vaddr->t2h_msg = 0; 208 209 dp_umac_reset_debug("shmem value - t2h_msg: 0x%x", t2h_msg); 210 211 rx_event = UMAC_RESET_RX_EVENT_NONE; 212 213 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) { 214 rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET; 215 num_events++; 216 } 217 218 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_START_GET(t2h_msg)) { 219 rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_START; 220 num_events++; 221 } 222 223 if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_COMPLETE_GET(t2h_msg)) { 224 rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE; 225 num_events++; 226 } 227 228 dp_umac_reset_debug("deduced rx event: 0x%x", rx_event); 229 /* There should not be more than 1 event */ 230 if (num_events > 1) { 231 dp_umac_reset_err("Multiple events(0x%x) got posted", rx_event); 232 goto err; 233 } 234 235 return rx_event; 236 err: 237 qdf_assert_always(0); 238 return UMAC_RESET_RX_EVENT_ERROR; 239 } 240 241 /** 242 * dp_umac_reset_get_rx_event() - Extract the Rx event 243 * @umac_reset_ctx: UMAC reset context 244 * 245 * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event 246 */ 247 static inline enum umac_reset_rx_event 248 dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx *umac_reset_ctx) 249 { 250 return dp_umac_reset_get_rx_event_from_shmem(umac_reset_ctx); 251 } 252 253 /** 254 * dp_umac_reset_validate_n_update_state_machine_on_rx() - Validate the state 255 * machine for a given rx event and update the state machine 256 * @umac_reset_ctx: UMAC reset context 257 * @rx_event: Rx event 258 * @current_exp_state: Expected state 259 * @next_state: The state to which the state machine needs to be updated 260 * 261 * Return: QDF_STATUS of operation 262 */ 263 static QDF_STATUS 264 dp_umac_reset_validate_n_update_state_machine_on_rx( 265 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 266 enum umac_reset_rx_event rx_event, 267 enum umac_reset_state current_exp_state, 268 enum umac_reset_state next_state) 269 { 270 if (umac_reset_ctx->current_state != current_exp_state) { 271 dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d", 272 rx_event, 273 umac_reset_ctx->current_state); 274 qdf_assert_always(0); 275 return QDF_STATUS_E_FAILURE; 276 } 277 278 /* Update the state */ 279 umac_reset_ctx->current_state = next_state; 280 return QDF_STATUS_SUCCESS; 281 } 282 283 /** 284 * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset 285 * @dp_ctx: Interrupt context corresponding to UMAC reset 286 * 287 * Return: 0 incase of success, else failure 288 */ 289 static int dp_umac_reset_rx_event_handler(void *dp_ctx) 290 { 291 struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx; 292 struct dp_soc *soc = int_ctx->soc; 293 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 294 enum umac_reset_rx_event rx_event; 295 QDF_STATUS status = QDF_STATUS_E_INVAL; 296 enum umac_reset_action action; 297 298 if (!soc) { 299 dp_umac_reset_err("DP SOC is null"); 300 goto exit; 301 } 302 303 umac_reset_ctx = &soc->umac_reset_ctx; 304 305 dp_umac_reset_debug("enter"); 306 rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx); 307 308 switch (rx_event) { 309 case UMAC_RESET_RX_EVENT_NONE: 310 /* This interrupt is not meant for us, so exit */ 311 dp_umac_reset_debug("Not a UMAC reset event"); 312 status = QDF_STATUS_SUCCESS; 313 goto exit; 314 315 case UMAC_RESET_RX_EVENT_DO_PRE_RESET: 316 umac_reset_ctx->ts.pre_reset_start = 317 qdf_get_log_timestamp_usecs(); 318 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 319 umac_reset_ctx, rx_event, 320 UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, 321 UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED); 322 323 action = UMAC_RESET_ACTION_DO_PRE_RESET; 324 break; 325 326 case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: 327 umac_reset_ctx->ts.post_reset_start = 328 qdf_get_log_timestamp_usecs(); 329 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 330 umac_reset_ctx, rx_event, 331 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, 332 UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED); 333 334 action = UMAC_RESET_ACTION_DO_POST_RESET_START; 335 break; 336 337 case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: 338 umac_reset_ctx->ts.post_reset_complete_start = 339 qdf_get_log_timestamp_usecs(); 340 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 341 umac_reset_ctx, rx_event, 342 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, 343 UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED); 344 345 action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE; 346 break; 347 348 case UMAC_RESET_RX_EVENT_ERROR: 349 dp_umac_reset_err("Error Rx event"); 350 goto exit; 351 352 default: 353 dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event); 354 goto exit; 355 } 356 357 /* Call the handler for this event */ 358 if (QDF_IS_STATUS_SUCCESS(status)) { 359 if (!umac_reset_ctx->rx_actions.cb[action]) { 360 dp_umac_reset_err("rx callback is NULL"); 361 goto exit; 362 } 363 364 status = umac_reset_ctx->rx_actions.cb[action](soc); 365 } 366 367 exit: 368 return qdf_status_to_os_return(status); 369 } 370 371 QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc) 372 { 373 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 374 int msi_vector_count, ret; 375 uint32_t msi_base_data, msi_vector_start; 376 uint32_t umac_reset_vector, umac_reset_irq; 377 378 if (!soc) { 379 dp_umac_reset_err("DP SOC is null"); 380 return QDF_STATUS_E_NULL_VALUE; 381 } 382 383 if (!soc->features.umac_hw_reset_support) { 384 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 385 return QDF_STATUS_SUCCESS; 386 } 387 388 umac_reset_ctx = &soc->umac_reset_ctx; 389 390 if (pld_get_enable_intx(soc->osdev->dev)) { 391 dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode"); 392 return QDF_STATUS_E_FAILURE; 393 } 394 395 ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP", 396 &msi_vector_count, &msi_base_data, 397 &msi_vector_start); 398 if (ret) { 399 dp_umac_reset_err("UMAC reset is only supported in MSI interrupt mode"); 400 return QDF_STATUS_E_FAILURE; 401 } 402 403 if (umac_reset_ctx->intr_offset < 0 || 404 umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) { 405 dp_umac_reset_err("Invalid interrupt offset"); 406 return QDF_STATUS_E_FAILURE; 407 } 408 409 umac_reset_vector = msi_vector_start + 410 (umac_reset_ctx->intr_offset % msi_vector_count); 411 412 /* Get IRQ number */ 413 umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, umac_reset_vector); 414 415 /* Finally register to this IRQ from HIF layer */ 416 return hif_register_umac_reset_handler( 417 soc->hif_handle, 418 dp_umac_reset_rx_event_handler, 419 &soc->intr_ctx[umac_reset_ctx->intr_offset], 420 umac_reset_irq); 421 } 422 423 QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc) 424 { 425 if (!soc) { 426 dp_umac_reset_err("DP SOC is null"); 427 return QDF_STATUS_E_NULL_VALUE; 428 } 429 430 if (!soc->features.umac_hw_reset_support) { 431 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 432 return QDF_STATUS_SUCCESS; 433 } 434 435 return hif_unregister_umac_reset_handler(soc->hif_handle); 436 } 437 438 QDF_STATUS dp_umac_reset_register_rx_action_callback( 439 struct dp_soc *soc, 440 QDF_STATUS (*handler)(struct dp_soc *soc), 441 enum umac_reset_action action) 442 { 443 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 444 445 if (!soc) { 446 dp_umac_reset_err("DP SOC is null"); 447 return QDF_STATUS_E_NULL_VALUE; 448 } 449 450 if (!soc->features.umac_hw_reset_support) { 451 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 452 return QDF_STATUS_E_NOSUPPORT; 453 } 454 455 if (action >= UMAC_RESET_ACTION_MAX) { 456 dp_umac_reset_err("invalid action: %d", action); 457 return QDF_STATUS_E_INVAL; 458 } 459 460 umac_reset_ctx = &soc->umac_reset_ctx; 461 462 umac_reset_ctx->rx_actions.cb[action] = handler; 463 464 return QDF_STATUS_SUCCESS; 465 } 466 467 /** 468 * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory 469 * @umac_reset_ctx: UMAC reset context 470 * @tx_cmd: Tx command to be posted 471 * 472 * Return: QDF status of operation 473 */ 474 static QDF_STATUS 475 dp_umac_reset_post_tx_cmd_via_shmem( 476 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 477 enum umac_reset_tx_cmd tx_cmd) 478 { 479 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 480 481 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 482 if (!shmem_vaddr) { 483 dp_umac_reset_err("Shared memory address is NULL"); 484 return QDF_STATUS_E_NULL_VALUE; 485 } 486 487 switch (tx_cmd) { 488 case UMAC_RESET_TX_CMD_PRE_RESET_DONE: 489 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET( 490 shmem_vaddr->h2t_msg, 1); 491 492 umac_reset_ctx->ts.pre_reset_done = 493 qdf_get_log_timestamp_usecs(); 494 break; 495 496 case UMAC_RESET_TX_CMD_POST_RESET_START_DONE: 497 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET( 498 shmem_vaddr->h2t_msg, 1); 499 500 umac_reset_ctx->ts.post_reset_done = 501 qdf_get_log_timestamp_usecs(); 502 break; 503 504 case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE: 505 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET( 506 shmem_vaddr->h2t_msg, 1); 507 508 umac_reset_ctx->ts.post_reset_complete_done = 509 qdf_get_log_timestamp_usecs(); 510 break; 511 512 default: 513 dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd); 514 return QDF_STATUS_E_FAILURE; 515 } 516 517 return QDF_STATUS_SUCCESS; 518 } 519 520 /** 521 * dp_umac_reset_notify_target() - Notify the target about completion of action. 522 * @umac_reset_ctx: UMAC reset context 523 * 524 * This API figures out the Tx command that needs to be posted based on the 525 * current state in the state machine. Also, updates the state machine once the 526 * Tx command has been posted. 527 * 528 * Return: QDF status of operation 529 */ 530 static QDF_STATUS 531 dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) 532 { 533 enum umac_reset_state next_state; 534 enum umac_reset_tx_cmd tx_cmd; 535 QDF_STATUS status; 536 537 switch (umac_reset_ctx->current_state) { 538 case UMAC_RESET_STATE_HOST_PRE_RESET_DONE: 539 tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE; 540 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START; 541 break; 542 543 case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE: 544 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE; 545 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE; 546 break; 547 548 case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: 549 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE; 550 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; 551 break; 552 553 default: 554 dp_umac_reset_err("Invalid state(%d) during Tx", 555 umac_reset_ctx->current_state); 556 qdf_assert_always(0); 557 return QDF_STATUS_E_FAILURE; 558 } 559 560 status = dp_umac_reset_post_tx_cmd_via_shmem(umac_reset_ctx, tx_cmd); 561 if (QDF_IS_STATUS_ERROR(status)) { 562 dp_umac_reset_err("Couldn't post Tx cmd"); 563 qdf_assert_always(0); 564 return status; 565 } 566 567 /* Update the state machine */ 568 umac_reset_ctx->current_state = next_state; 569 570 return status; 571 } 572 573 /** 574 * dp_umac_reset_notify_completion() - Notify that a given action has been 575 * completed 576 * @soc: DP soc object 577 * @next_state: The state to which the state machine needs to be updated due to 578 * this completion 579 * 580 * Return: QDF status of operation 581 */ 582 static QDF_STATUS dp_umac_reset_notify_completion( 583 struct dp_soc *soc, 584 enum umac_reset_state next_state) 585 { 586 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 587 588 if (!soc) { 589 dp_umac_reset_err("DP SOC is null"); 590 return QDF_STATUS_E_NULL_VALUE; 591 } 592 593 umac_reset_ctx = &soc->umac_reset_ctx; 594 595 /* Update the state first */ 596 umac_reset_ctx->current_state = next_state; 597 598 return dp_umac_reset_notify_target(umac_reset_ctx); 599 } 600 601 QDF_STATUS dp_umac_reset_notify_action_completion( 602 struct dp_soc *soc, 603 enum umac_reset_action action) 604 { 605 enum umac_reset_state next_state; 606 607 if (!soc) { 608 dp_umac_reset_err("DP SOC is null"); 609 return QDF_STATUS_E_NULL_VALUE; 610 } 611 612 if (!soc->features.umac_hw_reset_support) { 613 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 614 return QDF_STATUS_E_NOSUPPORT; 615 } 616 617 switch (action) { 618 case UMAC_RESET_ACTION_DO_PRE_RESET: 619 next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE; 620 break; 621 622 case UMAC_RESET_ACTION_DO_POST_RESET_START: 623 next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE; 624 break; 625 626 case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE: 627 next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE; 628 break; 629 630 default: 631 dp_umac_reset_err("Invalid action"); 632 return QDF_STATUS_E_FAILURE; 633 } 634 635 return dp_umac_reset_notify_completion(soc, next_state); 636 } 637