mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
DCE-KMD: Refactor dce-os-worker.c/.h
- dce-os-worker.c/.h module exposes functionality which allows
DCE KMD clients to wait/signal events.
- The current abstraction of this module has following drawbacks
which this change attempts to address:
* Name: dce-os-worker is a misnomer
- Rename to dce-wait-cond.c/.h and make it a dce-kmd core file.
- Rename functions accordingly.
* dce-os-worker module initializes data structures from tegra_dce
which makes it ineligible for re-use.
- dce-client-ipc can re-use this module as it uses exact
same functionality.
- But this module is tied with DCE-KMD core such that it has
functions that operate on fixed known inputs.
- dce_os_work_cond_sw_resource_init/deinit()
Inits/Deinits most but not all condition var resources
from tegra_dce. Eg. dce-client-ipc resources
are not initialized.
- Move this function to new core file:dce-waiters.c
- All other functions require msg_id as input and can only
operate on DCE_WAIT* resources making it ineligible
to be used by other clients like dce-client-ipc.
- Refactor these fucntions to operate on
individual wait conditions so that all DCE-KMD
core modules can reuse them.
- Additionally, this change will also remove unused functions
and macros from dce-os-cond.c/.h
- dce-client-ipc will also switch to use dce-wait-cond interface
for client ipc waits.
- Make dce-os-cond.h a common file and move OS specific impl
to dce-os-cond-internal.h
JIRA TDS-16581
Change-Id: Ie8c6ec724e48cde66917fab4aa43e7da464ef8fb
Signed-off-by: anupamg <anupamg@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3258562
Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Reviewed-by: Arun Swain <arswain@nvidia.com>
This commit is contained in:
@@ -22,7 +22,8 @@ tegra-dce-$(CONFIG_TEGRA_DCE) += dce-ast.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-reset.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-smb.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-ss.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-os-worker.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-wait-cond.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-waiters.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-fsm.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-init-deinit.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-mailbox.o
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ int dce_admin_ipc_wait(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = dce_os_wait_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
ret = dce_wait_cond_wait_interruptible(d, &d->ipc_waits[DCE_WAIT_ADMIN_IPC], true, 0);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
@@ -623,7 +623,7 @@ int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
DCE_WARN_ON_NOT_NULL(params);
|
||||
|
||||
dce_os_wakeup_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
dce_wait_cond_signal_interruptible(d, &d->ipc_waits[DCE_WAIT_ADMIN_IPC]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -833,7 +833,7 @@ int dce_admin_send_enter_sc7(struct tegra_dce *d,
|
||||
}
|
||||
|
||||
/* Wait for SC7 Enter done */
|
||||
ret = dce_os_wait_interruptible(d, DCE_WAIT_SC7_ENTER);
|
||||
ret = dce_wait_cond_wait_interruptible(d, &d->ipc_waits[DCE_WAIT_SC7_ENTER], true, 0);
|
||||
if (ret) {
|
||||
dce_os_err(d, "SC7 Enter wait was interrupted with err:%d", ret);
|
||||
goto out;
|
||||
|
||||
@@ -71,7 +71,7 @@ int dce_handle_boot_cmd_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
DCE_WARN_ON_NOT_NULL(params);
|
||||
|
||||
dce_os_wakeup_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
dce_wait_cond_signal_interruptible(d, &d->ipc_waits[DCE_WAIT_BOOT_CMD]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params)
|
||||
if (ret)
|
||||
dce_os_err(d, "failed to send DCE_BOOT_COMPLETE_RECEIVED event");
|
||||
|
||||
dce_os_cond_wait_reset(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
dce_wait_cond_reset(d, &d->ipc_waits[DCE_WAIT_BOOT_COMPLETE]);
|
||||
goto boot_done;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params)
|
||||
|
||||
dce_os_debug(d, "Waiting for dce fw to boot...");
|
||||
|
||||
ret = dce_os_wait_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
ret = dce_wait_cond_wait_interruptible(d, &d->ipc_waits[DCE_WAIT_BOOT_COMPLETE], true, 0);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
@@ -139,7 +139,7 @@ int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
DCE_WARN_ON_NOT_NULL(params);
|
||||
|
||||
dce_os_wakeup_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
dce_wait_cond_signal_interruptible(d, &d->ipc_waits[DCE_WAIT_BOOT_COMPLETE]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ static void dce_handle_irq_status(struct tegra_dce *d, u32 status)
|
||||
|
||||
if (status & DCE_IRQ_LOG_READY) {
|
||||
dce_os_info(d, "DCE trace log buffers available");
|
||||
dce_os_wakeup_interruptible(d, DCE_WAIT_LOG);
|
||||
dce_wait_cond_signal_interruptible(d, &d->ipc_waits[DCE_WAIT_LOG]);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -370,7 +370,7 @@ static int dce_mailbox_wait_boot_interface(struct tegra_dce *d)
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
ret = dce_os_wait_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
ret = dce_wait_cond_wait_interruptible(d, &d->ipc_waits[DCE_WAIT_BOOT_CMD], true, 0);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
|
||||
@@ -180,9 +180,8 @@ int tegra_dce_register_ipc_client(u32 type,
|
||||
cl->handle = handle;
|
||||
cl->int_type = int_type;
|
||||
cl->callback_fn = callback_fn;
|
||||
dce_os_atomic_set(&cl->complete, 0);
|
||||
|
||||
ret = dce_os_cond_init(&cl->recv_wait);
|
||||
ret = dce_wait_cond_init(d, &cl->recv_wait);
|
||||
if (ret) {
|
||||
dce_os_err(d, "dce condition initialization failed for int_type: [%u]",
|
||||
int_type);
|
||||
@@ -213,8 +212,7 @@ int tegra_dce_unregister_ipc_client(u32 handle)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dce_os_cond_destroy(&cl->recv_wait);
|
||||
dce_os_atomic_set(&cl->complete, 0);
|
||||
dce_wait_cond_deinit(cl->d, &cl->recv_wait);
|
||||
|
||||
return dce_client_ipc_handle_free(cl);
|
||||
}
|
||||
@@ -302,30 +300,38 @@ int dce_client_ipc_wait(struct tegra_dce *d, u32 int_type)
|
||||
{
|
||||
uint32_t type;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
int ret = 0;
|
||||
|
||||
type = dce_client_get_type(int_type);
|
||||
if (type >= DCE_CLIENT_IPC_TYPE_MAX) {
|
||||
dce_os_err(d, "Failed to retrieve client info for int_type: [%d]",
|
||||
int_type);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cl = d->d_clients[type];
|
||||
if ((cl == NULL) || (cl->int_type != int_type)) {
|
||||
dce_os_err(d, "Failed to retrieve client info for int_type: [%d]",
|
||||
int_type);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
retry_wait:
|
||||
DCE_OS_COND_WAIT_INTERRUPTIBLE(&cl->recv_wait,
|
||||
dce_os_atomic_read(&cl->complete) == 1);
|
||||
if (dce_os_atomic_read(&cl->complete) != 1)
|
||||
ret = dce_wait_cond_wait_interruptible(d, &cl->recv_wait, true, 0);
|
||||
if (ret) {
|
||||
if (ret == -ERESTARTSYS) { /* Interrupt. */
|
||||
dce_os_debug(d, "Client [%u] wait interrupted: retrying.", type);
|
||||
goto retry_wait;
|
||||
} else { /* Unexpected error. */
|
||||
dce_os_err(d, "Client [%u] unexpected err: [%d]", type, ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
dce_os_atomic_set(&cl->complete, 0);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dce_client_process_event_ipc(struct tegra_dce *d,
|
||||
@@ -417,6 +423,5 @@ void dce_client_ipc_wakeup(struct tegra_dce *d, u32 ch_type)
|
||||
if (type == DCE_CLIENT_IPC_TYPE_RM_EVENT)
|
||||
return dce_client_schedule_event_work(d);
|
||||
|
||||
dce_os_atomic_set(&cl->complete, 1);
|
||||
dce_os_cond_signal_interruptible(&cl->recv_wait);
|
||||
dce_wait_cond_signal_interruptible(d, &cl->recv_wait);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <dce.h>
|
||||
@@ -71,7 +71,7 @@ int dce_driver_init(struct tegra_dce *d)
|
||||
goto err_pm_init;
|
||||
}
|
||||
|
||||
ret = dce_os_work_cond_sw_resource_init(d);
|
||||
ret = dce_waiters_init(d);
|
||||
if (ret) {
|
||||
dce_os_err(d, "dce sw resource init failed");
|
||||
goto err_sw_init;
|
||||
@@ -86,7 +86,7 @@ int dce_driver_init(struct tegra_dce *d)
|
||||
return ret;
|
||||
|
||||
err_fsm_init:
|
||||
dce_os_work_cond_sw_resource_deinit(d);
|
||||
dce_waiters_deinit(d);
|
||||
err_sw_init:
|
||||
dce_pm_deinit(d);
|
||||
err_pm_init:
|
||||
@@ -115,7 +115,7 @@ void dce_driver_deinit(struct tegra_dce *d)
|
||||
|
||||
dce_fsm_deinit_unlocked(d);
|
||||
|
||||
dce_os_work_cond_sw_resource_deinit(d);
|
||||
dce_waiters_deinit(d);
|
||||
|
||||
dce_pm_deinit(d);
|
||||
|
||||
|
||||
@@ -272,13 +272,6 @@ void dce_os_log_msg(struct tegra_dce *d, const char *func_name, int line,
|
||||
dce_print(func_name, line, type, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_init - Initialize a condition variable
|
||||
*
|
||||
* @cond - The condition variable to initialize
|
||||
*
|
||||
* Initialize a condition variable before using it.
|
||||
*/
|
||||
int dce_os_cond_init(struct dce_os_cond *cond)
|
||||
{
|
||||
init_waitqueue_head(&cond->wq);
|
||||
@@ -287,43 +280,11 @@ int dce_os_cond_init(struct dce_os_cond *cond)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_destroy - Destroy a condition variable
|
||||
*
|
||||
* @cond - The condition variable to destroy
|
||||
*/
|
||||
void dce_os_cond_destroy(struct dce_os_cond *cond)
|
||||
{
|
||||
cond->initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_signal - Signal a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up a waiter for a condition variable to check if its condition has been
|
||||
* satisfied.
|
||||
*
|
||||
* The waiter is using an uninterruptible wait.
|
||||
*/
|
||||
void dce_os_cond_signal(struct dce_os_cond *cond)
|
||||
{
|
||||
WARN_ON(!cond->initialized);
|
||||
|
||||
wake_up(&cond->wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_signal_interruptible - Signal a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up a waiter for a condition variable to check if its condition has been
|
||||
* satisfied.
|
||||
*
|
||||
* The waiter is using an interruptible wait.
|
||||
*/
|
||||
void dce_os_cond_signal_interruptible(struct dce_os_cond *cond)
|
||||
{
|
||||
WARN_ON(!cond->initialized);
|
||||
@@ -331,37 +292,6 @@ void dce_os_cond_signal_interruptible(struct dce_os_cond *cond)
|
||||
wake_up_interruptible(&cond->wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_broadcast - Signal all waiters of a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up all waiters for a condition variable to check if their conditions
|
||||
* have been satisfied.
|
||||
*
|
||||
* The waiters are using an uninterruptible wait.
|
||||
*/
|
||||
int dce_os_cond_broadcast(struct dce_os_cond *cond)
|
||||
{
|
||||
if (!cond->initialized)
|
||||
return -EINVAL;
|
||||
|
||||
wake_up_all(&cond->wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_cond_broadcast_interruptible - Signal all waiters of a condition
|
||||
* variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up all waiters for a condition variable to check if their conditions
|
||||
* have been satisfied.
|
||||
*
|
||||
* The waiters are using an interruptible wait.
|
||||
*/
|
||||
int dce_os_cond_broadcast_interruptible(struct dce_os_cond *cond)
|
||||
{
|
||||
if (!cond->initialized)
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <dce.h>
|
||||
#include <dce-os-cond.h>
|
||||
#include <dce-os-lock.h>
|
||||
#include <dce-os-worker.h>
|
||||
#include <dce-os-utils.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/*
|
||||
* dce_os_wait_interruptible : Wait for a given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_os_wait_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_os_err(d, "Invalid wait requested %u", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
|
||||
/*
|
||||
* It is possible that we received the ACK from DCE even before we
|
||||
* start waiting. But that should not be an issue as wait->complete
|
||||
* Will be "1" and we immediately exit from the wait.
|
||||
*/
|
||||
DCE_OS_COND_WAIT_INTERRUPTIBLE(&wait->cond_wait,
|
||||
dce_os_atomic_read(&wait->complete) == 1);
|
||||
|
||||
if (dce_os_atomic_read(&wait->complete) != 1)
|
||||
return -EINTR;
|
||||
|
||||
/*
|
||||
* Clear wait->complete as soon as we exit from wait (consume the wake call)
|
||||
* So that when the next dce_os_wait_interruptible is called, it doesn't see old
|
||||
* wait->complete state.
|
||||
*/
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_os_wakeup_interruptible : Wakeup waiting task on given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_os_wakeup_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_os_err(d, "Invalid wait requested %u", msg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
|
||||
/*
|
||||
* Set wait->complete to "1", so if the wait is called even after
|
||||
* "dce_os_cond_signal_interruptible", it'll see the complete variable
|
||||
* as "1" and exit the wait immediately.
|
||||
*/
|
||||
dce_os_atomic_set(&wait->complete, 1);
|
||||
dce_os_cond_signal_interruptible(&wait->cond_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_os_cond_wait_reset : reset condition wait variable to zero
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_os_cond_wait_reset(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_os_err(d, "Invalid wait requested %u", msg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_work_cond_sw_resource_init : Init dce workqueues related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_os_work_cond_sw_resource_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (dce_os_cond_init(&d->dce_bootstrap_done)) {
|
||||
dce_os_err(d, "dce boot wait condition init failed");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
if (dce_os_cond_init(&wait->cond_wait)) {
|
||||
dce_os_err(d, "dce wait condition %d init failed", i);
|
||||
ret = -1;
|
||||
goto init_error;
|
||||
}
|
||||
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
init_error:
|
||||
while (i >= 0) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_os_cond_destroy(&wait->cond_wait);
|
||||
i--;
|
||||
}
|
||||
dce_os_cond_destroy(&d->dce_bootstrap_done);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_os_work_cond_sw_resource_deinit : de-init dce workqueues related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_os_work_cond_sw_resource_deinit(struct tegra_dce *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_os_cond_destroy(&wait->cond_wait);
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
dce_os_cond_destroy(&d->dce_bootstrap_done);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ int dce_pm_handle_sc7_enter_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
DCE_WARN_ON_NOT_NULL(params);
|
||||
|
||||
dce_os_wakeup_interruptible(d, DCE_WAIT_SC7_ENTER);
|
||||
dce_wait_cond_signal_interruptible(d, &d->ipc_waits[DCE_WAIT_SC7_ENTER]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
156
drivers/platform/tegra/dce/dce-wait-cond.c
Normal file
156
drivers/platform/tegra/dce/dce-wait-cond.c
Normal file
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <dce-os-cond.h>
|
||||
#include <dce-wait-cond.h>
|
||||
#include <dce-os-utils.h>
|
||||
#include <dce-os-log.h>
|
||||
#include <dce.h>
|
||||
|
||||
/*
|
||||
* dce_wait_cond_wait_interruptible : Wait for a given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to init.
|
||||
* @reset : Boolean input to indicate if to reset condition.
|
||||
* If reset is set to true, clear wait->complete as soon as we exit from wait (consume wake).
|
||||
* Client can use this, if they want the next dce_wait_cond_wait_interruptible call to
|
||||
* not see the old wait->complete state.
|
||||
* @timeout_ms : Wait timeout in ms. 0 for no timeout.
|
||||
*
|
||||
* Return : 0 if successful, -ETIMEOUT on timeout, -ERESTARTSYS on interrupt.
|
||||
* -EINVAL if invalid input args.
|
||||
*
|
||||
* Note: Since multiple clients wait on a broadcast event, the user is responsible
|
||||
* to reset the condition only when all clients have consumed the call.
|
||||
*/
|
||||
int dce_wait_cond_wait_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait,
|
||||
bool reset, u32 timeout_ms)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DCE_WARN_ON_NULL(d);
|
||||
|
||||
if (timeout_ms == 0) {
|
||||
ret = DCE_OS_COND_WAIT_INTERRUPTIBLE(&wait->cond_wait,
|
||||
dce_os_atomic_read(&wait->complete) == 1);
|
||||
} else {
|
||||
ret = DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT(&wait->cond_wait,
|
||||
dce_os_atomic_read(&wait->complete) == 1,
|
||||
timeout_ms);
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT returns remaining jiffies
|
||||
* if condition was evaluated to true before timeout.
|
||||
* Set return value to SUCCESS in this case.
|
||||
*/
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Skip reset if interrupted by a signal or any other error. */
|
||||
if ((ret == 0) && reset)
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_wait_cond_signal_interruptible : Wakeup waiting task on given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to init.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_wait_cond_signal_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait)
|
||||
{
|
||||
DCE_WARN_ON_NULL(d);
|
||||
|
||||
/*
|
||||
* Set wait->complete to "1", so if the wait is called even after
|
||||
* "dce_os_cond_signal_interruptible", it'll see the complete variable
|
||||
* as "1" and exit the wait immediately.
|
||||
*/
|
||||
dce_os_atomic_set(&wait->complete, 1);
|
||||
dce_os_cond_signal_interruptible(&wait->cond_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_wait_cond_reset : reset condition wait variable to zero
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to init.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_wait_cond_reset(struct tegra_dce *d, struct dce_wait_cond *wait)
|
||||
{
|
||||
DCE_WARN_ON_NULL(d);
|
||||
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_wait_cond_init : Init DCE OS wait condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to init.
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_wait_cond_init(struct tegra_dce *d, struct dce_wait_cond *wait)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dce_os_cond_init(&wait->cond_wait)) {
|
||||
dce_os_err(d, "dce boot wait condition init failed");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_wait_cond_deinit : de-init dce workqueues related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to init.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_wait_cond_deinit(struct tegra_dce *d, struct dce_wait_cond *wait)
|
||||
{
|
||||
DCE_WARN_ON_NULL(d);
|
||||
|
||||
dce_os_atomic_set(&wait->complete, 0);
|
||||
dce_os_cond_destroy(&wait->cond_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_wait_cond_broadcast_interruptible - Signal all waiters of a condition
|
||||
* variable
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @wait : DCE OS wait condition to signal.
|
||||
*
|
||||
* Wake up all waiters for a condition variable.
|
||||
*
|
||||
* The waiters are using an interruptible wait.
|
||||
*/
|
||||
void dce_wait_cond_broadcast_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait)
|
||||
{
|
||||
DCE_WARN_ON_NULL(d);
|
||||
/*
|
||||
* Set wait->complete to "1", so if the wait is called even after
|
||||
* "dce_wait_cond_broadcast_interruptible", it'll see the complete variable
|
||||
* as "1" and exit the wait immediately.
|
||||
*/
|
||||
dce_os_atomic_set(&wait->complete, 1);
|
||||
dce_os_cond_broadcast_interruptible(&wait->cond_wait);
|
||||
}
|
||||
53
drivers/platform/tegra/dce/dce-waiters.c
Normal file
53
drivers/platform/tegra/dce/dce-waiters.c
Normal file
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <dce.h>
|
||||
|
||||
int dce_waiters_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (dce_os_cond_init(&d->dce_bootstrap_done)) {
|
||||
dce_os_err(d, "dce boot wait condition init failed");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
if (dce_wait_cond_init(d, wait)) {
|
||||
dce_os_err(d, "dce wait condition %d init failed", i);
|
||||
ret = -1;
|
||||
goto init_error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
init_error:
|
||||
while (i >= 0) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_wait_cond_deinit(d, wait);
|
||||
i--;
|
||||
}
|
||||
dce_os_cond_destroy(&d->dce_bootstrap_done);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dce_waiters_deinit(struct tegra_dce *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_wait_cond_deinit(d, wait);
|
||||
}
|
||||
|
||||
dce_os_cond_destroy(&d->dce_bootstrap_done);
|
||||
}
|
||||
@@ -22,8 +22,7 @@
|
||||
* @int_type : IPC interface type for above IPC type as defined in CPU driver
|
||||
* @d : pointer to OS agnostic dce struct. Stores all runtime info for dce
|
||||
* cluster elements
|
||||
* @recv_wait : condition variable used for IPC synchronization
|
||||
* @complete : atomic variable used for IPC synchronization
|
||||
* @recv_wait : wait condition variable used for IPC synchronization
|
||||
* @callback_fn : function pointer to the callback function passed by the
|
||||
* client during registration
|
||||
*/
|
||||
@@ -34,8 +33,7 @@ struct tegra_dce_client_ipc {
|
||||
uint32_t handle;
|
||||
uint32_t int_type;
|
||||
struct tegra_dce *d;
|
||||
struct dce_os_cond recv_wait;
|
||||
dce_os_atomic_t complete;
|
||||
struct dce_wait_cond recv_wait;
|
||||
tegra_dce_client_ipc_callback_t callback_fn;
|
||||
};
|
||||
|
||||
|
||||
28
drivers/platform/tegra/dce/include/dce-wait-cond.h
Normal file
28
drivers/platform/tegra/dce/include/dce-wait-cond.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DCE_WAIT_COND_H
|
||||
#define DCE_WAIT_COND_H
|
||||
|
||||
#include <dce-os-cond.h>
|
||||
#include <dce-os-lock.h>
|
||||
#include <dce-os-atomic.h>
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
struct dce_wait_cond {
|
||||
dce_os_atomic_t complete;
|
||||
struct dce_os_cond cond_wait;
|
||||
};
|
||||
|
||||
int dce_wait_cond_init(struct tegra_dce *d, struct dce_wait_cond *wait);
|
||||
void dce_wait_cond_deinit(struct tegra_dce *d, struct dce_wait_cond *wait);
|
||||
int dce_wait_cond_wait_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait,
|
||||
bool reset, u32 timeout_ms);
|
||||
void dce_wait_cond_signal_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait);
|
||||
void dce_wait_cond_reset(struct tegra_dce *d, struct dce_wait_cond *wait);
|
||||
void dce_wait_cond_broadcast_interruptible(struct tegra_dce *d, struct dce_wait_cond *wait);
|
||||
|
||||
#endif /* DCE_WAIT_COND_H */
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <dce-os-lock.h>
|
||||
#include <dce-os-cond.h>
|
||||
#include <dce-regs.h>
|
||||
#include <dce-os-worker.h>
|
||||
#include <dce-wait-cond.h>
|
||||
#include <dce-fsm.h>
|
||||
#include <dce-pm.h>
|
||||
#include <dce-mailbox.h>
|
||||
@@ -27,6 +27,13 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DCE_WARN_ON_NULL(x) \
|
||||
do { \
|
||||
if (x == NULL) { \
|
||||
dce_os_warn(d, "Unexpected NULL value for " #x "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DCE_MAX_CPU_IRQS 4
|
||||
|
||||
/**
|
||||
@@ -79,6 +86,16 @@
|
||||
#define DCE_ADMIN_CH_CL_DBG_BUFF_COUNT 1U
|
||||
#define DCE_ADMIN_CH_CL_DBG_PERF_BUFF_COUNT 1U
|
||||
|
||||
/**
|
||||
* DCE Wait condition IDs.
|
||||
*/
|
||||
#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 tegra_dce;
|
||||
|
||||
/**
|
||||
@@ -398,6 +415,9 @@ struct dce_ipc_message *dce_admin_channel_client_buffer_get(
|
||||
void dce_admin_channel_client_buffer_put(
|
||||
struct tegra_dce *d, struct dce_ipc_message *pmsg);
|
||||
|
||||
int dce_waiters_init(struct tegra_dce *d);
|
||||
void dce_waiters_deinit(struct tegra_dce *d);
|
||||
|
||||
/**
|
||||
* Functions to be used in debug mode only.
|
||||
*
|
||||
|
||||
82
drivers/platform/tegra/dce/os/include/dce-os-cond.h
Normal file
82
drivers/platform/tegra/dce/os/include/dce-os-cond.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DCE_OS_COND_H
|
||||
#define DCE_OS_COND_H
|
||||
|
||||
#include <dce-os-cond-internal.h>
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_INTERRUPTIBLE - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ERESTARTSYS
|
||||
* on signal.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE(c, condition) \
|
||||
DCE_OS_COND_WAIT_INTERRUPTIBLE_INTERNAL(c, condition)
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
* @timeout_ms - Timeout in milliseconds, or 0 for infinite wait.
|
||||
* This parameter must be a u32. Since this is a macro, this is
|
||||
* enforced by assigning a typecast NULL pointer to a u32 tmp
|
||||
* variable which will generate a compiler warning (or error if
|
||||
* the warning is configured as an error).
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ETIMEOUT if
|
||||
* the wait timed out with condition false or -ERESTARTSYS on
|
||||
* signal.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT(c, condition, timeout_ms) \
|
||||
DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT_INTERNAL(c, condition, timeout_ms)
|
||||
|
||||
/**
|
||||
* dce_os_cond_init - Initialize a condition variable
|
||||
*
|
||||
* @cond - The condition variable to initialize
|
||||
*
|
||||
* Initialize a condition variable before using it.
|
||||
*/
|
||||
int dce_os_cond_init(struct dce_os_cond *cond);
|
||||
|
||||
/**
|
||||
* dce_os_cond_destroy - Destroy a condition variable
|
||||
*
|
||||
* @cond - The condition variable to destroy
|
||||
*/
|
||||
void dce_os_cond_signal_interruptible(struct dce_os_cond *cond);
|
||||
|
||||
/**
|
||||
* dce_os_cond_signal_interruptible - Signal a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up a waiter for a condition variable to check if its condition has been
|
||||
* satisfied.
|
||||
*
|
||||
* The waiter is using an interruptible wait.
|
||||
*/
|
||||
int dce_os_cond_broadcast_interruptible(struct dce_os_cond *cond);
|
||||
|
||||
/**
|
||||
* dce_os_cond_broadcast_interruptible - Signal all waiters of a condition
|
||||
* variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up all waiters for a condition variable to check if their conditions
|
||||
* have been satisfied.
|
||||
*
|
||||
* The waiters are using an interruptible wait.
|
||||
*/
|
||||
void dce_os_cond_destroy(struct dce_os_cond *cond);
|
||||
|
||||
#endif /* DCE_OS_COND_H */
|
||||
@@ -1,33 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DCE_OS_WORKER_H
|
||||
#define DCE_OS_WORKER_H
|
||||
|
||||
#include <dce-os-cond.h>
|
||||
#include <dce-os-lock.h>
|
||||
#include <dce-os-atomic.h>
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
#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 {
|
||||
dce_os_atomic_t complete;
|
||||
struct dce_os_cond cond_wait;
|
||||
};
|
||||
|
||||
int dce_os_work_cond_sw_resource_init(struct tegra_dce *d);
|
||||
void dce_os_work_cond_sw_resource_deinit(struct tegra_dce *d);
|
||||
int dce_os_wait_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
void dce_os_wakeup_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
void dce_os_cond_wait_reset(struct tegra_dce *d, u32 msg_id);
|
||||
|
||||
#endif /* DCE_OS_WORKER_H */
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DCE_OS_COND_INTERNAL_H
|
||||
#define DCE_OS_COND_INTERNAL_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
struct dce_os_cond {
|
||||
bool initialized;
|
||||
wait_queue_head_t wq;
|
||||
};
|
||||
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE_INTERNAL(c, condition) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT_INTERNAL(c, condition, timeout_ms) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
/* This is the assignment to enforce a u32 for timeout_ms */ \
|
||||
u32 *tmp = (typeof(timeout_ms) *)NULL; \
|
||||
(void)tmp; \
|
||||
if (timeout_ms > 0U) { \
|
||||
long _ret = wait_event_interruptible_timeout((c)->wq, \
|
||||
condition, msecs_to_jiffies(timeout_ms)); \
|
||||
if (_ret == 0) \
|
||||
ret = -ETIMEDOUT; \
|
||||
else if (_ret == -ERESTARTSYS) \
|
||||
ret = -ERESTARTSYS; \
|
||||
} else { \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#endif /* DCE_OS_COND_INTERNAL_H */
|
||||
@@ -1,125 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DCE_OS_COND_H
|
||||
#define DCE_OS_COND_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
struct dce_os_cond {
|
||||
bool initialized;
|
||||
wait_queue_head_t wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
*
|
||||
* Wait for a condition to become true.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT(c, condition) \
|
||||
({\
|
||||
int ret = 0; \
|
||||
wait_event((c)->wq, condition); \
|
||||
ret;\
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_INTERRUPTIBLE - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ERESTARTSYS
|
||||
* on signal.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE(c, condition) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_TIMEOUT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
* @timeout_ms - Timeout in milliseconds, or 0 for infinite wait.
|
||||
* This parameter must be a u32. Since this is a macro, this is
|
||||
* enforced by assigning a typecast NULL pointer to a u32 tmp
|
||||
* variable which will generate a compiler warning (or error if
|
||||
* the warning is configured as an error).
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ETIMEOUT if
|
||||
* the wait timed out with condition false.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT_TIMEOUT(c, condition, timeout_ms) \
|
||||
({\
|
||||
int ret = 0; \
|
||||
/* This is the assignment to enforce a u32 for timeout_ms */ \
|
||||
u32 *tmp = (typeof(timeout_ms) *)NULL; \
|
||||
(void)tmp; \
|
||||
if (timeout_ms > 0U) { \
|
||||
long _ret = wait_event_timeout((c)->wq, condition, \
|
||||
msecs_to_jiffies(timeout_ms)); \
|
||||
if (_ret == 0) \
|
||||
ret = -ETIMEDOUT; \
|
||||
} else { \
|
||||
wait_event((c)->wq, condition); \
|
||||
} \
|
||||
ret;\
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
* @timeout_ms - Timeout in milliseconds, or 0 for infinite wait.
|
||||
* This parameter must be a u32. Since this is a macro, this is
|
||||
* enforced by assigning a typecast NULL pointer to a u32 tmp
|
||||
* variable which will generate a compiler warning (or error if
|
||||
* the warning is configured as an error).
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ETIMEOUT if
|
||||
* the wait timed out with condition false or -ERESTARTSYS on
|
||||
* signal.
|
||||
*/
|
||||
#define DCE_OS_COND_WAIT_INTERRUPTIBLE_TIMEOUT(c, condition, timeout_ms) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
/* This is the assignment to enforce a u32 for timeout_ms */ \
|
||||
u32 *tmp = (typeof(timeout_ms) *)NULL; \
|
||||
(void)tmp; \
|
||||
if (timeout_ms > 0U) { \
|
||||
long _ret = wait_event_interruptible_timeout((c)->wq, \
|
||||
condition, msecs_to_jiffies(timeout_ms)); \
|
||||
if (_ret == 0) \
|
||||
ret = -ETIMEDOUT; \
|
||||
else if (_ret == -ERESTARTSYS) \
|
||||
ret = -ERESTARTSYS; \
|
||||
} else { \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
int dce_os_cond_init(struct dce_os_cond *cond);
|
||||
|
||||
void dce_os_cond_signal(struct dce_os_cond *cond);
|
||||
|
||||
void dce_os_cond_signal_interruptible(struct dce_os_cond *cond);
|
||||
|
||||
int dce_os_cond_broadcast(struct dce_os_cond *cond);
|
||||
|
||||
int dce_os_cond_broadcast_interruptible(struct dce_os_cond *cond);
|
||||
|
||||
void dce_os_cond_destroy(struct dce_os_cond *cond);
|
||||
|
||||
#endif /* DCE_OS_COND_H */
|
||||
Reference in New Issue
Block a user