#ifndef __M32R_LOCAL_H1#define __M32R_LOCAL_H23/*4* linux/include/asm-m32r/local.h5*6* M32R version:7* Copyright (C) 2001, 2002 Hitoshi Yamamoto8* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>9* Copyright (C) 2007 Mathieu Desnoyers <[email protected]>10*/1112#include <linux/percpu.h>13#include <asm/assembler.h>14#include <asm/system.h>15#include <asm/local.h>1617/*18* Atomic operations that C can't guarantee us. Useful for19* resource counting etc..20*/2122/*23* Make sure gcc doesn't try to be clever and move things around24* on us. We need to use _exactly_ the address the user gave us,25* not some alias that contains the same information.26*/27typedef struct { volatile int counter; } local_t;2829#define LOCAL_INIT(i) { (i) }3031/**32* local_read - read local variable33* @l: pointer of type local_t34*35* Atomically reads the value of @l.36*/37#define local_read(l) ((l)->counter)3839/**40* local_set - set local variable41* @l: pointer of type local_t42* @i: required value43*44* Atomically sets the value of @l to @i.45*/46#define local_set(l, i) (((l)->counter) = (i))4748/**49* local_add_return - add long to local variable and return it50* @i: long value to add51* @l: pointer of type local_t52*53* Atomically adds @i to @l and return (@i + @l).54*/55static inline long local_add_return(long i, local_t *l)56{57unsigned long flags;58long result;5960local_irq_save(flags);61__asm__ __volatile__ (62"# local_add_return \n\t"63DCACHE_CLEAR("%0", "r4", "%1")64"ld %0, @%1; \n\t"65"add %0, %2; \n\t"66"st %0, @%1; \n\t"67: "=&r" (result)68: "r" (&l->counter), "r" (i)69: "memory"70#ifdef CONFIG_CHIP_M32700_TS171, "r4"72#endif /* CONFIG_CHIP_M32700_TS1 */73);74local_irq_restore(flags);7576return result;77}7879/**80* local_sub_return - subtract long from local variable and return it81* @i: long value to subtract82* @l: pointer of type local_t83*84* Atomically subtracts @i from @l and return (@l - @i).85*/86static inline long local_sub_return(long i, local_t *l)87{88unsigned long flags;89long result;9091local_irq_save(flags);92__asm__ __volatile__ (93"# local_sub_return \n\t"94DCACHE_CLEAR("%0", "r4", "%1")95"ld %0, @%1; \n\t"96"sub %0, %2; \n\t"97"st %0, @%1; \n\t"98: "=&r" (result)99: "r" (&l->counter), "r" (i)100: "memory"101#ifdef CONFIG_CHIP_M32700_TS1102, "r4"103#endif /* CONFIG_CHIP_M32700_TS1 */104);105local_irq_restore(flags);106107return result;108}109110/**111* local_add - add long to local variable112* @i: long value to add113* @l: pointer of type local_t114*115* Atomically adds @i to @l.116*/117#define local_add(i, l) ((void) local_add_return((i), (l)))118119/**120* local_sub - subtract the local variable121* @i: long value to subtract122* @l: pointer of type local_t123*124* Atomically subtracts @i from @l.125*/126#define local_sub(i, l) ((void) local_sub_return((i), (l)))127128/**129* local_sub_and_test - subtract value from variable and test result130* @i: integer value to subtract131* @l: pointer of type local_t132*133* Atomically subtracts @i from @l and returns134* true if the result is zero, or false for all135* other cases.136*/137#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)138139/**140* local_inc_return - increment local variable and return it141* @l: pointer of type local_t142*143* Atomically increments @l by 1 and returns the result.144*/145static inline long local_inc_return(local_t *l)146{147unsigned long flags;148long result;149150local_irq_save(flags);151__asm__ __volatile__ (152"# local_inc_return \n\t"153DCACHE_CLEAR("%0", "r4", "%1")154"ld %0, @%1; \n\t"155"addi %0, #1; \n\t"156"st %0, @%1; \n\t"157: "=&r" (result)158: "r" (&l->counter)159: "memory"160#ifdef CONFIG_CHIP_M32700_TS1161, "r4"162#endif /* CONFIG_CHIP_M32700_TS1 */163);164local_irq_restore(flags);165166return result;167}168169/**170* local_dec_return - decrement local variable and return it171* @l: pointer of type local_t172*173* Atomically decrements @l by 1 and returns the result.174*/175static inline long local_dec_return(local_t *l)176{177unsigned long flags;178long result;179180local_irq_save(flags);181__asm__ __volatile__ (182"# local_dec_return \n\t"183DCACHE_CLEAR("%0", "r4", "%1")184"ld %0, @%1; \n\t"185"addi %0, #-1; \n\t"186"st %0, @%1; \n\t"187: "=&r" (result)188: "r" (&l->counter)189: "memory"190#ifdef CONFIG_CHIP_M32700_TS1191, "r4"192#endif /* CONFIG_CHIP_M32700_TS1 */193);194local_irq_restore(flags);195196return result;197}198199/**200* local_inc - increment local variable201* @l: pointer of type local_t202*203* Atomically increments @l by 1.204*/205#define local_inc(l) ((void)local_inc_return(l))206207/**208* local_dec - decrement local variable209* @l: pointer of type local_t210*211* Atomically decrements @l by 1.212*/213#define local_dec(l) ((void)local_dec_return(l))214215/**216* local_inc_and_test - increment and test217* @l: pointer of type local_t218*219* Atomically increments @l by 1220* and returns true if the result is zero, or false for all221* other cases.222*/223#define local_inc_and_test(l) (local_inc_return(l) == 0)224225/**226* local_dec_and_test - decrement and test227* @l: pointer of type local_t228*229* Atomically decrements @l by 1 and230* returns true if the result is 0, or false for all231* other cases.232*/233#define local_dec_and_test(l) (local_dec_return(l) == 0)234235/**236* local_add_negative - add and test if negative237* @l: pointer of type local_t238* @i: integer value to add239*240* Atomically adds @i to @l and returns true241* if the result is negative, or false when242* result is greater than or equal to zero.243*/244#define local_add_negative(i, l) (local_add_return((i), (l)) < 0)245246#define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))247#define local_xchg(v, new) (xchg_local(&((l)->counter), new))248249/**250* local_add_unless - add unless the number is a given value251* @l: pointer of type local_t252* @a: the amount to add to l...253* @u: ...unless l is equal to u.254*255* Atomically adds @a to @l, so long as it was not @u.256* Returns non-zero if @l was not @u, and zero otherwise.257*/258static inline int local_add_unless(local_t *l, long a, long u)259{260long c, old;261c = local_read(l);262for (;;) {263if (unlikely(c == (u)))264break;265old = local_cmpxchg((l), c, c + (a));266if (likely(old == c))267break;268c = old;269}270return c != (u);271}272273#define local_inc_not_zero(l) local_add_unless((l), 1, 0)274275static inline void local_clear_mask(unsigned long mask, local_t *addr)276{277unsigned long flags;278unsigned long tmp;279280local_irq_save(flags);281__asm__ __volatile__ (282"# local_clear_mask \n\t"283DCACHE_CLEAR("%0", "r5", "%1")284"ld %0, @%1; \n\t"285"and %0, %2; \n\t"286"st %0, @%1; \n\t"287: "=&r" (tmp)288: "r" (addr), "r" (~mask)289: "memory"290#ifdef CONFIG_CHIP_M32700_TS1291, "r5"292#endif /* CONFIG_CHIP_M32700_TS1 */293);294local_irq_restore(flags);295}296297static inline void local_set_mask(unsigned long mask, local_t *addr)298{299unsigned long flags;300unsigned long tmp;301302local_irq_save(flags);303__asm__ __volatile__ (304"# local_set_mask \n\t"305DCACHE_CLEAR("%0", "r5", "%1")306"ld %0, @%1; \n\t"307"or %0, %2; \n\t"308"st %0, @%1; \n\t"309: "=&r" (tmp)310: "r" (addr), "r" (mask)311: "memory"312#ifdef CONFIG_CHIP_M32700_TS1313, "r5"314#endif /* CONFIG_CHIP_M32700_TS1 */315);316local_irq_restore(flags);317}318319/* Atomic operations are already serializing on m32r */320#define smp_mb__before_local_dec() barrier()321#define smp_mb__after_local_dec() barrier()322#define smp_mb__before_local_inc() barrier()323#define smp_mb__after_local_inc() barrier()324325/* Use these for per-cpu local_t variables: on some archs they are326* much more efficient than these naive implementations. Note they take327* a variable, not an address.328*/329330#define __local_inc(l) ((l)->a.counter++)331#define __local_dec(l) ((l)->a.counter++)332#define __local_add(i, l) ((l)->a.counter += (i))333#define __local_sub(i, l) ((l)->a.counter -= (i))334335/* Use these for per-cpu local_t variables: on some archs they are336* much more efficient than these naive implementations. Note they take337* a variable, not an address.338*/339340#endif /* __M32R_LOCAL_H */341342343