13bed8d67469cc7129b0babc0211c32fa68408ce0David Howells/*
23bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * Copyright 2004-2011 Analog Devices Inc.
33bed8d67469cc7129b0babc0211c32fa68408ce0David Howells *
43bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * Licensed under the GPL-2 or later.
53bed8d67469cc7129b0babc0211c32fa68408ce0David Howells */
63bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
73bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#ifndef __ARCH_BLACKFIN_CMPXCHG__
83bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define __ARCH_BLACKFIN_CMPXCHG__
93bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
103bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#ifdef CONFIG_SMP
113bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
123bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#include <linux/linkage.h>
133bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
143bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value);
153bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value);
163bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value);
173bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr,
183bed8d67469cc7129b0babc0211c32fa68408ce0David Howells					unsigned long new, unsigned long old);
193bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr,
203bed8d67469cc7129b0babc0211c32fa68408ce0David Howells					unsigned long new, unsigned long old);
213bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsasmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr,
223bed8d67469cc7129b0babc0211c32fa68408ce0David Howells					unsigned long new, unsigned long old);
233bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
243bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsstatic inline unsigned long __xchg(unsigned long x, volatile void *ptr,
253bed8d67469cc7129b0babc0211c32fa68408ce0David Howells				   int size)
263bed8d67469cc7129b0babc0211c32fa68408ce0David Howells{
273bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	unsigned long tmp;
283bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
293bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	switch (size) {
303bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 1:
313bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_xchg_1_asm(ptr, x);
323bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
333bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 2:
343bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_xchg_2_asm(ptr, x);
353bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
363bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 4:
373bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_xchg_4_asm(ptr, x);
383bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
393bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	}
403bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
413bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	return tmp;
423bed8d67469cc7129b0babc0211c32fa68408ce0David Howells}
433bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
443bed8d67469cc7129b0babc0211c32fa68408ce0David Howells/*
453bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * Atomic compare and exchange.  Compare OLD with MEM, if identical,
463bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * store NEW in MEM.  Return the initial value in MEM.  Success is
473bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * indicated by comparing RETURN with OLD.
483bed8d67469cc7129b0babc0211c32fa68408ce0David Howells */
493bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsstatic inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
503bed8d67469cc7129b0babc0211c32fa68408ce0David Howells				      unsigned long new, int size)
513bed8d67469cc7129b0babc0211c32fa68408ce0David Howells{
523bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	unsigned long tmp;
533bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
543bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	switch (size) {
553bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 1:
563bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_cmpxchg_1_asm(ptr, new, old);
573bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
583bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 2:
593bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_cmpxchg_2_asm(ptr, new, old);
603bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
613bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 4:
623bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		tmp = __raw_cmpxchg_4_asm(ptr, new, old);
633bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
643bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	}
653bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
663bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	return tmp;
673bed8d67469cc7129b0babc0211c32fa68408ce0David Howells}
683bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define cmpxchg(ptr, o, n) \
693bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
703bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		(unsigned long)(n), sizeof(*(ptr))))
713bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
723bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#else /* !CONFIG_SMP */
733bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
743bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#include <mach/blackfin.h>
753bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#include <asm/irqflags.h>
763bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
773bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsstruct __xchg_dummy {
783bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	unsigned long a[100];
793bed8d67469cc7129b0babc0211c32fa68408ce0David Howells};
803bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define __xg(x) ((volatile struct __xchg_dummy *)(x))
813bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
823bed8d67469cc7129b0babc0211c32fa68408ce0David Howellsstatic inline unsigned long __xchg(unsigned long x, volatile void *ptr,
833bed8d67469cc7129b0babc0211c32fa68408ce0David Howells				   int size)
843bed8d67469cc7129b0babc0211c32fa68408ce0David Howells{
853bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	unsigned long tmp = 0;
863bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	unsigned long flags;
873bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
883bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	flags = hard_local_irq_save();
893bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
903bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	switch (size) {
913bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 1:
923bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		__asm__ __volatile__
933bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			("%0 = b%2 (z);\n\t"
943bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 "b%2 = %1;\n\t"
953bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
963bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
973bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 2:
983bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		__asm__ __volatile__
993bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			("%0 = w%2 (z);\n\t"
1003bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 "w%2 = %1;\n\t"
1013bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
1023bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
1033bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	case 4:
1043bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		__asm__ __volatile__
1053bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			("%0 = %2;\n\t"
1063bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 "%2 = %1;\n\t"
1073bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
1083bed8d67469cc7129b0babc0211c32fa68408ce0David Howells		break;
1093bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	}
1103bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	hard_local_irq_restore(flags);
1113bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	return tmp;
1123bed8d67469cc7129b0babc0211c32fa68408ce0David Howells}
1133bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1143bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#include <asm-generic/cmpxchg-local.h>
1153bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1163bed8d67469cc7129b0babc0211c32fa68408ce0David Howells/*
1173bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
1183bed8d67469cc7129b0babc0211c32fa68408ce0David Howells * them available.
1193bed8d67469cc7129b0babc0211c32fa68408ce0David Howells */
1203bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define cmpxchg_local(ptr, o, n)				  	       \
1213bed8d67469cc7129b0babc0211c32fa68408ce0David Howells	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
1223bed8d67469cc7129b0babc0211c32fa68408ce0David Howells			(unsigned long)(n), sizeof(*(ptr))))
1233bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
1243bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1251512cdc3572dac34a1809764f9a646cde7e82407Paul Gortmaker#define cmpxchg(ptr, o, n)	cmpxchg_local((ptr), (o), (n))
1261512cdc3572dac34a1809764f9a646cde7e82407Paul Gortmaker#define cmpxchg64(ptr, o, n)	cmpxchg64_local((ptr), (o), (n))
1273bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1283bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#endif /* !CONFIG_SMP */
1293bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1303bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
1313bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#define tas(ptr) ((void)xchg((ptr), 1))
1323bed8d67469cc7129b0babc0211c32fa68408ce0David Howells
1333bed8d67469cc7129b0babc0211c32fa68408ce0David Howells#endif /* __ARCH_BLACKFIN_CMPXCHG__ */
134