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
This commit is contained in:
njl 2004-05-05 20:04:14 +00:00
parent 548661dd93
commit d8e9ab4ec6
4 changed files with 64 additions and 114 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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) \

View File

@ -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 */