4fe4e621b7b6224354fab186620cab8bf35cecd2
[safe/jmp/linux-2.6] / arch / ia64 / xen / xen_pv_ops.c
1 /******************************************************************************
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
32 #include "irq_xen.h"
33
34 /***************************************************************************
35  * general info
36  */
37 static 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
48 static void __init
49 xen_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 /***************************************************************************
59  * pv_init_ops
60  * initialization hooks.
61  */
62
63 static void
64 xen_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
71 static int
72 xen_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
79 static struct notifier_block xen_panic_block = {
80         xen_panic_event, NULL, 0 /* try to go last */
81 };
82
83 static void xen_pm_power_off(void)
84 {
85         local_irq_disable();
86         HYPERVISOR_shutdown(SHUTDOWN_poweroff);
87 }
88
89 static void __init
90 xen_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
100 static int __init
101 xen_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
109 static void __init
110 xen_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
130 static void __init
131 xen_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
143 static int __init
144 xen_arch_setup_nomca(void)
145 {
146         return 1;
147 }
148
149 static void __init
150 xen_post_smp_prepare_boot_cpu(void)
151 {
152         xen_setup_vcpu_info_placement();
153 }
154
155 static 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 /***************************************************************************
168  * pv_cpu_ops
169  * intrinsics hooks.
170  */
171
172 static 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
198 static 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! */
228 static void
229 xen_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) */
240 static void
241 xen_rsm_i(void)
242 {
243         xen_set_virtual_psr_i(0);
244         barrier();
245 }
246
247 static unsigned long
248 xen_get_psr_i(void)
249 {
250         return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
251 }
252
253 static void
254 xen_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
262 static 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
280 /******************************************************************************
281  * replacement of hand written assembly codes.
282  */
283
284 extern char xen_switch_to;
285 extern char xen_leave_syscall;
286 extern char xen_work_processed_syscall;
287 extern char xen_leave_kernel;
288
289 const 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
296 /***************************************************************************
297  * pv_iosapic_ops
298  * iosapic read/write hooks.
299  */
300 static void
301 xen_pcat_compat_init(void)
302 {
303         /* nothing */
304 }
305
306 static struct irq_chip*
307 xen_iosapic_get_irq_chip(unsigned long trigger)
308 {
309         return NULL;
310 }
311
312 static unsigned int
313 xen_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
327 static void
328 xen_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
339 static 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 /***************************************************************************
348  * pv_ops initialization
349  */
350
351 void __init
352 xen_setup_pv_ops(void)
353 {
354         xen_info_init();
355         pv_info = xen_info;
356         pv_init_ops = xen_init_ops;
357         pv_cpu_ops = xen_cpu_ops;
358         pv_iosapic_ops = xen_iosapic_ops;
359         pv_irq_ops = xen_irq_ops;
360
361         paravirt_cpu_asm_init(&xen_cpu_asm_switch);
362 }