116 lines
2.7 KiB
C
116 lines
2.7 KiB
C
|
/* MN10300 Atomic xchg/cmpxchg operations
|
||
|
*
|
||
|
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||
|
* Written by David Howells (dhowells@redhat.com)
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public Licence
|
||
|
* as published by the Free Software Foundation; either version
|
||
|
* 2 of the Licence, or (at your option) any later version.
|
||
|
*/
|
||
|
#ifndef _ASM_CMPXCHG_H
|
||
|
#define _ASM_CMPXCHG_H
|
||
|
|
||
|
#include <asm/irqflags.h>
|
||
|
|
||
|
#ifdef CONFIG_SMP
|
||
|
#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
|
||
|
static inline
|
||
|
unsigned long __xchg(volatile unsigned long *m, unsigned long val)
|
||
|
{
|
||
|
unsigned long status;
|
||
|
unsigned long oldval;
|
||
|
|
||
|
asm volatile(
|
||
|
"1: mov %4,(_AAR,%3) \n"
|
||
|
" mov (_ADR,%3),%1 \n"
|
||
|
" mov %5,(_ADR,%3) \n"
|
||
|
" mov (_ADR,%3),%0 \n" /* flush */
|
||
|
" mov (_ASR,%3),%0 \n"
|
||
|
" or %0,%0 \n"
|
||
|
" bne 1b \n"
|
||
|
: "=&r"(status), "=&r"(oldval), "=m"(*m)
|
||
|
: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
|
||
|
: "memory", "cc");
|
||
|
|
||
|
return oldval;
|
||
|
}
|
||
|
|
||
|
static inline unsigned long __cmpxchg(volatile unsigned long *m,
|
||
|
unsigned long old, unsigned long new)
|
||
|
{
|
||
|
unsigned long status;
|
||
|
unsigned long oldval;
|
||
|
|
||
|
asm volatile(
|
||
|
"1: mov %4,(_AAR,%3) \n"
|
||
|
" mov (_ADR,%3),%1 \n"
|
||
|
" cmp %5,%1 \n"
|
||
|
" bne 2f \n"
|
||
|
" mov %6,(_ADR,%3) \n"
|
||
|
"2: mov (_ADR,%3),%0 \n" /* flush */
|
||
|
" mov (_ASR,%3),%0 \n"
|
||
|
" or %0,%0 \n"
|
||
|
" bne 1b \n"
|
||
|
: "=&r"(status), "=&r"(oldval), "=m"(*m)
|
||
|
: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
|
||
|
"r"(old), "r"(new)
|
||
|
: "memory", "cc");
|
||
|
|
||
|
return oldval;
|
||
|
}
|
||
|
#else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
|
||
|
#error "No SMP atomic operation support!"
|
||
|
#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
|
||
|
|
||
|
#else /* CONFIG_SMP */
|
||
|
|
||
|
/*
|
||
|
* Emulate xchg for non-SMP MN10300
|
||
|
*/
|
||
|
struct __xchg_dummy { unsigned long a[100]; };
|
||
|
#define __xg(x) ((struct __xchg_dummy *)(x))
|
||
|
|
||
|
static inline
|
||
|
unsigned long __xchg(volatile unsigned long *m, unsigned long val)
|
||
|
{
|
||
|
unsigned long oldval;
|
||
|
unsigned long flags;
|
||
|
|
||
|
flags = arch_local_cli_save();
|
||
|
oldval = *m;
|
||
|
*m = val;
|
||
|
arch_local_irq_restore(flags);
|
||
|
return oldval;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Emulate cmpxchg for non-SMP MN10300
|
||
|
*/
|
||
|
static inline unsigned long __cmpxchg(volatile unsigned long *m,
|
||
|
unsigned long old, unsigned long new)
|
||
|
{
|
||
|
unsigned long oldval;
|
||
|
unsigned long flags;
|
||
|
|
||
|
flags = arch_local_cli_save();
|
||
|
oldval = *m;
|
||
|
if (oldval == old)
|
||
|
*m = new;
|
||
|
arch_local_irq_restore(flags);
|
||
|
return oldval;
|
||
|
}
|
||
|
|
||
|
#endif /* CONFIG_SMP */
|
||
|
|
||
|
#define xchg(ptr, v) \
|
||
|
((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
|
||
|
(unsigned long)(v)))
|
||
|
|
||
|
#define cmpxchg(ptr, o, n) \
|
||
|
((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
|
||
|
(unsigned long)(o), \
|
||
|
(unsigned long)(n)))
|
||
|
|
||
|
#endif /* _ASM_CMPXCHG_H */
|