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