···11+/*22+ * Atomic operations for the Hexagon architecture33+ *44+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.55+ *66+ *77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License version 2 and99+ * only version 2 as published by the Free Software Foundation.1010+ *1111+ * This program is distributed in the hope that it will be useful,1212+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1414+ * GNU General Public License for more details.1515+ *1616+ * You should have received a copy of the GNU General Public License1717+ * along with this program; if not, write to the Free Software1818+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA1919+ * 02110-1301, USA.2020+ */2121+2222+#ifndef _ASM_ATOMIC_H2323+#define _ASM_ATOMIC_H2424+2525+#include <linux/types.h>2626+2727+#define ATOMIC_INIT(i) { (i) }2828+#define atomic_set(v, i) ((v)->counter = (i))2929+3030+/**3131+ * atomic_read - reads a word, atomically3232+ * @v: pointer to atomic value3333+ *3434+ * Assumes all word reads on our architecture are atomic.3535+ */3636+#define atomic_read(v) ((v)->counter)3737+3838+/**3939+ * atomic_xchg - atomic4040+ * @v: pointer to memory to change4141+ * @new: new value (technically passed in a register -- see xchg)4242+ */4343+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))4444+4545+4646+/**4747+ * atomic_cmpxchg - atomic compare-and-exchange values4848+ * @v: pointer to value to change4949+ * @old: desired old value to match5050+ * @new: new value to put in5151+ *5252+ * Parameters are then pointer, value-in-register, value-in-register,5353+ * and the output is the old value.5454+ *5555+ * Apparently this is complicated for archs that don't support5656+ * the memw_locked like we do (or it's broken or whatever).5757+ *5858+ * Kind of the lynchpin of the rest of the generically defined routines.5959+ * Remember V2 had that bug with dotnew predicate set by memw_locked.6060+ *6161+ * "old" is "expected" old val, __oldval is actual old value6262+ */6363+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)6464+{6565+ int __oldval;6666+6767+ asm volatile(6868+ "1: %0 = memw_locked(%1);\n"6969+ " { P0 = cmp.eq(%0,%2);\n"7070+ " if (!P0.new) jump:nt 2f; }\n"7171+ " memw_locked(%1,P0) = %3;\n"7272+ " if (!P0) jump 1b;\n"7373+ "2:\n"7474+ : "=&r" (__oldval)7575+ : "r" (&v->counter), "r" (old), "r" (new)7676+ : "memory", "p0"7777+ );7878+7979+ return __oldval;8080+}8181+8282+static inline int atomic_add_return(int i, atomic_t *v)8383+{8484+ int output;8585+8686+ __asm__ __volatile__ (8787+ "1: %0 = memw_locked(%1);\n"8888+ " %0 = add(%0,%2);\n"8989+ " memw_locked(%1,P3)=%0;\n"9090+ " if !P3 jump 1b;\n"9191+ : "=&r" (output)9292+ : "r" (&v->counter), "r" (i)9393+ : "memory", "p3"9494+ );9595+ return output;9696+9797+}9898+9999+#define atomic_add(i, v) atomic_add_return(i, (v))100100+101101+static inline int atomic_sub_return(int i, atomic_t *v)102102+{103103+ int output;104104+ __asm__ __volatile__ (105105+ "1: %0 = memw_locked(%1);\n"106106+ " %0 = sub(%0,%2);\n"107107+ " memw_locked(%1,P3)=%0\n"108108+ " if !P3 jump 1b;\n"109109+ : "=&r" (output)110110+ : "r" (&v->counter), "r" (i)111111+ : "memory", "p3"112112+ );113113+ return output;114114+}115115+116116+#define atomic_sub(i, v) atomic_sub_return(i, (v))117117+118118+/**119119+ * atomic_add_unless - add unless the number is a given value120120+ * @v: pointer to value121121+ * @a: amount to add122122+ * @u: unless value is equal to u123123+ *124124+ * Returns 1 if the add happened, 0 if it didn't.125125+ */126126+static inline int __atomic_add_unless(atomic_t *v, int a, int u)127127+{128128+ int output, __oldval;129129+ asm volatile(130130+ "1: %0 = memw_locked(%2);"131131+ " {"132132+ " p3 = cmp.eq(%0, %4);"133133+ " if (p3.new) jump:nt 2f;"134134+ " %0 = add(%0, %3);"135135+ " %1 = #0;"136136+ " }"137137+ " memw_locked(%2, p3) = %0;"138138+ " {"139139+ " if !p3 jump 1b;"140140+ " %1 = #1;"141141+ " }"142142+ "2:"143143+ : "=&r" (__oldval), "=&r" (output)144144+ : "r" (v), "r" (a), "r" (u)145145+ : "memory", "p3"146146+ );147147+ return output;148148+}149149+150150+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)151151+152152+#define atomic_inc(v) atomic_add(1, (v))153153+#define atomic_dec(v) atomic_sub(1, (v))154154+155155+#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)156156+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)157157+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, (v)) == 0)158158+#define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0)159159+160160+161161+#define atomic_inc_return(v) (atomic_add_return(1, v))162162+#define atomic_dec_return(v) (atomic_sub_return(1, v))163163+164164+#endif