xref: /openbmc/linux/arch/parisc/include/asm/ldcw.h (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2527dcdccSDavid Howells #ifndef __PARISC_LDCW_H
3527dcdccSDavid Howells #define __PARISC_LDCW_H
4527dcdccSDavid Howells 
5527dcdccSDavid Howells #ifndef CONFIG_PA20
6527dcdccSDavid Howells /* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
7527dcdccSDavid Howells    and GCC only guarantees 8-byte alignment for stack locals, we can't
8527dcdccSDavid Howells    be assured of 16-byte alignment for atomic lock data even if we
9527dcdccSDavid Howells    specify "__attribute ((aligned(16)))" in the type declaration.  So,
10527dcdccSDavid Howells    we use a struct containing an array of four ints for the atomic lock
11527dcdccSDavid Howells    type and dynamically select the 16-byte aligned int from the array
12527dcdccSDavid Howells    for the semaphore.  */
13527dcdccSDavid Howells 
14527dcdccSDavid Howells #define __PA_LDCW_ALIGNMENT	16
15527dcdccSDavid Howells #define __ldcw_align(a) ({					\
16527dcdccSDavid Howells 	unsigned long __ret = (unsigned long) &(a)->lock[0];	\
17527dcdccSDavid Howells 	__ret = (__ret + __PA_LDCW_ALIGNMENT - 1)		\
18527dcdccSDavid Howells 		& ~(__PA_LDCW_ALIGNMENT - 1);			\
19527dcdccSDavid Howells 	(volatile unsigned int *) __ret;			\
20527dcdccSDavid Howells })
21527dcdccSDavid Howells #define __LDCW	"ldcw"
22527dcdccSDavid Howells 
23527dcdccSDavid Howells #else /*CONFIG_PA20*/
24527dcdccSDavid Howells /* From: "Jim Hull" <jim.hull of hp.com>
25527dcdccSDavid Howells    I've attached a summary of the change, but basically, for PA 2.0, as
26527dcdccSDavid Howells    long as the ",CO" (coherent operation) completer is specified, then the
27527dcdccSDavid Howells    16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
28527dcdccSDavid Howells    they only require "natural" alignment (4-byte for ldcw, 8-byte for
29527dcdccSDavid Howells    ldcd). */
30527dcdccSDavid Howells 
31527dcdccSDavid Howells #define __PA_LDCW_ALIGNMENT	4
32527dcdccSDavid Howells #define __ldcw_align(a) (&(a)->slock)
33527dcdccSDavid Howells #define __LDCW	"ldcw,co"
34527dcdccSDavid Howells 
35527dcdccSDavid Howells #endif /*!CONFIG_PA20*/
36527dcdccSDavid Howells 
3745db0738SJohn David Anglin /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
3845db0738SJohn David Anglin    We don't explicitly expose that "*a" may be written as reload
3945db0738SJohn David Anglin    fails to find a register in class R1_REGS when "a" needs to be
4045db0738SJohn David Anglin    reloaded when generating 64-bit PIC code.  Instead, we clobber
4145db0738SJohn David Anglin    memory to indicate to the compiler that the assembly code reads
4245db0738SJohn David Anglin    or writes to items other than those listed in the input and output
4345db0738SJohn David Anglin    operands.  This may pessimize the code somewhat but __ldcw is
44d14b3dfcSAndrea Gelmini    usually used within code blocks surrounded by memory barriers.  */
45527dcdccSDavid Howells #define __ldcw(a) ({						\
46527dcdccSDavid Howells 	unsigned __ret;						\
4745db0738SJohn David Anglin 	__asm__ __volatile__(__LDCW " 0(%1),%0"			\
4845db0738SJohn David Anglin 		: "=r" (__ret) : "r" (a) : "memory");		\
49527dcdccSDavid Howells 	__ret;							\
50527dcdccSDavid Howells })
51527dcdccSDavid Howells 
52527dcdccSDavid Howells #ifdef CONFIG_SMP
53527dcdccSDavid Howells # define __lock_aligned __attribute__((__section__(".data..lock_aligned")))
54527dcdccSDavid Howells #endif
55527dcdccSDavid Howells 
56527dcdccSDavid Howells #endif /* __PARISC_LDCW_H */
57