diff --git a/dp/wifi3.0/dp_umac_reset.c b/dp/wifi3.0/dp_umac_reset.c index 65bb7f8643..ecde8cf31b 100644 --- a/dp/wifi3.0/dp_umac_reset.c +++ b/dp/wifi3.0/dp_umac_reset.c @@ -62,7 +62,7 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx)); umac_reset_ctx->supported = true; - umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_PRE_RESET; + umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset); if (QDF_IS_STATUS_ERROR(status)) { @@ -70,7 +70,7 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) return status; } - alloc_size = sizeof(struct umac_reset_shmem) + + alloc_size = sizeof(htt_umac_hang_recovery_msg_shmem_t) + DP_UMAC_RESET_SHMEM_ALIGN - 1; umac_reset_ctx->shmem_vaddr_unaligned = qdf_mem_alloc_consistent(soc->osdev, soc->osdev->dev, @@ -91,6 +91,112 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) return QDF_STATUS_SUCCESS; } +/** + * dp_umac_reset_get_rx_event() - Extract the Rx event from the shared memory + * @umac_reset_ctx: UMAC reset context + * + * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event + */ +static enum umac_reset_rx_event +dp_umac_reset_get_rx_event_from_shmem( + struct dp_soc_umac_reset_ctx *umac_reset_ctx) +{ + htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; + uint32_t t2h_msg; + uint8_t num_events = 0; + enum umac_reset_rx_event rx_event; + + shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; + if (!shmem_vaddr) { + dp_umac_reset_err("Shared memory address is NULL"); + goto err; + } + + if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) { + dp_umac_reset_err("Shared memory got corrupted"); + goto err; + } + + /* Read the shared memory into a local variable */ + t2h_msg = shmem_vaddr->t2h_msg; + + /* Clear the shared memory right away */ + shmem_vaddr->t2h_msg = 0; + + dp_umac_reset_debug("shmem value - t2h_msg: 0x%x", t2h_msg); + + rx_event = UMAC_RESET_RX_EVENT_NONE; + + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) { + rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET; + num_events++; + } + + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_START_GET(t2h_msg)) { + rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_START; + num_events++; + } + + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_COMPLETE_GET(t2h_msg)) { + rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE; + num_events++; + } + + dp_umac_reset_debug("deduced rx event: 0x%x", rx_event); + /* There should not be more than 1 event */ + if (num_events > 1) { + dp_umac_reset_err("Multiple events(0x%x) got posted", rx_event); + goto err; + } + + return rx_event; +err: + qdf_assert_always(0); + return UMAC_RESET_RX_EVENT_ERROR; +} + +/** + * dp_umac_reset_get_rx_event() - Extract the Rx event + * @umac_reset_ctx: UMAC reset context + * + * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event + */ +static inline enum umac_reset_rx_event +dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx *umac_reset_ctx) +{ + return dp_umac_reset_get_rx_event_from_shmem(umac_reset_ctx); +} + +/** + * dp_umac_reset_validate_n_update_state_machine_on_rx() - Validate the state + * machine for a given rx event and update the state machine + * @umac_reset_ctx: UMAC reset context + * @rx_event: Rx event + * @current_exp_state: Expected state + * @next_state: The state to which the state machine needs to be updated + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS +dp_umac_reset_validate_n_update_state_machine_on_rx( + struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_rx_event rx_event, + enum umac_reset_state current_exp_state, + enum umac_reset_state next_state) +{ + if (umac_reset_ctx->current_state != current_exp_state) { + dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d", + rx_event, + umac_reset_ctx->current_state); + qdf_assert_always(0); + return QDF_STATUS_E_FAILURE; + } + + /* Update the state */ + umac_reset_ctx->current_state = next_state; + return QDF_STATUS_SUCCESS; +} + /** * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset * @dp_ctx: Interrupt context corresponding to UMAC reset @@ -99,8 +205,78 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) */ static int dp_umac_reset_rx_event_handler(void *dp_ctx) { - /* Note: This will be implemented in an upcoming change */ - return 0; + struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx; + struct dp_soc *soc = int_ctx->soc; + struct dp_soc_umac_reset_ctx *umac_reset_ctx; + enum umac_reset_rx_event rx_event; + QDF_STATUS status = QDF_STATUS_E_INVAL; + enum umac_reset_action action; + + if (!soc) { + dp_umac_reset_err("DP SOC is null"); + goto exit; + } + + umac_reset_ctx = &soc->umac_reset_ctx; + + dp_umac_reset_debug("enter"); + rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx); + + switch (rx_event) { + case UMAC_RESET_RX_EVENT_NONE: + /* This interrupt is not meant for us, so exit */ + dp_umac_reset_debug("Not a UMAC reset event"); + status = QDF_STATUS_SUCCESS; + goto exit; + + case UMAC_RESET_RX_EVENT_DO_PRE_RESET: + status = dp_umac_reset_validate_n_update_state_machine_on_rx( + umac_reset_ctx, rx_event, + UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, + UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED); + + action = UMAC_RESET_ACTION_DO_PRE_RESET; + break; + + case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: + status = dp_umac_reset_validate_n_update_state_machine_on_rx( + umac_reset_ctx, rx_event, + UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, + UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED); + + action = UMAC_RESET_ACTION_DO_POST_RESET_START; + break; + + case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: + status = dp_umac_reset_validate_n_update_state_machine_on_rx( + umac_reset_ctx, rx_event, + UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, + UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED); + + action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE; + break; + + case UMAC_RESET_RX_EVENT_ERROR: + dp_umac_reset_err("Error Rx event"); + goto exit; + + default: + dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event); + goto exit; + } + + /* Call the handler for this event */ + if (QDF_IS_STATUS_SUCCESS(status)) { + if (!umac_reset_ctx->rx_actions.cb[action]) { + dp_umac_reset_err("rx callback is NULL"); + goto exit; + } + + status = umac_reset_ctx->rx_actions.cb[action](soc); + } + +exit: + return qdf_status_to_os_return(status); } QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc) @@ -175,3 +351,27 @@ QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc) return hif_unregister_umac_reset_handler(soc->hif_handle); } + +QDF_STATUS dp_umac_reset_register_rx_action_callback( + struct dp_soc *soc, + QDF_STATUS (*handler)(struct dp_soc *soc), + enum umac_reset_action action) +{ + struct dp_soc_umac_reset_ctx *umac_reset_ctx; + + if (!soc) { + dp_umac_reset_err("DP SOC is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (action >= UMAC_RESET_ACTION_MAX) { + dp_umac_reset_err("invalid action: %d", action); + return QDF_STATUS_E_INVAL; + } + + umac_reset_ctx = &soc->umac_reset_ctx; + + umac_reset_ctx->rx_actions.cb[action] = handler; + + return QDF_STATUS_SUCCESS; +} diff --git a/dp/wifi3.0/dp_umac_reset.h b/dp/wifi3.0/dp_umac_reset.h index 65cfd2d3f7..e38d37f1db 100644 --- a/dp/wifi3.0/dp_umac_reset.h +++ b/dp/wifi3.0/dp_umac_reset.h @@ -20,6 +20,20 @@ #include struct dp_soc; +/** + * enum umac_reset_action - Actions supported by the UMAC reset + * @UMAC_RESET_ACTION_DO_PRE_RESET: DO_PRE_RESET + * @UMAC_RESET_ACTION_DO_POST_RESET_START: DO_POST_RESET_START + * @UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE: DO_POST_RESET_COMPLETE + * @UMAC_RESET_ACTION_MAX: Maximum actions + */ +enum umac_reset_action { + UMAC_RESET_ACTION_DO_PRE_RESET = 0, + UMAC_RESET_ACTION_DO_POST_RESET_START = 1, + UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE = 2, + UMAC_RESET_ACTION_MAX +}; + #ifdef DP_UMAC_HW_RESET_SUPPORT #define dp_umac_reset_alert(params...) \ QDF_TRACE_FATAL(QDF_MODULE_ID_DP_UMAC_RESET, params) @@ -36,33 +50,62 @@ struct dp_soc; #define DP_UMAC_RESET_SHMEM_ALIGN 8 /** - * enum umac_reset_state - States required for UMAC reset state machine - * @UMAC_RESET_STATE_WAIT_FOR_PRE_RESET: Waiting for the PRE_RESET event - * @UMAC_RESET_STATE_PRE_RESET_RECEIVED: Received the PRE_RESET event - * @UMAC_RESET_STATE_HOST_PRE_RESET_COMPLETED: Host has completed handling the + * enum umac_reset_state - States required by the UMAC reset state machine + * @UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET: Waiting for the DO_PRE_RESET event + * @UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED: Received the DO_PRE_RESET event + * @UMAC_RESET_STATE_HOST_PRE_RESET_DONE: Host has completed handling the * PRE_RESET event - * @UMAC_RESET_STATE_WAIT_FOR_POST_RESET: Waiting for the POST_RESET event - * @UMAC_RESET_STATE_POST_RESET_RECEIVED: Received the POST_RESET event - * @UMAC_RESET_STATE_HOST_POST_RESET_COMPLETED: Host has completed handling the - * POST_RESET event + * @UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START: Waiting for the + * DO_POST_RESET_START event + * @UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED: Received the + * DO_POST_RESET_START event + * @UMAC_RESET_STATE_HOST_POST_RESET_START_DONE: Host has completed handling the + * POST_RESET_START event + * @UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE: Waiting for the + * DO_POST_RESET_COMPLETE event + * @UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED: Received the + * DO_POST_RESET_COMPLETE event + * @UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: Host has completed handling + * the DO_POST_RESET_COMPLETE event */ enum umac_reset_state { - UMAC_RESET_STATE_WAIT_FOR_PRE_RESET = 0, - UMAC_RESET_STATE_PRE_RESET_RECEIVED, - UMAC_RESET_STATE_HOST_PRE_RESET_COMPLETED, - UMAC_RESET_STATE_WAIT_FOR_POST_RESET, - UMAC_RESET_STATE_POST_RESET_RECEIVED, - UMAC_RESET_STATE_HOST_POST_RESET_COMPLETED, + UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET = 0, + UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED, + UMAC_RESET_STATE_HOST_PRE_RESET_DONE, + + UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, + UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED, + UMAC_RESET_STATE_HOST_POST_RESET_START_DONE, + + UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, + UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED, + UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE, }; /** - * struct umac_reset_shmem - Shared memory layout for UMAC reset feature - * @t2h_indication: target to host communicaton - * @h2t_indication: host to target communicaton + * enum umac_reset_rx_event - Rx events deduced by the UMAC reset + * @UMAC_RESET_RX_EVENT_NONE: No event + * @UMAC_RESET_RX_EVENT_DO_PRE_RESET: DO_PRE_RESET event + * @UMAC_RESET_RX_EVENT_DO_POST_RESET_START: DO_POST_RESET_START event + * @UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: DO_POST_RESET_COMPELTE event + * @UMAC_RESET_RX_EVENT_ERROR: Error while processing the Rx event */ -struct umac_reset_shmem { - uint32_t t2h_indication; - uint32_t h2t_indication; +enum umac_reset_rx_event { + UMAC_RESET_RX_EVENT_NONE = 0x0, + UMAC_RESET_RX_EVENT_DO_PRE_RESET = 0x1, + UMAC_RESET_RX_EVENT_DO_POST_RESET_START = 0x2, + UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE = 0x4, + + UMAC_RESET_RX_EVENT_ERROR = 0xFFFFFFFF, +}; + +/** + * struct umac_reset_rx_actions - callbacks for handling UMAC reset actions + * @cb: Array of pointers where each pointer contains callback for each UMAC + * reset action for that index + */ +struct umac_reset_rx_actions { + QDF_STATUS (*cb[UMAC_RESET_ACTION_MAX])(struct dp_soc *soc); }; /** @@ -74,15 +117,19 @@ struct umac_reset_shmem { * @intr_offset: Offset of the UMAC reset interrupt w.r.t DP base interrupt * @current_state: current state of the UMAC reset state machine * @supported: Whether UMAC reset is supported on this soc + * @shmem_exp_magic_num: Expected magic number in the shared memory + * @rx_actions: callbacks for handling UMAC reset actions */ struct dp_soc_umac_reset_ctx { qdf_dma_addr_t shmem_paddr_unaligned; - struct umac_reset_shmem *shmem_vaddr_unaligned; + void *shmem_vaddr_unaligned; qdf_dma_addr_t shmem_paddr_aligned; - struct umac_reset_shmem *shmem_vaddr_aligned; + htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr_aligned; int intr_offset; enum umac_reset_state current_state; bool supported; + uint32_t shmem_exp_magic_num; + struct umac_reset_rx_actions rx_actions; }; /** @@ -108,11 +155,34 @@ QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc); * Return: QDF status of operation */ QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc); + +/** + * dp_umac_reset_register_rx_action_callback() - Register a callback for a given + * UMAC reset action + * @soc: DP soc object + * @handler: callback handler to be registered + * @action: UMAC reset action for which @handler needs to be registered + * + * Return: QDF status of operation + */ +QDF_STATUS dp_umac_reset_register_rx_action_callback( + struct dp_soc *soc, + QDF_STATUS (*handler)(struct dp_soc *soc), + enum umac_reset_action action); #else static inline QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) { return QDF_STATUS_SUCCESS; } + +static inline +QDF_STATUS dp_umac_reset_register_rx_action_callback( + struct dp_soc *soc, + QDF_STATUS (*handler)(struct dp_soc *soc), + enum umac_reset_action action) +{ + return QDF_STATUS_SUCCESS; +} #endif /* DP_UMAC_HW_RESET_SUPPORT */ #endif /* _DP_UMAC_RESET_H_ */