#ifndef _ASM_M32R_ATOMIC_H1#define _ASM_M32R_ATOMIC_H23/*4* linux/include/asm-m32r/atomic.h5*6* M32R version:7* Copyright (C) 2001, 2002 Hitoshi Yamamoto8* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>9*/1011#include <linux/types.h>12#include <asm/assembler.h>13#include <asm/system.h>1415/*16* Atomic operations that C can't guarantee us. Useful for17* resource counting etc..18*/1920#define ATOMIC_INIT(i) { (i) }2122/**23* atomic_read - read atomic variable24* @v: pointer of type atomic_t25*26* Atomically reads the value of @v.27*/28#define atomic_read(v) (*(volatile int *)&(v)->counter)2930/**31* atomic_set - set atomic variable32* @v: pointer of type atomic_t33* @i: required value34*35* Atomically sets the value of @v to @i.36*/37#define atomic_set(v,i) (((v)->counter) = (i))3839/**40* atomic_add_return - add integer to atomic variable and return it41* @i: integer value to add42* @v: pointer of type atomic_t43*44* Atomically adds @i to @v and return (@i + @v).45*/46static __inline__ int atomic_add_return(int i, atomic_t *v)47{48unsigned long flags;49int result;5051local_irq_save(flags);52__asm__ __volatile__ (53"# atomic_add_return \n\t"54DCACHE_CLEAR("%0", "r4", "%1")55M32R_LOCK" %0, @%1; \n\t"56"add %0, %2; \n\t"57M32R_UNLOCK" %0, @%1; \n\t"58: "=&r" (result)59: "r" (&v->counter), "r" (i)60: "memory"61#ifdef CONFIG_CHIP_M32700_TS162, "r4"63#endif /* CONFIG_CHIP_M32700_TS1 */64);65local_irq_restore(flags);6667return result;68}6970/**71* atomic_sub_return - subtract integer from atomic variable and return it72* @i: integer value to subtract73* @v: pointer of type atomic_t74*75* Atomically subtracts @i from @v and return (@v - @i).76*/77static __inline__ int atomic_sub_return(int i, atomic_t *v)78{79unsigned long flags;80int result;8182local_irq_save(flags);83__asm__ __volatile__ (84"# atomic_sub_return \n\t"85DCACHE_CLEAR("%0", "r4", "%1")86M32R_LOCK" %0, @%1; \n\t"87"sub %0, %2; \n\t"88M32R_UNLOCK" %0, @%1; \n\t"89: "=&r" (result)90: "r" (&v->counter), "r" (i)91: "memory"92#ifdef CONFIG_CHIP_M32700_TS193, "r4"94#endif /* CONFIG_CHIP_M32700_TS1 */95);96local_irq_restore(flags);9798return result;99}100101/**102* atomic_add - add integer to atomic variable103* @i: integer value to add104* @v: pointer of type atomic_t105*106* Atomically adds @i to @v.107*/108#define atomic_add(i,v) ((void) atomic_add_return((i), (v)))109110/**111* atomic_sub - subtract the atomic variable112* @i: integer value to subtract113* @v: pointer of type atomic_t114*115* Atomically subtracts @i from @v.116*/117#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))118119/**120* atomic_sub_and_test - subtract value from variable and test result121* @i: integer value to subtract122* @v: pointer of type atomic_t123*124* Atomically subtracts @i from @v and returns125* true if the result is zero, or false for all126* other cases.127*/128#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)129130/**131* atomic_inc_return - increment atomic variable and return it132* @v: pointer of type atomic_t133*134* Atomically increments @v by 1 and returns the result.135*/136static __inline__ int atomic_inc_return(atomic_t *v)137{138unsigned long flags;139int result;140141local_irq_save(flags);142__asm__ __volatile__ (143"# atomic_inc_return \n\t"144DCACHE_CLEAR("%0", "r4", "%1")145M32R_LOCK" %0, @%1; \n\t"146"addi %0, #1; \n\t"147M32R_UNLOCK" %0, @%1; \n\t"148: "=&r" (result)149: "r" (&v->counter)150: "memory"151#ifdef CONFIG_CHIP_M32700_TS1152, "r4"153#endif /* CONFIG_CHIP_M32700_TS1 */154);155local_irq_restore(flags);156157return result;158}159160/**161* atomic_dec_return - decrement atomic variable and return it162* @v: pointer of type atomic_t163*164* Atomically decrements @v by 1 and returns the result.165*/166static __inline__ int atomic_dec_return(atomic_t *v)167{168unsigned long flags;169int result;170171local_irq_save(flags);172__asm__ __volatile__ (173"# atomic_dec_return \n\t"174DCACHE_CLEAR("%0", "r4", "%1")175M32R_LOCK" %0, @%1; \n\t"176"addi %0, #-1; \n\t"177M32R_UNLOCK" %0, @%1; \n\t"178: "=&r" (result)179: "r" (&v->counter)180: "memory"181#ifdef CONFIG_CHIP_M32700_TS1182, "r4"183#endif /* CONFIG_CHIP_M32700_TS1 */184);185local_irq_restore(flags);186187return result;188}189190/**191* atomic_inc - increment atomic variable192* @v: pointer of type atomic_t193*194* Atomically increments @v by 1.195*/196#define atomic_inc(v) ((void)atomic_inc_return(v))197198/**199* atomic_dec - decrement atomic variable200* @v: pointer of type atomic_t201*202* Atomically decrements @v by 1.203*/204#define atomic_dec(v) ((void)atomic_dec_return(v))205206/**207* atomic_inc_and_test - increment and test208* @v: pointer of type atomic_t209*210* Atomically increments @v by 1211* and returns true if the result is zero, or false for all212* other cases.213*/214#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)215216/**217* atomic_dec_and_test - decrement and test218* @v: pointer of type atomic_t219*220* Atomically decrements @v by 1 and221* returns true if the result is 0, or false for all222* other cases.223*/224#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)225226/**227* atomic_add_negative - add and test if negative228* @v: pointer of type atomic_t229* @i: integer value to add230*231* Atomically adds @i to @v and returns true232* if the result is negative, or false when233* result is greater than or equal to zero.234*/235#define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)236237#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))238#define atomic_xchg(v, new) (xchg(&((v)->counter), new))239240/**241* atomic_add_unless - add unless the number is a given value242* @v: pointer of type atomic_t243* @a: the amount to add to v...244* @u: ...unless v is equal to u.245*246* Atomically adds @a to @v, so long as it was not @u.247* Returns non-zero if @v was not @u, and zero otherwise.248*/249static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)250{251int c, old;252c = atomic_read(v);253for (;;) {254if (unlikely(c == (u)))255break;256old = atomic_cmpxchg((v), c, c + (a));257if (likely(old == c))258break;259c = old;260}261return c != (u);262}263264#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)265266static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr)267{268unsigned long flags;269unsigned long tmp;270271local_irq_save(flags);272__asm__ __volatile__ (273"# atomic_clear_mask \n\t"274DCACHE_CLEAR("%0", "r5", "%1")275M32R_LOCK" %0, @%1; \n\t"276"and %0, %2; \n\t"277M32R_UNLOCK" %0, @%1; \n\t"278: "=&r" (tmp)279: "r" (addr), "r" (~mask)280: "memory"281#ifdef CONFIG_CHIP_M32700_TS1282, "r5"283#endif /* CONFIG_CHIP_M32700_TS1 */284);285local_irq_restore(flags);286}287288static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr)289{290unsigned long flags;291unsigned long tmp;292293local_irq_save(flags);294__asm__ __volatile__ (295"# atomic_set_mask \n\t"296DCACHE_CLEAR("%0", "r5", "%1")297M32R_LOCK" %0, @%1; \n\t"298"or %0, %2; \n\t"299M32R_UNLOCK" %0, @%1; \n\t"300: "=&r" (tmp)301: "r" (addr), "r" (mask)302: "memory"303#ifdef CONFIG_CHIP_M32700_TS1304, "r5"305#endif /* CONFIG_CHIP_M32700_TS1 */306);307local_irq_restore(flags);308}309310/* Atomic operations are already serializing on m32r */311#define smp_mb__before_atomic_dec() barrier()312#define smp_mb__after_atomic_dec() barrier()313#define smp_mb__before_atomic_inc() barrier()314#define smp_mb__after_atomic_inc() barrier()315316#include <asm-generic/atomic-long.h>317#endif /* _ASM_M32R_ATOMIC_H */318319320