linux/include/asm-generic/cmpxchg-local.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H
   3#define __ASM_GENERIC_CMPXCHG_LOCAL_H
   4
   5#include <linux/types.h>
   6#include <linux/irqflags.h>
   7
   8extern unsigned long wrong_size_cmpxchg(volatile void *ptr)
   9        __noreturn;
  10
  11/*
  12 * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned
  13 * long parameter, supporting various types of architectures.
  14 */
  15static inline unsigned long __cmpxchg_local_generic(volatile void *ptr,
  16                unsigned long old, unsigned long new, int size)
  17{
  18        unsigned long flags, prev;
  19
  20        /*
  21         * Sanity checking, compile-time.
  22         */
  23        if (size == 8 && sizeof(unsigned long) != 8)
  24                wrong_size_cmpxchg(ptr);
  25
  26        raw_local_irq_save(flags);
  27        switch (size) {
  28        case 1: prev = *(u8 *)ptr;
  29                if (prev == old)
  30                        *(u8 *)ptr = (u8)new;
  31                break;
  32        case 2: prev = *(u16 *)ptr;
  33                if (prev == old)
  34                        *(u16 *)ptr = (u16)new;
  35                break;
  36        case 4: prev = *(u32 *)ptr;
  37                if (prev == old)
  38                        *(u32 *)ptr = (u32)new;
  39                break;
  40        case 8: prev = *(u64 *)ptr;
  41                if (prev == old)
  42                        *(u64 *)ptr = (u64)new;
  43                break;
  44        default:
  45                wrong_size_cmpxchg(ptr);
  46        }
  47        raw_local_irq_restore(flags);
  48        return prev;
  49}
  50
  51/*
  52 * Generic version of __cmpxchg64_local. Takes an u64 parameter.
  53 */
  54static inline u64 __cmpxchg64_local_generic(volatile void *ptr,
  55                u64 old, u64 new)
  56{
  57        u64 prev;
  58        unsigned long flags;
  59
  60        raw_local_irq_save(flags);
  61        prev = *(u64 *)ptr;
  62        if (prev == old)
  63                *(u64 *)ptr = new;
  64        raw_local_irq_restore(flags);
  65        return prev;
  66}
  67
  68#endif
  69