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 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 317 umac_reset_ctx, rx_event, 318 UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, 319 UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED); 320 321 action = UMAC_RESET_ACTION_DO_PRE_RESET; 322 break; 323 324 case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: 325 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 326 umac_reset_ctx, rx_event, 327 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, 328 UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED); 329 330 action = UMAC_RESET_ACTION_DO_POST_RESET_START; 331 break; 332 333 case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: 334 status = dp_umac_reset_validate_n_update_state_machine_on_rx( 335 umac_reset_ctx, rx_event, 336 UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, 337 UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED); 338 339 action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE; 340 break; 341 342 case UMAC_RESET_RX_EVENT_ERROR: 343 dp_umac_reset_err("Error Rx event"); 344 goto exit; 345 346 default: 347 dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event); 348 goto exit; 349 } 350 351 /* Call the handler for this event */ 352 if (QDF_IS_STATUS_SUCCESS(status)) { 353 if (!umac_reset_ctx->rx_actions.cb[action]) { 354 dp_umac_reset_err("rx callback is NULL"); 355 goto exit; 356 } 357 358 status = umac_reset_ctx->rx_actions.cb[action](soc); 359 } 360 361 exit: 362 return qdf_status_to_os_return(status); 363 } 364 365 QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc) 366 { 367 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 368 int msi_vector_count, ret; 369 uint32_t msi_base_data, msi_vector_start; 370 uint32_t umac_reset_vector, umac_reset_irq; 371 372 if (!soc) { 373 dp_umac_reset_err("DP SOC is null"); 374 return QDF_STATUS_E_NULL_VALUE; 375 } 376 377 if (!soc->features.umac_hw_reset_support) { 378 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 379 return QDF_STATUS_SUCCESS; 380 } 381 382 umac_reset_ctx = &soc->umac_reset_ctx; 383 384 if (pld_get_enable_intx(soc->osdev->dev)) { 385 dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode"); 386 return QDF_STATUS_E_FAILURE; 387 } 388 389 ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP", 390 &msi_vector_count, &msi_base_data, 391 &msi_vector_start); 392 if (ret) { 393 dp_umac_reset_err("UMAC reset is only supported in MSI interrupt mode"); 394 return QDF_STATUS_E_FAILURE; 395 } 396 397 if (umac_reset_ctx->intr_offset < 0 || 398 umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) { 399 dp_umac_reset_err("Invalid interrupt offset"); 400 return QDF_STATUS_E_FAILURE; 401 } 402 403 umac_reset_vector = msi_vector_start + 404 (umac_reset_ctx->intr_offset % msi_vector_count); 405 406 /* Get IRQ number */ 407 umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, umac_reset_vector); 408 409 /* Finally register to this IRQ from HIF layer */ 410 return hif_register_umac_reset_handler( 411 soc->hif_handle, 412 dp_umac_reset_rx_event_handler, 413 &soc->intr_ctx[umac_reset_ctx->intr_offset], 414 umac_reset_irq); 415 } 416 417 QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc) 418 { 419 if (!soc) { 420 dp_umac_reset_err("DP SOC is null"); 421 return QDF_STATUS_E_NULL_VALUE; 422 } 423 424 if (!soc->features.umac_hw_reset_support) { 425 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 426 return QDF_STATUS_SUCCESS; 427 } 428 429 return hif_unregister_umac_reset_handler(soc->hif_handle); 430 } 431 432 QDF_STATUS dp_umac_reset_register_rx_action_callback( 433 struct dp_soc *soc, 434 QDF_STATUS (*handler)(struct dp_soc *soc), 435 enum umac_reset_action action) 436 { 437 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 438 439 if (!soc) { 440 dp_umac_reset_err("DP SOC is null"); 441 return QDF_STATUS_E_NULL_VALUE; 442 } 443 444 if (!soc->features.umac_hw_reset_support) { 445 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 446 return QDF_STATUS_E_NOSUPPORT; 447 } 448 449 if (action >= UMAC_RESET_ACTION_MAX) { 450 dp_umac_reset_err("invalid action: %d", action); 451 return QDF_STATUS_E_INVAL; 452 } 453 454 umac_reset_ctx = &soc->umac_reset_ctx; 455 456 umac_reset_ctx->rx_actions.cb[action] = handler; 457 458 return QDF_STATUS_SUCCESS; 459 } 460 461 /** 462 * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory 463 * @umac_reset_ctx: UMAC reset context 464 * @tx_cmd: Tx command to be posted 465 * 466 * Return: QDF status of operation 467 */ 468 static QDF_STATUS 469 dp_umac_reset_post_tx_cmd_via_shmem( 470 struct dp_soc_umac_reset_ctx *umac_reset_ctx, 471 enum umac_reset_tx_cmd tx_cmd) 472 { 473 htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; 474 475 shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; 476 if (!shmem_vaddr) { 477 dp_umac_reset_err("Shared memory address is NULL"); 478 return QDF_STATUS_E_NULL_VALUE; 479 } 480 481 switch (tx_cmd) { 482 case UMAC_RESET_TX_CMD_PRE_RESET_DONE: 483 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET( 484 shmem_vaddr->h2t_msg, 1); 485 break; 486 487 case UMAC_RESET_TX_CMD_POST_RESET_START_DONE: 488 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET( 489 shmem_vaddr->h2t_msg, 1); 490 break; 491 492 case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE: 493 HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET( 494 shmem_vaddr->h2t_msg, 1); 495 break; 496 497 default: 498 dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd); 499 return QDF_STATUS_E_FAILURE; 500 } 501 502 return QDF_STATUS_SUCCESS; 503 } 504 505 /** 506 * dp_umac_reset_notify_target() - Notify the target about completion of action. 507 * @umac_reset_ctx: UMAC reset context 508 * 509 * This API figures out the Tx command that needs to be posted based on the 510 * current state in the state machine. Also, updates the state machine once the 511 * Tx command has been posted. 512 * 513 * Return: QDF status of operation 514 */ 515 static QDF_STATUS 516 dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) 517 { 518 enum umac_reset_state next_state; 519 enum umac_reset_tx_cmd tx_cmd; 520 QDF_STATUS status; 521 522 switch (umac_reset_ctx->current_state) { 523 case UMAC_RESET_STATE_HOST_PRE_RESET_DONE: 524 tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE; 525 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START; 526 break; 527 528 case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE: 529 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE; 530 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE; 531 break; 532 533 case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: 534 tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE; 535 next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; 536 break; 537 538 default: 539 dp_umac_reset_err("Invalid state(%d) during Tx", 540 umac_reset_ctx->current_state); 541 qdf_assert_always(0); 542 return QDF_STATUS_E_FAILURE; 543 } 544 545 status = dp_umac_reset_post_tx_cmd_via_shmem(umac_reset_ctx, tx_cmd); 546 if (QDF_IS_STATUS_ERROR(status)) { 547 dp_umac_reset_err("Couldn't post Tx cmd"); 548 qdf_assert_always(0); 549 return status; 550 } 551 552 /* Update the state machine */ 553 umac_reset_ctx->current_state = next_state; 554 555 return status; 556 } 557 558 /** 559 * dp_umac_reset_notify_completion() - Notify that a given action has been 560 * completed 561 * @soc: DP soc object 562 * @next_state: The state to which the state machine needs to be updated due to 563 * this completion 564 * 565 * Return: QDF status of operation 566 */ 567 static QDF_STATUS dp_umac_reset_notify_completion( 568 struct dp_soc *soc, 569 enum umac_reset_state next_state) 570 { 571 struct dp_soc_umac_reset_ctx *umac_reset_ctx; 572 573 if (!soc) { 574 dp_umac_reset_err("DP SOC is null"); 575 return QDF_STATUS_E_NULL_VALUE; 576 } 577 578 umac_reset_ctx = &soc->umac_reset_ctx; 579 580 /* Update the state first */ 581 umac_reset_ctx->current_state = next_state; 582 583 return dp_umac_reset_notify_target(umac_reset_ctx); 584 } 585 586 QDF_STATUS dp_umac_reset_notify_action_completion( 587 struct dp_soc *soc, 588 enum umac_reset_action action) 589 { 590 enum umac_reset_state next_state; 591 592 if (!soc) { 593 dp_umac_reset_err("DP SOC is null"); 594 return QDF_STATUS_E_NULL_VALUE; 595 } 596 597 if (!soc->features.umac_hw_reset_support) { 598 dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); 599 return QDF_STATUS_E_NOSUPPORT; 600 } 601 602 switch (action) { 603 case UMAC_RESET_ACTION_DO_PRE_RESET: 604 next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE; 605 break; 606 607 case UMAC_RESET_ACTION_DO_POST_RESET_START: 608 next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE; 609 break; 610 611 case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE: 612 next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE; 613 break; 614 615 default: 616 dp_umac_reset_err("Invalid action"); 617 return QDF_STATUS_E_FAILURE; 618 } 619 620 return dp_umac_reset_notify_completion(soc, next_state); 621 } 622