blob: 4fe4e621b7b6224354fab186620cab8bf35cecd2 [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>
27
28#include <asm/xen/hypervisor.h>
29#include <asm/xen/xencomm.h>
30#include <asm/xen/privop.h>
31
Isaku Yamahata7477de92008-10-17 11:18:07 +090032#include "irq_xen.h"
33
Isaku Yamahata080104c2008-10-17 11:17:58 +090034/***************************************************************************
35 * general info
36 */
37static struct pv_info xen_info __initdata = {
38 .kernel_rpl = 2, /* or 1: determin at runtime */
39 .paravirt_enabled = 1,
40 .name = "Xen/ia64",
41};
42
43#define IA64_RSC_PL_SHIFT 2
44#define IA64_RSC_PL_BIT_SIZE 2
45#define IA64_RSC_PL_MASK \
46 (((1UL << IA64_RSC_PL_BIT_SIZE) - 1) << IA64_RSC_PL_SHIFT)
47
48static void __init
49xen_info_init(void)
50{
51 /* Xenified Linux/ia64 may run on pl = 1 or 2.
52 * determin at run time. */
53 unsigned long rsc = ia64_getreg(_IA64_REG_AR_RSC);
54 unsigned int rpl = (rsc & IA64_RSC_PL_MASK) >> IA64_RSC_PL_SHIFT;
55 xen_info.kernel_rpl = rpl;
56}
57
58/***************************************************************************
Isaku Yamahatab5a26e42008-10-17 11:17:59 +090059 * pv_init_ops
60 * initialization hooks.
61 */
62
63static void
64xen_panic_hypercall(struct unw_frame_info *info, void *arg)
65{
66 current->thread.ksp = (__u64)info->sw - 16;
67 HYPERVISOR_shutdown(SHUTDOWN_crash);
68 /* we're never actually going to get here... */
69}
70
71static int
72xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
73{
74 unw_init_running(xen_panic_hypercall, NULL);
75 /* we're never actually going to get here... */
76 return NOTIFY_DONE;
77}
78
79static struct notifier_block xen_panic_block = {
80 xen_panic_event, NULL, 0 /* try to go last */
81};
82
83static void xen_pm_power_off(void)
84{
85 local_irq_disable();
86 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
87}
88
89static void __init
90xen_banner(void)
91{
92 printk(KERN_INFO
93 "Running on Xen! pl = %d start_info_pfn=0x%lx nr_pages=%ld "
94 "flags=0x%x\n",
95 xen_info.kernel_rpl,
96 HYPERVISOR_shared_info->arch.start_info_pfn,
97 xen_start_info->nr_pages, xen_start_info->flags);
98}
99
100static int __init
101xen_reserve_memory(struct rsvd_region *region)
102{
103 region->start = (unsigned long)__va(
104 (HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT));
105 region->end = region->start + PAGE_SIZE;
106 return 1;
107}
108
109static void __init
110xen_arch_setup_early(void)
111{
112 struct shared_info *s;
113 BUG_ON(!xen_pv_domain());
114
115 s = HYPERVISOR_shared_info;
116 xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT);
117
118 /* Must be done before any hypercall. */
119 xencomm_initialize();
120
121 xen_setup_features();
122 /* Register a call for panic conditions. */
123 atomic_notifier_chain_register(&panic_notifier_list,
124 &xen_panic_block);
125 pm_power_off = xen_pm_power_off;
126
127 xen_ia64_enable_opt_feature();
128}
129
130static void __init
131xen_arch_setup_console(char **cmdline_p)
132{
133 add_preferred_console("xenboot", 0, NULL);
134 add_preferred_console("tty", 0, NULL);
135 /* use hvc_xen */
136 add_preferred_console("hvc", 0, NULL);
137
138#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
139 conswitchp = NULL;
140#endif
141}
142
143static int __init
144xen_arch_setup_nomca(void)
145{
146 return 1;
147}
148
149static void __init
150xen_post_smp_prepare_boot_cpu(void)
151{
152 xen_setup_vcpu_info_placement();
153}
154
155static const struct pv_init_ops xen_init_ops __initdata = {
156 .banner = xen_banner,
157
158 .reserve_memory = xen_reserve_memory,
159
160 .arch_setup_early = xen_arch_setup_early,
161 .arch_setup_console = xen_arch_setup_console,
162 .arch_setup_nomca = xen_arch_setup_nomca,
163
164 .post_smp_prepare_boot_cpu = xen_post_smp_prepare_boot_cpu,
165};
166
167/***************************************************************************
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900168 * pv_cpu_ops
169 * intrinsics hooks.
170 */
171
172static void xen_setreg(int regnum, unsigned long val)
173{
174 switch (regnum) {
175 case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7:
176 xen_set_kr(regnum - _IA64_REG_AR_KR0, val);
177 break;
178#ifdef CONFIG_IA32_SUPPORT
179 case _IA64_REG_AR_EFLAG:
180 xen_set_eflag(val);
181 break;
182#endif
183 case _IA64_REG_CR_TPR:
184 xen_set_tpr(val);
185 break;
186 case _IA64_REG_CR_ITM:
187 xen_set_itm(val);
188 break;
189 case _IA64_REG_CR_EOI:
190 xen_eoi(val);
191 break;
192 default:
193 ia64_native_setreg_func(regnum, val);
194 break;
195 }
196}
197
198static unsigned long xen_getreg(int regnum)
199{
200 unsigned long res;
201
202 switch (regnum) {
203 case _IA64_REG_PSR:
204 res = xen_get_psr();
205 break;
206#ifdef CONFIG_IA32_SUPPORT
207 case _IA64_REG_AR_EFLAG:
208 res = xen_get_eflag();
209 break;
210#endif
211 case _IA64_REG_CR_IVR:
212 res = xen_get_ivr();
213 break;
214 case _IA64_REG_CR_TPR:
215 res = xen_get_tpr();
216 break;
217 default:
218 res = ia64_native_getreg_func(regnum);
219 break;
220 }
221 return res;
222}
223
224/* turning on interrupts is a bit more complicated.. write to the
225 * memory-mapped virtual psr.i bit first (to avoid race condition),
226 * then if any interrupts were pending, we have to execute a hyperprivop
227 * to ensure the pending interrupt gets delivered; else we're done! */
228static void
229xen_ssm_i(void)
230{
231 int old = xen_get_virtual_psr_i();
232 xen_set_virtual_psr_i(1);
233 barrier();
234 if (!old && xen_get_virtual_pend())
235 xen_hyper_ssm_i();
236}
237
238/* turning off interrupts can be paravirtualized simply by writing
239 * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */
240static void
241xen_rsm_i(void)
242{
243 xen_set_virtual_psr_i(0);
244 barrier();
245}
246
247static unsigned long
248xen_get_psr_i(void)
249{
250 return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
251}
252
253static void
254xen_intrin_local_irq_restore(unsigned long mask)
255{
256 if (mask & IA64_PSR_I)
257 xen_ssm_i();
258 else
259 xen_rsm_i();
260}
261
262static const struct pv_cpu_ops xen_cpu_ops __initdata = {
263 .fc = xen_fc,
264 .thash = xen_thash,
265 .get_cpuid = xen_get_cpuid,
266 .get_pmd = xen_get_pmd,
267 .getreg = xen_getreg,
268 .setreg = xen_setreg,
269 .ptcga = xen_ptcga,
270 .get_rr = xen_get_rr,
271 .set_rr = xen_set_rr,
272 .set_rr0_to_rr4 = xen_set_rr0_to_rr4,
273 .ssm_i = xen_ssm_i,
274 .rsm_i = xen_rsm_i,
275 .get_psr_i = xen_get_psr_i,
276 .intrin_local_irq_restore
277 = xen_intrin_local_irq_restore,
278};
279
Isaku Yamahata16583bc2008-10-17 11:18:04 +0900280/******************************************************************************
281 * replacement of hand written assembly codes.
282 */
283
284extern char xen_switch_to;
285extern char xen_leave_syscall;
286extern char xen_work_processed_syscall;
287extern char xen_leave_kernel;
288
289const struct pv_cpu_asm_switch xen_cpu_asm_switch = {
290 .switch_to = (unsigned long)&xen_switch_to,
291 .leave_syscall = (unsigned long)&xen_leave_syscall,
292 .work_processed_syscall = (unsigned long)&xen_work_processed_syscall,
293 .leave_kernel = (unsigned long)&xen_leave_kernel,
294};
295
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900296/***************************************************************************
Isaku Yamahatabcdd4872008-10-17 11:18:05 +0900297 * pv_iosapic_ops
298 * iosapic read/write hooks.
299 */
300static void
301xen_pcat_compat_init(void)
302{
303 /* nothing */
304}
305
306static struct irq_chip*
307xen_iosapic_get_irq_chip(unsigned long trigger)
308{
309 return NULL;
310}
311
312static unsigned int
313xen_iosapic_read(char __iomem *iosapic, unsigned int reg)
314{
315 struct physdev_apic apic_op;
316 int ret;
317
318 apic_op.apic_physbase = (unsigned long)iosapic -
319 __IA64_UNCACHED_OFFSET;
320 apic_op.reg = reg;
321 ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
322 if (ret)
323 return ret;
324 return apic_op.value;
325}
326
327static void
328xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
329{
330 struct physdev_apic apic_op;
331
332 apic_op.apic_physbase = (unsigned long)iosapic -
333 __IA64_UNCACHED_OFFSET;
334 apic_op.reg = reg;
335 apic_op.value = val;
336 HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
337}
338
339static const struct pv_iosapic_ops xen_iosapic_ops __initdata = {
340 .pcat_compat_init = xen_pcat_compat_init,
341 .__get_irq_chip = xen_iosapic_get_irq_chip,
342
343 .__read = xen_iosapic_read,
344 .__write = xen_iosapic_write,
345};
346
347/***************************************************************************
Isaku Yamahata080104c2008-10-17 11:17:58 +0900348 * pv_ops initialization
349 */
350
351void __init
352xen_setup_pv_ops(void)
353{
354 xen_info_init();
355 pv_info = xen_info;
Isaku Yamahatab5a26e42008-10-17 11:17:59 +0900356 pv_init_ops = xen_init_ops;
Isaku Yamahata4b83ce42008-10-17 11:18:00 +0900357 pv_cpu_ops = xen_cpu_ops;
Isaku Yamahatabcdd4872008-10-17 11:18:05 +0900358 pv_iosapic_ops = xen_iosapic_ops;
Isaku Yamahata7477de92008-10-17 11:18:07 +0900359 pv_irq_ops = xen_irq_ops;
Isaku Yamahata16583bc2008-10-17 11:18:04 +0900360
361 paravirt_cpu_asm_init(&xen_cpu_asm_switch);
Isaku Yamahata080104c2008-10-17 11:17:58 +0900362}