Author: phoudoin Date: 2009-10-26 23:01:59 +0100 (Mon, 26 Oct 2009) New Revision: 33781 Changeset: http://dev.haiku-os.org/changeset/33781/haiku Modified: haiku/trunk/src/add-ons/kernel/bus_managers/acpi/include/platform/achaiku.h haiku/trunk/src/add-ons/kernel/bus_managers/acpi/oshaiku.c Log: Apply patch by tqh: fix ACPI hang at boot (#4762) Global lock/unlock assembly code was broken, reworked based on what FreeBSD does. Thanks! Modified: haiku/trunk/src/add-ons/kernel/bus_managers/acpi/include/platform/achaiku.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/acpi/include/platform/achaiku.h 2009-10-26 20:21:55 UTC (rev 33780) +++ haiku/trunk/src/add-ons/kernel/bus_managers/acpi/include/platform/achaiku.h 2009-10-26 22:01:59 UTC (rev 33781) @@ -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 */ Modified: haiku/trunk/src/add-ons/kernel/bus_managers/acpi/oshaiku.c =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/acpi/oshaiku.c 2009-10-26 20:21:55 UTC (rev 33780) +++ haiku/trunk/src/add-ons/kernel/bus_managers/acpi/oshaiku.c 2009-10-26 22:01:59 UTC (rev 33781) @@ -157,7 +157,7 @@ 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 @@ if (status == AE_OK) sACPIRoot = address; } - dprintf("AcpiOsGetRootPointer returning %p\n", (void *)sACPIRoot); return sACPIRoot; #else return AeLocalGetRootPointer(); @@ -445,14 +444,14 @@ #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 @@ 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 @@ 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 @@ break; default: - dprintf("AcpiOsReadPort: unhandeld width: %u\n", width); return AE_ERROR; } @@ -1027,7 +1023,6 @@ break; default: - dprintf("AcpiOsWritePort: unhandeld width: %u\n", width); return AE_ERROR; } @@ -1107,11 +1102,19 @@ * *****************************************************************************/ 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 @@ 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 @@ 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 @@ AcpiOsSignal(UINT32 function, void *info) { DEBUG_FUNCTION(); + switch (function) { case ACPI_SIGNAL_FATAL: #ifdef _KERNEL_MODE @@ -1195,3 +1206,56 @@ 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); +}