Files
Chromebook-Device-Nyan-NVID…/drivers/platform/x86/intel_dptf/esif_ccb_lock.h
2025-04-06 23:50:55 -05:00

320 lines
12 KiB
C

/*******************************************************************************
** This file is provided under a dual BSD/GPLv2 license. When using or
** redistributing this file, you may do so under either license.
**
** GPL LICENSE SUMMARY
**
** Copyright (c) 2013 Intel Corporation All Rights Reserved
**
** This program is free software; you can redistribute it and/or modify it under
** the terms of version 2 of the GNU General Public License as published by the
** Free Software Foundation.
**
** This program is distributed in the hope that 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.
**
** You should have received a copy of the GNU General Public License along with
** this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
** The full GNU General Public License is included in this distribution in the
** file called LICENSE.GPL.
**
** BSD LICENSE
**
** Copyright (c) 2013 Intel Corporation All Rights Reserved
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this
** list of conditions and the following disclaimer.
** * 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.
** * Neither the name of Intel Corporation nor the names of its contributors may
** be used to endorse or promote products derived from this software without
** specific prior written permission.
**
** 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.
**
*******************************************************************************/
#ifndef _ESIF_CCB_LOCK_H_
#define _ESIF_CCB_LOCK_H_
/******************************************************************************
* KERNEL LOCKS
******************************************************************************/
#ifdef ESIF_ATTR_KERNEL
/* Use Shareable Read/Write Locks */
#ifdef ESIF_ATTR_OS_LINUX
typedef rwlock_t esif_ccb_lock_t;
typedef struct rw_semaphore esif_ccb_low_priority_thread_lock_t;
#define esif_ccb_lock_init(lockPtr) rwlock_init(lockPtr)
#define esif_ccb_lock_uninit(lockPtr) /* not used */
#define esif_ccb_write_lock(lockPtr) write_lock(lockPtr)
#define esif_ccb_write_unlock(lockPtr) write_unlock(lockPtr)
#define esif_ccb_read_lock(lockPtr) read_lock(lockPtr)
#define esif_ccb_read_unlock(lockPtr) read_unlock(lockPtr)
#define esif_ccb_low_priority_thread_lock_init(lockPtr) init_rwsem(lockPtr)
#define esif_ccb_low_priority_thread_lock_uninit(lockPtr) /* not used */
#define esif_ccb_low_priority_thread_write_lock(lockPtr) down_write(lockPtr)
#define esif_ccb_low_priority_thread_write_unlock(lockPtr) up_write(lockPtr)
#define esif_ccb_low_priority_thread_read_lock(lockPtr) down_read(lockPtr)
#define esif_ccb_low_priority_thread_read_unlock(lockPtr) up_read(lockPtr)
#endif /* ESIF_ATTR_OS_LINUX */
#ifdef ESIF_ATTR_OS_WINDOWS
typedef struct esif_ccb_lock {
WDFSPINLOCK lock; /* Spin Lock */
} esif_ccb_lock_t;
typedef struct esif_ccb_low_priority_thread_lock {
WDFWAITLOCK lock; /* Wait Lock */
} esif_ccb_low_priority_thread_lock_t;
static ESIF_INLINE void esif_ccb_lock_init (esif_ccb_lock_t *lockPtr)
{
/* TODO: Change creation functions to return status and check in code */
NTSTATUS stat;
stat = WdfSpinLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &lockPtr->lock);
NT_SUCCESS(stat);
}
#define esif_ccb_lock_uninit(lockPtr) /* not used */
_IRQL_raises_(DISPATCH_LEVEL)
_IRQL_saves_global_(OldIrql, lockPtr->lock)
_Requires_lock_not_held_(lockPtr->lock)
_Acquires_lock_(lockPtr->lock)
static ESIF_INLINE void esif_ccb_write_lock (esif_ccb_lock_t *lockPtr)
{WdfSpinLockAcquire(lockPtr->lock);}
_IRQL_restores_global_(OldIrql, lockPtr->lock)
_IRQL_requires_(DISPATCH_LEVEL)
_Requires_lock_held_(lockPtr->lock)
_Releases_lock_(lockPtr->lock)
static ESIF_INLINE void esif_ccb_write_unlock (esif_ccb_lock_t *lockPtr)
{WdfSpinLockRelease(lockPtr->lock);}
_IRQL_raises_(DISPATCH_LEVEL)
_IRQL_saves_global_(OldIrql, lockPtr)
_Acquires_lock_(lockPtr->lock)
static ESIF_INLINE void esif_ccb_read_lock (esif_ccb_lock_t *lockPtr)
{WdfSpinLockAcquire(lockPtr->lock);}
_IRQL_restores_global_(OldIrql, lockPtr)
_IRQL_requires_(DISPATCH_LEVEL)
_Releases_lock_(lockPtr->lock)
static ESIF_INLINE void esif_ccb_read_unlock (esif_ccb_lock_t *lockPtr)
{WdfSpinLockRelease(lockPtr->lock);}
static ESIF_INLINE void esif_ccb_low_priority_thread_lock_init (
esif_ccb_low_priority_thread_lock_t *lockPtr)
{
/* TODO: Change creation functions to return status and check in code */
NTSTATUS stat;
stat = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &lockPtr->lock);
NT_SUCCESS(stat);
}
#define esif_ccb_low_priority_thread_lock_uninit(lockPtr) /* not used */
static ESIF_INLINE void esif_ccb_low_priority_thread_write_lock (
esif_ccb_low_priority_thread_lock_t *lockPtr)
{WdfWaitLockAcquire(lockPtr->lock, NULL);} /* Wait forever */
static ESIF_INLINE void esif_ccb_low_priority_thread_write_unlock (
esif_ccb_low_priority_thread_lock_t *lockPtr)
{WdfWaitLockRelease(lockPtr->lock);}
static ESIF_INLINE void esif_ccb_low_priority_thread_read_lock (
esif_ccb_low_priority_thread_lock_t *lockPtr)
{WdfWaitLockAcquire(lockPtr->lock, NULL);} /* Wait forever */
static ESIF_INLINE void esif_ccb_low_priority_thread_read_unlock (
esif_ccb_low_priority_thread_lock_t *lockPtr)
{WdfWaitLockRelease(lockPtr->lock);}
#endif /* ESIF_ATTR_OS_WINDOWS */
#endif /* ESIF_ATTR_KERNEL */
/******************************************************************************
* USER LOCKS
******************************************************************************/
#ifdef ESIF_ATTR_USER
#include "esif.h"
#include "esif_ccb_atomic.h"
/* Spinlock */
typedef atomic_t esif_ccb_spinlock_t;
#define esif_ccb_spinlock_init(lockPtr) *(lockPtr) = ATOMIC_INIT(0)
#define esif_ccb_spinlock_uninit(lockPtr) (lockPtr)
#define esif_ccb_spinlock_lock(lockPtr) while (atomic_set(lockPtr, 1) == 1) {;}
#define esif_ccb_spinlock_unlock(lockPtr) atomic_set(lockPtr, 0)
#ifdef ESIF_ATTR_OS_LINUX
#include <pthread.h>
#define PTHREAD_MUTEX_INIT_TYPE(mutex, type) do { static pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, type); pthread_mutex_init(mutex, &attr); } while (0)
/* Emulate Critical Section */
typedef pthread_mutex_t esif_ccb_critical_section_t;
#define esif_ccb_critical_section_init(csPtr) PTHREAD_MUTEX_INIT_TYPE(csPtr, PTHREAD_MUTEX_RECURSIVE)
#define esif_ccb_critical_section_uninit(csPtr) pthread_mutex_destroy(csPtr)
#define esif_ccb_critical_section_enter(csPtr) pthread_mutex_lock(csPtr) /* reentrant */
#define esif_ccb_critical_section_leave(csPtr) pthread_mutex_unlock(csPtr) /* reentrant */
/* Mutex */
typedef pthread_mutex_t esif_ccb_mutex_t;
#define esif_ccb_mutex_init(mutexPtr) PTHREAD_MUTEX_INIT_TYPE(mutexPtr, PTHREAD_MUTEX_RECURSIVE)
#define esif_ccb_mutex_uninit(mutexPtr) pthread_mutex_destroy(mutexPtr)
#define esif_ccb_mutex_lock(mutexPtr) pthread_mutex_lock(mutexPtr) /* reentrant */
#define esif_ccb_mutex_unlock(mutexPtr) pthread_mutex_unlock(mutexPtr) /* reentrant */
/* RW Lock */
typedef pthread_rwlock_t esif_ccb_lock_t;
#define esif_ccb_lock_init(lockPtr) pthread_rwlock_init(lockPtr, NULL)
#define esif_ccb_lock_uninit(lockPtr) pthread_rwlock_destroy(lockPtr)
#define esif_ccb_write_lock(lockPtr) pthread_rwlock_wrlock(lockPtr) /* NOT reentrant */
#define esif_ccb_write_unlock(lockPtr) pthread_rwlock_unlock(lockPtr) /* NOT reentrant */
#define esif_ccb_read_lock(lockPtr) pthread_rwlock_rdlock(lockPtr) /* reentrant */
#define esif_ccb_read_unlock(lockPtr) pthread_rwlock_unlock(lockPtr) /* reentrant */
#endif /* ESIF_ATTR_OS_LINUX */
#ifdef ESIF_ATTR_OS_WINDOWS
/* Critical Section */
typedef CRITICAL_SECTION esif_ccb_critical_section_t;
#define esif_ccb_critical_section_init(csPtr) InitializeCriticalSection(csPtr)
#define esif_ccb_critical_section_uninit(csPtr) DeleteCriticalSection(csPtr)
#define esif_ccb_critical_section_enter(csPtr) EnterCriticalSection(csPtr) /* reentrant */
#define esif_ccb_critical_section_leave(csPtr) LeaveCriticalSection(csPtr) /* reentrant */
/* Mutex */
typedef HANDLE esif_ccb_mutex_t;
#define esif_ccb_mutex_init(mutexPtr) *mutexPtr = CreateMutex(NULL, FALSE, NULL)
#define esif_ccb_mutex_uninit(mutexPtr) CloseHandle(*mutexPtr)
#define esif_ccb_mutex_lock(mutexPtr) WaitForSingleObject(*mutexPtr, INFINITE) /* reentrant */
#define esif_ccb_mutex_unlock(mutexPtr) ReleaseMutex(*mutexPtr) /* reentrant */
/* RW Lock */
/* Wrapper for SRWLOCKs to allow nested READ locks in Windows
* This is necessary to avoid WHQL errors and potential deadlocks in Windows
* This is unecessary for Linux since pthread_rwlock_t is read reentrant
*/
typedef struct esif_ccb_lock_s {
SRWLOCK lock; /* Slim Read/Write Lock */
esif_ccb_spinlock_t spinlock; /* Spinlock for managing lock and ref_count */
UInt32 ref_count; /* Count of Acquired References to shared READ lock */
} esif_ccb_lock_t;
/* Initialize */
static ESIF_INLINE void esif_ccb_lock_init(esif_ccb_lock_t *lockPtr)
{
InitializeSRWLock(&lockPtr->lock);
esif_ccb_spinlock_init(&lockPtr->spinlock);
lockPtr->ref_count = 0;
}
/* Uninitialize */
static ESIF_INLINE void esif_ccb_lock_uninit(esif_ccb_lock_t *lockPtr)
{
esif_ccb_spinlock_uninit(&lockPtr->spinlock);
}
/* NOT Reentrant Write Lock */
static ESIF_INLINE void esif_ccb_write_lock(esif_ccb_lock_t *lockPtr)
{
AcquireSRWLockExclusive(&lockPtr->lock);
}
/* NOT Reentrant Write Unlock */
static ESIF_INLINE void esif_ccb_write_unlock(esif_ccb_lock_t *lockPtr)
{
ReleaseSRWLockExclusive(&lockPtr->lock);
}
/* Reentrant Read Lock */
static ESIF_INLINE void esif_ccb_read_lock(esif_ccb_lock_t *lockPtr)
{
BOOL release = FALSE;
/* Acquire spinlock to see if any readers have acquired the lock
* If so just increment ref_count, otherwise Acquire lock outside spinlock
*/
esif_ccb_spinlock_lock(&lockPtr->spinlock);
if (lockPtr->ref_count > 0) {
++lockPtr->ref_count;
}
else {
esif_ccb_spinlock_unlock(&lockPtr->spinlock);
AcquireSRWLockShared(&lockPtr->lock);
/* After acquiring lock, update ref_count after re-acquiring spinlock */
esif_ccb_spinlock_lock(&lockPtr->spinlock);
if (++lockPtr->ref_count > 1) {
release = TRUE;
}
}
esif_ccb_spinlock_unlock(&lockPtr->spinlock);
/* If multiple threads Acquired locks, all but one will release it here */
if (release) {
ReleaseSRWLockShared(&lockPtr->lock);
}
}
/* Reentrant Read Unlock */
static ESIF_INLINE void esif_ccb_read_unlock(esif_ccb_lock_t *lockPtr)
{
BOOL release = FALSE;
/* Aquire spinlock to see if this is the last reader referencing this lock
* If this is the last reader, Release the lock outside of the spinlock
*/
esif_ccb_spinlock_lock(&lockPtr->spinlock);
if (--lockPtr->ref_count == 0) {
release = TRUE;
}
esif_ccb_spinlock_unlock(&lockPtr->spinlock);
if (release) {
ReleaseSRWLockShared(&lockPtr->lock);
}
}
#endif /* ESIF_ATTR_OS_WINDOWS */
#endif /* ESIF_ATTR_USER */
#endif /* _ESIF_CCB_LOCK_H_ */
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/