Linux Audio

Check our new training course

Loading...
v6.8
  1/*
  2 * 1,2 and 4 byte cmpxchg and xchg implementations for OpenRISC.
  3 *
  4 * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
  5 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
  6 *
  7 * This file is licensed under the terms of the GNU General Public License
  8 * version 2.  This program is licensed "as is" without any warranty of any
  9 * kind, whether express or implied.
 10 *
 11 * Note:
 12 * The portable implementations of 1 and 2 byte xchg and cmpxchg using a 4
 13 * byte cmpxchg is sourced heavily from the sh and mips implementations.
 14 */
 15
 16#ifndef __ASM_OPENRISC_CMPXCHG_H
 17#define __ASM_OPENRISC_CMPXCHG_H
 18
 19#include  <linux/bits.h>
 20#include  <linux/compiler.h>
 21#include  <linux/types.h>
 22
 23#define __HAVE_ARCH_CMPXCHG 1
 24
 25static inline unsigned long cmpxchg_u32(volatile void *ptr,
 26		unsigned long old, unsigned long new)
 27{
 28	__asm__ __volatile__(
 29		"1:	l.lwa %0, 0(%1)		\n"
 30		"	l.sfeq %0, %2		\n"
 31		"	l.bnf 2f		\n"
 32		"	 l.nop			\n"
 33		"	l.swa 0(%1), %3		\n"
 34		"	l.bnf 1b		\n"
 35		"	 l.nop			\n"
 36		"2:				\n"
 37		: "=&r"(old)
 38		: "r"(ptr), "r"(old), "r"(new)
 39		: "cc", "memory");
 40
 41	return old;
 42}
 43
 44static inline unsigned long xchg_u32(volatile void *ptr,
 45		unsigned long val)
 46{
 47	__asm__ __volatile__(
 48		"1:	l.lwa %0, 0(%1)		\n"
 49		"	l.swa 0(%1), %2		\n"
 50		"	l.bnf 1b		\n"
 51		"	 l.nop			\n"
 52		: "=&r"(val)
 53		: "r"(ptr), "r"(val)
 54		: "cc", "memory");
 55
 56	return val;
 57}
 58
 59static inline u32 cmpxchg_small(volatile void *ptr, u32 old, u32 new,
 60				int size)
 61{
 62	int off = (unsigned long)ptr % sizeof(u32);
 63	volatile u32 *p = ptr - off;
 64#ifdef __BIG_ENDIAN
 65	int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 66#else
 67	int bitoff = off * BITS_PER_BYTE;
 68#endif
 69	u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
 70	u32 load32, old32, new32;
 71	u32 ret;
 72
 73	load32 = READ_ONCE(*p);
 74
 75	while (true) {
 76		ret = (load32 & bitmask) >> bitoff;
 77		if (old != ret)
 78			return ret;
 79
 80		old32 = (load32 & ~bitmask) | (old << bitoff);
 81		new32 = (load32 & ~bitmask) | (new << bitoff);
 82
 83		/* Do 32 bit cmpxchg */
 84		load32 = cmpxchg_u32(p, old32, new32);
 85		if (load32 == old32)
 86			return old;
 87	}
 88}
 89
 90/* xchg */
 91
 92static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
 93{
 94	int off = (unsigned long)ptr % sizeof(u32);
 95	volatile u32 *p = ptr - off;
 96#ifdef __BIG_ENDIAN
 97	int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 98#else
 99	int bitoff = off * BITS_PER_BYTE;
100#endif
101	u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
102	u32 oldv, newv;
103	u32 ret;
104
105	do {
106		oldv = READ_ONCE(*p);
107		ret = (oldv & bitmask) >> bitoff;
108		newv = (oldv & ~bitmask) | (x << bitoff);
109	} while (cmpxchg_u32(p, oldv, newv) != oldv);
110
111	return ret;
112}
113
114/*
115 * This function doesn't exist, so you'll get a linker error
116 * if something tries to do an invalid cmpxchg().
117 */
118extern unsigned long __cmpxchg_called_with_bad_pointer(void)
119	__compiletime_error("Bad argument size for cmpxchg");
120
121static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
122		unsigned long new, int size)
123{
124	switch (size) {
125	case 1:
126	case 2:
127		return cmpxchg_small(ptr, old, new, size);
128	case 4:
129		return cmpxchg_u32(ptr, old, new);
130	default:
131		return __cmpxchg_called_with_bad_pointer();
132	}
133}
134
135#define arch_cmpxchg(ptr, o, n)						\
136	({								\
137		(__typeof__(*(ptr))) __cmpxchg((ptr),			\
138					       (unsigned long)(o),	\
139					       (unsigned long)(n),	\
140					       sizeof(*(ptr)));		\
141	})
142
143/*
144 * This function doesn't exist, so you'll get a linker error if
145 * something tries to do an invalidly-sized xchg().
146 */
147extern unsigned long __xchg_called_with_bad_pointer(void)
148	__compiletime_error("Bad argument size for xchg");
149
150static inline unsigned long
151__arch_xchg(volatile void *ptr, unsigned long with, int size)
152{
153	switch (size) {
154	case 1:
155	case 2:
156		return xchg_small(ptr, with, size);
157	case 4:
158		return xchg_u32(ptr, with);
159	default:
160		return __xchg_called_with_bad_pointer();
161	}
162}
163
164#define arch_xchg(ptr, with) 						\
165	({								\
166		(__typeof__(*(ptr))) __arch_xchg((ptr),			\
167						 (unsigned long)(with),	\
168						 sizeof(*(ptr)));	\
169	})
170
171#endif /* __ASM_OPENRISC_CMPXCHG_H */
v6.2
  1/*
  2 * 1,2 and 4 byte cmpxchg and xchg implementations for OpenRISC.
  3 *
  4 * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
  5 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
  6 *
  7 * This file is licensed under the terms of the GNU General Public License
  8 * version 2.  This program is licensed "as is" without any warranty of any
  9 * kind, whether express or implied.
 10 *
 11 * Note:
 12 * The portable implementations of 1 and 2 byte xchg and cmpxchg using a 4
 13 * byte cmpxchg is sourced heavily from the sh and mips implementations.
 14 */
 15
 16#ifndef __ASM_OPENRISC_CMPXCHG_H
 17#define __ASM_OPENRISC_CMPXCHG_H
 18
 19#include  <linux/bits.h>
 20#include  <linux/compiler.h>
 21#include  <linux/types.h>
 22
 23#define __HAVE_ARCH_CMPXCHG 1
 24
 25static inline unsigned long cmpxchg_u32(volatile void *ptr,
 26		unsigned long old, unsigned long new)
 27{
 28	__asm__ __volatile__(
 29		"1:	l.lwa %0, 0(%1)		\n"
 30		"	l.sfeq %0, %2		\n"
 31		"	l.bnf 2f		\n"
 32		"	 l.nop			\n"
 33		"	l.swa 0(%1), %3		\n"
 34		"	l.bnf 1b		\n"
 35		"	 l.nop			\n"
 36		"2:				\n"
 37		: "=&r"(old)
 38		: "r"(ptr), "r"(old), "r"(new)
 39		: "cc", "memory");
 40
 41	return old;
 42}
 43
 44static inline unsigned long xchg_u32(volatile void *ptr,
 45		unsigned long val)
 46{
 47	__asm__ __volatile__(
 48		"1:	l.lwa %0, 0(%1)		\n"
 49		"	l.swa 0(%1), %2		\n"
 50		"	l.bnf 1b		\n"
 51		"	 l.nop			\n"
 52		: "=&r"(val)
 53		: "r"(ptr), "r"(val)
 54		: "cc", "memory");
 55
 56	return val;
 57}
 58
 59static inline u32 cmpxchg_small(volatile void *ptr, u32 old, u32 new,
 60				int size)
 61{
 62	int off = (unsigned long)ptr % sizeof(u32);
 63	volatile u32 *p = ptr - off;
 64#ifdef __BIG_ENDIAN
 65	int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 66#else
 67	int bitoff = off * BITS_PER_BYTE;
 68#endif
 69	u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
 70	u32 load32, old32, new32;
 71	u32 ret;
 72
 73	load32 = READ_ONCE(*p);
 74
 75	while (true) {
 76		ret = (load32 & bitmask) >> bitoff;
 77		if (old != ret)
 78			return ret;
 79
 80		old32 = (load32 & ~bitmask) | (old << bitoff);
 81		new32 = (load32 & ~bitmask) | (new << bitoff);
 82
 83		/* Do 32 bit cmpxchg */
 84		load32 = cmpxchg_u32(p, old32, new32);
 85		if (load32 == old32)
 86			return old;
 87	}
 88}
 89
 90/* xchg */
 91
 92static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
 93{
 94	int off = (unsigned long)ptr % sizeof(u32);
 95	volatile u32 *p = ptr - off;
 96#ifdef __BIG_ENDIAN
 97	int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 98#else
 99	int bitoff = off * BITS_PER_BYTE;
100#endif
101	u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
102	u32 oldv, newv;
103	u32 ret;
104
105	do {
106		oldv = READ_ONCE(*p);
107		ret = (oldv & bitmask) >> bitoff;
108		newv = (oldv & ~bitmask) | (x << bitoff);
109	} while (cmpxchg_u32(p, oldv, newv) != oldv);
110
111	return ret;
112}
113
114/*
115 * This function doesn't exist, so you'll get a linker error
116 * if something tries to do an invalid cmpxchg().
117 */
118extern unsigned long __cmpxchg_called_with_bad_pointer(void)
119	__compiletime_error("Bad argument size for cmpxchg");
120
121static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
122		unsigned long new, int size)
123{
124	switch (size) {
125	case 1:
126	case 2:
127		return cmpxchg_small(ptr, old, new, size);
128	case 4:
129		return cmpxchg_u32(ptr, old, new);
130	default:
131		return __cmpxchg_called_with_bad_pointer();
132	}
133}
134
135#define arch_cmpxchg(ptr, o, n)						\
136	({								\
137		(__typeof__(*(ptr))) __cmpxchg((ptr),			\
138					       (unsigned long)(o),	\
139					       (unsigned long)(n),	\
140					       sizeof(*(ptr)));		\
141	})
142
143/*
144 * This function doesn't exist, so you'll get a linker error if
145 * something tries to do an invalidly-sized xchg().
146 */
147extern unsigned long __xchg_called_with_bad_pointer(void)
148	__compiletime_error("Bad argument size for xchg");
149
150static inline unsigned long __xchg(volatile void *ptr, unsigned long with,
151		int size)
152{
153	switch (size) {
154	case 1:
155	case 2:
156		return xchg_small(ptr, with, size);
157	case 4:
158		return xchg_u32(ptr, with);
159	default:
160		return __xchg_called_with_bad_pointer();
161	}
162}
163
164#define arch_xchg(ptr, with) 						\
165	({								\
166		(__typeof__(*(ptr))) __xchg((ptr),			\
167					    (unsigned long)(with),	\
168					    sizeof(*(ptr)));		\
169	})
170
171#endif /* __ASM_OPENRISC_CMPXCHG_H */