18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Bit operations for the Hexagon architecture
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef _ASM_BITOPS_H
98c2ecf20Sopenharmony_ci#define _ASM_BITOPS_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/compiler.h>
128c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
138c2ecf20Sopenharmony_ci#include <asm/atomic.h>
148c2ecf20Sopenharmony_ci#include <asm/barrier.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#ifdef __KERNEL__
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * The offset calculations for these are based on BITS_PER_LONG == 32
208c2ecf20Sopenharmony_ci * (i.e. I get to shift by #5-2 (32 bits per long, 4 bytes per access),
218c2ecf20Sopenharmony_ci * mask by 0x0000001F)
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Typically, R10 is clobbered for address, R11 bit nr, and R12 is temp
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/**
278c2ecf20Sopenharmony_ci * test_and_clear_bit - clear a bit and return its old value
288c2ecf20Sopenharmony_ci * @nr:  bit number to clear
298c2ecf20Sopenharmony_ci * @addr:  pointer to memory
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistatic inline int test_and_clear_bit(int nr, volatile void *addr)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	int oldval;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
368c2ecf20Sopenharmony_ci	"	{R10 = %1; R11 = asr(%2,#5); }\n"
378c2ecf20Sopenharmony_ci	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
388c2ecf20Sopenharmony_ci	"1:	R12 = memw_locked(R10);\n"
398c2ecf20Sopenharmony_ci	"	{ P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n"
408c2ecf20Sopenharmony_ci	"	memw_locked(R10,P1) = R12;\n"
418c2ecf20Sopenharmony_ci	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
428c2ecf20Sopenharmony_ci	: "=&r" (oldval)
438c2ecf20Sopenharmony_ci	: "r" (addr), "r" (nr)
448c2ecf20Sopenharmony_ci	: "r10", "r11", "r12", "p0", "p1", "memory"
458c2ecf20Sopenharmony_ci	);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return oldval;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/**
518c2ecf20Sopenharmony_ci * test_and_set_bit - set a bit and return its old value
528c2ecf20Sopenharmony_ci * @nr:  bit number to set
538c2ecf20Sopenharmony_ci * @addr:  pointer to memory
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistatic inline int test_and_set_bit(int nr, volatile void *addr)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	int oldval;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
608c2ecf20Sopenharmony_ci	"	{R10 = %1; R11 = asr(%2,#5); }\n"
618c2ecf20Sopenharmony_ci	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
628c2ecf20Sopenharmony_ci	"1:	R12 = memw_locked(R10);\n"
638c2ecf20Sopenharmony_ci	"	{ P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n"
648c2ecf20Sopenharmony_ci	"	memw_locked(R10,P1) = R12;\n"
658c2ecf20Sopenharmony_ci	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
668c2ecf20Sopenharmony_ci	: "=&r" (oldval)
678c2ecf20Sopenharmony_ci	: "r" (addr), "r" (nr)
688c2ecf20Sopenharmony_ci	: "r10", "r11", "r12", "p0", "p1", "memory"
698c2ecf20Sopenharmony_ci	);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return oldval;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/**
778c2ecf20Sopenharmony_ci * test_and_change_bit - toggle a bit and return its old value
788c2ecf20Sopenharmony_ci * @nr:  bit number to set
798c2ecf20Sopenharmony_ci * @addr:  pointer to memory
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_cistatic inline int test_and_change_bit(int nr, volatile void *addr)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	int oldval;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
868c2ecf20Sopenharmony_ci	"	{R10 = %1; R11 = asr(%2,#5); }\n"
878c2ecf20Sopenharmony_ci	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
888c2ecf20Sopenharmony_ci	"1:	R12 = memw_locked(R10);\n"
898c2ecf20Sopenharmony_ci	"	{ P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n"
908c2ecf20Sopenharmony_ci	"	memw_locked(R10,P1) = R12;\n"
918c2ecf20Sopenharmony_ci	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
928c2ecf20Sopenharmony_ci	: "=&r" (oldval)
938c2ecf20Sopenharmony_ci	: "r" (addr), "r" (nr)
948c2ecf20Sopenharmony_ci	: "r10", "r11", "r12", "p0", "p1", "memory"
958c2ecf20Sopenharmony_ci	);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return oldval;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * Atomic, but doesn't care about the return value.
1038c2ecf20Sopenharmony_ci * Rewrite later to save a cycle or two.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline void clear_bit(int nr, volatile void *addr)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	test_and_clear_bit(nr, addr);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic inline void set_bit(int nr, volatile void *addr)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	test_and_set_bit(nr, addr);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline void change_bit(int nr, volatile void *addr)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	test_and_change_bit(nr, addr);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/*
1238c2ecf20Sopenharmony_ci * These are allowed to be non-atomic.  In fact the generic flavors are
1248c2ecf20Sopenharmony_ci * in non-atomic.h.  Would it be better to use intrinsics for this?
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * OK, writes in our architecture do not invalidate LL/SC, so this has to
1278c2ecf20Sopenharmony_ci * be atomic, particularly for things like slab_lock and slab_unlock.
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_cistatic inline void __clear_bit(int nr, volatile unsigned long *addr)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	test_and_clear_bit(nr, addr);
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline void __set_bit(int nr, volatile unsigned long *addr)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	test_and_set_bit(nr, addr);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline void __change_bit(int nr, volatile unsigned long *addr)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	test_and_change_bit(nr, addr);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/*  Apparently, at least some of these are allowed to be non-atomic  */
1468c2ecf20Sopenharmony_cistatic inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	return test_and_clear_bit(nr, addr);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	return test_and_set_bit(nr, addr);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	return test_and_change_bit(nr, addr);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic inline int __test_bit(int nr, const volatile unsigned long *addr)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	int retval;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	asm volatile(
1668c2ecf20Sopenharmony_ci	"{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n"
1678c2ecf20Sopenharmony_ci	: "=&r" (retval)
1688c2ecf20Sopenharmony_ci	: "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG)
1698c2ecf20Sopenharmony_ci	: "p0"
1708c2ecf20Sopenharmony_ci	);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return retval;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#define test_bit(nr, addr) __test_bit(nr, addr)
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/*
1788c2ecf20Sopenharmony_ci * ffz - find first zero in word.
1798c2ecf20Sopenharmony_ci * @word: The word to search
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * Undefined if no zero exists, so code should check against ~0UL first.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic inline long ffz(int x)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	int r;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	asm("%0 = ct1(%1);\n"
1888c2ecf20Sopenharmony_ci		: "=&r" (r)
1898c2ecf20Sopenharmony_ci		: "r" (x));
1908c2ecf20Sopenharmony_ci	return r;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/*
1948c2ecf20Sopenharmony_ci * fls - find last (most-significant) bit set
1958c2ecf20Sopenharmony_ci * @x: the word to search
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * This is defined the same way as ffs.
1988c2ecf20Sopenharmony_ci * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_cistatic inline int fls(unsigned int x)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	int r;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	asm("{ %0 = cl0(%1);}\n"
2058c2ecf20Sopenharmony_ci		"%0 = sub(#32,%0);\n"
2068c2ecf20Sopenharmony_ci		: "=&r" (r)
2078c2ecf20Sopenharmony_ci		: "r" (x)
2088c2ecf20Sopenharmony_ci		: "p0");
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return r;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * ffs - find first bit set
2158c2ecf20Sopenharmony_ci * @x: the word to search
2168c2ecf20Sopenharmony_ci *
2178c2ecf20Sopenharmony_ci * This is defined the same way as
2188c2ecf20Sopenharmony_ci * the libc and compiler builtin ffs routines, therefore
2198c2ecf20Sopenharmony_ci * differs in spirit from the above ffz (man ffs).
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_cistatic inline int ffs(int x)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	int r;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n"
2268c2ecf20Sopenharmony_ci		"{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n"
2278c2ecf20Sopenharmony_ci		: "=&r" (r)
2288c2ecf20Sopenharmony_ci		: "r" (x)
2298c2ecf20Sopenharmony_ci		: "p0");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return r;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/*
2358c2ecf20Sopenharmony_ci * __ffs - find first bit in word.
2368c2ecf20Sopenharmony_ci * @word: The word to search
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * Undefined if no bit exists, so code should check against 0 first.
2398c2ecf20Sopenharmony_ci *
2408c2ecf20Sopenharmony_ci * bits_per_long assumed to be 32
2418c2ecf20Sopenharmony_ci * numbering starts at 0 I think (instead of 1 like ffs)
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic inline unsigned long __ffs(unsigned long word)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int num;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	asm("%0 = ct0(%1);\n"
2488c2ecf20Sopenharmony_ci		: "=&r" (num)
2498c2ecf20Sopenharmony_ci		: "r" (word));
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return num;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/*
2558c2ecf20Sopenharmony_ci * __fls - find last (most-significant) set bit in a long word
2568c2ecf20Sopenharmony_ci * @word: the word to search
2578c2ecf20Sopenharmony_ci *
2588c2ecf20Sopenharmony_ci * Undefined if no set bit exists, so code should check against 0 first.
2598c2ecf20Sopenharmony_ci * bits_per_long assumed to be 32
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_cistatic inline unsigned long __fls(unsigned long word)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	int num;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	asm("%0 = cl0(%1);\n"
2668c2ecf20Sopenharmony_ci		"%0 = sub(#31,%0);\n"
2678c2ecf20Sopenharmony_ci		: "=&r" (num)
2688c2ecf20Sopenharmony_ci		: "r" (word));
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return num;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci#include <asm-generic/bitops/lock.h>
2748c2ecf20Sopenharmony_ci#include <asm-generic/bitops/find.h>
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci#include <asm-generic/bitops/fls64.h>
2778c2ecf20Sopenharmony_ci#include <asm-generic/bitops/sched.h>
2788c2ecf20Sopenharmony_ci#include <asm-generic/bitops/hweight.h>
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci#include <asm-generic/bitops/le.h>
2818c2ecf20Sopenharmony_ci#include <asm-generic/bitops/ext2-atomic.h>
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci#endif /* __KERNEL__ */
2848c2ecf20Sopenharmony_ci#endif
285