linux/arch/hexagon/include/asm/bitops.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Bit operations for the Hexagon architecture
   4 *
   5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
   6 */
   7
   8#ifndef _ASM_BITOPS_H
   9#define _ASM_BITOPS_H
  10
  11#include <linux/compiler.h>
  12#include <asm/byteorder.h>
  13#include <asm/atomic.h>
  14#include <asm/barrier.h>
  15
  16#ifdef __KERNEL__
  17
  18/*
  19 * The offset calculations for these are based on BITS_PER_LONG == 32
  20 * (i.e. I get to shift by #5-2 (32 bits per long, 4 bytes per access),
  21 * mask by 0x0000001F)
  22 *
  23 * Typically, R10 is clobbered for address, R11 bit nr, and R12 is temp
  24 */
  25
  26/**
  27 * test_and_clear_bit - clear a bit and return its old value
  28 * @nr:  bit number to clear
  29 * @addr:  pointer to memory
  30 */
  31static inline int test_and_clear_bit(int nr, volatile void *addr)
  32{
  33        int oldval;
  34
  35        __asm__ __volatile__ (
  36        "       {R10 = %1; R11 = asr(%2,#5); }\n"
  37        "       {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
  38        "1:     R12 = memw_locked(R10);\n"
  39        "       { P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n"
  40        "       memw_locked(R10,P1) = R12;\n"
  41        "       {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
  42        : "=&r" (oldval)
  43        : "r" (addr), "r" (nr)
  44        : "r10", "r11", "r12", "p0", "p1", "memory"
  45        );
  46
  47        return oldval;
  48}
  49
  50/**
  51 * test_and_set_bit - set a bit and return its old value
  52 * @nr:  bit number to set
  53 * @addr:  pointer to memory
  54 */
  55static inline int test_and_set_bit(int nr, volatile void *addr)
  56{
  57        int oldval;
  58
  59        __asm__ __volatile__ (
  60        "       {R10 = %1; R11 = asr(%2,#5); }\n"
  61        "       {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
  62        "1:     R12 = memw_locked(R10);\n"
  63        "       { P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n"
  64        "       memw_locked(R10,P1) = R12;\n"
  65        "       {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
  66        : "=&r" (oldval)
  67        : "r" (addr), "r" (nr)
  68        : "r10", "r11", "r12", "p0", "p1", "memory"
  69        );
  70
  71
  72        return oldval;
  73
  74}
  75
  76/**
  77 * test_and_change_bit - toggle a bit and return its old value
  78 * @nr:  bit number to set
  79 * @addr:  pointer to memory
  80 */
  81static inline int test_and_change_bit(int nr, volatile void *addr)
  82{
  83        int oldval;
  84
  85        __asm__ __volatile__ (
  86        "       {R10 = %1; R11 = asr(%2,#5); }\n"
  87        "       {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
  88        "1:     R12 = memw_locked(R10);\n"
  89        "       { P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n"
  90        "       memw_locked(R10,P1) = R12;\n"
  91        "       {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
  92        : "=&r" (oldval)
  93        : "r" (addr), "r" (nr)
  94        : "r10", "r11", "r12", "p0", "p1", "memory"
  95        );
  96
  97        return oldval;
  98
  99}
 100
 101/*
 102 * Atomic, but doesn't care about the return value.
 103 * Rewrite later to save a cycle or two.
 104 */
 105
 106static inline void clear_bit(int nr, volatile void *addr)
 107{
 108        test_and_clear_bit(nr, addr);
 109}
 110
 111static inline void set_bit(int nr, volatile void *addr)
 112{
 113        test_and_set_bit(nr, addr);
 114}
 115
 116static inline void change_bit(int nr, volatile void *addr)
 117{
 118        test_and_change_bit(nr, addr);
 119}
 120
 121
 122/*
 123 * These are allowed to be non-atomic.  In fact the generic flavors are
 124 * in non-atomic.h.  Would it be better to use intrinsics for this?
 125 *
 126 * OK, writes in our architecture do not invalidate LL/SC, so this has to
 127 * be atomic, particularly for things like slab_lock and slab_unlock.
 128 *
 129 */
 130static inline void __clear_bit(int nr, volatile unsigned long *addr)
 131{
 132        test_and_clear_bit(nr, addr);
 133}
 134
 135static inline void __set_bit(int nr, volatile unsigned long *addr)
 136{
 137        test_and_set_bit(nr, addr);
 138}
 139
 140static inline void __change_bit(int nr, volatile unsigned long *addr)
 141{
 142        test_and_change_bit(nr, addr);
 143}
 144
 145/*  Apparently, at least some of these are allowed to be non-atomic  */
 146static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 147{
 148        return test_and_clear_bit(nr, addr);
 149}
 150
 151static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
 152{
 153        return test_and_set_bit(nr, addr);
 154}
 155
 156static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
 157{
 158        return test_and_change_bit(nr, addr);
 159}
 160
 161static inline int __test_bit(int nr, const volatile unsigned long *addr)
 162{
 163        int retval;
 164
 165        asm volatile(
 166        "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n"
 167        : "=&r" (retval)
 168        : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG)
 169        : "p0"
 170        );
 171
 172        return retval;
 173}
 174
 175#define test_bit(nr, addr) __test_bit(nr, addr)
 176
 177/*
 178 * ffz - find first zero in word.
 179 * @word: The word to search
 180 *
 181 * Undefined if no zero exists, so code should check against ~0UL first.
 182 */
 183static inline long ffz(int x)
 184{
 185        int r;
 186
 187        asm("%0 = ct1(%1);\n"
 188                : "=&r" (r)
 189                : "r" (x));
 190        return r;
 191}
 192
 193/*
 194 * fls - find last (most-significant) bit set
 195 * @x: the word to search
 196 *
 197 * This is defined the same way as ffs.
 198 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
 199 */
 200static inline int fls(unsigned int x)
 201{
 202        int r;
 203
 204        asm("{ %0 = cl0(%1);}\n"
 205                "%0 = sub(#32,%0);\n"
 206                : "=&r" (r)
 207                : "r" (x)
 208                : "p0");
 209
 210        return r;
 211}
 212
 213/*
 214 * ffs - find first bit set
 215 * @x: the word to search
 216 *
 217 * This is defined the same way as
 218 * the libc and compiler builtin ffs routines, therefore
 219 * differs in spirit from the above ffz (man ffs).
 220 */
 221static inline int ffs(int x)
 222{
 223        int r;
 224
 225        asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n"
 226                "{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n"
 227                : "=&r" (r)
 228                : "r" (x)
 229                : "p0");
 230
 231        return r;
 232}
 233
 234/*
 235 * __ffs - find first bit in word.
 236 * @word: The word to search
 237 *
 238 * Undefined if no bit exists, so code should check against 0 first.
 239 *
 240 * bits_per_long assumed to be 32
 241 * numbering starts at 0 I think (instead of 1 like ffs)
 242 */
 243static inline unsigned long __ffs(unsigned long word)
 244{
 245        int num;
 246
 247        asm("%0 = ct0(%1);\n"
 248                : "=&r" (num)
 249                : "r" (word));
 250
 251        return num;
 252}
 253
 254/*
 255 * __fls - find last (most-significant) set bit in a long word
 256 * @word: the word to search
 257 *
 258 * Undefined if no set bit exists, so code should check against 0 first.
 259 * bits_per_long assumed to be 32
 260 */
 261static inline unsigned long __fls(unsigned long word)
 262{
 263        int num;
 264
 265        asm("%0 = cl0(%1);\n"
 266                "%0 = sub(#31,%0);\n"
 267                : "=&r" (num)
 268                : "r" (word));
 269
 270        return num;
 271}
 272
 273#include <asm-generic/bitops/lock.h>
 274#include <asm-generic/bitops/find.h>
 275
 276#include <asm-generic/bitops/fls64.h>
 277#include <asm-generic/bitops/sched.h>
 278#include <asm-generic/bitops/hweight.h>
 279
 280#include <asm-generic/bitops/le.h>
 281#include <asm-generic/bitops/ext2-atomic.h>
 282
 283#endif /* __KERNEL__ */
 284#endif
 285