]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/ia64/xen/xen_pv_ops.c
c236f04ffad5d1e821fafb4f5b9486ea657145b9
[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 /***************************************************************************
33  * general info
34  */
35 static struct pv_info xen_info __initdata = {
36         .kernel_rpl = 2,        /* or 1: determin at runtime */
37         .paravirt_enabled = 1,
38         .name = "Xen/ia64",
39 };
40
41 #define IA64_RSC_PL_SHIFT       2
42 #define IA64_RSC_PL_BIT_SIZE    2
43 #define IA64_RSC_PL_MASK        \
44         (((1UL << IA64_RSC_PL_BIT_SIZE) - 1) << IA64_RSC_PL_SHIFT)
45
46 static void __init
47 xen_info_init(void)
48 {
49         /* Xenified Linux/ia64 may run on pl = 1 or 2.
50          * determin at run time. */
51         unsigned long rsc = ia64_getreg(_IA64_REG_AR_RSC);
52         unsigned int rpl = (rsc & IA64_RSC_PL_MASK) >> IA64_RSC_PL_SHIFT;
53         xen_info.kernel_rpl = rpl;
54 }
55
56 /***************************************************************************
57  * pv_init_ops
58  * initialization hooks.
59  */
60
61 static void
62 xen_panic_hypercall(struct unw_frame_info *info, void *arg)
63 {
64         current->thread.ksp = (__u64)info->sw - 16;
65         HYPERVISOR_shutdown(SHUTDOWN_crash);
66         /* we're never actually going to get here... */
67 }
68
69 static int
70 xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
71 {
72         unw_init_running(xen_panic_hypercall, NULL);
73         /* we're never actually going to get here... */
74         return NOTIFY_DONE;
75 }
76
77 static struct notifier_block xen_panic_block = {
78         xen_panic_event, NULL, 0 /* try to go last */
79 };
80
81 static void xen_pm_power_off(void)
82 {
83         local_irq_disable();
84         HYPERVISOR_shutdown(SHUTDOWN_poweroff);
85 }
86
87 static void __init
88 xen_banner(void)
89 {
90         printk(KERN_INFO
91                "Running on Xen! pl = %d start_info_pfn=0x%lx nr_pages=%ld "
92                "flags=0x%x\n",
93                xen_info.kernel_rpl,
94                HYPERVISOR_shared_info->arch.start_info_pfn,
95                xen_start_info->nr_pages, xen_start_info->flags);
96 }
97
98 static int __init
99 xen_reserve_memory(struct rsvd_region *region)
100 {
101         region->start = (unsigned long)__va(
102                 (HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT));
103         region->end   = region->start + PAGE_SIZE;
104         return 1;
105 }
106
107 static void __init
108 xen_arch_setup_early(void)
109 {
110         struct shared_info *s;
111         BUG_ON(!xen_pv_domain());
112
113         s = HYPERVISOR_shared_info;
114         xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT);
115
116         /* Must be done before any hypercall.  */
117         xencomm_initialize();
118
119         xen_setup_features();
120         /* Register a call for panic conditions. */
121         atomic_notifier_chain_register(&panic_notifier_list,
122                                        &xen_panic_block);
123         pm_power_off = xen_pm_power_off;
124
125         xen_ia64_enable_opt_feature();
126 }
127
128 static void __init
129 xen_arch_setup_console(char **cmdline_p)
130 {
131         add_preferred_console("xenboot", 0, NULL);
132         add_preferred_console("tty", 0, NULL);
133         /* use hvc_xen */
134         add_preferred_console("hvc", 0, NULL);
135
136 #if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
137         conswitchp = NULL;
138 #endif
139 }
140
141 static int __init
142 xen_arch_setup_nomca(void)
143 {
144         return 1;
145 }
146
147 static void __init
148 xen_post_smp_prepare_boot_cpu(void)
149 {
150         xen_setup_vcpu_info_placement();
151 }
152
153 static const struct pv_init_ops xen_init_ops __initdata = {
154         .banner = xen_banner,
155
156         .reserve_memory = xen_reserve_memory,
157
158         .arch_setup_early = xen_arch_setup_early,
159         .arch_setup_console = xen_arch_setup_console,
160         .arch_setup_nomca = xen_arch_setup_nomca,
161
162         .post_smp_prepare_boot_cpu = xen_post_smp_prepare_boot_cpu,
163 };
164
165 /***************************************************************************
166  * pv_cpu_ops
167  * intrinsics hooks.
168  */
169
170 static void xen_setreg(int regnum, unsigned long val)
171 {
172         switch (regnum) {
173         case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7:
174                 xen_set_kr(regnum - _IA64_REG_AR_KR0, val);
175                 break;
176 #ifdef CONFIG_IA32_SUPPORT
177         case _IA64_REG_AR_EFLAG:
178                 xen_set_eflag(val);
179                 break;
180 #endif
181         case _IA64_REG_CR_TPR:
182                 xen_set_tpr(val);
183                 break;
184         case _IA64_REG_CR_ITM:
185                 xen_set_itm(val);
186                 break;
187         case _IA64_REG_CR_EOI:
188                 xen_eoi(val);
189                 break;
190         default:
191                 ia64_native_setreg_func(regnum, val);
192                 break;
193         }
194 }
195
196 static unsigned long xen_getreg(int regnum)
197 {
198         unsigned long res;
199
200         switch (regnum) {
201         case _IA64_REG_PSR:
202                 res = xen_get_psr();
203                 break;
204 #ifdef CONFIG_IA32_SUPPORT
205         case _IA64_REG_AR_EFLAG:
206                 res = xen_get_eflag();
207                 break;
208 #endif
209         case _IA64_REG_CR_IVR:
210                 res = xen_get_ivr();
211                 break;
212         case _IA64_REG_CR_TPR:
213                 res = xen_get_tpr();
214                 break;
215         default:
216                 res = ia64_native_getreg_func(regnum);
217                 break;
218         }
219         return res;
220 }
221
222 /* turning on interrupts is a bit more complicated.. write to the
223  * memory-mapped virtual psr.i bit first (to avoid race condition),
224  * then if any interrupts were pending, we have to execute a hyperprivop
225  * to ensure the pending interrupt gets delivered; else we're done! */
226 static void
227 xen_ssm_i(void)
228 {
229         int old = xen_get_virtual_psr_i();
230         xen_set_virtual_psr_i(1);
231         barrier();
232         if (!old && xen_get_virtual_pend())
233                 xen_hyper_ssm_i();
234 }
235
236 /* turning off interrupts can be paravirtualized simply by writing
237  * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */
238 static void
239 xen_rsm_i(void)
240 {
241         xen_set_virtual_psr_i(0);
242         barrier();
243 }
244
245 static unsigned long
246 xen_get_psr_i(void)
247 {
248         return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
249 }
250
251 static void
252 xen_intrin_local_irq_restore(unsigned long mask)
253 {
254         if (mask & IA64_PSR_I)
255                 xen_ssm_i();
256         else
257                 xen_rsm_i();
258 }
259
260 static const struct pv_cpu_ops xen_cpu_ops __initdata = {
261         .fc             = xen_fc,
262         .thash          = xen_thash,
263         .get_cpuid      = xen_get_cpuid,
264         .get_pmd        = xen_get_pmd,
265         .getreg         = xen_getreg,
266         .setreg         = xen_setreg,
267         .ptcga          = xen_ptcga,
268         .get_rr         = xen_get_rr,
269         .set_rr         = xen_set_rr,
270         .set_rr0_to_rr4 = xen_set_rr0_to_rr4,
271         .ssm_i          = xen_ssm_i,
272         .rsm_i          = xen_rsm_i,
273         .get_psr_i      = xen_get_psr_i,
274         .intrin_local_irq_restore
275                         = xen_intrin_local_irq_restore,
276 };
277
278 /***************************************************************************
279  * pv_ops initialization
280  */
281
282 void __init
283 xen_setup_pv_ops(void)
284 {
285         xen_info_init();
286         pv_info = xen_info;
287         pv_init_ops = xen_init_ops;
288         pv_cpu_ops = xen_cpu_ops;
289 }