Apply patch by tqh: fix ACPI hang at boot (#4762)

Global lock/unlock assembly code was broken, reworked based on 
what FreeBSD does.
Thanks!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33781 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Philippe Houdoin 2009-10-26 22:01:59 +00:00
parent 9b060d03d7
commit 912d4ba92b
2 changed files with 95 additions and 52 deletions

View File

@ -160,37 +160,16 @@
#define ACPI_FLUSH_CPU_CACHE() __asm __volatile("wbinvd");
#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"); \
/* Based on FreeBSD's due to lack of documentation */
extern int AcpiOsAcquireGlobalLock(uint32 *lock);
extern int AcpiOsReleaseGlobalLock(uint32 *lock);
#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) do { \
(Acq) = AcpiOsAcquireGlobalLock(&((GLptr)->GlobalLock)); \
} 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"); \
#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) do { \
(Acq) = AcpiOsReleaseGlobalLock(&((GLptr)->GlobalLock)); \
} while (0)
#else /* _KERNEL_MODE */

View File

@ -157,7 +157,7 @@ ACPI_MODULE_NAME("Haiku ACPI Module")
dprintf("acpi[%ld]: %s\n", find_thread(NULL), __PRETTY_FUNCTION__);
# define DEBUG_FUNCTION_F(x, y...) \
dprintf("acpi[%ld]: %s(" x ")\n", find_thread(NULL), __PRETTY_FUNCTION__, y);
# if DEBUG_OSHAIKU = 1
# if DEBUG_OSHAIKU == 1
// No verbose debugging, do nothing
# define DEBUG_FUNCTION_V()
# define DEBUG_FUNCTION_VF(x, y...)
@ -243,7 +243,6 @@ AcpiOsGetRootPointer()
if (status == AE_OK)
sACPIRoot = address;
}
dprintf("AcpiOsGetRootPointer returning %p\n", (void *)sACPIRoot);
return sACPIRoot;
#else
return AeLocalGetRootPointer();
@ -445,14 +444,14 @@ AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS where, ACPI_SIZE length)
#ifdef _KERNEL_MODE
void *there;
area_id area = map_physical_memory("acpi_physical_mem_area", (void *)where,
length, B_ANY_KERNEL_ADDRESS, 0, &there);
length, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, &there);
DEBUG_FUNCTION_F("addr: 0x%08lx; length: %lu; mapped: %p; area: %ld",
(addr_t)where, (size_t)length, there, area);
if (area < 0) {
dprintf("ACPI: cannot map memory at 0x%08x, length %d\n", where, length);
return NULL;
}
return there;
#else
return NULL;
@ -611,7 +610,8 @@ AcpiOsWaitSemaphore(ACPI_SEMAPHORE handle, UINT32 units, UINT16 timeout)
break;
}
}
DEBUG_FUNCTION_VF("result: %lu", (uint32)result);
DEBUG_FUNCTION_VF("sem: %ld; count: %lu; timeout: %u result: %lu",
handle, units, timeout, (uint32)result);
return result;
}
@ -890,22 +890,19 @@ ACPI_STATUS
AcpiOsReadPciConfiguration(ACPI_PCI_ID *pciId, UINT32 reg, void *value,
UINT32 width)
{
uint32 *val;
val = value;
#ifdef _KERNEL_MODE
UINT32 val = gPCIManager->read_pci_config(
pciId->Bus, pciId->Device, pciId->Function, reg, width / 8);
DEBUG_FUNCTION();
switch (width) {
case 8:
*(UINT8 *) value = val;
break;
case 16:
*(UINT16 *) value = val;
break;
case 32:
*(UINT32 *) value = val;
*val = gPCIManager->read_pci_config(
pciId->Bus, pciId->Device, pciId->Function, reg, width / 8);
break;
default:
dprintf("AcpiOsReadPciConfiguration unhandled width: %u\n", width);
return AE_ERROR;
}
return AE_OK;
@ -983,7 +980,6 @@ AcpiOsReadPort(ACPI_IO_ADDRESS address, UINT32 *value, UINT32 width)
break;
default:
dprintf("AcpiOsReadPort: unhandeld width: %u\n", width);
return AE_ERROR;
}
@ -1027,7 +1023,6 @@ AcpiOsWritePort(ACPI_IO_ADDRESS address, UINT32 value, UINT32 width)
break;
default:
dprintf("AcpiOsWritePort: unhandeld width: %u\n", width);
return AE_ERROR;
}
@ -1107,11 +1102,19 @@ AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS address, UINT32 value, UINT32 width)
*
*****************************************************************************/
BOOLEAN
AcpiOsReadable(void *pointer, ACPI_SIZE Length)
AcpiOsReadable(void *pointer, ACPI_SIZE length)
{
//TODO: Look if this is really ok.
area_id id;
area_info info;
DEBUG_FUNCTION_F("addr: %p; length: %lu", pointer, (size_t)length);
return TRUE;
id = area_for(pointer);
if (id == B_ERROR)
return false;
if (get_area_info(id, &info) != B_OK)
return false;
return info.protection & B_KERNEL_READ_AREA &&
(pointer + length) <= (info.address + info.ram_size);
}
@ -1130,9 +1133,17 @@ AcpiOsReadable(void *pointer, ACPI_SIZE Length)
BOOLEAN
AcpiOsWritable(void *pointer, ACPI_SIZE length)
{
//TODO: Look if this is really ok.
area_id id;
area_info info;
DEBUG_FUNCTION_F("addr: %p; length: %lu", pointer, (size_t)length);
return TRUE;
id = area_for(pointer);
if (id == B_ERROR)
return false;
if (get_area_info(id, &info) != B_OK)
return false;
return info.protection & (B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) &&
(pointer + length) <= (info.address + info.ram_size);
}
@ -1154,12 +1165,11 @@ ACPI_THREAD_ID
AcpiOsGetThreadId()
{
thread_id thread = find_thread(NULL);
return thread;
//TODO: Look if this is needed.
//TODO: Handle if thread_id is 0.
// ACPI treats a 0 return as an error,
// but we are thread 0 in early boot
//return thread == 0 ? 1 : thread;
return thread == 0 ? 1 : thread;
}
@ -1179,6 +1189,7 @@ ACPI_STATUS
AcpiOsSignal(UINT32 function, void *info)
{
DEBUG_FUNCTION();
switch (function) {
case ACPI_SIGNAL_FATAL:
#ifdef _KERNEL_MODE
@ -1195,3 +1206,56 @@ AcpiOsSignal(UINT32 function, void *info)
return AE_OK;
}
/*
* Adapted from FreeBSD since the documentation of its intended impl
* is lacking.
* Section 5.2.10.1: global lock acquire/release functions */
#define GL_ACQUIRED (-1)
#define GL_BUSY 0
#define GL_BIT_PENDING 0x01
#define GL_BIT_OWNED 0x02
#define GL_BIT_MASK (GL_BIT_PENDING | GL_BIT_OWNED)
/*
* Adapted from FreeBSD since the documentation of its intended impl
* is lacking.
* 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
AcpiOsAcquireGlobalLock(uint32 *lock)
{
uint32 new;
uint32 old;
do {
old = *lock;
new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) |
((old >> 1) & GL_BIT_PENDING);
atomic_test_and_set(lock, new, old);
} while (*lock == old);
return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY);
}
/*
* Adapted from FreeBSD since the documentation of its intended impl
* is lacking.
* 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
AcpiOsReleaseGlobalLock(uint32 *lock)
{
uint32 new;
uint32 old;
do {
old = *lock;
new = old & ~GL_BIT_MASK;
atomic_test_and_set(lock, new, old);
} while (*lock == old);
return (old & GL_BIT_PENDING);
}