]>
Commit | Line | Data |
---|---|---|
6a930a95 BS |
1 | From: Russ Anderson <rja@sgi.com> |
2 | Subject: x86: Add UV bios call infrastructure | |
3 | References: bnc#442455 | |
4 | ||
5 | Add the EFI callback function and associated wrapper code. | |
6 | Initialize SAL system table entry info at boot time. | |
7 | ||
8 | Signed-off-by: Russ Anderson <rja@sgi.com> | |
9 | Signed-off-by: Paul Jackson <pj@sgi.com> | |
10 | Acked-by: Bernhard Walle <bwalle@suse.de> | |
11 | ||
12 | --- | |
13 | arch/x86/kernel/bios_uv.c | 101 ++++++++++++++++++++++++++++++--------- | |
14 | arch/x86/kernel/genx2apic_uv_x.c | 1 | |
15 | include/asm-x86/efi.h | 14 +++++ | |
16 | include/asm-x86/uv/bios.h | 73 +++++++++++++++------------- | |
17 | 4 files changed, 136 insertions(+), 53 deletions(-) | |
18 | ||
19 | --- a/arch/x86/kernel/bios_uv.c | |
20 | +++ b/arch/x86/kernel/bios_uv.c | |
21 | @@ -1,8 +1,6 @@ | |
22 | /* | |
23 | * BIOS run time interface routines. | |
24 | * | |
25 | - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | |
26 | - * | |
27 | * This program is free software; you can redistribute it and/or modify | |
28 | * it under the terms of the GNU General Public License as published by | |
29 | * the Free Software Foundation; either version 2 of the License, or | |
30 | @@ -16,33 +14,94 @@ | |
31 | * You should have received a copy of the GNU General Public License | |
32 | * along with this program; if not, write to the Free Software | |
33 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
34 | + * | |
35 | + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | |
36 | + * Copyright (c) Russ Anderson | |
37 | */ | |
38 | ||
39 | +#include <linux/efi.h> | |
40 | +#include <asm/efi.h> | |
41 | +#include <linux/io.h> | |
42 | #include <asm/uv/bios.h> | |
43 | ||
44 | -const char * | |
45 | -x86_bios_strerror(long status) | |
46 | +struct uv_systab uv_systab; | |
47 | + | |
48 | +s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) | |
49 | { | |
50 | - const char *str; | |
51 | - switch (status) { | |
52 | - case 0: str = "Call completed without error"; break; | |
53 | - case -1: str = "Not implemented"; break; | |
54 | - case -2: str = "Invalid argument"; break; | |
55 | - case -3: str = "Call completed with error"; break; | |
56 | - default: str = "Unknown BIOS status code"; break; | |
57 | - } | |
58 | - return str; | |
59 | + struct uv_systab *tab = &uv_systab; | |
60 | + | |
61 | + if (!tab->function) | |
62 | + /* | |
63 | + * BIOS does not support UV systab | |
64 | + */ | |
65 | + return BIOS_STATUS_UNIMPLEMENTED; | |
66 | + | |
67 | + return efi_call6((void *)__va(tab->function), | |
68 | + (u64)which, a1, a2, a3, a4, a5); | |
69 | } | |
70 | ||
71 | -long | |
72 | -x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second, | |
73 | - unsigned long *drift_info) | |
74 | +s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, | |
75 | + u64 a4, u64 a5) | |
76 | { | |
77 | - struct uv_bios_retval isrv; | |
78 | + unsigned long bios_flags; | |
79 | + s64 ret; | |
80 | + | |
81 | + local_irq_save(bios_flags); | |
82 | + ret = uv_bios_call(which, a1, a2, a3, a4, a5); | |
83 | + local_irq_restore(bios_flags); | |
84 | + | |
85 | + return ret; | |
86 | +} | |
87 | + | |
88 | +s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, | |
89 | + u64 a4, u64 a5) | |
90 | +{ | |
91 | + s64 ret; | |
92 | + | |
93 | + preempt_disable(); | |
94 | + ret = uv_bios_call(which, a1, a2, a3, a4, a5); | |
95 | + preempt_enable(); | |
96 | ||
97 | - BIOS_CALL(isrv, BIOS_FREQ_BASE, which, 0, 0, 0, 0, 0, 0); | |
98 | - *ticks_per_second = isrv.v0; | |
99 | - *drift_info = isrv.v1; | |
100 | - return isrv.status; | |
101 | + return ret; | |
102 | +} | |
103 | + | |
104 | +long | |
105 | +x86_bios_freq_base(unsigned long clock_type, unsigned long *ticks_per_second, | |
106 | + unsigned long *drift_info) | |
107 | +{ | |
108 | + return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type, | |
109 | + (u64)ticks_per_second, 0, 0, 0); | |
110 | } | |
111 | EXPORT_SYMBOL_GPL(x86_bios_freq_base); | |
112 | + | |
113 | + | |
114 | +#ifdef CONFIG_EFI | |
115 | +void uv_bios_init(void) | |
116 | +{ | |
117 | + struct uv_systab *tab; | |
118 | + | |
119 | + if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || | |
120 | + (efi.uv_systab == (unsigned long)NULL)) { | |
121 | + printk(KERN_CRIT "No EFI UV System Table.\n"); | |
122 | + uv_systab.function = (unsigned long)NULL; | |
123 | + return; | |
124 | + } | |
125 | + | |
126 | + tab = (struct uv_systab *)ioremap(efi.uv_systab, | |
127 | + sizeof(struct uv_systab)); | |
128 | + if (strncmp(tab->signature, "UVST", 4) != 0) | |
129 | + printk(KERN_ERR "bad signature in UV system table!"); | |
130 | + | |
131 | + /* | |
132 | + * Copy table to permanent spot for later use. | |
133 | + */ | |
134 | + memcpy(&uv_systab, tab, sizeof(struct uv_systab)); | |
135 | + iounmap(tab); | |
136 | + | |
137 | + printk(KERN_INFO "EFI UV System Table Revision %d\n", tab->revision); | |
138 | +} | |
139 | +#else /* !CONFIG_EFI */ | |
140 | + | |
141 | +void uv_bios_init(void) { } | |
142 | +#endif | |
143 | + | |
144 | --- a/arch/x86/kernel/genx2apic_uv_x.c | |
145 | +++ b/arch/x86/kernel/genx2apic_uv_x.c | |
146 | @@ -522,6 +522,7 @@ void __init uv_system_init(void) | |
147 | gnode_upper = (((unsigned long)node_id.s.node_id) & | |
148 | ~((1 << n_val) - 1)) << m_val; | |
149 | ||
150 | + uv_bios_init(); | |
151 | uv_rtc_init(); | |
152 | ||
153 | for_each_present_cpu(cpu) { | |
154 | --- a/include/asm-x86/efi.h | |
155 | +++ b/include/asm-x86/efi.h | |
156 | @@ -49,6 +49,20 @@ extern u64 efi_call5(void *fp, u64 arg1, | |
157 | extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3, | |
158 | u64 arg4, u64 arg5, u64 arg6); | |
159 | ||
160 | + | |
161 | +#ifndef CONFIG_EFI | |
162 | +/* | |
163 | + * IF EFI is not configured, have the EFI calls return -ENOSYS. | |
164 | + */ | |
165 | +#define efi_call0(_f) (-ENOSYS) | |
166 | +#define efi_call1(_f, _a1) (-ENOSYS) | |
167 | +#define efi_call2(_f, _a1, _a2) (-ENOSYS) | |
168 | +#define efi_call3(_f, _a1, _a2, _a3) (-ENOSYS) | |
169 | +#define efi_call4(_f, _a1, _a2, _a3, _a4) (-ENOSYS) | |
170 | +#define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) | |
171 | +#define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) | |
172 | +#endif /* CONFIG_EFI */ | |
173 | + | |
174 | #define efi_call_phys0(f) \ | |
175 | efi_call0((void *)(f)) | |
176 | #define efi_call_phys1(f, a1) \ | |
177 | --- a/include/asm-x86/uv/bios.h | |
178 | +++ b/include/asm-x86/uv/bios.h | |
179 | @@ -2,9 +2,7 @@ | |
180 | #define _ASM_X86_BIOS_H | |
181 | ||
182 | /* | |
183 | - * BIOS layer definitions. | |
184 | - * | |
185 | - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | |
186 | + * UV BIOS layer definitions. | |
187 | * | |
188 | * This program is free software; you can redistribute it and/or modify | |
189 | * it under the terms of the GNU General Public License as published by | |
190 | @@ -19,50 +17,61 @@ | |
191 | * You should have received a copy of the GNU General Public License | |
192 | * along with this program; if not, write to the Free Software | |
193 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
194 | + * | |
195 | + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | |
196 | + * Copyright (c) Russ Anderson | |
197 | */ | |
198 | ||
199 | #include <linux/rtc.h> | |
200 | ||
201 | -#define BIOS_FREQ_BASE 0x01000001 | |
202 | +/* | |
203 | + * Values for the BIOS calls. It is passed as the first * argument in the | |
204 | + * BIOS call. Passing any other value in the first argument will result | |
205 | + * in a BIOS_STATUS_UNIMPLEMENTED return status. | |
206 | + */ | |
207 | +enum uv_bios_cmd { | |
208 | + UV_BIOS_COMMON, | |
209 | + UV_BIOS_GET_SN_INFO, | |
210 | + UV_BIOS_FREQ_BASE | |
211 | +}; | |
212 | ||
213 | +/* | |
214 | + * Status values returned from a BIOS call. | |
215 | + */ | |
216 | enum { | |
217 | - BIOS_FREQ_BASE_PLATFORM = 0, | |
218 | - BIOS_FREQ_BASE_INTERVAL_TIMER = 1, | |
219 | - BIOS_FREQ_BASE_REALTIME_CLOCK = 2 | |
220 | + BIOS_STATUS_SUCCESS = 0, | |
221 | + BIOS_STATUS_UNIMPLEMENTED = -ENOSYS, | |
222 | + BIOS_STATUS_EINVAL = -EINVAL, | |
223 | + BIOS_STATUS_UNAVAIL = -EBUSY | |
224 | }; | |
225 | ||
226 | -# define BIOS_CALL(result, a0, a1, a2, a3, a4, a5, a6, a7) \ | |
227 | - do { \ | |
228 | - /* XXX - the real call goes here */ \ | |
229 | - result.status = BIOS_STATUS_UNIMPLEMENTED; \ | |
230 | - isrv.v0 = 0; \ | |
231 | - isrv.v1 = 0; \ | |
232 | - } while (0) | |
233 | +/* | |
234 | + * The UV system table describes specific firmware | |
235 | + * capabilities available to the Linux kernel at runtime. | |
236 | + */ | |
237 | +struct uv_systab { | |
238 | + char signature[4]; /* must be "UVST" */ | |
239 | + u32 revision; /* distinguish different firmware revs */ | |
240 | + u64 function; /* BIOS runtime callback function ptr */ | |
241 | +}; | |
242 | ||
243 | enum { | |
244 | - BIOS_STATUS_SUCCESS = 0, | |
245 | - BIOS_STATUS_UNIMPLEMENTED = -1, | |
246 | - BIOS_STATUS_EINVAL = -2, | |
247 | - BIOS_STATUS_ERROR = -3 | |
248 | + BIOS_FREQ_BASE_PLATFORM = 0, | |
249 | + BIOS_FREQ_BASE_INTERVAL_TIMER = 1, | |
250 | + BIOS_FREQ_BASE_REALTIME_CLOCK = 2 | |
251 | }; | |
252 | ||
253 | -struct uv_bios_retval { | |
254 | - /* | |
255 | - * A zero status value indicates call completed without error. | |
256 | - * A negative status value indicates reason of call failure. | |
257 | - * A positive status value indicates success but an | |
258 | - * informational value should be printed (e.g., "reboot for | |
259 | - * change to take effect"). | |
260 | - */ | |
261 | - s64 status; | |
262 | - u64 v0; | |
263 | - u64 v1; | |
264 | - u64 v2; | |
265 | -}; | |
266 | +/* | |
267 | + * bios calls have 6 parameters | |
268 | + */ | |
269 | +extern s64 uv_bios_call(enum uv_bios_cmd, u64, u64, u64, u64, u64); | |
270 | +extern s64 uv_bios_call_irqsave(enum uv_bios_cmd, u64, u64, u64, u64, u64); | |
271 | +extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64); | |
272 | + | |
273 | +extern void uv_bios_init(void); | |
274 | ||
275 | extern long | |
276 | x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second, | |
277 | unsigned long *drift_info); | |
278 | -extern const char *x86_bios_strerror(long status); | |
279 | ||
280 | #endif /* _ASM_X86_BIOS_H */ |