X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/d7a2c48131317a7895c1ed86cc9b5a64e502acc4..477d3c1cb94fc723c033f6ad0897a6a3d65046b6:/sys/cpu/i386/include/atomic.h diff --git a/sys/cpu/i386/include/atomic.h b/sys/cpu/i386/include/atomic.h index 022aa93392..87f3dce71d 100644 --- a/sys/cpu/i386/include/atomic.h +++ b/sys/cpu/i386/include/atomic.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/i386/include/atomic.h,v 1.9.2.1 2000/07/07 00:38:47 obrien Exp $ - * $DragonFly: src/sys/cpu/i386/include/atomic.h,v 1.8 2004/07/29 20:31:13 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/atomic.h,v 1.15 2005/10/13 00:02:46 dillon Exp $ */ #ifndef _MACHINE_ATOMIC_H_ #define _MACHINE_ATOMIC_H_ @@ -127,19 +127,31 @@ ATOMIC_ASM(add, long, "addl %1,%0", v) ATOMIC_ASM(subtract, long, "subl %1,%0", v) /* - * atomic_poll_acquire_int(P) Returns non-zero on success, 0 on failure + * atomic_poll_acquire_int(P) Returns non-zero on success, 0 if the lock + * has already been acquired. * atomic_poll_release_int(P) * - * Currently these are hacks just to support the NDIS driver. + * These support the NDIS driver and are also used for IPIQ interlocks + * between cpus. Both the acquisition and release must be + * cache-synchronizing instructions. */ #if defined(KLD_MODULE) +extern int atomic_swap_int(volatile int *addr, int value); extern int atomic_poll_acquire_int(volatile u_int *p); extern void atomic_poll_release_int(volatile u_int *p); #else +static __inline int +atomic_swap_int(volatile int *addr, int value) +{ + __asm __volatile("xchgl %0, %1" : + "=r" (value), "=m" (*addr) : "0" (value) : "memory"); + return (value); +} + static __inline int atomic_poll_acquire_int(volatile u_int *p) @@ -154,7 +166,175 @@ static __inline void atomic_poll_release_int(volatile u_int *p) { - __asm __volatile("movl $0,%0" : "+m" (*p)); + __asm __volatile(MPLOCKED "btrl $0,%0" : "+m" (*p)); +} + +#endif + +/* + * These functions operate on a 32 bit interrupt interlock which is defined + * as follows: + * + * bit 0-30 interrupt handler disabled bits (counter) + * bit 31 interrupt handler currently running bit (1 = run) + * + * atomic_intr_cond_test(P) Determine if the interlock is in an + * acquired state. Returns 0 if it not + * acquired, non-zero if it is. + * + * atomic_intr_cond_try(P) + * Increment the request counter and attempt to + * set bit 31 to acquire the interlock. If + * we are unable to set bit 31 the request + * counter is decremented and we return -1, + * otherwise we return 0. + * + * atomic_intr_cond_enter(P, func, arg) + * Increment the request counter and attempt to + * set bit 31 to acquire the interlock. If + * we are unable to set bit 31 func(arg) is + * called in a loop until we are able to set + * bit 31. + * + * atomic_intr_cond_exit(P, func, arg) + * Decrement the request counter and clear bit + * 31. If the request counter is still non-zero + * call func(arg) once. + * + * atomic_intr_handler_disable(P) + * Set bit 30, indicating that the interrupt + * handler has been disabled. Must be called + * after the hardware is disabled. + * + * Returns bit 31 indicating whether a serialized + * accessor is active (typically the interrupt + * handler is running). 0 == not active, + * non-zero == active. + * + * atomic_intr_handler_enable(P) + * Clear bit 30, indicating that the interrupt + * handler has been enabled. Must be called + * before the hardware is actually enabled. + * + * atomic_intr_handler_is_enabled(P) + * Returns bit 30, 0 indicates that the handler + * is enabled, non-zero indicates that it is + * disabled. The request counter portion of + * the field is ignored. + */ + +#ifndef __ATOMIC_INTR_T +#define __ATOMIC_INTR_T +typedef volatile int atomic_intr_t; +#endif + +#if defined(KLD_MODULE) + +void atomic_intr_init(atomic_intr_t *p); +int atomic_intr_handler_disable(atomic_intr_t *p); +void atomic_intr_handler_enable(atomic_intr_t *p); +int atomic_intr_handler_is_enabled(atomic_intr_t *p); +int atomic_intr_cond_test(atomic_intr_t *p); +int atomic_intr_cond_try(atomic_intr_t *p); +void atomic_intr_cond_enter(atomic_intr_t *p, void (*func)(void *), void *arg); +void atomic_intr_cond_exit(atomic_intr_t *p, void (*func)(void *), void *arg); + +#else + +static __inline +void +atomic_intr_init(atomic_intr_t *p) +{ + *p = 0; +} + +static __inline +int +atomic_intr_handler_disable(atomic_intr_t *p) +{ + int data; + + __asm __volatile(MPLOCKED "orl $0x40000000,%1; movl %1,%%eax; " \ + "andl $0x80000000,%%eax" \ + : "=a"(data) , "+m"(*p)); + return(data); +} + +static __inline +void +atomic_intr_handler_enable(atomic_intr_t *p) +{ + __asm __volatile(MPLOCKED "andl $0xBFFFFFFF,%0" : "+m" (*p)); +} + +static __inline +int +atomic_intr_handler_is_enabled(atomic_intr_t *p) +{ + int data; + + __asm __volatile("movl %1,%%eax; andl $0x40000000,%%eax" \ + : "=a"(data) : "m"(*p)); + return(data); +} + +static __inline +void +atomic_intr_cond_enter(atomic_intr_t *p, void (*func)(void *), void *arg) +{ + __asm __volatile(MPLOCKED "incl %0; " \ + "1: ;" \ + MPLOCKED "btsl $31,%0; jnc 2f; " \ + "pushl %2; call *%1; addl $4,%%esp; " \ + "jmp 1b; " \ + "2: ;" \ + : "+m" (*p) \ + : "r"(func), "m"(arg) \ + : "ax", "cx", "dx"); +} + +/* + * Attempt to enter the interrupt condition variable. Returns zero on + * success, 1 on failure. + */ +static __inline +int +atomic_intr_cond_try(atomic_intr_t *p) +{ + int ret; + + __asm __volatile(MPLOCKED "incl %0; " \ + "1: ;" \ + "subl %%eax,%%eax; " \ + MPLOCKED "btsl $31,%0; jnc 2f; " \ + MPLOCKED "decl %0; " \ + "movl $1,%%eax;" \ + "2: ;" \ + : "+m" (*p), "=a"(ret) \ + : : "cx", "dx"); + return (ret); +} + + +static __inline +int +atomic_intr_cond_test(atomic_intr_t *p) +{ + return((int)(*p & 0x80000000)); +} + +static __inline +void +atomic_intr_cond_exit(atomic_intr_t *p, void (*func)(void *), void *arg) +{ + __asm __volatile(MPLOCKED "decl %0; " \ + MPLOCKED "btrl $31,%0; " \ + "testl $0x3FFFFFFF,%0; jz 1f; " \ + "pushl %2; call *%1; addl $4,%%esp; " \ + "1: ;" \ + : "+m" (*p) \ + : "r"(func), "m"(arg) \ + : "ax", "cx", "dx"); } #endif