mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +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
@@ -17,6 +17,7 @@ tegra-dce-y += \
|
||||
dce-hsp-smb.o \
|
||||
dce-hsp-ss.o \
|
||||
dce-worker.o \
|
||||
dce-fsm.o \
|
||||
dce-init-deinit.o \
|
||||
dce-mailbox.o \
|
||||
dce-bootstrap.o \
|
||||
|
||||
@@ -23,48 +23,29 @@
|
||||
* dce_admin_ipc_wait - Waits for message from DCE.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @w_type : Requested wait type.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type)
|
||||
{
|
||||
int ret = 0;
|
||||
enum dce_worker_event_id_type event = EVENT_ID_DCE_INVALID_EVENT;
|
||||
struct admin_rpc_post_boot_info *admin_rpc = &d->admin_rpc;
|
||||
|
||||
switch (w_type) {
|
||||
case DCE_IPC_WAIT_TYPE_RPC:
|
||||
event = EVENT_ID_DCE_IPC_MESSAGE_SENT;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid wait type [%d]", w_type);
|
||||
break;
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "Admin IPC wait was interrupted with err:%d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dce_is_bootstrap_done(d)) {
|
||||
DCE_COND_WAIT_INTERRUPTIBLE(&admin_rpc->recv_wait,
|
||||
atomic_read(&admin_rpc->complete) == 1,
|
||||
0);
|
||||
atomic_set(&admin_rpc->complete, 0);
|
||||
} else {
|
||||
if (event != EVENT_ID_DCE_INVALID_EVENT)
|
||||
dce_worker_thread_wait(d, event);
|
||||
else {
|
||||
dce_err(d, "Invalid event type [%d]", event);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (dce_worker_get_state(d)
|
||||
== STATE_DCE_WORKER_ABORTED)
|
||||
ret = -1;
|
||||
end:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_interface_isr - Isr for the CCPLEX<->DCE admin interface
|
||||
* dce_admin_wakeup_ipc - wakeup process, waiting for Admin RPC
|
||||
*
|
||||
* @d : Pointer to tegra_de struct.
|
||||
*
|
||||
@@ -72,25 +53,11 @@ end:
|
||||
*/
|
||||
static void dce_admin_wakeup_ipc(struct tegra_dce *d)
|
||||
{
|
||||
enum dce_worker_event_id_type event = EVENT_ID_DCE_IPC_SIGNAL_RECEIVED;
|
||||
int ret;
|
||||
|
||||
dce_worker_thread_wakeup(d, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_wakeup_rpc_post_boot - Wakeup process waiting for response
|
||||
* from DCE for Admin rpc interface.
|
||||
*
|
||||
* @d : Pointer to tegra_de struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_admin_ipc_post_boot_wakeup(struct tegra_dce *d)
|
||||
{
|
||||
struct admin_rpc_post_boot_info *admin_rpc = &d->admin_rpc;
|
||||
|
||||
atomic_set(&admin_rpc->complete, 1);
|
||||
dce_cond_signal_interruptible(&admin_rpc->recv_wait);
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "Error while posting ADMIN_IPC_MSG_RECEIVED event");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +92,7 @@ void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type)
|
||||
}
|
||||
|
||||
if (ch_type == DCE_IPC_CH_KMD_TYPE_ADMIN) {
|
||||
if (dce_is_bootstrap_done(d))
|
||||
dce_admin_ipc_post_boot_wakeup(d);
|
||||
else
|
||||
dce_admin_wakeup_ipc(d);
|
||||
dce_admin_wakeup_ipc(d);
|
||||
} else {
|
||||
dce_client_ipc_wakeup(d, ch_type);
|
||||
}
|
||||
@@ -199,7 +163,6 @@ out:
|
||||
int dce_admin_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct admin_rpc_post_boot_info *admin_rpc = &d->admin_rpc;
|
||||
|
||||
d->boot_status |= DCE_EARLY_INIT_START;
|
||||
ret = dce_ipc_allocate_region(d);
|
||||
@@ -214,18 +177,9 @@ int dce_admin_init(struct tegra_dce *d)
|
||||
goto err_channel_init;
|
||||
}
|
||||
|
||||
ret = dce_cond_init(&admin_rpc->recv_wait);
|
||||
if (ret) {
|
||||
dce_err(d, "Admin post-bootstrap RPC cond init failed");
|
||||
goto err_admin_postboot_rpc_init;
|
||||
}
|
||||
atomic_set(&admin_rpc->complete, 0);
|
||||
|
||||
d->boot_status |= DCE_EARLY_INIT_DONE;
|
||||
return 0;
|
||||
|
||||
err_admin_postboot_rpc_init:
|
||||
dce_cond_destroy(&admin_rpc->recv_wait);
|
||||
err_channel_init:
|
||||
dce_ipc_free_region(d);
|
||||
err_ipc_reg_alloc:
|
||||
@@ -243,11 +197,6 @@ err_ipc_reg_alloc:
|
||||
*/
|
||||
void dce_admin_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct admin_rpc_post_boot_info *admin_rpc = &d->admin_rpc;
|
||||
|
||||
atomic_set(&admin_rpc->complete, 0);
|
||||
dce_cond_destroy(&admin_rpc->recv_wait);
|
||||
|
||||
dce_admin_channel_deinit(d);
|
||||
|
||||
dce_ipc_free_region(d);
|
||||
@@ -330,14 +279,61 @@ void dce_admin_free_message(struct tegra_dce *d,
|
||||
int dce_admin_send_msg(struct tegra_dce *d, struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_admin_send_msg_params params;
|
||||
|
||||
params.msg = msg;
|
||||
|
||||
ret = dce_fsm_post_event(d,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
(void *)¶ms);
|
||||
if (ret)
|
||||
dce_err(d, "Unable to send msg invalid FSM state");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_msg - Sends messages on Admin Channel
|
||||
* synchronously and waits for an ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg : Pointer to allocated message.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg;
|
||||
struct dce_admin_send_msg_params *admin_params =
|
||||
(struct dce_admin_send_msg_params *)params;
|
||||
|
||||
/*
|
||||
* Do not handle admin IPC if bootstrap is not completed
|
||||
*/
|
||||
if ((d->boot_status & DCE_FW_BOOTSTRAP_DONE) == 0) {
|
||||
dce_err(d, "Bootstrap not yet completed\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Error check on msg */
|
||||
msg = admin_params->msg;
|
||||
|
||||
ret = dce_ipc_send_message_sync(d, DCE_IPC_CHANNEL_TYPE_ADMIN, msg);
|
||||
if (ret)
|
||||
dce_err(d, "Error sending admin message on admin interface");
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_get_ipc_channel_info - Provides channel's
|
||||
* buff details
|
||||
|
||||
@@ -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",
|
||||
|
||||
513
drivers/platform/tegra/dce/dce-fsm.c
Normal file
513
drivers/platform/tegra/dce/dce-fsm.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (c) 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,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <dce.h>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
struct dce_event_process_struct {
|
||||
enum dce_fsm_event_id_type event;
|
||||
int (*fsm_event_handle)(struct tegra_dce *d, void *params);
|
||||
};
|
||||
|
||||
static struct dce_event_process_struct event_process_table[] = {
|
||||
{
|
||||
.event = EVENT_ID_DCE_FSM_START,
|
||||
.fsm_event_handle = dce_handle_fsm_start_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_boot_complete_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_boot_complete_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_boot_cmd_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_boot_cmd_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
.fsm_event_handle = dce_admin_handle_ipc_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED,
|
||||
.fsm_event_handle = dce_admin_handle_ipc_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_SC7_ENTER_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_LOG_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_LOG_READY_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ABORT_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_CRASH_LOG_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_FSM_STOP,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
};
|
||||
|
||||
#define DCE_MAX_EVENTS_IDS (sizeof(event_process_table) / \
|
||||
sizeof(struct dce_event_process_struct))
|
||||
|
||||
/**
|
||||
* dce_handle_fsm_start_event - Callback handler function for FSM_START event.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_fsm_start_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_event_stub - Stub callback handler function.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_handle_event_stub(struct tegra_dce *d, void *params)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_set_state - Set the FSM state based on event
|
||||
*
|
||||
* This Function is called with Mutex held.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event for which FSM state need to be set
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static void
|
||||
dce_fsm_set_state(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs = 0;
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_BOOT_WAIT;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_BOOT_COMPLETE);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_BOOT_COMPLETE);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_BOOTCMD_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_BOOT_CMD);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_BOOT_CMD);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_ADMIN_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_ADMIN_IPC);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_ADMIN_IPC);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_SC7_ENTER_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_SC7_ENTER);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_SC7_ENTERED;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_SC7_ENTER);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_LOG_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_LOG_READY_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_LOG);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_LOG);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
fsm->c_state = STATE_DCE_INVALID;
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
dce_debug(d, "DCE Abort received");
|
||||
fsm->c_state = STATE_DCE_ABORT;
|
||||
/*
|
||||
* TODO: error handling
|
||||
* wake-up any waiting process avoid kernel watchdog
|
||||
* trigger and crash
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "INVALID EVENT [%d]", event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_fsm_validate_event - Validate event agaist current FSM state
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @event : Posted FSM event
|
||||
*
|
||||
* @return : ESUCCESS if event valid else error code
|
||||
*/
|
||||
static int
|
||||
dce_fsm_validate_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
enum dce_fsm_state curr_state;
|
||||
|
||||
if (event > EVENT_ID_DCE_FSM_STOP) {
|
||||
dce_err(d, "Invalid event received [%d]\n", event);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Should we check This??
|
||||
if (fsm->initialized == false) {
|
||||
dce_err(d, "FSM is not initialized yet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
curr_state = fsm->c_state;
|
||||
dce_debug(d, "Called for event [%d], curr_state:[%d]", event, curr_state);
|
||||
switch (curr_state) {
|
||||
case STATE_DCE_INVALID:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_FSM_IDLE:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_BOOT_WAIT:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED: // TODO: Do we need this here
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_BOOTCMD_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_ADMIN_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_SC7_ENTER_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_LOG_READY_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_SC7_ENTERED:
|
||||
//
|
||||
// STATE_DCE_SC7_ENTERED is short lived state for now
|
||||
// FSM can expect only EVENT_ID_DCE_FSM_START event here
|
||||
//
|
||||
dce_err(d, "Event received while in STATE_DCE_SC7_ENTERED state");
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid state:[%d] event received [%d]\n", curr_state,
|
||||
event);
|
||||
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dce_err(d, "dce event handling failed for event[%d] curr state [%d]",
|
||||
event, curr_state);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_fsm_get_event_index : Get index of event in event_process_table
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : event for which index is requested
|
||||
* @return : index of event in event_process_table or DCE_MAX_EVENTS_IDS
|
||||
*/
|
||||
static u32
|
||||
dce_fsm_get_event_index(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
for (id = 0; id < DCE_MAX_EVENTS_IDS; id++) {
|
||||
struct dce_event_process_struct *e =
|
||||
&event_process_table[id];
|
||||
|
||||
if (e->event == event)
|
||||
break;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_post - Post event to FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event for which FSM state need to be set.
|
||||
* @data : Event specific data to pass to the callback function.
|
||||
*
|
||||
* Return : 0 if successful else error code.
|
||||
*/
|
||||
int dce_fsm_post_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event,
|
||||
void *data)
|
||||
{
|
||||
u32 id;
|
||||
int ret = 0;
|
||||
enum dce_fsm_state prev_state;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
|
||||
ret = dce_fsm_validate_event(d, event);
|
||||
if (ret) {
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
prev_state = fsm->c_state;
|
||||
dce_fsm_set_state(d, event);
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
/*
|
||||
* call callback function with mutex unlocked
|
||||
*/
|
||||
id = dce_fsm_get_event_index(d, event);
|
||||
if ((id < DCE_MAX_EVENTS_IDS) &&
|
||||
(event_process_table[id].fsm_event_handle != NULL)) {
|
||||
ret = event_process_table[id].fsm_event_handle(d, data);
|
||||
if (ret) {
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
dce_err(d, "Callback failed: Resetting state old:new [%d:%d]",
|
||||
prev_state, fsm->c_state);
|
||||
fsm->c_state = prev_state;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_start - Schedule a work to start the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void.
|
||||
*/
|
||||
void dce_fsm_start(struct tegra_dce *d)
|
||||
{
|
||||
dce_schedule_work(&d->dce_bootstrap_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_stop - Post dce_fsm_stop event
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void.
|
||||
*/
|
||||
void dce_fsm_stop(struct tegra_dce *d)
|
||||
{
|
||||
dce_fsm_post_event(d, EVENT_ID_DCE_FSM_STOP, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_init - Init the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code.
|
||||
*/
|
||||
int dce_fsm_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
fsm->c_state = STATE_DCE_INVALID;
|
||||
ret = dce_mutex_init(&fsm->lock);
|
||||
if (ret) {
|
||||
dce_err(d, "dce mutex initialization failed for FSM");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
fsm->d = d;
|
||||
fsm->initialized = true;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_deinit - DeInit the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_fsm_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
fsm->initialized = false;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
dce_mutex_destroy(&fsm->lock);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, 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,
|
||||
@@ -44,15 +44,25 @@ int dce_driver_init(struct tegra_dce *d)
|
||||
goto err_client_init;
|
||||
}
|
||||
|
||||
ret = dce_worker_thread_init(d);
|
||||
ret = dce_sw_resource_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce worker thread init failed");
|
||||
goto err_worker_thread_init;
|
||||
dce_err(d, "dce sw resource init failed");
|
||||
goto err_sw_init;
|
||||
}
|
||||
|
||||
ret = dce_fsm_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce FSM init failed");
|
||||
goto err_fsm_init;
|
||||
}
|
||||
|
||||
dce_fsm_start(d);
|
||||
|
||||
return ret;
|
||||
|
||||
err_worker_thread_init:
|
||||
err_fsm_init:
|
||||
dce_sw_resource_deinit(d);
|
||||
err_sw_init:
|
||||
dce_client_deinit(d);
|
||||
err_client_init:
|
||||
dce_admin_deinit(d);
|
||||
@@ -75,7 +85,11 @@ err_boot_interface_init:
|
||||
void dce_driver_deinit(struct tegra_dce *d)
|
||||
{
|
||||
/* TODO : Reset DCE ? */
|
||||
dce_worker_thread_deinit(d);
|
||||
dce_fsm_stop(d);
|
||||
|
||||
dce_fsm_deinit(d);
|
||||
|
||||
dce_sw_resource_deinit(d);
|
||||
|
||||
dce_client_deinit(d);
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -171,15 +171,17 @@ void dce_mailbox_set_full_interrupt(struct tegra_dce *d, u8 id)
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_send_cmd_sync - Sends command via mailbox and waits for ack.
|
||||
* dce_handle_mailbox_send_cmd_sync - handler function for
|
||||
* mailbox_send_cmd_sync
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @cmd : The command to be sent.
|
||||
* @interface : boot or admin interface
|
||||
*
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
int dce_handle_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
@@ -203,6 +205,34 @@ int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_send_cmd_sync - Sends command via mailbox and waits for ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @cmd : The command to be sent.
|
||||
* @interface : boot or admin interface
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_send_cmd_params params;
|
||||
|
||||
params.cmd = cmd;
|
||||
params.interface = interface;
|
||||
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
(void *)¶ms);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to send msg ret :%d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_init_interface - Initializes the mailbox interface.
|
||||
*
|
||||
|
||||
@@ -231,6 +231,7 @@ static int tegra_dce_probe(struct platform_device *pdev)
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
dce_init_debug(d);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
req_intr_err:
|
||||
|
||||
@@ -576,6 +576,14 @@ void dce_thread_join(struct dce_thread *thread)
|
||||
usleep_range(10000, 20000);
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_get_nxt_pow_of_2 : get next power of 2 number for a given number
|
||||
*
|
||||
* @addr : Address of given number
|
||||
* @nbits : bits in given number
|
||||
*
|
||||
* Return : unsigned long next power of 2 value
|
||||
*/
|
||||
unsigned long dce_get_nxt_pow_of_2(unsigned long *addr, u8 nbits)
|
||||
{
|
||||
u8 l_bit = 0;
|
||||
@@ -600,3 +608,53 @@ unsigned long dce_get_nxt_pow_of_2(unsigned long *addr, u8 nbits)
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_schedule_work : schedule work in global workqueue
|
||||
*
|
||||
* @work : dce work to be scheduled
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_schedule_work(struct dce_work_struct *work)
|
||||
{
|
||||
schedule_work(&work->work);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_work_handle_fn : handler function for scheduled dce-work
|
||||
*
|
||||
* @work : Pointer to the scheduled work
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_work_handle_fn(struct work_struct *work)
|
||||
{
|
||||
struct dce_work_struct *dce_work = container_of(work,
|
||||
struct dce_work_struct,
|
||||
work);
|
||||
|
||||
if (dce_work->dce_work_fn != NULL)
|
||||
dce_work->dce_work_fn(dce_work->d);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_init_work : Init dce work structure
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @work : Pointer to dce work structure
|
||||
* @work_fn : worker function to be called
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_init_work(struct tegra_dce *d,
|
||||
struct dce_work_struct *work,
|
||||
void (*work_fn)(struct tegra_dce *d))
|
||||
{
|
||||
work->d = d;
|
||||
work->dce_work_fn = work_fn;
|
||||
|
||||
INIT_WORK(&work->work, dce_work_handle_fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION & AFFILIATES. 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,
|
||||
@@ -18,185 +18,76 @@
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_worker_wakeup_cond - Generic wake up condition for
|
||||
* dce_worker thread.
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce.
|
||||
*
|
||||
* Return : Boolean
|
||||
*/
|
||||
static bool dce_worker_wakeup_cond(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
return (w->state_changed == true ||
|
||||
dce_thread_should_stop(&w->wrk_thread));
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_wait - Will wait in a given state.
|
||||
/*
|
||||
* dce_wait_interruptible : Wait for a given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event that will trigger the wait.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Will change state and wait based on the event that
|
||||
* triggers the wait.
|
||||
*
|
||||
* Return : Void
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
void dce_worker_thread_wait(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event)
|
||||
int dce_wait_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
int ret;
|
||||
u32 timeout_val_ms = 0;
|
||||
enum dce_worker_state new_state;
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
if (w->state_changed == true) {
|
||||
w->state_changed = false;
|
||||
dce_warn(d, "Unexpected state_changed value");
|
||||
dce_mutex_unlock(&w->lock);
|
||||
return;
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_err(d, "Invalid wait requested %u", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET:
|
||||
if ((w->c_state != STATE_DCE_WORKER_IDLE) &&
|
||||
(w->c_state != STATE_DCE_WORKER_BOOT_WAIT)) {
|
||||
dce_warn(d, "Unexpected wait event [%d] rcvd in state [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_BOOT_WAIT;
|
||||
break;
|
||||
case EVENT_ID_DCE_IPC_SYNC_TRIGGERED:
|
||||
case EVENT_ID_DCE_IPC_MESSAGE_SENT:
|
||||
new_state = STATE_DCE_WORKER_WFI;
|
||||
break;
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE:
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
default:
|
||||
dce_warn(d, "Invalid wait event [%d] rcvd in state [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
atomic_set(&wait->complete, 0);
|
||||
|
||||
w->c_state = new_state;
|
||||
dce_mutex_unlock(&w->lock);
|
||||
DCE_COND_WAIT_INTERRUPTIBLE(&wait->cond_wait,
|
||||
atomic_read(&wait->complete) == 1,
|
||||
0);
|
||||
|
||||
if (new_state == STATE_DCE_WORKER_BOOT_WAIT)
|
||||
timeout_val_ms = 1000;
|
||||
if (atomic_read(&wait->complete) != 1)
|
||||
return -EINTR;
|
||||
|
||||
ret = DCE_COND_WAIT_INTERRUPTIBLE(&w->cond,
|
||||
dce_worker_wakeup_cond(d),
|
||||
timeout_val_ms);
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
w->state_changed = false;
|
||||
|
||||
if (ret)
|
||||
w->c_state = STATE_DCE_WORKER_IDLE;
|
||||
|
||||
dce_mutex_unlock(&w->lock);
|
||||
atomic_set(&wait->complete, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_wakeup - Wakeup the dce worker thread
|
||||
/*
|
||||
* dce_wakeup_interruptible : Wakeup waiting task on given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event that will trigger the wakeup.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Will change state and wakeup the worker thread based on
|
||||
* the event that triggers it.
|
||||
*
|
||||
* Return : Void
|
||||
* Return : void
|
||||
*/
|
||||
void dce_worker_thread_wakeup(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event)
|
||||
void dce_wakeup_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
enum dce_worker_state new_state = w->c_state;
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
if (w->state_changed == true)
|
||||
dce_warn(d, "Unexpected state_changed value");
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_IPC_SIGNAL_RECEIVED:
|
||||
if (w->c_state != STATE_DCE_WORKER_WFI) {
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED:
|
||||
if (w->c_state != STATE_DCE_WORKER_BOOT_WAIT) {
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
case EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED:
|
||||
new_state = STATE_DCE_WORKER_HANDLE_DCE_ERROR;
|
||||
dce_warn(d, "Error Event Rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
break;
|
||||
case EVENT_ID_DCE_THREAD_ABORT_REQ_RECEIVED:
|
||||
if (dce_thread_should_stop(&w->wrk_thread))
|
||||
new_state = STATE_DCE_WORKER_ABORTED;
|
||||
else
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
break;
|
||||
default:
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_err(d, "Invalid wait requested %u", msg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
w->c_state = new_state;
|
||||
w->state_changed = true;
|
||||
dce_mutex_unlock(&w->lock);
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
|
||||
dce_cond_signal_interruptible(&w->cond);
|
||||
atomic_set(&wait->complete, 1);
|
||||
dce_cond_signal_interruptible(&wait->cond_wait);
|
||||
}
|
||||
|
||||
static void dce_handle_dce_error(struct tegra_dce *d)
|
||||
{
|
||||
/**
|
||||
* TODO : Handle error messages from DCE
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker - dce worker main function to manage dce thread states.
|
||||
/*
|
||||
* dce_start_boot_flow : Start dce bootstrap flow
|
||||
*
|
||||
* @arg : Void pointer to be typecast to tegra_dce struct before use.
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 on success.
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
static int dce_worker(void *arg)
|
||||
static int
|
||||
dce_start_boot_flow(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tegra_dce *d = (struct tegra_dce *)arg;
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
ret = dce_wait_boot_complete(d);
|
||||
if (ret) {
|
||||
dce_warn(d, "DCE_BOOT_FAILED: Boot didn't complete");
|
||||
goto worker_exit;
|
||||
}
|
||||
|
||||
ret = dce_start_bootstrap_flow(d);
|
||||
if (ret) {
|
||||
dce_warn(d, "DCE_BOOT_FAILED: Bootstrap flow didn't complete");
|
||||
goto worker_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dce_admin_ivc_channel_reset(d);
|
||||
@@ -209,106 +100,105 @@ static int dce_worker(void *arg)
|
||||
dce_info(d, "DCE_BOOT_DONE");
|
||||
}
|
||||
|
||||
do {
|
||||
dce_worker_thread_wait(d, EVENT_ID_DCE_BOOT_COMPLETE);
|
||||
|
||||
if (w->c_state == STATE_DCE_WORKER_HANDLE_DCE_ERROR) {
|
||||
dce_handle_dce_error(d);
|
||||
d->boot_status |= DCE_STATUS_FAILED;
|
||||
}
|
||||
} while ((w->c_state != STATE_DCE_WORKER_ABORTED) ||
|
||||
(!dce_thread_should_stop(&w->wrk_thread)));
|
||||
|
||||
worker_exit:
|
||||
if (w->c_state == STATE_DCE_WORKER_ABORTED)
|
||||
dce_warn(d, "Exiting Dce Worker Thread");
|
||||
exit:
|
||||
if (ret)
|
||||
d->boot_status |= DCE_STATUS_FAILED;
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_get_state - Gets the current state of dce_worker
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Current state
|
||||
*/
|
||||
enum dce_worker_state dce_worker_get_state(struct tegra_dce *d)
|
||||
{
|
||||
return d->wrk_info.c_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_init - Initializes the worker thread and
|
||||
* its corresponding resources.
|
||||
* dce_bootstrap_work_fn : execute fsm start and bootstrap flow
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if success.
|
||||
* Return : void
|
||||
*/
|
||||
int dce_worker_thread_init(struct tegra_dce *d)
|
||||
void dce_bootstrap_work_fn(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_worker_info *w
|
||||
= &d->wrk_info;
|
||||
|
||||
ret = dce_cond_init(&w->cond);
|
||||
if (ret) {
|
||||
dce_err(d, "dce condition initialization failed for worker");
|
||||
goto err_cond_init;
|
||||
if (d == NULL) {
|
||||
dce_err(d, "tegra_dce struct is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dce_mutex_init(&w->lock);
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_FSM_START, NULL);
|
||||
if (ret) {
|
||||
dce_err(d, "dce condition initialization failed for worker");
|
||||
goto err_lock_init;
|
||||
dce_err(d, "FSM start failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
w->state_changed = false;
|
||||
|
||||
w->c_state = STATE_DCE_WORKER_IDLE;
|
||||
|
||||
ret = dce_thread_create(&w->wrk_thread, d,
|
||||
dce_worker, "dce_worker_thread");
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED, NULL);
|
||||
if (ret) {
|
||||
dce_err(d, "Dce Worker Thread creation failed");
|
||||
dce_mutex_unlock(&w->lock);
|
||||
goto err_thread_create;
|
||||
dce_err(d, "Error while posting DCE_BOOT_COMPLETE_REQUESTED event");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_mutex_unlock(&w->lock);
|
||||
ret = dce_start_boot_flow(d);
|
||||
if (ret) {
|
||||
dce_err(d, "DCE bootstrapping failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
/**
|
||||
* dce_sw_resource_init : Init dce workques related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_sw_resource_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
err_thread_create:
|
||||
dce_mutex_destroy(&w->lock);
|
||||
err_lock_init:
|
||||
dce_cond_destroy(&w->cond);
|
||||
err_cond_init:
|
||||
ret = dce_init_work(d, &d->dce_bootstrap_work, dce_bootstrap_work_fn);
|
||||
if (ret) {
|
||||
dce_err(d, "fsm_start work init failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
if (dce_cond_init(&wait->cond_wait)) {
|
||||
dce_err(d, "dce wait condition %d init failed", i);
|
||||
ret = -1;
|
||||
goto init_error;
|
||||
}
|
||||
|
||||
atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
init_error:
|
||||
while (i >= 0) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_cond_destroy(&wait->cond_wait);
|
||||
i--;
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_deinit - Kill the dce worker thread and
|
||||
* its corresponding resources.
|
||||
* dce_sw_resource_deinit : de-init dce workques related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return :Void
|
||||
* Return : void
|
||||
*/
|
||||
void dce_worker_thread_deinit(struct tegra_dce *d)
|
||||
void dce_sw_resource_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
int i;
|
||||
|
||||
if (dce_thread_is_running(&w->wrk_thread))
|
||||
dce_thread_stop(&w->wrk_thread);
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_thread_join(&w->wrk_thread);
|
||||
|
||||
dce_mutex_destroy(&w->lock);
|
||||
|
||||
dce_cond_destroy(&w->cond);
|
||||
dce_cond_destroy(&wait->cond_wait);
|
||||
atomic_set(&wait->complete, 0);
|
||||
}
|
||||
}
|
||||
|
||||
103
drivers/platform/tegra/dce/include/dce-fsm.h
Normal file
103
drivers/platform/tegra/dce/include/dce-fsm.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 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,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef DCE_FSM_H
|
||||
#define DCE_FSM_H
|
||||
|
||||
#include <dce-cond.h>
|
||||
#include <dce-lock.h>
|
||||
|
||||
/**
|
||||
* enum dce_fsm_event_id_type - IDs to be used to convey various
|
||||
* events throughout the life cycle of dce.
|
||||
*/
|
||||
enum dce_fsm_event_id_type {
|
||||
EVENT_ID_DCE_INVALID = -1,
|
||||
EVENT_ID_DCE_FSM_START = 0,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED,
|
||||
EVENT_ID_DCE_SC7_ENTER_REQUESTED,
|
||||
EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
|
||||
EVENT_ID_DCE_LOG_REQUESTED,
|
||||
EVENT_ID_DCE_LOG_READY_RECEIVED,
|
||||
EVENT_ID_DCE_ABORT_RECEIVED,
|
||||
EVENT_ID_DCE_CRASH_LOG_RECEIVED,
|
||||
EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED,
|
||||
EVENT_ID_DCE_FSM_STOP,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_fsm_state - Different states of dce.
|
||||
*/
|
||||
enum dce_fsm_state {
|
||||
STATE_DCE_INVALID = -1,
|
||||
STATE_DCE_FSM_IDLE = 0,
|
||||
STATE_DCE_BOOT_WAIT,
|
||||
STATE_DCE_BOOTCMD_WFI,
|
||||
STATE_DCE_ADMIN_WFI,
|
||||
STATE_DCE_SC7_ENTER_WFI,
|
||||
STATE_DCE_SC7_ENTERED,
|
||||
STATE_DCE_LOG_READY_WFI,
|
||||
STATE_DCE_ABORT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_fsm_info - contains info used by FSM
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @initialized : If FSM is initialized
|
||||
* @c_state : Current state of FSM
|
||||
* @lock : Mutex to protect FSM operations
|
||||
* @requested_ipcs : Indicate what IPCs/requests are currently running.
|
||||
* In case we support more than one FSM request at a time.
|
||||
*/
|
||||
struct dce_fsm_info {
|
||||
struct tegra_dce *d;
|
||||
bool initialized;
|
||||
enum dce_fsm_state c_state;
|
||||
struct dce_mutex lock;
|
||||
u32 requested_ipcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_mailbox_send_cmd_params - contains params for callback function
|
||||
* @cmd : u32 command to be send
|
||||
* @interface : interface id on which command need to be sent
|
||||
*/
|
||||
struct dce_mailbox_send_cmd_params {
|
||||
u32 cmd;
|
||||
u32 interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_admin_send_msg_params - contains params for callback function
|
||||
* @msg : Pointer to dce_ipc_msg
|
||||
*/
|
||||
struct dce_admin_send_msg_params {
|
||||
struct dce_ipc_message *msg;
|
||||
};
|
||||
|
||||
int dce_fsm_init(struct tegra_dce *d);
|
||||
void dce_fsm_start(struct tegra_dce *d);
|
||||
void dce_fsm_stop(struct tegra_dce *d);
|
||||
void dce_fsm_deinit(struct tegra_dce *d);
|
||||
int dce_fsm_post_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event,
|
||||
void *data);
|
||||
|
||||
int dce_handle_fsm_start_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_event_stub(struct tegra_dce *d, void *params);
|
||||
#endif
|
||||
@@ -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,
|
||||
@@ -57,6 +57,7 @@ void dce_mailbox_isr(struct tegra_dce *d);
|
||||
void dce_mailbox_set_full_interrupt(struct tegra_dce *d, u8 id);
|
||||
|
||||
int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface);
|
||||
int dce_handle_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface);
|
||||
|
||||
int dce_mailbox_init_interface(struct tegra_dce *d, u8 id, u8 s_mb,
|
||||
u8 r_mb, int (*dce_mailbox_wait)(struct tegra_dce *),
|
||||
|
||||
@@ -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,
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/**
|
||||
* This file contains all dce common fucntions and data strutcures which are
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION & AFFILIATES. 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,
|
||||
@@ -20,63 +20,22 @@
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
/**
|
||||
* enum dce_worker_event_id_type - IDs to be used to convey various
|
||||
* events thoughout the life cycle of dce worker thread.
|
||||
*/
|
||||
enum dce_worker_event_id_type {
|
||||
EVENT_ID_DCE_INVALID_EVENT = -1,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET = 0,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED = 1,
|
||||
EVENT_ID_DCE_IPC_SYNC_TRIGGERED = 2,
|
||||
EVENT_ID_DCE_IPC_MESSAGE_SENT = 3,
|
||||
EVENT_ID_DCE_IPC_SIGNAL_RECEIVED = 4,
|
||||
EVENT_ID_DCE_THREAD_ABORT_REQ_RECEIVED = 5,
|
||||
EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED = 6,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE = 7,
|
||||
#define DCE_WAIT_BOOT_COMPLETE 0
|
||||
#define DCE_WAIT_BOOT_CMD 1
|
||||
#define DCE_WAIT_ADMIN_IPC 2
|
||||
#define DCE_WAIT_SC7_ENTER 3
|
||||
#define DCE_WAIT_LOG 4
|
||||
#define DCE_MAX_WAIT 5
|
||||
|
||||
struct dce_wait_cond {
|
||||
atomic_t complete;
|
||||
struct dce_cond cond_wait;
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_worker_state - Different states of dce worker thread.
|
||||
*/
|
||||
enum dce_worker_state {
|
||||
STATE_DCE_WORKER_IDLE = 0,
|
||||
STATE_DCE_WORKER_BOOT_WAIT = 1,
|
||||
STATE_DCE_WORKER_WFI = 2,
|
||||
STATE_DCE_WORKER_ABORTED = 3,
|
||||
STATE_DCE_WORKER_HANDLE_DCE_ERROR = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_worker_info - Contains information to control and manage
|
||||
* dce worker thread throughout its lifecycle.
|
||||
* @wrk_thread : Event driven dce thread to manage initilaization and
|
||||
* release workflow.
|
||||
* @state_changed : Boolean to convey state changes.
|
||||
* @c_state : Stores the current state of dce worker thread. State changes
|
||||
* are triggered by vrious events.
|
||||
* @lock : Used for exclusive state modifications from thread and
|
||||
* interrupt context.
|
||||
* @cond : dce_cond to manage various thread states.
|
||||
*/
|
||||
struct dce_worker_info {
|
||||
struct dce_thread wrk_thread;
|
||||
bool state_changed;
|
||||
enum dce_worker_state c_state;
|
||||
struct dce_mutex lock;
|
||||
struct dce_cond cond;
|
||||
};
|
||||
|
||||
void dce_worker_thread_wait(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event);
|
||||
|
||||
void dce_worker_thread_wakeup(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event);
|
||||
|
||||
enum dce_worker_state dce_worker_get_state(struct tegra_dce *d);
|
||||
|
||||
int dce_worker_thread_init(struct tegra_dce *d);
|
||||
|
||||
void dce_worker_thread_deinit(struct tegra_dce *d);
|
||||
int dce_sw_resource_init(struct tegra_dce *d);
|
||||
void dce_sw_resource_deinit(struct tegra_dce *d);
|
||||
void dce_schedule_boot_complete_wait_worker(struct tegra_dce *d);
|
||||
int dce_wait_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
void dce_wakeup_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
|
||||
#endif
|
||||
|
||||
30
drivers/platform/tegra/dce/include/dce-workqueue.h
Normal file
30
drivers/platform/tegra/dce/include/dce-workqueue.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef DCE_WORKQUEUE_H
|
||||
#define DCE_WORKQUEUE_H
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct dce_work_struct {
|
||||
struct tegra_dce *d;
|
||||
struct work_struct work;
|
||||
void (*dce_work_fn)(struct tegra_dce *d);
|
||||
};
|
||||
|
||||
int dce_init_work(struct tegra_dce *d,
|
||||
struct dce_work_struct *work,
|
||||
void (*work_fn)(struct tegra_dce *d));
|
||||
void dce_schedule_work(struct dce_work_struct *work);
|
||||
|
||||
#endif
|
||||
@@ -24,8 +24,10 @@
|
||||
#include <dce-regs.h>
|
||||
#include <dce-thread.h>
|
||||
#include <dce-worker.h>
|
||||
#include <dce-fsm.h>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
#include <dce-workqueue.h>
|
||||
|
||||
#define DCE_MAX_CPU_IRQS 4
|
||||
|
||||
@@ -44,6 +46,7 @@
|
||||
/**
|
||||
* DCE Boot Status: FW Boot States
|
||||
*/
|
||||
#define DCE_FW_EARLY_BOOT_START DCE_BIT(16)
|
||||
#define DCE_FW_EARLY_BOOT_FAILED DCE_BIT(15)
|
||||
#define DCE_FW_EARLY_BOOT_DONE DCE_BIT(14)
|
||||
#define DCE_FW_BOOTSTRAP_START DCE_BIT(13)
|
||||
@@ -134,11 +137,6 @@ struct dce_firmware {
|
||||
u64 dma_handle;
|
||||
};
|
||||
|
||||
struct admin_rpc_post_boot_info {
|
||||
atomic_t complete;
|
||||
struct dce_cond recv_wait;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_dce - Primary OS independent tegra dce structure to hold dce
|
||||
* cluster's and it's element's runtime info.
|
||||
@@ -149,13 +147,17 @@ struct tegra_dce {
|
||||
*/
|
||||
u32 irq[DCE_MAX_CPU_IRQS];
|
||||
/**
|
||||
* @rpc_info - Data Structure to manage Admin RPC calls post boot.
|
||||
* @fsm_info - Data Structure to manage dce FSM states.
|
||||
*/
|
||||
struct admin_rpc_post_boot_info admin_rpc;
|
||||
struct dce_fsm_info fsm_info;
|
||||
/**
|
||||
* @wrk_info - Data Structure to manage dce worker thread states.
|
||||
* dce_bootstrap_work : dce work to be executed to start FSM flow
|
||||
*/
|
||||
struct dce_worker_info wrk_info;
|
||||
struct dce_work_struct dce_bootstrap_work;
|
||||
/**
|
||||
* dce_wait_info - Data structure to manage wait for different event types
|
||||
*/
|
||||
struct dce_wait_cond ipc_waits[DCE_MAX_WAIT];
|
||||
/**
|
||||
* @d_mb - Stores the current status of dce mailbox interfaces.
|
||||
*/
|
||||
@@ -349,10 +351,13 @@ const char *dce_get_fw_name(struct tegra_dce *d);
|
||||
int dce_driver_init(struct tegra_dce *d);
|
||||
void dce_driver_deinit(struct tegra_dce *d);
|
||||
|
||||
int dce_wait_boot_complete(struct tegra_dce *d);
|
||||
int dce_start_bootstrap_flow(struct tegra_dce *d);
|
||||
int dce_boot_interface_init(struct tegra_dce *d);
|
||||
void dce_boot_interface_deinit(struct tegra_dce *d);
|
||||
int dce_handle_boot_cmd_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_cmd_received_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params);
|
||||
|
||||
int dce_admin_init(struct tegra_dce *d);
|
||||
void dce_admin_deinit(struct tegra_dce *d);
|
||||
@@ -368,9 +373,14 @@ int dce_admin_get_ipc_channel_info(struct tegra_dce *d,
|
||||
struct dce_ipc_queue_info *q_info);
|
||||
int dce_admin_send_cmd_echo(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params);
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type);
|
||||
void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
bool dce_fw_boot_complete(struct tegra_dce *d);
|
||||
void dce_request_fw_boot_complete(struct tegra_dce *d);
|
||||
|
||||
/**
|
||||
* Functions to be used in debug mode only.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user