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:
@@ -160,37 +160,16 @@
|
|||||||
|
|
||||||
#define ACPI_FLUSH_CPU_CACHE() __asm __volatile("wbinvd");
|
#define ACPI_FLUSH_CPU_CACHE() __asm __volatile("wbinvd");
|
||||||
|
|
||||||
#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
|
/* Based on FreeBSD's due to lack of documentation */
|
||||||
do { \
|
extern int AcpiOsAcquireGlobalLock(uint32 *lock);
|
||||||
__asm __volatile( \
|
extern int AcpiOsReleaseGlobalLock(uint32 *lock);
|
||||||
"1: movl %1,%%eax ;" \
|
|
||||||
" movl %%eax,%%edx ;" \
|
#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) do { \
|
||||||
" andl %2,%%edx ;" \
|
(Acq) = AcpiOsAcquireGlobalLock(&((GLptr)->GlobalLock)); \
|
||||||
" 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)
|
} while (0)
|
||||||
|
|
||||||
#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
|
#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) do { \
|
||||||
do { \
|
(Acq) = AcpiOsReleaseGlobalLock(&((GLptr)->GlobalLock)); \
|
||||||
__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)
|
} while (0)
|
||||||
|
|
||||||
#else /* _KERNEL_MODE */
|
#else /* _KERNEL_MODE */
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ ACPI_MODULE_NAME("Haiku ACPI Module")
|
|||||||
dprintf("acpi[%ld]: %s\n", find_thread(NULL), __PRETTY_FUNCTION__);
|
dprintf("acpi[%ld]: %s\n", find_thread(NULL), __PRETTY_FUNCTION__);
|
||||||
# define DEBUG_FUNCTION_F(x, y...) \
|
# define DEBUG_FUNCTION_F(x, y...) \
|
||||||
dprintf("acpi[%ld]: %s(" x ")\n", find_thread(NULL), __PRETTY_FUNCTION__, 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
|
// No verbose debugging, do nothing
|
||||||
# define DEBUG_FUNCTION_V()
|
# define DEBUG_FUNCTION_V()
|
||||||
# define DEBUG_FUNCTION_VF(x, y...)
|
# define DEBUG_FUNCTION_VF(x, y...)
|
||||||
@@ -243,7 +243,6 @@ AcpiOsGetRootPointer()
|
|||||||
if (status == AE_OK)
|
if (status == AE_OK)
|
||||||
sACPIRoot = address;
|
sACPIRoot = address;
|
||||||
}
|
}
|
||||||
dprintf("AcpiOsGetRootPointer returning %p\n", (void *)sACPIRoot);
|
|
||||||
return sACPIRoot;
|
return sACPIRoot;
|
||||||
#else
|
#else
|
||||||
return AeLocalGetRootPointer();
|
return AeLocalGetRootPointer();
|
||||||
@@ -445,14 +444,14 @@ AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS where, ACPI_SIZE length)
|
|||||||
#ifdef _KERNEL_MODE
|
#ifdef _KERNEL_MODE
|
||||||
void *there;
|
void *there;
|
||||||
area_id area = map_physical_memory("acpi_physical_mem_area", (void *)where,
|
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",
|
DEBUG_FUNCTION_F("addr: 0x%08lx; length: %lu; mapped: %p; area: %ld",
|
||||||
(addr_t)where, (size_t)length, there, area);
|
(addr_t)where, (size_t)length, there, area);
|
||||||
if (area < 0) {
|
if (area < 0) {
|
||||||
dprintf("ACPI: cannot map memory at 0x%08x, length %d\n", where, length);
|
dprintf("ACPI: cannot map memory at 0x%08x, length %d\n", where, length);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return there;
|
return there;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -611,7 +610,8 @@ AcpiOsWaitSemaphore(ACPI_SEMAPHORE handle, UINT32 units, UINT16 timeout)
|
|||||||
break;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,22 +890,19 @@ ACPI_STATUS
|
|||||||
AcpiOsReadPciConfiguration(ACPI_PCI_ID *pciId, UINT32 reg, void *value,
|
AcpiOsReadPciConfiguration(ACPI_PCI_ID *pciId, UINT32 reg, void *value,
|
||||||
UINT32 width)
|
UINT32 width)
|
||||||
{
|
{
|
||||||
|
uint32 *val;
|
||||||
|
val = value;
|
||||||
#ifdef _KERNEL_MODE
|
#ifdef _KERNEL_MODE
|
||||||
UINT32 val = gPCIManager->read_pci_config(
|
|
||||||
pciId->Bus, pciId->Device, pciId->Function, reg, width / 8);
|
|
||||||
DEBUG_FUNCTION();
|
DEBUG_FUNCTION();
|
||||||
|
|
||||||
switch (width) {
|
switch (width) {
|
||||||
case 8:
|
case 8:
|
||||||
*(UINT8 *) value = val;
|
|
||||||
break;
|
|
||||||
case 16:
|
case 16:
|
||||||
*(UINT16 *) value = val;
|
|
||||||
break;
|
|
||||||
case 32:
|
case 32:
|
||||||
*(UINT32 *) value = val;
|
*val = gPCIManager->read_pci_config(
|
||||||
|
pciId->Bus, pciId->Device, pciId->Function, reg, width / 8);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintf("AcpiOsReadPciConfiguration unhandled width: %u\n", width);
|
|
||||||
return AE_ERROR;
|
return AE_ERROR;
|
||||||
}
|
}
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
@@ -983,7 +980,6 @@ AcpiOsReadPort(ACPI_IO_ADDRESS address, UINT32 *value, UINT32 width)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dprintf("AcpiOsReadPort: unhandeld width: %u\n", width);
|
|
||||||
return AE_ERROR;
|
return AE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,7 +1023,6 @@ AcpiOsWritePort(ACPI_IO_ADDRESS address, UINT32 value, UINT32 width)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dprintf("AcpiOsWritePort: unhandeld width: %u\n", width);
|
|
||||||
return AE_ERROR;
|
return AE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1107,11 +1102,19 @@ AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS address, UINT32 value, UINT32 width)
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
BOOLEAN
|
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);
|
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
|
BOOLEAN
|
||||||
AcpiOsWritable(void *pointer, ACPI_SIZE length)
|
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);
|
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()
|
AcpiOsGetThreadId()
|
||||||
{
|
{
|
||||||
thread_id thread = find_thread(NULL);
|
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,
|
// ACPI treats a 0 return as an error,
|
||||||
// but we are thread 0 in early boot
|
// 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)
|
AcpiOsSignal(UINT32 function, void *info)
|
||||||
{
|
{
|
||||||
DEBUG_FUNCTION();
|
DEBUG_FUNCTION();
|
||||||
|
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case ACPI_SIGNAL_FATAL:
|
case ACPI_SIGNAL_FATAL:
|
||||||
#ifdef _KERNEL_MODE
|
#ifdef _KERNEL_MODE
|
||||||
@@ -1195,3 +1206,56 @@ AcpiOsSignal(UINT32 function, void *info)
|
|||||||
|
|
||||||
return AE_OK;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user