Files
rtems/bsps/shared/acpi/osl/osl_sync.c
Matheus Pecoraro bd12e6f0af bsps/acpi: Shared ACPICA OSL methods and spec file
Add an implementation for port independent ACPICA OS Services Layer
methods and objacpi.yml spec file.
2024-08-06 21:28:15 +00:00

288 lines
6.6 KiB
C

/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2024 Matheus Pecoraro
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <acpi/acpica/acpi.h>
#include <rtems.h>
#include <errno.h>
#include <pthread.h>
static void ms_timeout_to_abs_timespec(uint32_t timeout, struct timespec *abstime)
{
clock_gettime(CLOCK_REALTIME, abstime);
abstime->tv_sec += timeout / 1000;
abstime->tv_nsec += (timeout % 1000) * 1000000;
}
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t wait_cond;
pthread_cond_t delete_cond;
uint32_t units;
uint32_t max_units;
uint32_t waiters;
bool is_pending_delete;
} acpi_semaphore;
ACPI_STATUS AcpiOsCreateSemaphore(
UINT32 MaxUnits,
UINT32 InitialUnits,
ACPI_SEMAPHORE* OutHandle
)
{
acpi_semaphore* ac_sem;
if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
return (AE_BAD_PARAMETER);
ac_sem = malloc(sizeof(acpi_semaphore));
if (ac_sem == NULL) {
return (AE_NO_MEMORY);
}
if (pthread_mutex_init(&ac_sem->mutex, NULL) != 0 ||
pthread_cond_init(&ac_sem->wait_cond, NULL) != 0 ||
pthread_cond_init(&ac_sem->delete_cond, NULL) != 0)
{
free(ac_sem);
return (AE_ERROR);
}
ac_sem->units = InitialUnits;
ac_sem->max_units = MaxUnits;
ac_sem->waiters = 0;
ac_sem->is_pending_delete = false;
/* Since we don't define ACPI_SEMAPHORE OutHandle is of type void** */
*OutHandle = (ACPI_SEMAPHORE) ac_sem;
return (AE_OK);
}
ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
{
int eno;
acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
if (ac_sem == NULL) {
return (AE_BAD_PARAMETER);
}
eno = pthread_mutex_lock(&ac_sem->mutex);
if (eno != 0) {
return (AE_ERROR);
}
/* Ensure there are no waiters left */
ac_sem->is_pending_delete = true;
pthread_cond_broadcast(&ac_sem->wait_cond);
while (ac_sem->waiters > 0) {
pthread_cond_wait(&ac_sem->delete_cond, &ac_sem->mutex);
}
pthread_mutex_unlock(&ac_sem->mutex);
pthread_mutex_destroy(&ac_sem->mutex);
pthread_cond_destroy(&ac_sem->wait_cond);
pthread_cond_destroy(&ac_sem->delete_cond);
free(ac_sem);
return (AE_OK);
}
ACPI_STATUS AcpiOsWaitSemaphore(
ACPI_SEMAPHORE Handle,
UINT32 Units,
UINT16 Timeout
)
{
int eno;
ACPI_STATUS ac_status = (AE_OK);
acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
if (ac_sem == NULL || Units == 0) {
return (AE_BAD_PARAMETER);
}
eno = pthread_mutex_lock(&ac_sem->mutex);
if (eno != 0) {
return (AE_ERROR);
}
if (ac_sem->max_units != ACPI_NO_UNIT_LIMIT && ac_sem->max_units < Units) {
return (AE_LIMIT);
}
switch (Timeout) {
case ACPI_DO_NOT_WAIT:
if (ac_sem->units < Units) {
ac_status = (AE_TIME);
}
break;
case ACPI_WAIT_FOREVER:
ac_sem->waiters++;
while (ac_sem->units < Units) {
pthread_cond_wait(&ac_sem->wait_cond, &ac_sem->mutex);
if (ac_sem->is_pending_delete) {
ac_status = (AE_ERROR);
pthread_cond_signal(&ac_sem->delete_cond);
break;
}
}
ac_sem->waiters--;
break;
default:
struct timespec abstime;
ms_timeout_to_abs_timespec(Timeout, &abstime);
ac_sem->waiters++;
while (ac_sem->units < Units) {
eno = pthread_cond_timedwait(&ac_sem->wait_cond, &ac_sem->mutex, &abstime);
if (ac_sem->is_pending_delete) {
ac_status = (AE_ERROR);
pthread_cond_signal(&ac_sem->delete_cond);
break;
}
if (eno == ETIMEDOUT) {
ac_status = (AE_TIME);
break;
}
}
ac_sem->waiters--;
break;
}
if (ac_status == (AE_OK)) {
ac_sem->units -= Units;
}
pthread_mutex_unlock(&ac_sem->mutex);
return ac_status;
}
ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
{
int eno;
acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
if (ac_sem == NULL || Units == 0) {
return (AE_BAD_PARAMETER);
}
eno = pthread_mutex_lock(&ac_sem->mutex);
if (eno != 0) {
return (AE_ERROR);
}
if (ac_sem->max_units != ACPI_NO_UNIT_LIMIT &&
ac_sem->units + Units > ac_sem->max_units)
{
return (AE_LIMIT);
}
ac_sem->units += Units;
/*
* Signal condition "Units" times to wake up the maximum amount of threads
* that could consume the new units
*/
while (Units--) {
pthread_cond_signal(&ac_sem->wait_cond);
}
pthread_mutex_unlock(&ac_sem->mutex);
return (AE_OK);
}
typedef struct {
pthread_mutex_t mutex;
} acpi_spinlock;
ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK* OutHandle)
{
acpi_spinlock* lock;
if (OutHandle == NULL)
return (AE_BAD_PARAMETER);
lock = malloc(sizeof(acpi_spinlock));
if (lock == NULL) {
return (AE_NO_MEMORY);
}
pthread_mutex_init(&lock->mutex, NULL);
/* Since we don't define ACPI_SPINLOCK OutHandle is of type void** */
*OutHandle = (ACPI_SPINLOCK) lock;
return (AE_OK);
}
void AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
{
acpi_spinlock* lock = (acpi_spinlock*) Handle;
if (lock == NULL) {
return;
}
pthread_mutex_destroy(&lock->mutex);
free(lock);
}
ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
{
acpi_spinlock* lock = (acpi_spinlock*) Handle;
if (lock == NULL) {
return 0;
}
pthread_mutex_lock(&lock->mutex);
return 0;
}
void AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
{
acpi_spinlock* lock = (acpi_spinlock*) Handle;
if (lock == NULL) {
return;
}
pthread_mutex_unlock(&lock->mutex);
}