···11+/*22+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#ifndef _ASM_ARC_ATOMIC_H1010+#define _ASM_ARC_ATOMIC_H1111+1212+#ifdef __KERNEL__1313+1414+#ifndef __ASSEMBLY__1515+1616+#include <linux/types.h>1717+#include <linux/compiler.h>1818+#include <asm/cmpxchg.h>1919+#include <asm/barrier.h>2020+#include <asm/smp.h>2121+2222+#define atomic_read(v) ((v)->counter)2323+2424+#ifdef CONFIG_ARC_HAS_LLSC2525+2626+#define atomic_set(v, i) (((v)->counter) = (i))2727+2828+static inline void atomic_add(int i, atomic_t *v)2929+{3030+ unsigned int temp;3131+3232+ __asm__ __volatile__(3333+ "1: llock %0, [%1] \n"3434+ " add %0, %0, %2 \n"3535+ " scond %0, [%1] \n"3636+ " bnz 1b \n"3737+ : "=&r"(temp) /* Early clobber, to prevent reg reuse */3838+ : "r"(&v->counter), "ir"(i)3939+ : "cc");4040+}4141+4242+static inline void atomic_sub(int i, atomic_t *v)4343+{4444+ unsigned int temp;4545+4646+ __asm__ __volatile__(4747+ "1: llock %0, [%1] \n"4848+ " sub %0, %0, %2 \n"4949+ " scond %0, [%1] \n"5050+ " bnz 1b \n"5151+ : "=&r"(temp)5252+ : "r"(&v->counter), "ir"(i)5353+ : "cc");5454+}5555+5656+/* add and also return the new value */5757+static inline int atomic_add_return(int i, atomic_t *v)5858+{5959+ unsigned int temp;6060+6161+ __asm__ __volatile__(6262+ "1: llock %0, [%1] \n"6363+ " add %0, %0, %2 \n"6464+ " scond %0, [%1] \n"6565+ " bnz 1b \n"6666+ : "=&r"(temp)6767+ : "r"(&v->counter), "ir"(i)6868+ : "cc");6969+7070+ return temp;7171+}7272+7373+static inline int atomic_sub_return(int i, atomic_t *v)7474+{7575+ unsigned int temp;7676+7777+ __asm__ __volatile__(7878+ "1: llock %0, [%1] \n"7979+ " sub %0, %0, %2 \n"8080+ " scond %0, [%1] \n"8181+ " bnz 1b \n"8282+ : "=&r"(temp)8383+ : "r"(&v->counter), "ir"(i)8484+ : "cc");8585+8686+ return temp;8787+}8888+8989+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)9090+{9191+ unsigned int temp;9292+9393+ __asm__ __volatile__(9494+ "1: llock %0, [%1] \n"9595+ " bic %0, %0, %2 \n"9696+ " scond %0, [%1] \n"9797+ " bnz 1b \n"9898+ : "=&r"(temp)9999+ : "r"(addr), "ir"(mask)100100+ : "cc");101101+}102102+103103+#else /* !CONFIG_ARC_HAS_LLSC */104104+105105+#ifndef CONFIG_SMP106106+107107+ /* violating atomic_xxx API locking protocol in UP for optimization sake */108108+#define atomic_set(v, i) (((v)->counter) = (i))109109+110110+#else111111+112112+static inline void atomic_set(atomic_t *v, int i)113113+{114114+ /*115115+ * Independent of hardware support, all of the atomic_xxx() APIs need116116+ * to follow the same locking rules to make sure that a "hardware"117117+ * atomic insn (e.g. LD) doesn't clobber an "emulated" atomic insn118118+ * sequence119119+ *120120+ * Thus atomic_set() despite being 1 insn (and seemingly atomic)121121+ * requires the locking.122122+ */123123+ unsigned long flags;124124+125125+ atomic_ops_lock(flags);126126+ v->counter = i;127127+ atomic_ops_unlock(flags);128128+}129129+#endif130130+131131+/*132132+ * Non hardware assisted Atomic-R-M-W133133+ * Locking would change to irq-disabling only (UP) and spinlocks (SMP)134134+ */135135+136136+static inline void atomic_add(int i, atomic_t *v)137137+{138138+ unsigned long flags;139139+140140+ atomic_ops_lock(flags);141141+ v->counter += i;142142+ atomic_ops_unlock(flags);143143+}144144+145145+static inline void atomic_sub(int i, atomic_t *v)146146+{147147+ unsigned long flags;148148+149149+ atomic_ops_lock(flags);150150+ v->counter -= i;151151+ atomic_ops_unlock(flags);152152+}153153+154154+static inline int atomic_add_return(int i, atomic_t *v)155155+{156156+ unsigned long flags;157157+ unsigned long temp;158158+159159+ atomic_ops_lock(flags);160160+ temp = v->counter;161161+ temp += i;162162+ v->counter = temp;163163+ atomic_ops_unlock(flags);164164+165165+ return temp;166166+}167167+168168+static inline int atomic_sub_return(int i, atomic_t *v)169169+{170170+ unsigned long flags;171171+ unsigned long temp;172172+173173+ atomic_ops_lock(flags);174174+ temp = v->counter;175175+ temp -= i;176176+ v->counter = temp;177177+ atomic_ops_unlock(flags);178178+179179+ return temp;180180+}181181+182182+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)183183+{184184+ unsigned long flags;185185+186186+ atomic_ops_lock(flags);187187+ *addr &= ~mask;188188+ atomic_ops_unlock(flags);189189+}190190+191191+#endif /* !CONFIG_ARC_HAS_LLSC */192192+193193+/**194194+ * __atomic_add_unless - add unless the number is a given value195195+ * @v: pointer of type atomic_t196196+ * @a: the amount to add to v...197197+ * @u: ...unless v is equal to u.198198+ *199199+ * Atomically adds @a to @v, so long as it was not @u.200200+ * Returns the old value of @v201201+ */202202+#define __atomic_add_unless(v, a, u) \203203+({ \204204+ int c, old; \205205+ c = atomic_read(v); \206206+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c)\207207+ c = old; \208208+ c; \209209+})210210+211211+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)212212+213213+#define atomic_inc(v) atomic_add(1, v)214214+#define atomic_dec(v) atomic_sub(1, v)215215+216216+#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)217217+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)218218+#define atomic_inc_return(v) atomic_add_return(1, (v))219219+#define atomic_dec_return(v) atomic_sub_return(1, (v))220220+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)221221+222222+#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0)223223+224224+#define ATOMIC_INIT(i) { (i) }225225+226226+#include <asm-generic/atomic64.h>227227+228228+#endif229229+230230+#endif231231+232232+#endif
+42
arch/arc/include/asm/barrier.h
···11+/*22+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#ifndef __ASM_BARRIER_H1010+#define __ASM_BARRIER_H1111+1212+#ifndef __ASSEMBLY__1313+1414+/* TODO-vineetg: Need to see what this does, don't we need sync anywhere */1515+#define mb() __asm__ __volatile__ ("" : : : "memory")1616+#define rmb() mb()1717+#define wmb() mb()1818+#define set_mb(var, value) do { var = value; mb(); } while (0)1919+#define set_wmb(var, value) do { var = value; wmb(); } while (0)2020+#define read_barrier_depends() mb()2121+2222+/* TODO-vineetg verify the correctness of macros here */2323+#ifdef CONFIG_SMP2424+#define smp_mb() mb()2525+#define smp_rmb() rmb()2626+#define smp_wmb() wmb()2727+#else2828+#define smp_mb() barrier()2929+#define smp_rmb() barrier()3030+#define smp_wmb() barrier()3131+#endif3232+3333+#define smp_mb__before_atomic_dec() barrier()3434+#define smp_mb__after_atomic_dec() barrier()3535+#define smp_mb__before_atomic_inc() barrier()3636+#define smp_mb__after_atomic_inc() barrier()3737+3838+#define smp_read_barrier_depends() do { } while (0)3939+4040+#endif4141+4242+#endif
+516
arch/arc/include/asm/bitops.h
···11+/*22+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#ifndef _ASM_BITOPS_H1010+#define _ASM_BITOPS_H1111+1212+#ifndef _LINUX_BITOPS_H1313+#error only <linux/bitops.h> can be included directly1414+#endif1515+1616+#ifdef __KERNEL__1717+1818+#ifndef __ASSEMBLY__1919+2020+#include <linux/types.h>2121+#include <linux/compiler.h>2222+2323+/*2424+ * Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns.2525+ * The Kconfig glue ensures that in SMP, this is only set if the container2626+ * SoC/platform has cross-core coherent LLOCK/SCOND2727+ */2828+#if defined(CONFIG_ARC_HAS_LLSC)2929+3030+static inline void set_bit(unsigned long nr, volatile unsigned long *m)3131+{3232+ unsigned int temp;3333+3434+ m += nr >> 5;3535+3636+ if (__builtin_constant_p(nr))3737+ nr &= 0x1f;3838+3939+ __asm__ __volatile__(4040+ "1: llock %0, [%1] \n"4141+ " bset %0, %0, %2 \n"4242+ " scond %0, [%1] \n"4343+ " bnz 1b \n"4444+ : "=&r"(temp)4545+ : "r"(m), "ir"(nr)4646+ : "cc");4747+}4848+4949+static inline void clear_bit(unsigned long nr, volatile unsigned long *m)5050+{5151+ unsigned int temp;5252+5353+ m += nr >> 5;5454+5555+ if (__builtin_constant_p(nr))5656+ nr &= 0x1f;5757+5858+ __asm__ __volatile__(5959+ "1: llock %0, [%1] \n"6060+ " bclr %0, %0, %2 \n"6161+ " scond %0, [%1] \n"6262+ " bnz 1b \n"6363+ : "=&r"(temp)6464+ : "r"(m), "ir"(nr)6565+ : "cc");6666+}6767+6868+static inline void change_bit(unsigned long nr, volatile unsigned long *m)6969+{7070+ unsigned int temp;7171+7272+ m += nr >> 5;7373+7474+ if (__builtin_constant_p(nr))7575+ nr &= 0x1f;7676+7777+ __asm__ __volatile__(7878+ "1: llock %0, [%1] \n"7979+ " bxor %0, %0, %2 \n"8080+ " scond %0, [%1] \n"8181+ " bnz 1b \n"8282+ : "=&r"(temp)8383+ : "r"(m), "ir"(nr)8484+ : "cc");8585+}8686+8787+/*8888+ * Semantically:8989+ * Test the bit9090+ * if clear9191+ * set it and return 0 (old value)9292+ * else9393+ * return 1 (old value).9494+ *9595+ * Since ARC lacks a equivalent h/w primitive, the bit is set unconditionally9696+ * and the old value of bit is returned9797+ */9898+static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m)9999+{100100+ unsigned long old, temp;101101+102102+ m += nr >> 5;103103+104104+ if (__builtin_constant_p(nr))105105+ nr &= 0x1f;106106+107107+ __asm__ __volatile__(108108+ "1: llock %0, [%2] \n"109109+ " bset %1, %0, %3 \n"110110+ " scond %1, [%2] \n"111111+ " bnz 1b \n"112112+ : "=&r"(old), "=&r"(temp)113113+ : "r"(m), "ir"(nr)114114+ : "cc");115115+116116+ return (old & (1 << nr)) != 0;117117+}118118+119119+static inline int120120+test_and_clear_bit(unsigned long nr, volatile unsigned long *m)121121+{122122+ unsigned int old, temp;123123+124124+ m += nr >> 5;125125+126126+ if (__builtin_constant_p(nr))127127+ nr &= 0x1f;128128+129129+ __asm__ __volatile__(130130+ "1: llock %0, [%2] \n"131131+ " bclr %1, %0, %3 \n"132132+ " scond %1, [%2] \n"133133+ " bnz 1b \n"134134+ : "=&r"(old), "=&r"(temp)135135+ : "r"(m), "ir"(nr)136136+ : "cc");137137+138138+ return (old & (1 << nr)) != 0;139139+}140140+141141+static inline int142142+test_and_change_bit(unsigned long nr, volatile unsigned long *m)143143+{144144+ unsigned int old, temp;145145+146146+ m += nr >> 5;147147+148148+ if (__builtin_constant_p(nr))149149+ nr &= 0x1f;150150+151151+ __asm__ __volatile__(152152+ "1: llock %0, [%2] \n"153153+ " bxor %1, %0, %3 \n"154154+ " scond %1, [%2] \n"155155+ " bnz 1b \n"156156+ : "=&r"(old), "=&r"(temp)157157+ : "r"(m), "ir"(nr)158158+ : "cc");159159+160160+ return (old & (1 << nr)) != 0;161161+}162162+163163+#else /* !CONFIG_ARC_HAS_LLSC */164164+165165+#include <asm/smp.h>166166+167167+/*168168+ * Non hardware assisted Atomic-R-M-W169169+ * Locking would change to irq-disabling only (UP) and spinlocks (SMP)170170+ *171171+ * There's "significant" micro-optimization in writing our own variants of172172+ * bitops (over generic variants)173173+ *174174+ * (1) The generic APIs have "signed" @nr while we have it "unsigned"175175+ * This avoids extra code to be generated for pointer arithmatic, since176176+ * is "not sure" that index is NOT -ve177177+ * (2) Utilize the fact that ARCompact bit fidding insn (BSET/BCLR/ASL) etc178178+ * only consider bottom 5 bits of @nr, so NO need to mask them off.179179+ * (GCC Quirk: however for constant @nr we still need to do the masking180180+ * at compile time)181181+ */182182+183183+static inline void set_bit(unsigned long nr, volatile unsigned long *m)184184+{185185+ unsigned long temp, flags;186186+ m += nr >> 5;187187+188188+ if (__builtin_constant_p(nr))189189+ nr &= 0x1f;190190+191191+ bitops_lock(flags);192192+193193+ temp = *m;194194+ *m = temp | (1UL << nr);195195+196196+ bitops_unlock(flags);197197+}198198+199199+static inline void clear_bit(unsigned long nr, volatile unsigned long *m)200200+{201201+ unsigned long temp, flags;202202+ m += nr >> 5;203203+204204+ if (__builtin_constant_p(nr))205205+ nr &= 0x1f;206206+207207+ bitops_lock(flags);208208+209209+ temp = *m;210210+ *m = temp & ~(1UL << nr);211211+212212+ bitops_unlock(flags);213213+}214214+215215+static inline void change_bit(unsigned long nr, volatile unsigned long *m)216216+{217217+ unsigned long temp, flags;218218+ m += nr >> 5;219219+220220+ if (__builtin_constant_p(nr))221221+ nr &= 0x1f;222222+223223+ bitops_lock(flags);224224+225225+ temp = *m;226226+ *m = temp ^ (1UL << nr);227227+228228+ bitops_unlock(flags);229229+}230230+231231+static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m)232232+{233233+ unsigned long old, flags;234234+ m += nr >> 5;235235+236236+ if (__builtin_constant_p(nr))237237+ nr &= 0x1f;238238+239239+ bitops_lock(flags);240240+241241+ old = *m;242242+ *m = old | (1 << nr);243243+244244+ bitops_unlock(flags);245245+246246+ return (old & (1 << nr)) != 0;247247+}248248+249249+static inline int250250+test_and_clear_bit(unsigned long nr, volatile unsigned long *m)251251+{252252+ unsigned long old, flags;253253+ m += nr >> 5;254254+255255+ if (__builtin_constant_p(nr))256256+ nr &= 0x1f;257257+258258+ bitops_lock(flags);259259+260260+ old = *m;261261+ *m = old & ~(1 << nr);262262+263263+ bitops_unlock(flags);264264+265265+ return (old & (1 << nr)) != 0;266266+}267267+268268+static inline int269269+test_and_change_bit(unsigned long nr, volatile unsigned long *m)270270+{271271+ unsigned long old, flags;272272+ m += nr >> 5;273273+274274+ if (__builtin_constant_p(nr))275275+ nr &= 0x1f;276276+277277+ bitops_lock(flags);278278+279279+ old = *m;280280+ *m = old ^ (1 << nr);281281+282282+ bitops_unlock(flags);283283+284284+ return (old & (1 << nr)) != 0;285285+}286286+287287+#endif /* CONFIG_ARC_HAS_LLSC */288288+289289+/***************************************290290+ * Non atomic variants291291+ **************************************/292292+293293+static inline void __set_bit(unsigned long nr, volatile unsigned long *m)294294+{295295+ unsigned long temp;296296+ m += nr >> 5;297297+298298+ if (__builtin_constant_p(nr))299299+ nr &= 0x1f;300300+301301+ temp = *m;302302+ *m = temp | (1UL << nr);303303+}304304+305305+static inline void __clear_bit(unsigned long nr, volatile unsigned long *m)306306+{307307+ unsigned long temp;308308+ m += nr >> 5;309309+310310+ if (__builtin_constant_p(nr))311311+ nr &= 0x1f;312312+313313+ temp = *m;314314+ *m = temp & ~(1UL << nr);315315+}316316+317317+static inline void __change_bit(unsigned long nr, volatile unsigned long *m)318318+{319319+ unsigned long temp;320320+ m += nr >> 5;321321+322322+ if (__builtin_constant_p(nr))323323+ nr &= 0x1f;324324+325325+ temp = *m;326326+ *m = temp ^ (1UL << nr);327327+}328328+329329+static inline int330330+__test_and_set_bit(unsigned long nr, volatile unsigned long *m)331331+{332332+ unsigned long old;333333+ m += nr >> 5;334334+335335+ if (__builtin_constant_p(nr))336336+ nr &= 0x1f;337337+338338+ old = *m;339339+ *m = old | (1 << nr);340340+341341+ return (old & (1 << nr)) != 0;342342+}343343+344344+static inline int345345+__test_and_clear_bit(unsigned long nr, volatile unsigned long *m)346346+{347347+ unsigned long old;348348+ m += nr >> 5;349349+350350+ if (__builtin_constant_p(nr))351351+ nr &= 0x1f;352352+353353+ old = *m;354354+ *m = old & ~(1 << nr);355355+356356+ return (old & (1 << nr)) != 0;357357+}358358+359359+static inline int360360+__test_and_change_bit(unsigned long nr, volatile unsigned long *m)361361+{362362+ unsigned long old;363363+ m += nr >> 5;364364+365365+ if (__builtin_constant_p(nr))366366+ nr &= 0x1f;367367+368368+ old = *m;369369+ *m = old ^ (1 << nr);370370+371371+ return (old & (1 << nr)) != 0;372372+}373373+374374+/*375375+ * This routine doesn't need to be atomic.376376+ */377377+static inline int378378+__constant_test_bit(unsigned int nr, const volatile unsigned long *addr)379379+{380380+ return ((1UL << (nr & 31)) &381381+ (((const volatile unsigned int *)addr)[nr >> 5])) != 0;382382+}383383+384384+static inline int385385+__test_bit(unsigned int nr, const volatile unsigned long *addr)386386+{387387+ unsigned long mask;388388+389389+ addr += nr >> 5;390390+391391+ /* ARC700 only considers 5 bits in bit-fiddling insn */392392+ mask = 1 << nr;393393+394394+ return ((mask & *addr) != 0);395395+}396396+397397+#define test_bit(nr, addr) (__builtin_constant_p(nr) ? \398398+ __constant_test_bit((nr), (addr)) : \399399+ __test_bit((nr), (addr)))400400+401401+/*402402+ * Count the number of zeros, starting from MSB403403+ * Helper for fls( ) friends404404+ * This is a pure count, so (1-32) or (0-31) doesn't apply405405+ * It could be 0 to 32, based on num of 0's in there406406+ * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31407407+ */408408+static inline __attribute__ ((const)) int clz(unsigned int x)409409+{410410+ unsigned int res;411411+412412+ __asm__ __volatile__(413413+ " norm.f %0, %1 \n"414414+ " mov.n %0, 0 \n"415415+ " add.p %0, %0, 1 \n"416416+ : "=r"(res)417417+ : "r"(x)418418+ : "cc");419419+420420+ return res;421421+}422422+423423+static inline int constant_fls(int x)424424+{425425+ int r = 32;426426+427427+ if (!x)428428+ return 0;429429+ if (!(x & 0xffff0000u)) {430430+ x <<= 16;431431+ r -= 16;432432+ }433433+ if (!(x & 0xff000000u)) {434434+ x <<= 8;435435+ r -= 8;436436+ }437437+ if (!(x & 0xf0000000u)) {438438+ x <<= 4;439439+ r -= 4;440440+ }441441+ if (!(x & 0xc0000000u)) {442442+ x <<= 2;443443+ r -= 2;444444+ }445445+ if (!(x & 0x80000000u)) {446446+ x <<= 1;447447+ r -= 1;448448+ }449449+ return r;450450+}451451+452452+/*453453+ * fls = Find Last Set in word454454+ * @result: [1-32]455455+ * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0456456+ */457457+static inline __attribute__ ((const)) int fls(unsigned long x)458458+{459459+ if (__builtin_constant_p(x))460460+ return constant_fls(x);461461+462462+ return 32 - clz(x);463463+}464464+465465+/*466466+ * __fls: Similar to fls, but zero based (0-31)467467+ */468468+static inline __attribute__ ((const)) int __fls(unsigned long x)469469+{470470+ if (!x)471471+ return 0;472472+ else473473+ return fls(x) - 1;474474+}475475+476476+/*477477+ * ffs = Find First Set in word (LSB to MSB)478478+ * @result: [1-32], 0 if all 0's479479+ */480480+#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })481481+482482+/*483483+ * __ffs: Similar to ffs, but zero based (0-31)484484+ */485485+static inline __attribute__ ((const)) int __ffs(unsigned long word)486486+{487487+ if (!word)488488+ return word;489489+490490+ return ffs(word) - 1;491491+}492492+493493+/*494494+ * ffz = Find First Zero in word.495495+ * @return:[0-31], 32 if all 1's496496+ */497497+#define ffz(x) __ffs(~(x))498498+499499+/* TODO does this affect uni-processor code */500500+#define smp_mb__before_clear_bit() barrier()501501+#define smp_mb__after_clear_bit() barrier()502502+503503+#include <asm-generic/bitops/hweight.h>504504+#include <asm-generic/bitops/fls64.h>505505+#include <asm-generic/bitops/sched.h>506506+#include <asm-generic/bitops/lock.h>507507+508508+#include <asm-generic/bitops/find.h>509509+#include <asm-generic/bitops/le.h>510510+#include <asm-generic/bitops/ext2-atomic-setbit.h>511511+512512+#endif /* !__ASSEMBLY__ */513513+514514+#endif /* __KERNEL__ */515515+516516+#endif
+143
arch/arc/include/asm/cmpxchg.h
···11+/*22+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#ifndef __ASM_ARC_CMPXCHG_H1010+#define __ASM_ARC_CMPXCHG_H1111+1212+#include <linux/types.h>1313+#include <asm/smp.h>1414+1515+#ifdef CONFIG_ARC_HAS_LLSC1616+1717+static inline unsigned long1818+__cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)1919+{2020+ unsigned long prev;2121+2222+ __asm__ __volatile__(2323+ "1: llock %0, [%1] \n"2424+ " brne %0, %2, 2f \n"2525+ " scond %3, [%1] \n"2626+ " bnz 1b \n"2727+ "2: \n"2828+ : "=&r"(prev)2929+ : "r"(ptr), "ir"(expected),3030+ "r"(new) /* can't be "ir". scond can't take limm for "b" */3131+ : "cc");3232+3333+ return prev;3434+}3535+3636+#else3737+3838+static inline unsigned long3939+__cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)4040+{4141+ unsigned long flags;4242+ int prev;4343+ volatile unsigned long *p = ptr;4444+4545+ atomic_ops_lock(flags);4646+ prev = *p;4747+ if (prev == expected)4848+ *p = new;4949+ atomic_ops_unlock(flags);5050+ return prev;5151+}5252+5353+#endif /* CONFIG_ARC_HAS_LLSC */5454+5555+#define cmpxchg(ptr, o, n) ((typeof(*(ptr)))__cmpxchg((ptr), \5656+ (unsigned long)(o), (unsigned long)(n)))5757+5858+/*5959+ * Since not supported natively, ARC cmpxchg() uses atomic_ops_lock (UP/SMP)6060+ * just to gaurantee semantics.6161+ * atomic_cmpxchg() needs to use the same locks as it's other atomic siblings6262+ * which also happens to be atomic_ops_lock.6363+ *6464+ * Thus despite semantically being different, implementation of atomic_cmpxchg()6565+ * is same as cmpxchg().6666+ */6767+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))6868+6969+7070+/*7171+ * xchg (reg with memory) based on "Native atomic" EX insn7272+ */7373+static inline unsigned long __xchg(unsigned long val, volatile void *ptr,7474+ int size)7575+{7676+ extern unsigned long __xchg_bad_pointer(void);7777+7878+ switch (size) {7979+ case 4:8080+ __asm__ __volatile__(8181+ " ex %0, [%1] \n"8282+ : "+r"(val)8383+ : "r"(ptr)8484+ : "memory");8585+8686+ return val;8787+ }8888+ return __xchg_bad_pointer();8989+}9090+9191+#define _xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \9292+ sizeof(*(ptr))))9393+9494+/*9595+ * On ARC700, EX insn is inherently atomic, so by default "vanilla" xchg() need9696+ * not require any locking. However there's a quirk.9797+ * ARC lacks native CMPXCHG, thus emulated (see above), using external locking -9898+ * incidently it "reuses" the same atomic_ops_lock used by atomic APIs.9999+ * Now, llist code uses cmpxchg() and xchg() on same data, so xchg() needs to100100+ * abide by same serializing rules, thus ends up using atomic_ops_lock as well.101101+ *102102+ * This however is only relevant if SMP and/or ARC lacks LLSC103103+ * if (UP or LLSC)104104+ * xchg doesn't need serialization105105+ * else <==> !(UP or LLSC) <==> (!UP and !LLSC) <==> (SMP and !LLSC)106106+ * xchg needs serialization107107+ */108108+109109+#if !defined(CONFIG_ARC_HAS_LLSC) && defined(CONFIG_SMP)110110+111111+#define xchg(ptr, with) \112112+({ \113113+ unsigned long flags; \114114+ typeof(*(ptr)) old_val; \115115+ \116116+ atomic_ops_lock(flags); \117117+ old_val = _xchg(ptr, with); \118118+ atomic_ops_unlock(flags); \119119+ old_val; \120120+})121121+122122+#else123123+124124+#define xchg(ptr, with) _xchg(ptr, with)125125+126126+#endif127127+128128+/*129129+ * "atomic" variant of xchg()130130+ * REQ: It needs to follow the same serialization rules as other atomic_xxx()131131+ * Since xchg() doesn't always do that, it would seem that following defintion132132+ * is incorrect. But here's the rationale:133133+ * SMP : Even xchg() takes the atomic_ops_lock, so OK.134134+ * LLSC: atomic_ops_lock are not relevent at all (even if SMP, since LLSC135135+ * is natively "SMP safe", no serialization required).136136+ * UP : other atomics disable IRQ, so no way a difft ctxt atomic_xchg()137137+ * could clobber them. atomic_xchg() itself would be 1 insn, so it138138+ * can't be clobbered by others. Thus no serialization required when139139+ * atomic_xchg is involved.140140+ */141141+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))142142+143143+#endif
+34
arch/arc/include/asm/smp.h
···11+/*22+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#ifndef __ASM_ARC_SMP_H1010+#define __ASM_ARC_SMP_H1111+1212+/*1313+ * ARC700 doesn't support atomic Read-Modify-Write ops.1414+ * Originally Interrupts had to be disabled around code to gaurantee atomicity.1515+ * The LLOCK/SCOND insns allow writing interrupt-hassle-free based atomic ops1616+ * based on retry-if-irq-in-atomic (with hardware assist).1717+ * However despite these, we provide the IRQ disabling variant1818+ *1919+ * (1) These insn were introduced only in 4.10 release. So for older released2020+ * support needed.2121+ */2222+#ifndef CONFIG_ARC_HAS_LLSC2323+2424+#include <linux/irqflags.h>2525+2626+#define atomic_ops_lock(flags) local_irq_save(flags)2727+#define atomic_ops_unlock(flags) local_irq_restore(flags)2828+2929+#define bitops_lock(flags) local_irq_save(flags)3030+#define bitops_unlock(flags) local_irq_restore(flags)3131+3232+#endif /* !CONFIG_ARC_HAS_LLSC */3333+3434+#endif