blob: fe72308321b6a9fbc88b288c4a4b7f1ce83be3d9 [file] [log] [blame]
Isaku Yamahata080104c2008-10-17 11:17:58 +09001/******************************************************************************
2 * arch/ia64/xen/xen_pv_ops.c
3 *
4 * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
5 * VA Linux Systems Japan K.K.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <linux/console.h>
24#include <linux/irq.h>
25#include <linux/kernel.h>
26#include <linux/pm.h>
Isaku Yamahata533bd152009-03-04 21:05:35 +090027#include <linux/unistd.h>
Isaku Yamahata080104c2008-10-17 11:17:58 +090028
29#include <asm/xen/hypervisor.h>
30#include <asm/xen/xencomm.h>
31#include <asm/xen/privop.h>
32
Isaku Yamahata7477de92008-10-17 11:18:07 +090033#include "irq_xen.h"
Isaku Yamahatadcbbecd2008-10-17 11:18:08 +090034#include "time.h"
Isaku Yamahata7477de92008-10-17 11:18:07 +090035
Isaku Yamahata080104c2008-10-17 11:17:58 +090036/***************************************************************************
37 * general info
38 */
39static struct pv_info xen_info __initdata = {
40 .kernel_rpl = 2, /* or 1: determin at runtime */
41 .paravirt_enabled = 1,
42 .name = "Xen/ia64",
43};
44
45#define IA64_RSC_PL_SHIFT 2
46#define IA64_RSC_PL_BIT_SIZE 2
47#define IA64_RSC_PL_MASK \
48 (((1UL << IA64_RSC_PL_BIT_SIZE) - 1) << IA64_RSC_PL_SHIFT)
49
50static void __init
51xen_info_init(void)
52{
53 /* Xenified Linux/ia64 may run on pl = 1 or 2.
54 * determin at run time. */
55 unsigned long rsc = ia64_getreg(_IA64_REG_AR_RSC);
56 unsigned int rpl = (rsc & IA64_RSC_PL_MASK) >> IA64_RSC_PL_SHIFT;
57 xen_info.kernel_rpl = rpl;
58}
59
60/***************************************************************************
Isaku Yamahatab5a26e42008-10-17 11:17:59 +090061 * pv_init_ops
62 * initialization hooks.
63 */
64
65static void
66xen_panic_hypercall(struct unw_frame_info *info, void *arg)
67{
68 current->thread.ksp = (__u64)info->sw - 16;
69 HYPERVISOR_shutdown(SHUTDOWN_crash);
70 /* we're never actually going to get here... */
71}
72
73static int
74xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
75{
76 unw_init_running(xen_panic_hypercall, NULL);
77 /* we're never actually going to get here... */
78 return NOTIFY_DONE;
79}
80
81static struct notifier_block xen_panic_block = {
82 xen_panic_event, NULL, 0 /* try to go last */
83};
84
85static void xen_pm_power_off(void)
86{
87 local_irq_disable();
88 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
89}
90
91static void __init
92xen_banner(void)
93{
94 printk(KERN_INFO
95 "Running on Xen! pl = %d start_info_pfn=0x%lx nr_pages=%ld "
96 "flags=0x%x\n",
97 xen_info.kernel_rpl,
98 HYPERVISOR_shared_info->arch.start_info_pfn,
99 xen_start_info->nr_pages, xen_start_info->flags);
100}
101
102static int __init
103xen_reserve_memory(struct rsvd_region *region)
104{
105 region->start = (unsigned long)__va(
106 (HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT));
107 region->end = region->start + PAGE_SIZE;
108 return 1;
109}
110
111static void __init
112xen_arch_setup_early(void)
113{
114 struct shared_info *s;
115 BUG_ON(!xen_pv_domain());
116
117 s = HYPERVISOR_shared_info;
118 xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT);
119
120 /* Must be done before any hypercall. */
121 xencomm_initialize();
122
123 xen_setup_features();
124 /* Register a call for panic conditions. */
125 atomic_notifier_chain_register(&panic_notifier_list,
126 &xen_panic_block);
127 pm_power_off = xen_pm_power_off;
128
129 xen_ia64_enable_opt_feature();
130}
131
132static void __init
133xen_arch_setup_console(char **cmdline_p)
134{
135 add_preferred_console("xenboot", 0, NULL);
136 add_preferred_console("tty", 0, NULL);
137 /* use hvc_xen */
138 add_preferred_console("hvc", 0, NULL);
139
140#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
141 conswitchp = NULL;
142#endif
143}
144
145static int __init
146xen_arch_setup_nomca(void)
147{
148 return 1;
149}
150
151static void __init
152xen_post_smp_prepare_boot_cpu(void)
153{
154 xen_setup_vcpu_info_placement();
155}
156
Tony Luckec8148d2009-02-19 12:05:00 -0800157static const struct pv_init_ops xen_init_ops __initconst = {
Isaku Yamahatab5a26e42008-10-17 11:17:59 +0900158 .banner = xen_banner,
159
160 .reserve_memory = xen_reserve_memory,
161
162 .arch_setup_early = xen_arch_setup_early,
163 .arch_setup_console = xen_arch_setup_console,
164 .arch_setup_nomca = xen_arch_setup_nomca,
165
166 .post_smp_prepare_boot_cpu = xen_post_smp_prepare_boot_cpu,
167};
168
169/***************************************************************************
Isaku Yamahata533bd152009-03-04 21:05:35 +0900170 * pv_fsys_data
171 * addresses for fsys
172 */
173
174extern unsigned long xen_fsyscall_table[NR_syscalls];
175extern char xen_fsys_bubble_down[];
176struct pv_fsys_data xen_fsys_data __initdata = {
177 .fsyscall_table = (unsigned long *)xen_fsyscall_table,
178 .fsys_bubble_down = (void *)xen_fsys_bubble_down,
179};
180
181/***************************************************************************
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900182 * pv_cpu_ops
183 * intrinsics hooks.
184 */
185
186static void xen_setreg(int regnum, unsigned long val)
187{
188 switch (regnum) {
189 case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7:
190 xen_set_kr(regnum - _IA64_REG_AR_KR0, val);
191 break;
192#ifdef CONFIG_IA32_SUPPORT
193 case _IA64_REG_AR_EFLAG:
194 xen_set_eflag(val);
195 break;
196#endif
197 case _IA64_REG_CR_TPR:
198 xen_set_tpr(val);
199 break;
200 case _IA64_REG_CR_ITM:
201 xen_set_itm(val);
202 break;
203 case _IA64_REG_CR_EOI:
204 xen_eoi(val);
205 break;
206 default:
207 ia64_native_setreg_func(regnum, val);
208 break;
209 }
210}
211
212static unsigned long xen_getreg(int regnum)
213{
214 unsigned long res;
215
216 switch (regnum) {
217 case _IA64_REG_PSR:
218 res = xen_get_psr();
219 break;
220#ifdef CONFIG_IA32_SUPPORT
221 case _IA64_REG_AR_EFLAG:
222 res = xen_get_eflag();
223 break;
224#endif
225 case _IA64_REG_CR_IVR:
226 res = xen_get_ivr();
227 break;
228 case _IA64_REG_CR_TPR:
229 res = xen_get_tpr();
230 break;
231 default:
232 res = ia64_native_getreg_func(regnum);
233 break;
234 }
235 return res;
236}
237
238/* turning on interrupts is a bit more complicated.. write to the
239 * memory-mapped virtual psr.i bit first (to avoid race condition),
240 * then if any interrupts were pending, we have to execute a hyperprivop
241 * to ensure the pending interrupt gets delivered; else we're done! */
242static void
243xen_ssm_i(void)
244{
245 int old = xen_get_virtual_psr_i();
246 xen_set_virtual_psr_i(1);
247 barrier();
248 if (!old && xen_get_virtual_pend())
249 xen_hyper_ssm_i();
250}
251
252/* turning off interrupts can be paravirtualized simply by writing
253 * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */
254static void
255xen_rsm_i(void)
256{
257 xen_set_virtual_psr_i(0);
258 barrier();
259}
260
261static unsigned long
262xen_get_psr_i(void)
263{
264 return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
265}
266
267static void
268xen_intrin_local_irq_restore(unsigned long mask)
269{
270 if (mask & IA64_PSR_I)
271 xen_ssm_i();
272 else
273 xen_rsm_i();
274}
275
Isaku Yamahatae8c3b422009-03-04 21:05:32 +0900276static const struct pv_cpu_ops xen_cpu_ops __initconst = {
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900277 .fc = xen_fc,
278 .thash = xen_thash,
279 .get_cpuid = xen_get_cpuid,
280 .get_pmd = xen_get_pmd,
281 .getreg = xen_getreg,
282 .setreg = xen_setreg,
283 .ptcga = xen_ptcga,
284 .get_rr = xen_get_rr,
285 .set_rr = xen_set_rr,
286 .set_rr0_to_rr4 = xen_set_rr0_to_rr4,
287 .ssm_i = xen_ssm_i,
288 .rsm_i = xen_rsm_i,
289 .get_psr_i = xen_get_psr_i,
290 .intrin_local_irq_restore
291 = xen_intrin_local_irq_restore,
292};
293
Isaku Yamahata16583bc2008-10-17 11:18:04 +0900294/******************************************************************************
295 * replacement of hand written assembly codes.
296 */
297
298extern char xen_switch_to;
299extern char xen_leave_syscall;
300extern char xen_work_processed_syscall;
301extern char xen_leave_kernel;
302
303const struct pv_cpu_asm_switch xen_cpu_asm_switch = {
304 .switch_to = (unsigned long)&xen_switch_to,
305 .leave_syscall = (unsigned long)&xen_leave_syscall,
306 .work_processed_syscall = (unsigned long)&xen_work_processed_syscall,
307 .leave_kernel = (unsigned long)&xen_leave_kernel,
308};
309
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900310/***************************************************************************
Isaku Yamahatabcdd4872008-10-17 11:18:05 +0900311 * pv_iosapic_ops
312 * iosapic read/write hooks.
313 */
314static void
315xen_pcat_compat_init(void)
316{
317 /* nothing */
318}
319
320static struct irq_chip*
321xen_iosapic_get_irq_chip(unsigned long trigger)
322{
323 return NULL;
324}
325
326static unsigned int
327xen_iosapic_read(char __iomem *iosapic, unsigned int reg)
328{
329 struct physdev_apic apic_op;
330 int ret;
331
332 apic_op.apic_physbase = (unsigned long)iosapic -
333 __IA64_UNCACHED_OFFSET;
334 apic_op.reg = reg;
335 ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
336 if (ret)
337 return ret;
338 return apic_op.value;
339}
340
341static void
342xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
343{
344 struct physdev_apic apic_op;
345
346 apic_op.apic_physbase = (unsigned long)iosapic -
347 __IA64_UNCACHED_OFFSET;
348 apic_op.reg = reg;
349 apic_op.value = val;
350 HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
351}
352
Tony Luckec8148d2009-02-19 12:05:00 -0800353static const struct pv_iosapic_ops xen_iosapic_ops __initconst = {
Isaku Yamahatabcdd4872008-10-17 11:18:05 +0900354 .pcat_compat_init = xen_pcat_compat_init,
355 .__get_irq_chip = xen_iosapic_get_irq_chip,
356
357 .__read = xen_iosapic_read,
358 .__write = xen_iosapic_write,
359};
360
361/***************************************************************************
Isaku Yamahata080104c2008-10-17 11:17:58 +0900362 * pv_ops initialization
363 */
364
365void __init
366xen_setup_pv_ops(void)
367{
368 xen_info_init();
369 pv_info = xen_info;
Isaku Yamahatab5a26e42008-10-17 11:17:59 +0900370 pv_init_ops = xen_init_ops;
Isaku Yamahata533bd152009-03-04 21:05:35 +0900371 pv_fsys_data = xen_fsys_data;
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900372 pv_cpu_ops = xen_cpu_ops;
Isaku Yamahatabcdd4872008-10-17 11:18:05 +0900373 pv_iosapic_ops = xen_iosapic_ops;
Isaku Yamahata7477de92008-10-17 11:18:07 +0900374 pv_irq_ops = xen_irq_ops;
Isaku Yamahatadcbbecd2008-10-17 11:18:08 +0900375 pv_time_ops = xen_time_ops;
Isaku Yamahata16583bc2008-10-17 11:18:04 +0900376
377 paravirt_cpu_asm_init(&xen_cpu_asm_switch);
Isaku Yamahata080104c2008-10-17 11:17:58 +0900378}