mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
platform: dce: reworked dce FSM design
Redesign DCE KMD drive state machine to handle new PM events. Bug 3583331 Change-Id: I89adcfa2f311a9a1e86b70e14821468203365266 Signed-off-by: Mahesh Kumar <mahkumar@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2673665 Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> Reviewed-by: Arun Swain <arswain@nvidia.com> GVS: Gerrit_Virtual_Submit
This commit is contained in:
committed by
Laxman Dewangan
parent
a6cc70f8d5
commit
28a1cfd1c1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,96 +14,136 @@
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-boot-cmds.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
/**
|
||||
* dce_boot_complete - Checks if dce has complelted boot.
|
||||
* dce_fw_boot_complete - Checks if dce has complelted boot.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if boot is complete
|
||||
*/
|
||||
static inline bool dce_boot_complete(struct tegra_dce *d)
|
||||
inline bool dce_fw_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
return !!(dce_ss_get_state(d, DCE_BOOT_SEMA)
|
||||
& DCE_BOOT_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_boot_poll_boot_complete - Poll until dce boot is complete.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_boot_poll_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (!dce_boot_complete(d)) {
|
||||
dce_worker_thread_wait(d,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET);
|
||||
}
|
||||
|
||||
if (dce_worker_get_state(d) == STATE_DCE_WORKER_ABORTED)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_req_boot_irq_sync - Requests DCE to raise an
|
||||
* interrupt on boot completion.
|
||||
* dce_request_fw_boot_complete - Requests DCE to raise an
|
||||
* interrupt on boot completion.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if sucessful.
|
||||
* Return : void
|
||||
*/
|
||||
static int dce_req_boot_irq_sync(struct tegra_dce *d)
|
||||
inline void dce_request_fw_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#define DCE_BOOT_INIT_BPOS 31U
|
||||
dce_ss_set(d, DCE_BOOT_INIT_BPOS, DCE_BOOT_SEMA);
|
||||
#undef DCE_BOOT_INIT_BPOS
|
||||
}
|
||||
|
||||
dce_info(d, "Waiting on dce fw to boot...");
|
||||
/**
|
||||
* dce_handle_boot_cmd_requested_event - callback handler function for event
|
||||
* EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_cmd_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_send_cmd_params *mbox_params =
|
||||
(struct dce_mailbox_send_cmd_params *)params;
|
||||
|
||||
ret = dce_boot_poll_boot_complete(d);
|
||||
if (ret)
|
||||
dce_err(d, "DCE Boot Complete Poll Interrupted");
|
||||
dce_debug(d, "cmd:%u interface:%u", mbox_params->cmd, mbox_params->interface);
|
||||
|
||||
ret = dce_handle_mailbox_send_cmd_sync(d, mbox_params->cmd,
|
||||
mbox_params->interface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_wait_boot_complete - Wait for the DCE to boot and be ready to receive
|
||||
* commands from CCPLEX driver.
|
||||
* dce_handle_boot_cmd_received_event - callback handler function for event
|
||||
* EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_wait_boot_complete(struct tegra_dce *d)
|
||||
int dce_handle_boot_cmd_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_complete_requested_event - callback handler function for
|
||||
* event EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED
|
||||
*
|
||||
* Wait for the DCE to boot and be ready to receive commands from CCPLEX driver.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dce_boot_complete(d))
|
||||
goto boot_done;
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_START;
|
||||
if (dce_fw_boot_complete(d)) {
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "failed to send DCE_BOOT_COMPLETE_RECEIVED event");
|
||||
|
||||
ret = dce_req_boot_irq_sync(d);
|
||||
goto boot_done;
|
||||
}
|
||||
|
||||
dce_request_fw_boot_complete(d);
|
||||
|
||||
dce_debug(d, "Waiting for dce fw to boot...");
|
||||
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "dce boot wait was interrupted with err:%d", ret);
|
||||
}
|
||||
|
||||
boot_done:
|
||||
if (!ret) {
|
||||
dce_set_boot_complete(d, true);
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_DONE;
|
||||
dce_info(d, "dce is ready to receive bootstrap commands");
|
||||
dce_debug(d, "dce is ready to receive bootstrap commands");
|
||||
} else {
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_FAILED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_complete_received_event - callback handler function for
|
||||
* event EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_irq_status - Handles irq status from DCE
|
||||
*
|
||||
@@ -114,31 +154,40 @@ boot_done:
|
||||
*/
|
||||
void dce_handle_irq_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
if (status & DCE_IRQ_LOG_OVERFLOW)
|
||||
dce_info(d, "DCE trace log overflow error received");
|
||||
|
||||
if (status & DCE_IRQ_LOG_READY)
|
||||
dce_info(d, "DCE trace log buffers available");
|
||||
|
||||
if (status & DCE_IRQ_CRASH_LOG)
|
||||
dce_info(d, "DCE crash log available");
|
||||
|
||||
if (status & DCE_IRQ_ABORT)
|
||||
dce_err(d, "DCE ucode abort occurred");
|
||||
|
||||
if (status & DCE_IRQ_READY) {
|
||||
dce_debug(d, "DCE IRQ Ready Received");
|
||||
(void)dce_fsm_post_event(d,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (status & DCE_IRQ_SC7_ENTERED)
|
||||
dce_info(d, "DCE can be safely powered-off now");
|
||||
|
||||
event = EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED;
|
||||
|
||||
if (status & DCE_IRQ_READY) {
|
||||
dce_info(d, "DCE IRQ Ready Received");
|
||||
event = EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED;
|
||||
if (status & DCE_IRQ_LOG_READY) {
|
||||
dce_info(d, "DCE trace log buffers available");
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_LOG);
|
||||
}
|
||||
|
||||
dce_worker_thread_wakeup(d, event);
|
||||
/*
|
||||
* FIXME: handle individual bits
|
||||
*/
|
||||
if (status & (DCE_IRQ_LOG_OVERFLOW | DCE_IRQ_CRASH_LOG |
|
||||
DCE_IRQ_ABORT)) {
|
||||
// Wrapper function around this ??
|
||||
// TODO: Wake All other waiting processes
|
||||
(void) dce_fsm_post_event(d, EVENT_ID_DCE_ABORT_RECEIVED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -152,14 +201,13 @@ void dce_handle_irq_status(struct tegra_dce *d, u32 status)
|
||||
*/
|
||||
void dce_bootstrap_handle_boot_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
event = EVENT_ID_DCE_IPC_SIGNAL_RECEIVED;
|
||||
|
||||
int ret = 0;
|
||||
dce_mailbox_store_interface_status(d, status,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
dce_worker_thread_wakeup(d, event);
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "Mbox bootstrap cmd failed");
|
||||
}
|
||||
|
||||
|
||||
@@ -242,18 +290,19 @@ static void dce_parse_boot_status_err(struct tegra_dce *d, u32 status)
|
||||
static int dce_mailbox_wait_boot_interface(struct tegra_dce *d)
|
||||
{
|
||||
u32 status;
|
||||
enum dce_worker_event_id_type event;
|
||||
int ret;
|
||||
|
||||
event = EVENT_ID_DCE_IPC_MESSAGE_SENT;
|
||||
|
||||
dce_worker_thread_wait(d, event);
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "dce mbox wait was interrupted with err:%d", ret);
|
||||
}
|
||||
|
||||
status = dce_mailbox_get_interface_status(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
if (dce_worker_get_state(d) == STATE_DCE_WORKER_ABORTED)
|
||||
return -EINTR;
|
||||
|
||||
if (status & DCE_BOOT_CMD_ERR_FLAG) {
|
||||
dce_parse_boot_status_err(d, status);
|
||||
dce_err(d, "Error code received on boot interface : 0x%x",
|
||||
|
||||
Reference in New Issue
Block a user