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:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user