108dbd0f8SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 28335896bSDavid Howells /* 38335896bSDavid Howells * xchg/cmpxchg operations for the Hexagon architecture 48335896bSDavid Howells * 5e1858b2aSRichard Kuo * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 68335896bSDavid Howells */ 78335896bSDavid Howells 88335896bSDavid Howells #ifndef _ASM_CMPXCHG_H 98335896bSDavid Howells #define _ASM_CMPXCHG_H 108335896bSDavid Howells 118335896bSDavid Howells /* 128335896bSDavid Howells * __xchg - atomically exchange a register and a memory location 138335896bSDavid Howells * @x: value to swap 148335896bSDavid Howells * @ptr: pointer to memory 158335896bSDavid Howells * @size: size of the value 168335896bSDavid Howells * 178335896bSDavid Howells * Only 4 bytes supported currently. 188335896bSDavid Howells * 198335896bSDavid Howells * Note: there was an errata for V2 about .new's and memw_locked. 208335896bSDavid Howells * 218335896bSDavid Howells */ 228335896bSDavid Howells static inline unsigned long __xchg(unsigned long x, volatile void *ptr, 238335896bSDavid Howells int size) 248335896bSDavid Howells { 258335896bSDavid Howells unsigned long retval; 268335896bSDavid Howells 278335896bSDavid Howells /* Can't seem to use printk or panic here, so just stop */ 288335896bSDavid Howells if (size != 4) do { asm volatile("brkpt;\n"); } while (1); 298335896bSDavid Howells 308335896bSDavid Howells __asm__ __volatile__ ( 318335896bSDavid Howells "1: %0 = memw_locked(%1);\n" /* load into retval */ 328335896bSDavid Howells " memw_locked(%1,P0) = %2;\n" /* store into memory */ 33780a0cfdSNick Desaulniers " if (!P0) jump 1b;\n" 348335896bSDavid Howells : "=&r" (retval) 358335896bSDavid Howells : "r" (ptr), "r" (x) 368335896bSDavid Howells : "memory", "p0" 378335896bSDavid Howells ); 388335896bSDavid Howells return retval; 398335896bSDavid Howells } 408335896bSDavid Howells 418335896bSDavid Howells /* 428335896bSDavid Howells * Atomically swap the contents of a register with memory. Should be atomic 438335896bSDavid Howells * between multiple CPU's and within interrupts on the same CPU. 448335896bSDavid Howells */ 45*94b63eb6SMark Rutland #define arch_xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ 468335896bSDavid Howells sizeof(*(ptr)))) 478335896bSDavid Howells 488335896bSDavid Howells /* 498335896bSDavid Howells * see rt-mutex-design.txt; cmpxchg supposedly checks if *ptr == A and swaps. 508335896bSDavid Howells * looks just like atomic_cmpxchg on our arch currently with a bunch of 518335896bSDavid Howells * variable casting. 528335896bSDavid Howells */ 538335896bSDavid Howells 54*94b63eb6SMark Rutland #define arch_cmpxchg(ptr, old, new) \ 558335896bSDavid Howells ({ \ 568335896bSDavid Howells __typeof__(ptr) __ptr = (ptr); \ 578335896bSDavid Howells __typeof__(*(ptr)) __old = (old); \ 588335896bSDavid Howells __typeof__(*(ptr)) __new = (new); \ 598335896bSDavid Howells __typeof__(*(ptr)) __oldval = 0; \ 608335896bSDavid Howells \ 618335896bSDavid Howells asm volatile( \ 628335896bSDavid Howells "1: %0 = memw_locked(%1);\n" \ 638335896bSDavid Howells " { P0 = cmp.eq(%0,%2);\n" \ 648335896bSDavid Howells " if (!P0.new) jump:nt 2f; }\n" \ 658335896bSDavid Howells " memw_locked(%1,p0) = %3;\n" \ 668335896bSDavid Howells " if (!P0) jump 1b;\n" \ 678335896bSDavid Howells "2:\n" \ 688335896bSDavid Howells : "=&r" (__oldval) \ 698335896bSDavid Howells : "r" (__ptr), "r" (__old), "r" (__new) \ 708335896bSDavid Howells : "memory", "p0" \ 718335896bSDavid Howells ); \ 728335896bSDavid Howells __oldval; \ 738335896bSDavid Howells }) 748335896bSDavid Howells 758335896bSDavid Howells #endif /* _ASM_CMPXCHG_H */ 76