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