linux-imx/drivers/acpi/acpica/exsystem.c
Paul Menzel 6eaf08770e ACPICA: executer/exsystem: Warn about sleeps greater than 10 ms
ACPICA commit 2a0d1d475e7ea1c815bee1e0692d81db9a7c909c

Quick boottime is important, so warn about sleeps greater than 10 ms.

Distribution Linux kernels reach initrd in 350 ms, so excessive delays
should be called out. 10 ms is chosen randomly, but three of such delays
would already make up ten percent of the boottime.

Link: https://github.com/acpica/acpica/commit/2a0d1d47
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reported-by: kernel test robot <lkp@intel.com>
2022-04-13 20:24:58 +02:00

290 lines
7.8 KiB
C

// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: exsystem - Interface to OS services
*
* Copyright (C) 2000 - 2022, Intel Corp.
*
*****************************************************************************/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acinterp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exsystem")
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_wait_semaphore
*
* PARAMETERS: semaphore - Semaphore to wait on
* timeout - Max time to wait
*
* RETURN: Status
*
* DESCRIPTION: Implements a semaphore wait with a check to see if the
* semaphore is available immediately. If it is not, the
* interpreter is released before waiting.
*
******************************************************************************/
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
status = acpi_os_wait_semaphore(semaphore, 1, ACPI_DO_NOT_WAIT);
if (ACPI_SUCCESS(status)) {
return_ACPI_STATUS(status);
}
if (status == AE_TIME) {
/* We must wait, so unlock the interpreter */
acpi_ex_exit_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"*** Thread awake after blocking, %s\n",
acpi_format_exception(status)));
/* Reacquire the interpreter */
acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_wait_mutex
*
* PARAMETERS: mutex - Mutex to wait on
* timeout - Max time to wait
*
* RETURN: Status
*
* DESCRIPTION: Implements a mutex wait with a check to see if the
* mutex is available immediately. If it is not, the
* interpreter is released before waiting.
*
******************************************************************************/
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
status = acpi_os_acquire_mutex(mutex, ACPI_DO_NOT_WAIT);
if (ACPI_SUCCESS(status)) {
return_ACPI_STATUS(status);
}
if (status == AE_TIME) {
/* We must wait, so unlock the interpreter */
acpi_ex_exit_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"*** Thread awake after blocking, %s\n",
acpi_format_exception(status)));
/* Reacquire the interpreter */
acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_do_stall
*
* PARAMETERS: how_long_us - The amount of time to stall,
* in microseconds
*
* RETURN: Status
*
* DESCRIPTION: Suspend running thread for specified amount of time.
* Note: ACPI specification requires that Stall() does not
* relinquish the processor, and delays longer than 100 usec
* should use Sleep() instead. We allow stalls up to 255 usec
* for compatibility with other interpreters and existing BIOSs.
*
******************************************************************************/
acpi_status acpi_ex_system_do_stall(u32 how_long_us)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_ENTRY();
if (how_long_us > 255) {
/*
* Longer than 255 microseconds, this is an error
*
* (ACPI specifies 100 usec as max, but this gives some slack in
* order to support existing BIOSs)
*/
ACPI_ERROR((AE_INFO,
"Time parameter is too large (%u)", how_long_us));
status = AE_AML_OPERAND_VALUE;
} else {
if (how_long_US > 100) {
ACPI_WARNING((AE_INFO,
"Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
how_long_us));
}
acpi_os_stall(how_long_us);
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_do_sleep
*
* PARAMETERS: how_long_ms - The amount of time to sleep,
* in milliseconds
*
* RETURN: None
*
* DESCRIPTION: Sleep the running thread for specified amount of time.
*
******************************************************************************/
acpi_status acpi_ex_system_do_sleep(u64 how_long_ms)
{
ACPI_FUNCTION_ENTRY();
/* Since this thread will sleep, we must release the interpreter */
acpi_ex_exit_interpreter();
/*
* Warn users about excessive sleep times, so ASL code can be improved to
* use polling or similar techniques.
*/
if (how_long_ms > 10) {
ACPI_WARNING((AE_INFO,
"Firmware issue: Excessive sleep time (%llu ms > 10 ms) in ACPI Control Method",
how_long_us));
}
/*
* For compatibility with other ACPI implementations and to prevent
* accidental deep sleeps, limit the sleep time to something reasonable.
*/
if (how_long_ms > ACPI_MAX_SLEEP) {
how_long_ms = ACPI_MAX_SLEEP;
}
acpi_os_sleep(how_long_ms);
/* And now we must get the interpreter again */
acpi_ex_enter_interpreter();
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_signal_event
*
* PARAMETERS: obj_desc - The object descriptor for this op
*
* RETURN: Status
*
* DESCRIPTION: Provides an access point to perform synchronization operations
* within the AML.
*
******************************************************************************/
acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(ex_system_signal_event);
if (obj_desc) {
status =
acpi_os_signal_semaphore(obj_desc->event.os_semaphore, 1);
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_wait_event
*
* PARAMETERS: time_desc - The 'time to delay' object descriptor
* obj_desc - The object descriptor for this op
*
* RETURN: Status
*
* DESCRIPTION: Provides an access point to perform synchronization operations
* within the AML. This operation is a request to wait for an
* event.
*
******************************************************************************/
acpi_status
acpi_ex_system_wait_event(union acpi_operand_object *time_desc,
union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(ex_system_wait_event);
if (obj_desc) {
status =
acpi_ex_system_wait_semaphore(obj_desc->event.os_semaphore,
(u16) time_desc->integer.
value);
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_reset_event
*
* PARAMETERS: obj_desc - The object descriptor for this op
*
* RETURN: Status
*
* DESCRIPTION: Reset an event to a known state.
*
******************************************************************************/
acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
acpi_semaphore temp_semaphore;
ACPI_FUNCTION_ENTRY();
/*
* We are going to simply delete the existing semaphore and
* create a new one!
*/
status =
acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore);
if (ACPI_SUCCESS(status)) {
(void)acpi_os_delete_semaphore(obj_desc->event.os_semaphore);
obj_desc->event.os_semaphore = temp_semaphore;
}
return (status);
}