162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License
562306a36Sopenharmony_ci * version 2.  This program is licensed "as is" without any warranty of any
662306a36Sopenharmony_ci * kind, whether express or implied.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef __ASM_OPENRISC_BITOPS_ATOMIC_H
1062306a36Sopenharmony_ci#define __ASM_OPENRISC_BITOPS_ATOMIC_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic inline void set_bit(int nr, volatile unsigned long *addr)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
1562306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
1662306a36Sopenharmony_ci	unsigned long tmp;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	__asm__ __volatile__(
1962306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%1)	\n"
2062306a36Sopenharmony_ci		"	l.or	%0,%0,%2	\n"
2162306a36Sopenharmony_ci		"	l.swa	0(%1),%0	\n"
2262306a36Sopenharmony_ci		"	l.bnf	1b		\n"
2362306a36Sopenharmony_ci		"	 l.nop			\n"
2462306a36Sopenharmony_ci		: "=&r"(tmp)
2562306a36Sopenharmony_ci		: "r"(p), "r"(mask)
2662306a36Sopenharmony_ci		: "cc", "memory");
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic inline void clear_bit(int nr, volatile unsigned long *addr)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
3262306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
3362306a36Sopenharmony_ci	unsigned long tmp;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	__asm__ __volatile__(
3662306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%1)	\n"
3762306a36Sopenharmony_ci		"	l.and	%0,%0,%2	\n"
3862306a36Sopenharmony_ci		"	l.swa	0(%1),%0	\n"
3962306a36Sopenharmony_ci		"	l.bnf	1b		\n"
4062306a36Sopenharmony_ci		"	 l.nop			\n"
4162306a36Sopenharmony_ci		: "=&r"(tmp)
4262306a36Sopenharmony_ci		: "r"(p), "r"(~mask)
4362306a36Sopenharmony_ci		: "cc", "memory");
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline void change_bit(int nr, volatile unsigned long *addr)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
4962306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
5062306a36Sopenharmony_ci	unsigned long tmp;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	__asm__ __volatile__(
5362306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%1)	\n"
5462306a36Sopenharmony_ci		"	l.xor	%0,%0,%2	\n"
5562306a36Sopenharmony_ci		"	l.swa	0(%1),%0	\n"
5662306a36Sopenharmony_ci		"	l.bnf	1b		\n"
5762306a36Sopenharmony_ci		"	 l.nop			\n"
5862306a36Sopenharmony_ci		: "=&r"(tmp)
5962306a36Sopenharmony_ci		: "r"(p), "r"(mask)
6062306a36Sopenharmony_ci		: "cc", "memory");
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic inline int test_and_set_bit(int nr, volatile unsigned long *addr)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
6662306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
6762306a36Sopenharmony_ci	unsigned long old;
6862306a36Sopenharmony_ci	unsigned long tmp;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	__asm__ __volatile__(
7162306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%2)	\n"
7262306a36Sopenharmony_ci		"	l.or	%1,%0,%3	\n"
7362306a36Sopenharmony_ci		"	l.swa	0(%2),%1	\n"
7462306a36Sopenharmony_ci		"	l.bnf	1b		\n"
7562306a36Sopenharmony_ci		"	 l.nop			\n"
7662306a36Sopenharmony_ci		: "=&r"(old), "=&r"(tmp)
7762306a36Sopenharmony_ci		: "r"(p), "r"(mask)
7862306a36Sopenharmony_ci		: "cc", "memory");
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return (old & mask) != 0;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
8662306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
8762306a36Sopenharmony_ci	unsigned long old;
8862306a36Sopenharmony_ci	unsigned long tmp;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	__asm__ __volatile__(
9162306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%2)	\n"
9262306a36Sopenharmony_ci		"	l.and	%1,%0,%3	\n"
9362306a36Sopenharmony_ci		"	l.swa	0(%2),%1	\n"
9462306a36Sopenharmony_ci		"	l.bnf	1b		\n"
9562306a36Sopenharmony_ci		"	 l.nop			\n"
9662306a36Sopenharmony_ci		: "=&r"(old), "=&r"(tmp)
9762306a36Sopenharmony_ci		: "r"(p), "r"(~mask)
9862306a36Sopenharmony_ci		: "cc", "memory");
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return (old & mask) != 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic inline int test_and_change_bit(int nr, volatile unsigned long *addr)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	unsigned long mask = BIT_MASK(nr);
10662306a36Sopenharmony_ci	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
10762306a36Sopenharmony_ci	unsigned long old;
10862306a36Sopenharmony_ci	unsigned long tmp;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	__asm__ __volatile__(
11162306a36Sopenharmony_ci		"1:	l.lwa	%0,0(%2)	\n"
11262306a36Sopenharmony_ci		"	l.xor	%1,%0,%3	\n"
11362306a36Sopenharmony_ci		"	l.swa	0(%2),%1	\n"
11462306a36Sopenharmony_ci		"	l.bnf	1b		\n"
11562306a36Sopenharmony_ci		"	 l.nop			\n"
11662306a36Sopenharmony_ci		: "=&r"(old), "=&r"(tmp)
11762306a36Sopenharmony_ci		: "r"(p), "r"(mask)
11862306a36Sopenharmony_ci		: "cc", "memory");
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return (old & mask) != 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#endif /* __ASM_OPENRISC_BITOPS_ATOMIC_H */
124