From d8e9ab4ec65f38caa457e11c85b771d6a1cf5839 Mon Sep 17 00:00:00 2001 From: njl Date: Wed, 5 May 2004 20:04:14 +0000 Subject: [PATCH] Add an MI implementation of the ACPI global lock routines and retire the individual asm versions. The global lock is shared between the BIOS and OS and thus cannot use our mutexes. It is defined in section 5.2.9.1 of the ACPI specification. Reviewed by: marcel, bde, jhb --- sys/amd64/include/acpica_machdep.h | 42 ++++---------------------- sys/dev/acpica/Osd/OsdSynch.c | 44 ++++++++++++++++++++++++++++ sys/i386/include/acpica_machdep.h | 45 ++++++---------------------- sys/ia64/include/acpica_machdep.h | 47 ++++-------------------------- 4 files changed, 64 insertions(+), 114 deletions(-) diff --git a/sys/amd64/include/acpica_machdep.h b/sys/amd64/include/acpica_machdep.h index ea501feaa724..07029e1037ce 100644 --- a/sys/amd64/include/acpica_machdep.h +++ b/sys/amd64/include/acpica_machdep.h @@ -59,44 +59,14 @@ #define ACPI_FLUSH_CPU_CACHE() wbinvd() -#define asm __asm -/*! [Begin] no source code translation - * - * A brief explanation as GNU inline assembly is a bit hairy - * %0 is the output parameter in EAX ("=a") - * %1 and %2 are the input parameters in ECX ("c") - * and an immediate value ("i") respectively - * All actual register references are preceded with "%%" as in "%%edx" - * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter are the operation altered non-output registers. - */ +/* Section 5.2.9.1: global lock acquire/release functions */ +extern int acpi_acquire_global_lock(uint32_t *lock); +extern int acpi_release_global_lock(uint32_t *lock); #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - asm("1: movl %1,%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,%1;" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - : "=a" (Acq), "+m" (GLptr) : "i" (~1L) : "edx"); \ - } while(0) - + ((Acq) = acpi_acquire_global_lock(GLptr)) #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - asm("1: movl %1,%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "lock; cmpxchgl %%edx,%1;" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - : "=a" (Acq), "+m" (GLptr) : "i" (~3L) : "edx"); \ - } while(0) - - -/*! [End] no source code translation !*/ + ((Acq) = acpi_release_global_lock(GLptr)) + #endif /* _KERNEL */ #define ACPI_MACHINE_WIDTH 64 diff --git a/sys/dev/acpica/Osd/OsdSynch.c b/sys/dev/acpica/Osd/OsdSynch.c index 5f3398e20a32..34b66fda394a 100644 --- a/sys/dev/acpica/Osd/OsdSynch.c +++ b/sys/dev/acpica/Osd/OsdSynch.c @@ -389,3 +389,47 @@ AcpiOsReleaseLock (ACPI_HANDLE Handle, UINT32 Flags) return; mtx_unlock(m); } + +/* 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_t *lock) +{ + uint32_t new, old; + + do { + old = *lock; + new = (((old & ~GL_BIT_MASK) | GL_BIT_OWNED) | + ((old >> 1) & GL_BIT_PENDING)); + } while (atomic_cmpset_acq_int(lock, old, new) == 0); + + 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_t *lock) +{ + uint32_t new, old; + + do { + old = *lock; + new = old & ~GL_BIT_MASK; + } while (atomic_cmpset_rel_int(lock, old, new) == 0); + + return (old & GL_BIT_PENDING); +} diff --git a/sys/i386/include/acpica_machdep.h b/sys/i386/include/acpica_machdep.h index 6ff98d8ba724..4eff57d08f77 100644 --- a/sys/i386/include/acpica_machdep.h +++ b/sys/i386/include/acpica_machdep.h @@ -59,46 +59,19 @@ #define ACPI_FLUSH_CPU_CACHE() wbinvd() -#define asm __asm +/* Section 5.2.9.1: global lock acquire/release functions */ +extern int acpi_acquire_global_lock(uint32_t *lock); +extern int acpi_release_global_lock(uint32_t *lock); +#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)) + /*! [Begin] no source code translation * - * A brief explanation as GNU inline assembly is a bit hairy - * %0 is the output parameter in EAX ("=a") - * %1 and %2 are the input parameters in ECX ("c") - * and an immediate value ("i") respectively - * All actual register references are preceded with "%%" as in "%%edx" - * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter are the operation altered non-output registers. - */ -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - asm("1: movl %1,%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,%1;" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - : "=a" (Acq), "+m" (GLptr) : "i" (~1L) : "edx"); \ - } while(0) - -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - asm("1: movl %1,%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "lock; cmpxchgl %%edx,%1;" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - : "=a" (Acq), "+m" (GLptr) : "i" (~3L) : "edx"); \ - } while(0) - - -/* * Math helper asm macros */ +#define asm __asm #define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ asm("divl %2;" \ :"=a"(q32), "=d"(r32) \ diff --git a/sys/ia64/include/acpica_machdep.h b/sys/ia64/include/acpica_machdep.h index f459b6ae3fcc..315476b0a859 100644 --- a/sys/ia64/include/acpica_machdep.h +++ b/sys/ia64/include/acpica_machdep.h @@ -61,50 +61,13 @@ #define ACPI_FLUSH_CPU_CACHE() /* XXX ia64_fc()? */ -/*! [Begin] no source code translation */ - +/* Section 5.2.9.1: global lock acquire/release functions */ +extern int acpi_acquire_global_lock(uint32_t *lock); +extern int acpi_release_global_lock(uint32_t *lock); #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - __asm__ volatile ("1: ld4 r29=[%1]\n" \ - ";;\n" \ - "mov ar.ccv=r29\n" \ - "mov r2=r29\n" \ - "shr.u r30=r29,1\n" \ - "and r29=-4,r29\n" \ - ";;\n" \ - "add r29=2,r29\n" \ - "and r30=1,r30\n" \ - ";;\n" \ - "add r29=r29,r30\n" \ - ";;\n" \ - "cmpxchg4.acq r30=[%1],r29,ar.ccv\n" \ - ";;\n" \ - "cmp.eq p6,p7=r2,r30\n" \ - "(p7) br.dpnt.few 1b\n" \ - "cmp.gt p8,p9=3,r29\n" \ - ";;\n" \ - "(p8) mov %0=-1\n" \ - "(p9) mov %0=r0\n" \ - :"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \ - } while (0) - + ((Acq) = acpi_acquire_global_lock(GLptr)) #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - __asm__ volatile ("1: ld4 r29=[%1]\n" \ - ";;\n" \ - "mov ar.ccv=r29\n" \ - "mov r2=r29\n" \ - "and r29=-4,r29\n" \ - ";;\n" \ - "cmpxchg4.acq r30=[%1],r29,ar.ccv\n" \ - ";;\n" \ - "cmp.eq p6,p7=r2,r30\n" \ - "(p7) br.dpnt.few 1b\n" \ - "and %0=1,r2\n" \ - ";;\n" \ - :"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \ - } while (0) -/*! [End] no source code translation !*/ + ((Acq) = acpi_release_global_lock(GLptr)) #endif /* _KERNEL */