Merge branch 'linus' into core/urgent, to pick up dependent commits
[sfrench/cifs-2.6.git] / arch / metag / kernel / user_gateway.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2010 Imagination Technologies Ltd.
4  *
5  * This file contains code that can be accessed from userspace and can
6  * access certain kernel data structures without the overhead of a system
7  * call.
8  */
9
10 #include <asm/metag_regs.h>
11 #include <asm/user_gateway.h>
12
13 /*
14  * User helpers.
15  *
16  * These are segment of kernel provided user code reachable from user space
17  * at a fixed address in kernel memory.  This is used to provide user space
18  * with some operations which require kernel help because of unimplemented
19  * native feature and/or instructions in some Meta CPUs. The idea is for
20  * this code to be executed directly in user mode for best efficiency but
21  * which is too intimate with the kernel counter part to be left to user
22  * libraries.  The kernel reserves the right to change this code as needed
23  * without warning. Only the entry points and their results are guaranteed
24  * to be stable.
25  *
26  * Each segment is 64-byte aligned.  This mechanism should be used only for
27  * for things that are really small and justified, and not be abused freely.
28  */
29         .text
30         .global ___user_gateway_start
31 ___user_gateway_start:
32
33         /* get_tls
34          * Offset:       0
35          * Description:  Get the TLS pointer for this process.
36          */
37         .global ___kuser_get_tls
38         .type   ___kuser_get_tls,function
39 ___kuser_get_tls:
40         MOVT    D1Ar1,#HI(USER_GATEWAY_PAGE + USER_GATEWAY_TLS)
41         ADD     D1Ar1,D1Ar1,#LO(USER_GATEWAY_PAGE + USER_GATEWAY_TLS)
42         MOV     D1Ar3,TXENABLE
43         AND     D1Ar3,D1Ar3,#(TXENABLE_THREAD_BITS)
44         LSR     D1Ar3,D1Ar3,#(TXENABLE_THREAD_S - 2)
45         GETD    D0Re0,[D1Ar1+D1Ar3]
46 ___kuser_get_tls_end:           /* Beyond this point the read will complete */
47         MOV     PC,D1RtP
48         .size   ___kuser_get_tls,.-___kuser_get_tls
49         .global ___kuser_get_tls_end
50
51         /* cmpxchg
52          * Offset:       64
53          * Description:  Replace the value at 'ptr' with 'newval' if the current
54          *               value is 'oldval'. Return zero if we succeeded,
55          *               non-zero otherwise.
56          *
57          * Reference prototype:
58          *
59          *      int __kuser_cmpxchg(int oldval, int newval, unsigned long *ptr)
60          *
61          */
62         .balign 64
63         .global ___kuser_cmpxchg
64         .type   ___kuser_cmpxchg,function
65 ___kuser_cmpxchg:
66 #ifdef CONFIG_SMP
67         /*
68          * We must use LNKGET/LNKSET with an SMP kernel because the other method
69          * does not provide atomicity across multiple CPUs.
70          */
71 0:      LNKGETD D0Re0,[D1Ar3]
72         CMP     D0Re0,D1Ar1
73         LNKSETDZ [D1Ar3],D0Ar2
74         BNZ     1f
75         DEFR    D0Re0,TXSTAT
76         ANDT    D0Re0,D0Re0,#HI(0x3f000000)
77         CMPT    D0Re0,#HI(0x02000000)
78         BNE     0b
79 #ifdef CONFIG_METAG_LNKGET_AROUND_CACHE
80         DCACHE  [D1Ar3], D0Re0
81 #endif
82 1:      MOV     D0Re0,#1
83         XORZ    D0Re0,D0Re0,D0Re0
84         MOV     PC,D1RtP
85 #else
86         GETD    D0Re0,[D1Ar3]
87         CMP     D0Re0,D1Ar1
88         SETDZ   [D1Ar3],D0Ar2
89 ___kuser_cmpxchg_end:           /* Beyond this point the write will complete */
90         MOV     D0Re0,#1
91         XORZ    D0Re0,D0Re0,D0Re0
92         MOV     PC,D1RtP
93 #endif /* CONFIG_SMP */
94         .size   ___kuser_cmpxchg,.-___kuser_cmpxchg
95         .global ___kuser_cmpxchg_end
96
97         .global ___user_gateway_end
98 ___user_gateway_end: