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