Rewrote the Global lock implementation by stealing code from NetBSD, and fudged around a bug in the IBM Thinkpad A21M ACPI firmware, involving the invocation of the _STA method. I suspect this may be a deeper bug -- I'll look into it later.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12463 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Nathan Whitehorn
2005-04-24 04:50:34 +00:00
parent 51a73c1e2b
commit 9d7e67b1bc
3 changed files with 37 additions and 52 deletions
@@ -187,11 +187,42 @@
#define ACPI_USE_SYSTEM_CLIBRARY
#define ACPI_USE_NATIVE_DIVIDE
extern int acpi_acquire_global_lock(uint32 *lock);
extern int acpi_release_global_lock(uint32 *lock);
/* The following Global Lock code stolen from NetBSD
src/sys/arch/i386/include/acpi_func.h which in turn
was stolen from Intel's spec document */
#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) ((Acq) = acpi_acquire_global_lock(GLptr))
#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) ((Acq) = acpi_release_global_lock(GLptr))
#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
do { \
__asm __volatile( \
"1: movl %1,%%eax ;" \
" movl %%eax,%%edx ;" \
" andl %2,%%edx ;" \
" btsl $0x1,%%edx ;" \
" adcl $0x0,%%edx ;" \
" lock ;" \
" cmpxchgl %%edx,%1 ;" \
" jnz 1b ;" \
" andb $0x3,%%dl ;" \
" cmpb $0x3,%%dl ;" \
" sbbl %%eax,%%eax ;" \
: "=&a" (Acq), "+m" (*GLptr) \
: "i" (~1L) \
: "edx"); \
} while (0)
#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
do { \
__asm __volatile( \
"1: movl %1,%%eax ;" \
" andl %2,%%edx ;" \
" lock ;" \
" cmpxchgl %%edx,%1 ;" \
" jnz 1b ;" \
" andl $0x1,%%eax ;" \
: "=&a" (Acq), "+m" (*GLptr) \
: "i" (~3L) \
: "edx"); \
} while (0)
/* Kernel doesn't have strupr, should be fixed. */
@@ -583,7 +583,7 @@ AcpiNsGetDeviceCallback (
}
/* Run _STA to determine if device is present */
#if 0
Status = AcpiUtExecute_STA (Node, &Flags);
if (ACPI_FAILURE (Status))
{
@@ -596,7 +596,7 @@ AcpiNsGetDeviceCallback (
return (AE_CTRL_DEPTH);
}
#endif
/* Filter based on device HID & CID */
if (Info->Hid != NULL)
@@ -1279,49 +1279,3 @@ AcpiOsSignal (
return (AE_OK);
}
/* The following stolen from FreeBSD */
/* Section 5.2.9.1: global lock acquire/release functions */
#define GL_ACQUIRED (-1)
#define GL_BUSY 0
#define GL_BIT_PENDING 0x1
#define GL_BIT_OWNED 0x2
#define GL_BIT_MASK (GL_BIT_PENDING | GL_BIT_OWNED)
/*
* Acquire the global lock. If busy, set the pending bit. The caller
* will wait for notification from the BIOS that the lock is available
* and then attempt to acquire it again.
*/
int
acpi_acquire_global_lock(uint32 *lock)
{
uint32 new, old;
do {
old = *lock;
new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) |
((old >> 1) & GL_BIT_PENDING);
} while (_atomic_test_and_set(lock, new, old) != old);
return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY);
}
/*
* Release the global lock, returning whether there is a waiter pending.
* If the BIOS set the pending bit, OSPM must notify the BIOS when it
* releases the lock.
*/
int
acpi_release_global_lock(uint32 *lock)
{
uint32 new, old;
do {
old = *lock;
new = old & ~GL_BIT_MASK;
} while (_atomic_test_and_set(lock, new, old) != old);
return (old & GL_BIT_PENDING);
}