1/* 2 * Copyright 2004-2011 Analog Devices Inc. 3 * 4 * Licensed under the GPL-2 or later. 5 */ 6 7#ifndef __ARCH_BLACKFIN_CMPXCHG__ 8#define __ARCH_BLACKFIN_CMPXCHG__ 9 10#ifdef CONFIG_SMP 11 12#include <linux/linkage.h> 13 14asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value); 15asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value); 16asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value); 17asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr, 18 unsigned long new, unsigned long old); 19asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr, 20 unsigned long new, unsigned long old); 21asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr, 22 unsigned long new, unsigned long old); 23 24static inline unsigned long __xchg(unsigned long x, volatile void *ptr, 25 int size) 26{ 27 unsigned long tmp; 28 29 switch (size) { 30 case 1: 31 tmp = __raw_xchg_1_asm(ptr, x); 32 break; 33 case 2: 34 tmp = __raw_xchg_2_asm(ptr, x); 35 break; 36 case 4: 37 tmp = __raw_xchg_4_asm(ptr, x); 38 break; 39 } 40 41 return tmp; 42} 43 44/* 45 * Atomic compare and exchange. Compare OLD with MEM, if identical, 46 * store NEW in MEM. Return the initial value in MEM. Success is 47 * indicated by comparing RETURN with OLD. 48 */ 49static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, 50 unsigned long new, int size) 51{ 52 unsigned long tmp; 53 54 switch (size) { 55 case 1: 56 tmp = __raw_cmpxchg_1_asm(ptr, new, old); 57 break; 58 case 2: 59 tmp = __raw_cmpxchg_2_asm(ptr, new, old); 60 break; 61 case 4: 62 tmp = __raw_cmpxchg_4_asm(ptr, new, old); 63 break; 64 } 65 66 return tmp; 67} 68#define cmpxchg(ptr, o, n) \ 69 ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ 70 (unsigned long)(n), sizeof(*(ptr)))) 71 72#else /* !CONFIG_SMP */ 73 74#include <mach/blackfin.h> 75#include <asm/irqflags.h> 76 77struct __xchg_dummy { 78 unsigned long a[100]; 79}; 80#define __xg(x) ((volatile struct __xchg_dummy *)(x)) 81 82static inline unsigned long __xchg(unsigned long x, volatile void *ptr, 83 int size) 84{ 85 unsigned long tmp = 0; 86 unsigned long flags; 87 88 flags = hard_local_irq_save(); 89 90 switch (size) { 91 case 1: 92 __asm__ __volatile__ 93 ("%0 = b%2 (z);\n\t" 94 "b%2 = %1;\n\t" 95 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); 96 break; 97 case 2: 98 __asm__ __volatile__ 99 ("%0 = w%2 (z);\n\t" 100 "w%2 = %1;\n\t" 101 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); 102 break; 103 case 4: 104 __asm__ __volatile__ 105 ("%0 = %2;\n\t" 106 "%2 = %1;\n\t" 107 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); 108 break; 109 } 110 hard_local_irq_restore(flags); 111 return tmp; 112} 113 114#include <asm-generic/cmpxchg-local.h> 115 116/* 117 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make 118 * them available. 119 */ 120#define cmpxchg_local(ptr, o, n) \ 121 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ 122 (unsigned long)(n), sizeof(*(ptr)))) 123#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 124 125#define cmpxchg(ptr, o, n) cmpxchg_local((ptr), (o), (n)) 126#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) 127 128#endif /* !CONFIG_SMP */ 129 130#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) 131#define tas(ptr) ((void)xchg((ptr), 1)) 132 133#endif /* __ARCH_BLACKFIN_CMPXCHG__ */ 134