Commit | Line | Data |
---|---|---|
ba5187db TS |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2005 Thiemo Seufer | |
70342287 | 7 | * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. |
ba5187db TS |
8 | * Author: Maciej W. Rozycki <macro@mips.com> |
9 | */ | |
10 | ||
11 | #include <linux/init.h> | |
12 | ||
13 | #include <asm/addrspace.h> | |
14 | #include <asm/bug.h> | |
8c41286e | 15 | #include <asm/cacheflush.h> |
ba5187db TS |
16 | |
17 | #ifndef CKSEG2 | |
18 | #define CKSEG2 CKSSEG | |
19 | #endif | |
20 | #ifndef TO_PHYS_MASK | |
21 | #define TO_PHYS_MASK -1 | |
22 | #endif | |
23 | ||
24 | /* | |
25 | * FUNC is executed in one of the uncached segments, depending on its | |
26 | * original address as follows: | |
27 | * | |
28 | * 1. If the original address is in CKSEG0 or CKSEG1, then the uncached | |
29 | * segment used is CKSEG1. | |
30 | * 2. If the original address is in XKPHYS, then the uncached segment | |
31 | * used is XKPHYS(2). | |
32 | * 3. Otherwise it's a bug. | |
33 | * | |
34 | * The same remapping is done with the stack pointer. Stack handling | |
35 | * works because we don't handle stack arguments or more complex return | |
36 | * values, so we can avoid sharing the same stack area between a cached | |
37 | * and the uncached mode. | |
38 | */ | |
078a55fc | 39 | unsigned long run_uncached(void *func) |
ba5187db TS |
40 | { |
41 | register long sp __asm__("$sp"); | |
42 | register long ret __asm__("$2"); | |
43 | long lfunc = (long)func, ufunc; | |
44 | long usp; | |
45 | ||
46 | if (sp >= (long)CKSEG0 && sp < (long)CKSEG2) | |
47 | usp = CKSEG1ADDR(sp); | |
c55197eb | 48 | #ifdef CONFIG_64BIT |
48ef2626 AS |
49 | else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0, 0) && |
50 | (long long)sp < (long long)PHYS_TO_XKPHYS(8, 0)) | |
51 | usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED, | |
ba5187db | 52 | XKPHYS_TO_PHYS((long long)sp)); |
c55197eb | 53 | #endif |
ba5187db TS |
54 | else { |
55 | BUG(); | |
56 | usp = sp; | |
57 | } | |
58 | if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2) | |
59 | ufunc = CKSEG1ADDR(lfunc); | |
c55197eb | 60 | #ifdef CONFIG_64BIT |
48ef2626 AS |
61 | else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0, 0) && |
62 | (long long)lfunc < (long long)PHYS_TO_XKPHYS(8, 0)) | |
63 | ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED, | |
ba5187db | 64 | XKPHYS_TO_PHYS((long long)lfunc)); |
c55197eb | 65 | #endif |
ba5187db TS |
66 | else { |
67 | BUG(); | |
68 | ufunc = lfunc; | |
69 | } | |
70 | ||
71 | __asm__ __volatile__ ( | |
72 | " move $16, $sp\n" | |
73 | " move $sp, %1\n" | |
74 | " jalr %2\n" | |
75 | " move $sp, $16" | |
76 | : "=r" (ret) | |
77 | : "r" (usp), "r" (ufunc) | |
78 | : "$16", "$31"); | |
79 | ||
80 | return ret; | |
81 | } |