1/* MN10300 Atomic xchg/cmpxchg operations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#ifndef _ASM_CMPXCHG_H
12#define _ASM_CMPXCHG_H
13
14#include <asm/irqflags.h>
15
16#ifdef CONFIG_SMP
17#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
18static inline
19unsigned long __xchg(volatile unsigned long *m, unsigned long val)
20{
21	unsigned long status;
22	unsigned long oldval;
23
24	asm volatile(
25		"1:	mov	%4,(_AAR,%3)	\n"
26		"	mov	(_ADR,%3),%1	\n"
27		"	mov	%5,(_ADR,%3)	\n"
28		"	mov	(_ADR,%3),%0	\n"	/* flush */
29		"	mov	(_ASR,%3),%0	\n"
30		"	or	%0,%0		\n"
31		"	bne	1b		\n"
32		: "=&r"(status), "=&r"(oldval), "=m"(*m)
33		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
34		: "memory", "cc");
35
36	return oldval;
37}
38
39static inline unsigned long __cmpxchg(volatile unsigned long *m,
40				      unsigned long old, unsigned long new)
41{
42	unsigned long status;
43	unsigned long oldval;
44
45	asm volatile(
46		"1:	mov	%4,(_AAR,%3)	\n"
47		"	mov	(_ADR,%3),%1	\n"
48		"	cmp	%5,%1		\n"
49		"	bne	2f		\n"
50		"	mov	%6,(_ADR,%3)	\n"
51		"2:	mov	(_ADR,%3),%0	\n"	/* flush */
52		"	mov	(_ASR,%3),%0	\n"
53		"	or	%0,%0		\n"
54		"	bne	1b		\n"
55		: "=&r"(status), "=&r"(oldval), "=m"(*m)
56		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
57		  "r"(old), "r"(new)
58		: "memory", "cc");
59
60	return oldval;
61}
62#else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
63#error "No SMP atomic operation support!"
64#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
65
66#else  /* CONFIG_SMP */
67
68/*
69 * Emulate xchg for non-SMP MN10300
70 */
71struct __xchg_dummy { unsigned long a[100]; };
72#define __xg(x) ((struct __xchg_dummy *)(x))
73
74static inline
75unsigned long __xchg(volatile unsigned long *m, unsigned long val)
76{
77	unsigned long oldval;
78	unsigned long flags;
79
80	flags = arch_local_cli_save();
81	oldval = *m;
82	*m = val;
83	arch_local_irq_restore(flags);
84	return oldval;
85}
86
87/*
88 * Emulate cmpxchg for non-SMP MN10300
89 */
90static inline unsigned long __cmpxchg(volatile unsigned long *m,
91				      unsigned long old, unsigned long new)
92{
93	unsigned long oldval;
94	unsigned long flags;
95
96	flags = arch_local_cli_save();
97	oldval = *m;
98	if (oldval == old)
99		*m = new;
100	arch_local_irq_restore(flags);
101	return oldval;
102}
103
104#endif /* CONFIG_SMP */
105
106#define xchg(ptr, v)						\
107	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
108				     (unsigned long)(v)))
109
110#define cmpxchg(ptr, o, n)					\
111	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
112					(unsigned long)(o),	\
113					(unsigned long)(n)))
114
115#endif /* _ASM_CMPXCHG_H */
116