18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * xchg/cmpxchg operations for the Hexagon architecture 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef _ASM_CMPXCHG_H 98c2ecf20Sopenharmony_ci#define _ASM_CMPXCHG_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * __xchg - atomically exchange a register and a memory location 138c2ecf20Sopenharmony_ci * @x: value to swap 148c2ecf20Sopenharmony_ci * @ptr: pointer to memory 158c2ecf20Sopenharmony_ci * @size: size of the value 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Only 4 bytes supported currently. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Note: there was an errata for V2 about .new's and memw_locked. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_cistatic inline unsigned long __xchg(unsigned long x, volatile void *ptr, 238c2ecf20Sopenharmony_ci int size) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci unsigned long retval; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* Can't seem to use printk or panic here, so just stop */ 288c2ecf20Sopenharmony_ci if (size != 4) do { asm volatile("brkpt;\n"); } while (1); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 318c2ecf20Sopenharmony_ci "1: %0 = memw_locked(%1);\n" /* load into retval */ 328c2ecf20Sopenharmony_ci " memw_locked(%1,P0) = %2;\n" /* store into memory */ 338c2ecf20Sopenharmony_ci " if (!P0) jump 1b;\n" 348c2ecf20Sopenharmony_ci : "=&r" (retval) 358c2ecf20Sopenharmony_ci : "r" (ptr), "r" (x) 368c2ecf20Sopenharmony_ci : "memory", "p0" 378c2ecf20Sopenharmony_ci ); 388c2ecf20Sopenharmony_ci return retval; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Atomically swap the contents of a register with memory. Should be atomic 438c2ecf20Sopenharmony_ci * between multiple CPU's and within interrupts on the same CPU. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ 468c2ecf20Sopenharmony_ci sizeof(*(ptr)))) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * see rt-mutex-design.txt; cmpxchg supposedly checks if *ptr == A and swaps. 508c2ecf20Sopenharmony_ci * looks just like atomic_cmpxchg on our arch currently with a bunch of 518c2ecf20Sopenharmony_ci * variable casting. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define cmpxchg(ptr, old, new) \ 558c2ecf20Sopenharmony_ci({ \ 568c2ecf20Sopenharmony_ci __typeof__(ptr) __ptr = (ptr); \ 578c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __old = (old); \ 588c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __new = (new); \ 598c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __oldval = 0; \ 608c2ecf20Sopenharmony_ci \ 618c2ecf20Sopenharmony_ci asm volatile( \ 628c2ecf20Sopenharmony_ci "1: %0 = memw_locked(%1);\n" \ 638c2ecf20Sopenharmony_ci " { P0 = cmp.eq(%0,%2);\n" \ 648c2ecf20Sopenharmony_ci " if (!P0.new) jump:nt 2f; }\n" \ 658c2ecf20Sopenharmony_ci " memw_locked(%1,p0) = %3;\n" \ 668c2ecf20Sopenharmony_ci " if (!P0) jump 1b;\n" \ 678c2ecf20Sopenharmony_ci "2:\n" \ 688c2ecf20Sopenharmony_ci : "=&r" (__oldval) \ 698c2ecf20Sopenharmony_ci : "r" (__ptr), "r" (__old), "r" (__new) \ 708c2ecf20Sopenharmony_ci : "memory", "p0" \ 718c2ecf20Sopenharmony_ci ); \ 728c2ecf20Sopenharmony_ci __oldval; \ 738c2ecf20Sopenharmony_ci}) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#endif /* _ASM_CMPXCHG_H */ 76