aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/xen
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/xen')
-rw-r--r--arch/ia64/xen/Kconfig26
-rw-r--r--arch/ia64/xen/Makefile22
-rw-r--r--arch/ia64/xen/grant-table.c155
-rw-r--r--arch/ia64/xen/hypercall.S91
-rw-r--r--arch/ia64/xen/hypervisor.c96
-rw-r--r--arch/ia64/xen/irq_xen.c435
-rw-r--r--arch/ia64/xen/irq_xen.h34
-rw-r--r--arch/ia64/xen/machvec.c4
-rw-r--r--arch/ia64/xen/suspend.c64
-rw-r--r--arch/ia64/xen/time.c213
-rw-r--r--arch/ia64/xen/time.h24
-rw-r--r--arch/ia64/xen/xcom_hcall.c441
-rw-r--r--arch/ia64/xen/xen_pv_ops.c364
-rw-r--r--arch/ia64/xen/xencomm.c105
-rw-r--r--arch/ia64/xen/xenivt.S52
-rw-r--r--arch/ia64/xen/xensetup.S83
16 files changed, 2209 insertions, 0 deletions
diff --git a/arch/ia64/xen/Kconfig b/arch/ia64/xen/Kconfig
new file mode 100644
index 000000000000..f1683a20275b
--- /dev/null
+++ b/arch/ia64/xen/Kconfig
@@ -0,0 +1,26 @@
1#
2# This Kconfig describes xen/ia64 options
3#
4
5config XEN
6 bool "Xen hypervisor support"
7 default y
8 depends on PARAVIRT && MCKINLEY && IA64_PAGE_SIZE_16KB && EXPERIMENTAL
9 select XEN_XENCOMM
10 select NO_IDLE_HZ
11
12 # those are required to save/restore.
13 select ARCH_SUSPEND_POSSIBLE
14 select SUSPEND
15 select PM_SLEEP
16 help
17 Enable Xen hypervisor support. Resulting kernel runs
18 both as a guest OS on Xen and natively on hardware.
19
20config XEN_XENCOMM
21 depends on XEN
22 bool
23
24config NO_IDLE_HZ
25 depends on XEN
26 bool
diff --git a/arch/ia64/xen/Makefile b/arch/ia64/xen/Makefile
new file mode 100644
index 000000000000..0ad0224693d9
--- /dev/null
+++ b/arch/ia64/xen/Makefile
@@ -0,0 +1,22 @@
1#
2# Makefile for Xen components
3#
4
5obj-y := hypercall.o xenivt.o xensetup.o xen_pv_ops.o irq_xen.o \
6 hypervisor.o xencomm.o xcom_hcall.o grant-table.o time.o suspend.o
7
8obj-$(CONFIG_IA64_GENERIC) += machvec.o
9
10AFLAGS_xenivt.o += -D__IA64_ASM_PARAVIRTUALIZED_XEN
11
12# xen multi compile
13ASM_PARAVIRT_MULTI_COMPILE_SRCS = ivt.S entry.S
14ASM_PARAVIRT_OBJS = $(addprefix xen-,$(ASM_PARAVIRT_MULTI_COMPILE_SRCS:.S=.o))
15obj-y += $(ASM_PARAVIRT_OBJS)
16define paravirtualized_xen
17AFLAGS_$(1) += -D__IA64_ASM_PARAVIRTUALIZED_XEN
18endef
19$(foreach o,$(ASM_PARAVIRT_OBJS),$(eval $(call paravirtualized_xen,$(o))))
20
21$(obj)/xen-%.o: $(src)/../kernel/%.S FORCE
22 $(call if_changed_dep,as_o_S)
diff --git a/arch/ia64/xen/grant-table.c b/arch/ia64/xen/grant-table.c
new file mode 100644
index 000000000000..777dd9a9108b
--- /dev/null
+++ b/arch/ia64/xen/grant-table.c
@@ -0,0 +1,155 @@
1/******************************************************************************
2 * arch/ia64/xen/grant-table.c
3 *
4 * Copyright (c) 2006 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/module.h>
24#include <linux/vmalloc.h>
25#include <linux/mm.h>
26
27#include <xen/interface/xen.h>
28#include <xen/interface/memory.h>
29#include <xen/grant_table.h>
30
31#include <asm/xen/hypervisor.h>
32
33struct vm_struct *xen_alloc_vm_area(unsigned long size)
34{
35 int order;
36 unsigned long virt;
37 unsigned long nr_pages;
38 struct vm_struct *area;
39
40 order = get_order(size);
41 virt = __get_free_pages(GFP_KERNEL, order);
42 if (virt == 0)
43 goto err0;
44 nr_pages = 1 << order;
45 scrub_pages(virt, nr_pages);
46
47 area = kmalloc(sizeof(*area), GFP_KERNEL);
48 if (area == NULL)
49 goto err1;
50
51 area->flags = VM_IOREMAP;
52 area->addr = (void *)virt;
53 area->size = size;
54 area->pages = NULL;
55 area->nr_pages = nr_pages;
56 area->phys_addr = 0; /* xenbus_map_ring_valloc uses this field! */
57
58 return area;
59
60err1:
61 free_pages(virt, order);
62err0:
63 return NULL;
64}
65EXPORT_SYMBOL_GPL(xen_alloc_vm_area);
66
67void xen_free_vm_area(struct vm_struct *area)
68{
69 unsigned int order = get_order(area->size);
70 unsigned long i;
71 unsigned long phys_addr = __pa(area->addr);
72
73 /* This area is used for foreign page mappping.
74 * So underlying machine page may not be assigned. */
75 for (i = 0; i < (1 << order); i++) {
76 unsigned long ret;
77 unsigned long gpfn = (phys_addr >> PAGE_SHIFT) + i;
78 struct xen_memory_reservation reservation = {
79 .nr_extents = 1,
80 .address_bits = 0,
81 .extent_order = 0,
82 .domid = DOMID_SELF
83 };
84 set_xen_guest_handle(reservation.extent_start, &gpfn);
85 ret = HYPERVISOR_memory_op(XENMEM_populate_physmap,
86 &reservation);
87 BUG_ON(ret != 1);
88 }
89 free_pages((unsigned long)area->addr, order);
90 kfree(area);
91}
92EXPORT_SYMBOL_GPL(xen_free_vm_area);
93
94
95/****************************************************************************
96 * grant table hack
97 * cmd: GNTTABOP_xxx
98 */
99
100int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
101 unsigned long max_nr_gframes,
102 struct grant_entry **__shared)
103{
104 *__shared = __va(frames[0] << PAGE_SHIFT);
105 return 0;
106}
107
108void arch_gnttab_unmap_shared(struct grant_entry *shared,
109 unsigned long nr_gframes)
110{
111 /* nothing */
112}
113
114static void
115gnttab_map_grant_ref_pre(struct gnttab_map_grant_ref *uop)
116{
117 uint32_t flags;
118
119 flags = uop->flags;
120
121 if (flags & GNTMAP_host_map) {
122 if (flags & GNTMAP_application_map) {
123 printk(KERN_DEBUG
124 "GNTMAP_application_map is not supported yet: "
125 "flags 0x%x\n", flags);
126 BUG();
127 }
128 if (flags & GNTMAP_contains_pte) {
129 printk(KERN_DEBUG
130 "GNTMAP_contains_pte is not supported yet: "
131 "flags 0x%x\n", flags);
132 BUG();
133 }
134 } else if (flags & GNTMAP_device_map) {
135 printk("GNTMAP_device_map is not supported yet 0x%x\n", flags);
136 BUG(); /* not yet. actually this flag is not used. */
137 } else {
138 BUG();
139 }
140}
141
142int
143HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
144{
145 if (cmd == GNTTABOP_map_grant_ref) {
146 unsigned int i;
147 for (i = 0; i < count; i++) {
148 gnttab_map_grant_ref_pre(
149 (struct gnttab_map_grant_ref *)uop + i);
150 }
151 }
152 return xencomm_hypercall_grant_table_op(cmd, uop, count);
153}
154
155EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
diff --git a/arch/ia64/xen/hypercall.S b/arch/ia64/xen/hypercall.S
new file mode 100644
index 000000000000..d4ff0b9e79f1
--- /dev/null
+++ b/arch/ia64/xen/hypercall.S
@@ -0,0 +1,91 @@
1/*
2 * Support routines for Xen hypercalls
3 *
4 * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer@hp.com>
5 * Copyright (C) 2008 Yaozu (Eddie) Dong <eddie.dong@intel.com>
6 */
7
8#include <asm/asmmacro.h>
9#include <asm/intrinsics.h>
10#include <asm/xen/privop.h>
11
12/*
13 * Hypercalls without parameter.
14 */
15#define __HCALL0(name,hcall) \
16 GLOBAL_ENTRY(name); \
17 break hcall; \
18 br.ret.sptk.many rp; \
19 END(name)
20
21/*
22 * Hypercalls with 1 parameter.
23 */
24#define __HCALL1(name,hcall) \
25 GLOBAL_ENTRY(name); \
26 mov r8=r32; \
27 break hcall; \
28 br.ret.sptk.many rp; \
29 END(name)
30
31/*
32 * Hypercalls with 2 parameters.
33 */
34#define __HCALL2(name,hcall) \
35 GLOBAL_ENTRY(name); \
36 mov r8=r32; \
37 mov r9=r33; \
38 break hcall; \
39 br.ret.sptk.many rp; \
40 END(name)
41
42__HCALL0(xen_get_psr, HYPERPRIVOP_GET_PSR)
43__HCALL0(xen_get_ivr, HYPERPRIVOP_GET_IVR)
44__HCALL0(xen_get_tpr, HYPERPRIVOP_GET_TPR)
45__HCALL0(xen_hyper_ssm_i, HYPERPRIVOP_SSM_I)
46
47__HCALL1(xen_set_tpr, HYPERPRIVOP_SET_TPR)
48__HCALL1(xen_eoi, HYPERPRIVOP_EOI)
49__HCALL1(xen_thash, HYPERPRIVOP_THASH)
50__HCALL1(xen_set_itm, HYPERPRIVOP_SET_ITM)
51__HCALL1(xen_get_rr, HYPERPRIVOP_GET_RR)
52__HCALL1(xen_fc, HYPERPRIVOP_FC)
53__HCALL1(xen_get_cpuid, HYPERPRIVOP_GET_CPUID)
54__HCALL1(xen_get_pmd, HYPERPRIVOP_GET_PMD)
55
56__HCALL2(xen_ptcga, HYPERPRIVOP_PTC_GA)
57__HCALL2(xen_set_rr, HYPERPRIVOP_SET_RR)
58__HCALL2(xen_set_kr, HYPERPRIVOP_SET_KR)
59
60#ifdef CONFIG_IA32_SUPPORT
61__HCALL1(xen_get_eflag, HYPERPRIVOP_GET_EFLAG)
62__HCALL1(xen_set_eflag, HYPERPRIVOP_SET_EFLAG) // refer SDM vol1 3.1.8
63#endif /* CONFIG_IA32_SUPPORT */
64
65GLOBAL_ENTRY(xen_set_rr0_to_rr4)
66 mov r8=r32
67 mov r9=r33
68 mov r10=r34
69 mov r11=r35
70 mov r14=r36
71 XEN_HYPER_SET_RR0_TO_RR4
72 br.ret.sptk.many rp
73 ;;
74END(xen_set_rr0_to_rr4)
75
76GLOBAL_ENTRY(xen_send_ipi)
77 mov r14=r32
78 mov r15=r33
79 mov r2=0x400
80 break 0x1000
81 ;;
82 br.ret.sptk.many rp
83 ;;
84END(xen_send_ipi)
85
86GLOBAL_ENTRY(__hypercall)
87 mov r2=r37
88 break 0x1000
89 br.ret.sptk.many b0
90 ;;
91END(__hypercall)
diff --git a/arch/ia64/xen/hypervisor.c b/arch/ia64/xen/hypervisor.c
new file mode 100644
index 000000000000..cac4d97c0b5a
--- /dev/null
+++ b/arch/ia64/xen/hypervisor.c
@@ -0,0 +1,96 @@
1/******************************************************************************
2 * arch/ia64/xen/hypervisor.c
3 *
4 * Copyright (c) 2006 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/efi.h>
24#include <asm/xen/hypervisor.h>
25#include <asm/xen/privop.h>
26
27#include "irq_xen.h"
28
29struct shared_info *HYPERVISOR_shared_info __read_mostly =
30 (struct shared_info *)XSI_BASE;
31EXPORT_SYMBOL(HYPERVISOR_shared_info);
32
33DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
34
35struct start_info *xen_start_info;
36EXPORT_SYMBOL(xen_start_info);
37
38EXPORT_SYMBOL(xen_domain_type);
39
40EXPORT_SYMBOL(__hypercall);
41
42/* Stolen from arch/x86/xen/enlighten.c */
43/*
44 * Flag to determine whether vcpu info placement is available on all
45 * VCPUs. We assume it is to start with, and then set it to zero on
46 * the first failure. This is because it can succeed on some VCPUs
47 * and not others, since it can involve hypervisor memory allocation,
48 * or because the guest failed to guarantee all the appropriate
49 * constraints on all VCPUs (ie buffer can't cross a page boundary).
50 *
51 * Note that any particular CPU may be using a placed vcpu structure,
52 * but we can only optimise if the all are.
53 *
54 * 0: not available, 1: available
55 */
56
57static void __init xen_vcpu_setup(int cpu)
58{
59 /*
60 * WARNING:
61 * before changing MAX_VIRT_CPUS,
62 * check that shared_info fits on a page
63 */
64 BUILD_BUG_ON(sizeof(struct shared_info) > PAGE_SIZE);
65 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
66}
67
68void __init xen_setup_vcpu_info_placement(void)
69{
70 int cpu;
71
72 for_each_possible_cpu(cpu)
73 xen_vcpu_setup(cpu);
74}
75
76void __cpuinit
77xen_cpu_init(void)
78{
79 xen_smp_intr_init();
80}
81
82/**************************************************************************
83 * opt feature
84 */
85void
86xen_ia64_enable_opt_feature(void)
87{
88 /* Enable region 7 identity map optimizations in Xen */
89 struct xen_ia64_opt_feature optf;
90
91 optf.cmd = XEN_IA64_OPTF_IDENT_MAP_REG7;
92 optf.on = XEN_IA64_OPTF_ON;
93 optf.pgprot = pgprot_val(PAGE_KERNEL);
94 optf.key = 0; /* No key on linux. */
95 HYPERVISOR_opt_feature(&optf);
96}
diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c
new file mode 100644
index 000000000000..af93aadb68bb
--- /dev/null
+++ b/arch/ia64/xen/irq_xen.c
@@ -0,0 +1,435 @@
1/******************************************************************************
2 * arch/ia64/xen/irq_xen.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/cpu.h>
24
25#include <xen/interface/xen.h>
26#include <xen/interface/callback.h>
27#include <xen/events.h>
28
29#include <asm/xen/privop.h>
30
31#include "irq_xen.h"
32
33/***************************************************************************
34 * pv_irq_ops
35 * irq operations
36 */
37
38static int
39xen_assign_irq_vector(int irq)
40{
41 struct physdev_irq irq_op;
42
43 irq_op.irq = irq;
44 if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op))
45 return -ENOSPC;
46
47 return irq_op.vector;
48}
49
50static void
51xen_free_irq_vector(int vector)
52{
53 struct physdev_irq irq_op;
54
55 if (vector < IA64_FIRST_DEVICE_VECTOR ||
56 vector > IA64_LAST_DEVICE_VECTOR)
57 return;
58
59 irq_op.vector = vector;
60 if (HYPERVISOR_physdev_op(PHYSDEVOP_free_irq_vector, &irq_op))
61 printk(KERN_WARNING "%s: xen_free_irq_vecotr fail vector=%d\n",
62 __func__, vector);
63}
64
65
66static DEFINE_PER_CPU(int, timer_irq) = -1;
67static DEFINE_PER_CPU(int, ipi_irq) = -1;
68static DEFINE_PER_CPU(int, resched_irq) = -1;
69static DEFINE_PER_CPU(int, cmc_irq) = -1;
70static DEFINE_PER_CPU(int, cmcp_irq) = -1;
71static DEFINE_PER_CPU(int, cpep_irq) = -1;
72#define NAME_SIZE 15
73static DEFINE_PER_CPU(char[NAME_SIZE], timer_name);
74static DEFINE_PER_CPU(char[NAME_SIZE], ipi_name);
75static DEFINE_PER_CPU(char[NAME_SIZE], resched_name);
76static DEFINE_PER_CPU(char[NAME_SIZE], cmc_name);
77static DEFINE_PER_CPU(char[NAME_SIZE], cmcp_name);
78static DEFINE_PER_CPU(char[NAME_SIZE], cpep_name);
79#undef NAME_SIZE
80
81struct saved_irq {
82 unsigned int irq;
83 struct irqaction *action;
84};
85/* 16 should be far optimistic value, since only several percpu irqs
86 * are registered early.
87 */
88#define MAX_LATE_IRQ 16
89static struct saved_irq saved_percpu_irqs[MAX_LATE_IRQ];
90static unsigned short late_irq_cnt;
91static unsigned short saved_irq_cnt;
92static int xen_slab_ready;
93
94#ifdef CONFIG_SMP
95/* Dummy stub. Though we may check XEN_RESCHEDULE_VECTOR before __do_IRQ,
96 * it ends up to issue several memory accesses upon percpu data and
97 * thus adds unnecessary traffic to other paths.
98 */
99static irqreturn_t
100xen_dummy_handler(int irq, void *dev_id)
101{
102
103 return IRQ_HANDLED;
104}
105
106static struct irqaction xen_ipi_irqaction = {
107 .handler = handle_IPI,
108 .flags = IRQF_DISABLED,
109 .name = "IPI"
110};
111
112static struct irqaction xen_resched_irqaction = {
113 .handler = xen_dummy_handler,
114 .flags = IRQF_DISABLED,
115 .name = "resched"
116};
117
118static struct irqaction xen_tlb_irqaction = {
119 .handler = xen_dummy_handler,
120 .flags = IRQF_DISABLED,
121 .name = "tlb_flush"
122};
123#endif
124
125/*
126 * This is xen version percpu irq registration, which needs bind
127 * to xen specific evtchn sub-system. One trick here is that xen
128 * evtchn binding interface depends on kmalloc because related
129 * port needs to be freed at device/cpu down. So we cache the
130 * registration on BSP before slab is ready and then deal them
131 * at later point. For rest instances happening after slab ready,
132 * we hook them to xen evtchn immediately.
133 *
134 * FIXME: MCA is not supported by far, and thus "nomca" boot param is
135 * required.
136 */
137static void
138__xen_register_percpu_irq(unsigned int cpu, unsigned int vec,
139 struct irqaction *action, int save)
140{
141 irq_desc_t *desc;
142 int irq = 0;
143
144 if (xen_slab_ready) {
145 switch (vec) {
146 case IA64_TIMER_VECTOR:
147 snprintf(per_cpu(timer_name, cpu),
148 sizeof(per_cpu(timer_name, cpu)),
149 "%s%d", action->name, cpu);
150 irq = bind_virq_to_irqhandler(VIRQ_ITC, cpu,
151 action->handler, action->flags,
152 per_cpu(timer_name, cpu), action->dev_id);
153 per_cpu(timer_irq, cpu) = irq;
154 break;
155 case IA64_IPI_RESCHEDULE:
156 snprintf(per_cpu(resched_name, cpu),
157 sizeof(per_cpu(resched_name, cpu)),
158 "%s%d", action->name, cpu);
159 irq = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, cpu,
160 action->handler, action->flags,
161 per_cpu(resched_name, cpu), action->dev_id);
162 per_cpu(resched_irq, cpu) = irq;
163 break;
164 case IA64_IPI_VECTOR:
165 snprintf(per_cpu(ipi_name, cpu),
166 sizeof(per_cpu(ipi_name, cpu)),
167 "%s%d", action->name, cpu);
168 irq = bind_ipi_to_irqhandler(XEN_IPI_VECTOR, cpu,
169 action->handler, action->flags,
170 per_cpu(ipi_name, cpu), action->dev_id);
171 per_cpu(ipi_irq, cpu) = irq;
172 break;
173 case IA64_CMC_VECTOR:
174 snprintf(per_cpu(cmc_name, cpu),
175 sizeof(per_cpu(cmc_name, cpu)),
176 "%s%d", action->name, cpu);
177 irq = bind_virq_to_irqhandler(VIRQ_MCA_CMC, cpu,
178 action->handler,
179 action->flags,
180 per_cpu(cmc_name, cpu),
181 action->dev_id);
182 per_cpu(cmc_irq, cpu) = irq;
183 break;
184 case IA64_CMCP_VECTOR:
185 snprintf(per_cpu(cmcp_name, cpu),
186 sizeof(per_cpu(cmcp_name, cpu)),
187 "%s%d", action->name, cpu);
188 irq = bind_ipi_to_irqhandler(XEN_CMCP_VECTOR, cpu,
189 action->handler,
190 action->flags,
191 per_cpu(cmcp_name, cpu),
192 action->dev_id);
193 per_cpu(cmcp_irq, cpu) = irq;
194 break;
195 case IA64_CPEP_VECTOR:
196 snprintf(per_cpu(cpep_name, cpu),
197 sizeof(per_cpu(cpep_name, cpu)),
198 "%s%d", action->name, cpu);
199 irq = bind_ipi_to_irqhandler(XEN_CPEP_VECTOR, cpu,
200 action->handler,
201 action->flags,
202 per_cpu(cpep_name, cpu),
203 action->dev_id);
204 per_cpu(cpep_irq, cpu) = irq;
205 break;
206 case IA64_CPE_VECTOR:
207 case IA64_MCA_RENDEZ_VECTOR:
208 case IA64_PERFMON_VECTOR:
209 case IA64_MCA_WAKEUP_VECTOR:
210 case IA64_SPURIOUS_INT_VECTOR:
211 /* No need to complain, these aren't supported. */
212 break;
213 default:
214 printk(KERN_WARNING "Percpu irq %d is unsupported "
215 "by xen!\n", vec);
216 break;
217 }
218 BUG_ON(irq < 0);
219
220 if (irq > 0) {
221 /*
222 * Mark percpu. Without this, migrate_irqs() will
223 * mark the interrupt for migrations and trigger it
224 * on cpu hotplug.
225 */
226 desc = irq_desc + irq;
227 desc->status |= IRQ_PER_CPU;
228 }
229 }
230
231 /* For BSP, we cache registered percpu irqs, and then re-walk
232 * them when initializing APs
233 */
234 if (!cpu && save) {
235 BUG_ON(saved_irq_cnt == MAX_LATE_IRQ);
236 saved_percpu_irqs[saved_irq_cnt].irq = vec;
237 saved_percpu_irqs[saved_irq_cnt].action = action;
238 saved_irq_cnt++;
239 if (!xen_slab_ready)
240 late_irq_cnt++;
241 }
242}
243
244static void
245xen_register_percpu_irq(ia64_vector vec, struct irqaction *action)
246{
247 __xen_register_percpu_irq(smp_processor_id(), vec, action, 1);
248}
249
250static void
251xen_bind_early_percpu_irq(void)
252{
253 int i;
254
255 xen_slab_ready = 1;
256 /* There's no race when accessing this cached array, since only
257 * BSP will face with such step shortly
258 */
259 for (i = 0; i < late_irq_cnt; i++)
260 __xen_register_percpu_irq(smp_processor_id(),
261 saved_percpu_irqs[i].irq,
262 saved_percpu_irqs[i].action, 0);
263}
264
265/* FIXME: There's no obvious point to check whether slab is ready. So
266 * a hack is used here by utilizing a late time hook.
267 */
268
269#ifdef CONFIG_HOTPLUG_CPU
270static int __devinit
271unbind_evtchn_callback(struct notifier_block *nfb,
272 unsigned long action, void *hcpu)
273{
274 unsigned int cpu = (unsigned long)hcpu;
275
276 if (action == CPU_DEAD) {
277 /* Unregister evtchn. */
278 if (per_cpu(cpep_irq, cpu) >= 0) {
279 unbind_from_irqhandler(per_cpu(cpep_irq, cpu), NULL);
280 per_cpu(cpep_irq, cpu) = -1;
281 }
282 if (per_cpu(cmcp_irq, cpu) >= 0) {
283 unbind_from_irqhandler(per_cpu(cmcp_irq, cpu), NULL);
284 per_cpu(cmcp_irq, cpu) = -1;
285 }
286 if (per_cpu(cmc_irq, cpu) >= 0) {
287 unbind_from_irqhandler(per_cpu(cmc_irq, cpu), NULL);
288 per_cpu(cmc_irq, cpu) = -1;
289 }
290 if (per_cpu(ipi_irq, cpu) >= 0) {
291 unbind_from_irqhandler(per_cpu(ipi_irq, cpu), NULL);
292 per_cpu(ipi_irq, cpu) = -1;
293 }
294 if (per_cpu(resched_irq, cpu) >= 0) {
295 unbind_from_irqhandler(per_cpu(resched_irq, cpu),
296 NULL);
297 per_cpu(resched_irq, cpu) = -1;
298 }
299 if (per_cpu(timer_irq, cpu) >= 0) {
300 unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL);
301 per_cpu(timer_irq, cpu) = -1;
302 }
303 }
304 return NOTIFY_OK;
305}
306
307static struct notifier_block unbind_evtchn_notifier = {
308 .notifier_call = unbind_evtchn_callback,
309 .priority = 0
310};
311#endif
312
313void xen_smp_intr_init_early(unsigned int cpu)
314{
315#ifdef CONFIG_SMP
316 unsigned int i;
317
318 for (i = 0; i < saved_irq_cnt; i++)
319 __xen_register_percpu_irq(cpu, saved_percpu_irqs[i].irq,
320 saved_percpu_irqs[i].action, 0);
321#endif
322}
323
324void xen_smp_intr_init(void)
325{
326#ifdef CONFIG_SMP
327 unsigned int cpu = smp_processor_id();
328 struct callback_register event = {
329 .type = CALLBACKTYPE_event,
330 .address = { .ip = (unsigned long)&xen_event_callback },
331 };
332
333 if (cpu == 0) {
334 /* Initialization was already done for boot cpu. */
335#ifdef CONFIG_HOTPLUG_CPU
336 /* Register the notifier only once. */
337 register_cpu_notifier(&unbind_evtchn_notifier);
338#endif
339 return;
340 }
341
342 /* This should be piggyback when setup vcpu guest context */
343 BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event));
344#endif /* CONFIG_SMP */
345}
346
347void __init
348xen_irq_init(void)
349{
350 struct callback_register event = {
351 .type = CALLBACKTYPE_event,
352 .address = { .ip = (unsigned long)&xen_event_callback },
353 };
354
355 xen_init_IRQ();
356 BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event));
357 late_time_init = xen_bind_early_percpu_irq;
358}
359
360void
361xen_platform_send_ipi(int cpu, int vector, int delivery_mode, int redirect)
362{
363#ifdef CONFIG_SMP
364 /* TODO: we need to call vcpu_up here */
365 if (unlikely(vector == ap_wakeup_vector)) {
366 /* XXX
367 * This should be in __cpu_up(cpu) in ia64 smpboot.c
368 * like x86. But don't want to modify it,
369 * keep it untouched.
370 */
371 xen_smp_intr_init_early(cpu);
372
373 xen_send_ipi(cpu, vector);
374 /* vcpu_prepare_and_up(cpu); */
375 return;
376 }
377#endif
378
379 switch (vector) {
380 case IA64_IPI_VECTOR:
381 xen_send_IPI_one(cpu, XEN_IPI_VECTOR);
382 break;
383 case IA64_IPI_RESCHEDULE:
384 xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
385 break;
386 case IA64_CMCP_VECTOR:
387 xen_send_IPI_one(cpu, XEN_CMCP_VECTOR);
388 break;
389 case IA64_CPEP_VECTOR:
390 xen_send_IPI_one(cpu, XEN_CPEP_VECTOR);
391 break;
392 case IA64_TIMER_VECTOR: {
393 /* this is used only once by check_sal_cache_flush()
394 at boot time */
395 static int used = 0;
396 if (!used) {
397 xen_send_ipi(cpu, IA64_TIMER_VECTOR);
398 used = 1;
399 break;
400 }
401 /* fallthrough */
402 }
403 default:
404 printk(KERN_WARNING "Unsupported IPI type 0x%x\n",
405 vector);
406 notify_remote_via_irq(0); /* defaults to 0 irq */
407 break;
408 }
409}
410
411static void __init
412xen_register_ipi(void)
413{
414#ifdef CONFIG_SMP
415 register_percpu_irq(IA64_IPI_VECTOR, &xen_ipi_irqaction);
416 register_percpu_irq(IA64_IPI_RESCHEDULE, &xen_resched_irqaction);
417 register_percpu_irq(IA64_IPI_LOCAL_TLB_FLUSH, &xen_tlb_irqaction);
418#endif
419}
420
421static void
422xen_resend_irq(unsigned int vector)
423{
424 (void)resend_irq_on_evtchn(vector);
425}
426
427const struct pv_irq_ops xen_irq_ops __initdata = {
428 .register_ipi = xen_register_ipi,
429
430 .assign_irq_vector = xen_assign_irq_vector,
431 .free_irq_vector = xen_free_irq_vector,
432 .register_percpu_irq = xen_register_percpu_irq,
433
434 .resend_irq = xen_resend_irq,
435};
diff --git a/arch/ia64/xen/irq_xen.h b/arch/ia64/xen/irq_xen.h
new file mode 100644
index 000000000000..26110f330c87
--- /dev/null
+++ b/arch/ia64/xen/irq_xen.h
@@ -0,0 +1,34 @@
1/******************************************************************************
2 * arch/ia64/xen/irq_xen.h
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#ifndef IRQ_XEN_H
24#define IRQ_XEN_H
25
26extern void (*late_time_init)(void);
27extern char xen_event_callback;
28void __init xen_init_IRQ(void);
29
30extern const struct pv_irq_ops xen_irq_ops __initdata;
31extern void xen_smp_intr_init(void);
32extern void xen_send_ipi(int cpu, int vec);
33
34#endif /* IRQ_XEN_H */
diff --git a/arch/ia64/xen/machvec.c b/arch/ia64/xen/machvec.c
new file mode 100644
index 000000000000..4ad588a7c279
--- /dev/null
+++ b/arch/ia64/xen/machvec.c
@@ -0,0 +1,4 @@
1#define MACHVEC_PLATFORM_NAME xen
2#define MACHVEC_PLATFORM_HEADER <asm/machvec_xen.h>
3#include <asm/machvec_init.h>
4
diff --git a/arch/ia64/xen/suspend.c b/arch/ia64/xen/suspend.c
new file mode 100644
index 000000000000..fd66b048c6fa
--- /dev/null
+++ b/arch/ia64/xen/suspend.c
@@ -0,0 +1,64 @@
1/******************************************************************************
2 * arch/ia64/xen/suspend.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 * suspend/resume
22 */
23
24#include <xen/xen-ops.h>
25#include <asm/xen/hypervisor.h>
26#include "time.h"
27
28void
29xen_mm_pin_all(void)
30{
31 /* nothing */
32}
33
34void
35xen_mm_unpin_all(void)
36{
37 /* nothing */
38}
39
40void xen_pre_device_suspend(void)
41{
42 /* nothing */
43}
44
45void
46xen_pre_suspend()
47{
48 /* nothing */
49}
50
51void
52xen_post_suspend(int suspend_cancelled)
53{
54 if (suspend_cancelled)
55 return;
56
57 xen_ia64_enable_opt_feature();
58 /* add more if necessary */
59}
60
61void xen_arch_resume(void)
62{
63 xen_timer_resume_on_aps();
64}
diff --git a/arch/ia64/xen/time.c b/arch/ia64/xen/time.c
new file mode 100644
index 000000000000..d15a94c330fb
--- /dev/null
+++ b/arch/ia64/xen/time.c
@@ -0,0 +1,213 @@
1/******************************************************************************
2 * arch/ia64/xen/time.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/delay.h>
24#include <linux/kernel_stat.h>
25#include <linux/posix-timers.h>
26#include <linux/irq.h>
27#include <linux/clocksource.h>
28
29#include <asm/timex.h>
30
31#include <asm/xen/hypervisor.h>
32
33#include <xen/interface/vcpu.h>
34
35#include "../kernel/fsyscall_gtod_data.h"
36
37DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
38DEFINE_PER_CPU(unsigned long, processed_stolen_time);
39DEFINE_PER_CPU(unsigned long, processed_blocked_time);
40
41/* taken from i386/kernel/time-xen.c */
42static void xen_init_missing_ticks_accounting(int cpu)
43{
44 struct vcpu_register_runstate_memory_area area;
45 struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
46 int rc;
47
48 memset(runstate, 0, sizeof(*runstate));
49
50 area.addr.v = runstate;
51 rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu,
52 &area);
53 WARN_ON(rc && rc != -ENOSYS);
54
55 per_cpu(processed_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
56 per_cpu(processed_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
57 + runstate->time[RUNSTATE_offline];
58}
59
60/*
61 * Runstate accounting
62 */
63/* stolen from arch/x86/xen/time.c */
64static void get_runstate_snapshot(struct vcpu_runstate_info *res)
65{
66 u64 state_time;
67 struct vcpu_runstate_info *state;
68
69 BUG_ON(preemptible());
70
71 state = &__get_cpu_var(runstate);
72
73 /*
74 * The runstate info is always updated by the hypervisor on
75 * the current CPU, so there's no need to use anything
76 * stronger than a compiler barrier when fetching it.
77 */
78 do {
79 state_time = state->state_entry_time;
80 rmb();
81 *res = *state;
82 rmb();
83 } while (state->state_entry_time != state_time);
84}
85
86#define NS_PER_TICK (1000000000LL/HZ)
87
88static unsigned long
89consider_steal_time(unsigned long new_itm)
90{
91 unsigned long stolen, blocked;
92 unsigned long delta_itm = 0, stolentick = 0;
93 int cpu = smp_processor_id();
94 struct vcpu_runstate_info runstate;
95 struct task_struct *p = current;
96
97 get_runstate_snapshot(&runstate);
98
99 /*
100 * Check for vcpu migration effect
101 * In this case, itc value is reversed.
102 * This causes huge stolen value.
103 * This function just checks and reject this effect.
104 */
105 if (!time_after_eq(runstate.time[RUNSTATE_blocked],
106 per_cpu(processed_blocked_time, cpu)))
107 blocked = 0;
108
109 if (!time_after_eq(runstate.time[RUNSTATE_runnable] +
110 runstate.time[RUNSTATE_offline],
111 per_cpu(processed_stolen_time, cpu)))
112 stolen = 0;
113
114 if (!time_after(delta_itm + new_itm, ia64_get_itc()))
115 stolentick = ia64_get_itc() - new_itm;
116
117 do_div(stolentick, NS_PER_TICK);
118 stolentick++;
119
120 do_div(stolen, NS_PER_TICK);
121
122 if (stolen > stolentick)
123 stolen = stolentick;
124
125 stolentick -= stolen;
126 do_div(blocked, NS_PER_TICK);
127
128 if (blocked > stolentick)
129 blocked = stolentick;
130
131 if (stolen > 0 || blocked > 0) {
132 account_steal_time(NULL, jiffies_to_cputime(stolen));
133 account_steal_time(idle_task(cpu), jiffies_to_cputime(blocked));
134 run_local_timers();
135
136 if (rcu_pending(cpu))
137 rcu_check_callbacks(cpu, user_mode(get_irq_regs()));
138
139 scheduler_tick();
140 run_posix_cpu_timers(p);
141 delta_itm += local_cpu_data->itm_delta * (stolen + blocked);
142
143 if (cpu == time_keeper_id) {
144 write_seqlock(&xtime_lock);
145 do_timer(stolen + blocked);
146 local_cpu_data->itm_next = delta_itm + new_itm;
147 write_sequnlock(&xtime_lock);
148 } else {
149 local_cpu_data->itm_next = delta_itm + new_itm;
150 }
151 per_cpu(processed_stolen_time, cpu) += NS_PER_TICK * stolen;
152 per_cpu(processed_blocked_time, cpu) += NS_PER_TICK * blocked;
153 }
154 return delta_itm;
155}
156
157static int xen_do_steal_accounting(unsigned long *new_itm)
158{
159 unsigned long delta_itm;
160 delta_itm = consider_steal_time(*new_itm);
161 *new_itm += delta_itm;
162 if (time_after(*new_itm, ia64_get_itc()) && delta_itm)
163 return 1;
164
165 return 0;
166}
167
168static void xen_itc_jitter_data_reset(void)
169{
170 u64 lcycle, ret;
171
172 do {
173 lcycle = itc_jitter_data.itc_lastcycle;
174 ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, 0);
175 } while (unlikely(ret != lcycle));
176}
177
178struct pv_time_ops xen_time_ops __initdata = {
179 .init_missing_ticks_accounting = xen_init_missing_ticks_accounting,
180 .do_steal_accounting = xen_do_steal_accounting,
181 .clocksource_resume = xen_itc_jitter_data_reset,
182};
183
184/* Called after suspend, to resume time. */
185static void xen_local_tick_resume(void)
186{
187 /* Just trigger a tick. */
188 ia64_cpu_local_tick();
189 touch_softlockup_watchdog();
190}
191
192void
193xen_timer_resume(void)
194{
195 unsigned int cpu;
196
197 xen_local_tick_resume();
198
199 for_each_online_cpu(cpu)
200 xen_init_missing_ticks_accounting(cpu);
201}
202
203static void ia64_cpu_local_tick_fn(void *unused)
204{
205 xen_local_tick_resume();
206 xen_init_missing_ticks_accounting(smp_processor_id());
207}
208
209void
210xen_timer_resume_on_aps(void)
211{
212 smp_call_function(&ia64_cpu_local_tick_fn, NULL, 1);
213}
diff --git a/arch/ia64/xen/time.h b/arch/ia64/xen/time.h
new file mode 100644
index 000000000000..f98d7e1a42f0
--- /dev/null
+++ b/arch/ia64/xen/time.h
@@ -0,0 +1,24 @@
1/******************************************************************************
2 * arch/ia64/xen/time.h
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
23extern struct pv_time_ops xen_time_ops __initdata;
24void xen_timer_resume_on_aps(void);
diff --git a/arch/ia64/xen/xcom_hcall.c b/arch/ia64/xen/xcom_hcall.c
new file mode 100644
index 000000000000..ccaf7431f7c8
--- /dev/null
+++ b/arch/ia64/xen/xcom_hcall.c
@@ -0,0 +1,441 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Tristan Gingold <tristan.gingold@bull.net>
17 *
18 * Copyright (c) 2007
19 * Isaku Yamahata <yamahata at valinux co jp>
20 * VA Linux Systems Japan K.K.
21 * consolidate mini and inline version.
22 */
23
24#include <linux/module.h>
25#include <xen/interface/xen.h>
26#include <xen/interface/memory.h>
27#include <xen/interface/grant_table.h>
28#include <xen/interface/callback.h>
29#include <xen/interface/vcpu.h>
30#include <asm/xen/hypervisor.h>
31#include <asm/xen/xencomm.h>
32
33/* Xencomm notes:
34 * This file defines hypercalls to be used by xencomm. The hypercalls simply
35 * create inlines or mini descriptors for pointers and then call the raw arch
36 * hypercall xencomm_arch_hypercall_XXX
37 *
38 * If the arch wants to directly use these hypercalls, simply define macros
39 * in asm/xen/hypercall.h, eg:
40 * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
41 *
42 * The arch may also define HYPERVISOR_xxx as a function and do more operations
43 * before/after doing the hypercall.
44 *
45 * Note: because only inline or mini descriptors are created these functions
46 * must only be called with in kernel memory parameters.
47 */
48
49int
50xencomm_hypercall_console_io(int cmd, int count, char *str)
51{
52 /* xen early printk uses console io hypercall before
53 * xencomm initialization. In that case, we just ignore it.
54 */
55 if (!xencomm_is_initialized())
56 return 0;
57
58 return xencomm_arch_hypercall_console_io
59 (cmd, count, xencomm_map_no_alloc(str, count));
60}
61EXPORT_SYMBOL_GPL(xencomm_hypercall_console_io);
62
63int
64xencomm_hypercall_event_channel_op(int cmd, void *op)
65{
66 struct xencomm_handle *desc;
67 desc = xencomm_map_no_alloc(op, sizeof(struct evtchn_op));
68 if (desc == NULL)
69 return -EINVAL;
70
71 return xencomm_arch_hypercall_event_channel_op(cmd, desc);
72}
73EXPORT_SYMBOL_GPL(xencomm_hypercall_event_channel_op);
74
75int
76xencomm_hypercall_xen_version(int cmd, void *arg)
77{
78 struct xencomm_handle *desc;
79 unsigned int argsize;
80
81 switch (cmd) {
82 case XENVER_version:
83 /* do not actually pass an argument */
84 return xencomm_arch_hypercall_xen_version(cmd, 0);
85 case XENVER_extraversion:
86 argsize = sizeof(struct xen_extraversion);
87 break;
88 case XENVER_compile_info:
89 argsize = sizeof(struct xen_compile_info);
90 break;
91 case XENVER_capabilities:
92 argsize = sizeof(struct xen_capabilities_info);
93 break;
94 case XENVER_changeset:
95 argsize = sizeof(struct xen_changeset_info);
96 break;
97 case XENVER_platform_parameters:
98 argsize = sizeof(struct xen_platform_parameters);
99 break;
100 case XENVER_get_features:
101 argsize = (arg == NULL) ? 0 : sizeof(struct xen_feature_info);
102 break;
103
104 default:
105 printk(KERN_DEBUG
106 "%s: unknown version op %d\n", __func__, cmd);
107 return -ENOSYS;
108 }
109
110 desc = xencomm_map_no_alloc(arg, argsize);
111 if (desc == NULL)
112 return -EINVAL;
113
114 return xencomm_arch_hypercall_xen_version(cmd, desc);
115}
116EXPORT_SYMBOL_GPL(xencomm_hypercall_xen_version);
117
118int
119xencomm_hypercall_physdev_op(int cmd, void *op)
120{
121 unsigned int argsize;
122
123 switch (cmd) {
124 case PHYSDEVOP_apic_read:
125 case PHYSDEVOP_apic_write:
126 argsize = sizeof(struct physdev_apic);
127 break;
128 case PHYSDEVOP_alloc_irq_vector:
129 case PHYSDEVOP_free_irq_vector:
130 argsize = sizeof(struct physdev_irq);
131 break;
132 case PHYSDEVOP_irq_status_query:
133 argsize = sizeof(struct physdev_irq_status_query);
134 break;
135
136 default:
137 printk(KERN_DEBUG
138 "%s: unknown physdev op %d\n", __func__, cmd);
139 return -ENOSYS;
140 }
141
142 return xencomm_arch_hypercall_physdev_op
143 (cmd, xencomm_map_no_alloc(op, argsize));
144}
145
146static int
147xencommize_grant_table_op(struct xencomm_mini **xc_area,
148 unsigned int cmd, void *op, unsigned int count,
149 struct xencomm_handle **desc)
150{
151 struct xencomm_handle *desc1;
152 unsigned int argsize;
153
154 switch (cmd) {
155 case GNTTABOP_map_grant_ref:
156 argsize = sizeof(struct gnttab_map_grant_ref);
157 break;
158 case GNTTABOP_unmap_grant_ref:
159 argsize = sizeof(struct gnttab_unmap_grant_ref);
160 break;
161 case GNTTABOP_setup_table:
162 {
163 struct gnttab_setup_table *setup = op;
164
165 argsize = sizeof(*setup);
166
167 if (count != 1)
168 return -EINVAL;
169 desc1 = __xencomm_map_no_alloc
170 (xen_guest_handle(setup->frame_list),
171 setup->nr_frames *
172 sizeof(*xen_guest_handle(setup->frame_list)),
173 *xc_area);
174 if (desc1 == NULL)
175 return -EINVAL;
176 (*xc_area)++;
177 set_xen_guest_handle(setup->frame_list, (void *)desc1);
178 break;
179 }
180 case GNTTABOP_dump_table:
181 argsize = sizeof(struct gnttab_dump_table);
182 break;
183 case GNTTABOP_transfer:
184 argsize = sizeof(struct gnttab_transfer);
185 break;
186 case GNTTABOP_copy:
187 argsize = sizeof(struct gnttab_copy);
188 break;
189 case GNTTABOP_query_size:
190 argsize = sizeof(struct gnttab_query_size);
191 break;
192 default:
193 printk(KERN_DEBUG "%s: unknown hypercall grant table op %d\n",
194 __func__, cmd);
195 BUG();
196 }
197
198 *desc = __xencomm_map_no_alloc(op, count * argsize, *xc_area);
199 if (*desc == NULL)
200 return -EINVAL;
201 (*xc_area)++;
202
203 return 0;
204}
205
206int
207xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
208 unsigned int count)
209{
210 int rc;
211 struct xencomm_handle *desc;
212 XENCOMM_MINI_ALIGNED(xc_area, 2);
213
214 rc = xencommize_grant_table_op(&xc_area, cmd, op, count, &desc);
215 if (rc)
216 return rc;
217
218 return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
219}
220EXPORT_SYMBOL_GPL(xencomm_hypercall_grant_table_op);
221
222int
223xencomm_hypercall_sched_op(int cmd, void *arg)
224{
225 struct xencomm_handle *desc;
226 unsigned int argsize;
227
228 switch (cmd) {
229 case SCHEDOP_yield:
230 case SCHEDOP_block:
231 argsize = 0;
232 break;
233 case SCHEDOP_shutdown:
234 argsize = sizeof(struct sched_shutdown);
235 break;
236 case SCHEDOP_poll:
237 {
238 struct sched_poll *poll = arg;
239 struct xencomm_handle *ports;
240
241 argsize = sizeof(struct sched_poll);
242 ports = xencomm_map_no_alloc(xen_guest_handle(poll->ports),
243 sizeof(*xen_guest_handle(poll->ports)));
244
245 set_xen_guest_handle(poll->ports, (void *)ports);
246 break;
247 }
248 default:
249 printk(KERN_DEBUG "%s: unknown sched op %d\n", __func__, cmd);
250 return -ENOSYS;
251 }
252
253 desc = xencomm_map_no_alloc(arg, argsize);
254 if (desc == NULL)
255 return -EINVAL;
256
257 return xencomm_arch_hypercall_sched_op(cmd, desc);
258}
259EXPORT_SYMBOL_GPL(xencomm_hypercall_sched_op);
260
261int
262xencomm_hypercall_multicall(void *call_list, int nr_calls)
263{
264 int rc;
265 int i;
266 struct multicall_entry *mce;
267 struct xencomm_handle *desc;
268 XENCOMM_MINI_ALIGNED(xc_area, nr_calls * 2);
269
270 for (i = 0; i < nr_calls; i++) {
271 mce = (struct multicall_entry *)call_list + i;
272
273 switch (mce->op) {
274 case __HYPERVISOR_update_va_mapping:
275 case __HYPERVISOR_mmu_update:
276 /* No-op on ia64. */
277 break;
278 case __HYPERVISOR_grant_table_op:
279 rc = xencommize_grant_table_op
280 (&xc_area,
281 mce->args[0], (void *)mce->args[1],
282 mce->args[2], &desc);
283 if (rc)
284 return rc;
285 mce->args[1] = (unsigned long)desc;
286 break;
287 case __HYPERVISOR_memory_op:
288 default:
289 printk(KERN_DEBUG
290 "%s: unhandled multicall op entry op %lu\n",
291 __func__, mce->op);
292 return -ENOSYS;
293 }
294 }
295
296 desc = xencomm_map_no_alloc(call_list,
297 nr_calls * sizeof(struct multicall_entry));
298 if (desc == NULL)
299 return -EINVAL;
300
301 return xencomm_arch_hypercall_multicall(desc, nr_calls);
302}
303EXPORT_SYMBOL_GPL(xencomm_hypercall_multicall);
304
305int
306xencomm_hypercall_callback_op(int cmd, void *arg)
307{
308 unsigned int argsize;
309 switch (cmd) {
310 case CALLBACKOP_register:
311 argsize = sizeof(struct callback_register);
312 break;
313 case CALLBACKOP_unregister:
314 argsize = sizeof(struct callback_unregister);
315 break;
316 default:
317 printk(KERN_DEBUG
318 "%s: unknown callback op %d\n", __func__, cmd);
319 return -ENOSYS;
320 }
321
322 return xencomm_arch_hypercall_callback_op
323 (cmd, xencomm_map_no_alloc(arg, argsize));
324}
325
326static int
327xencommize_memory_reservation(struct xencomm_mini *xc_area,
328 struct xen_memory_reservation *mop)
329{
330 struct xencomm_handle *desc;
331
332 desc = __xencomm_map_no_alloc(xen_guest_handle(mop->extent_start),
333 mop->nr_extents *
334 sizeof(*xen_guest_handle(mop->extent_start)),
335 xc_area);
336 if (desc == NULL)
337 return -EINVAL;
338
339 set_xen_guest_handle(mop->extent_start, (void *)desc);
340 return 0;
341}
342
343int
344xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
345{
346 GUEST_HANDLE(xen_pfn_t) extent_start_va[2] = { {NULL}, {NULL} };
347 struct xen_memory_reservation *xmr = NULL;
348 int rc;
349 struct xencomm_handle *desc;
350 unsigned int argsize;
351 XENCOMM_MINI_ALIGNED(xc_area, 2);
352
353 switch (cmd) {
354 case XENMEM_increase_reservation:
355 case XENMEM_decrease_reservation:
356 case XENMEM_populate_physmap:
357 xmr = (struct xen_memory_reservation *)arg;
358 set_xen_guest_handle(extent_start_va[0],
359 xen_guest_handle(xmr->extent_start));
360
361 argsize = sizeof(*xmr);
362 rc = xencommize_memory_reservation(xc_area, xmr);
363 if (rc)
364 return rc;
365 xc_area++;
366 break;
367
368 case XENMEM_maximum_ram_page:
369 argsize = 0;
370 break;
371
372 case XENMEM_add_to_physmap:
373 argsize = sizeof(struct xen_add_to_physmap);
374 break;
375
376 default:
377 printk(KERN_DEBUG "%s: unknown memory op %d\n", __func__, cmd);
378 return -ENOSYS;
379 }
380
381 desc = xencomm_map_no_alloc(arg, argsize);
382 if (desc == NULL)
383 return -EINVAL;
384
385 rc = xencomm_arch_hypercall_memory_op(cmd, desc);
386
387 switch (cmd) {
388 case XENMEM_increase_reservation:
389 case XENMEM_decrease_reservation:
390 case XENMEM_populate_physmap:
391 set_xen_guest_handle(xmr->extent_start,
392 xen_guest_handle(extent_start_va[0]));
393 break;
394 }
395
396 return rc;
397}
398EXPORT_SYMBOL_GPL(xencomm_hypercall_memory_op);
399
400int
401xencomm_hypercall_suspend(unsigned long srec)
402{
403 struct sched_shutdown arg;
404
405 arg.reason = SHUTDOWN_suspend;
406
407 return xencomm_arch_hypercall_sched_op(
408 SCHEDOP_shutdown, xencomm_map_no_alloc(&arg, sizeof(arg)));
409}
410
411long
412xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg)
413{
414 unsigned int argsize;
415 switch (cmd) {
416 case VCPUOP_register_runstate_memory_area: {
417 struct vcpu_register_runstate_memory_area *area =
418 (struct vcpu_register_runstate_memory_area *)arg;
419 argsize = sizeof(*arg);
420 set_xen_guest_handle(area->addr.h,
421 (void *)xencomm_map_no_alloc(area->addr.v,
422 sizeof(area->addr.v)));
423 break;
424 }
425
426 default:
427 printk(KERN_DEBUG "%s: unknown vcpu op %d\n", __func__, cmd);
428 return -ENOSYS;
429 }
430
431 return xencomm_arch_hypercall_vcpu_op(cmd, cpu,
432 xencomm_map_no_alloc(arg, argsize));
433}
434
435long
436xencomm_hypercall_opt_feature(void *arg)
437{
438 return xencomm_arch_hypercall_opt_feature(
439 xencomm_map_no_alloc(arg,
440 sizeof(struct xen_ia64_opt_feature)));
441}
diff --git a/arch/ia64/xen/xen_pv_ops.c b/arch/ia64/xen/xen_pv_ops.c
new file mode 100644
index 000000000000..04cd12350455
--- /dev/null
+++ b/arch/ia64/xen/xen_pv_ops.c
@@ -0,0 +1,364 @@
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 */
38static 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
49static void __init
50xen_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
64static void
65xen_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
72static int
73xen_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
80static struct notifier_block xen_panic_block = {
81 xen_panic_event, NULL, 0 /* try to go last */
82};
83
84static void xen_pm_power_off(void)
85{
86 local_irq_disable();
87 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
88}
89
90static void __init
91xen_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
101static int __init
102xen_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
110static void __init
111xen_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
131static void __init
132xen_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
144static int __init
145xen_arch_setup_nomca(void)
146{
147 return 1;
148}
149
150static void __init
151xen_post_smp_prepare_boot_cpu(void)
152{
153 xen_setup_vcpu_info_placement();
154}
155
156static 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
173static 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
199static 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! */
229static void
230xen_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) */
241static void
242xen_rsm_i(void)
243{
244 xen_set_virtual_psr_i(0);
245 barrier();
246}
247
248static unsigned long
249xen_get_psr_i(void)
250{
251 return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
252}
253
254static void
255xen_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
263static 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
285extern char xen_switch_to;
286extern char xen_leave_syscall;
287extern char xen_work_processed_syscall;
288extern char xen_leave_kernel;
289
290const 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 */
301static void
302xen_pcat_compat_init(void)
303{
304 /* nothing */
305}
306
307static struct irq_chip*
308xen_iosapic_get_irq_chip(unsigned long trigger)
309{
310 return NULL;
311}
312
313static unsigned int
314xen_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
328static void
329xen_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
340static 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
352void __init
353xen_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}
diff --git a/arch/ia64/xen/xencomm.c b/arch/ia64/xen/xencomm.c
new file mode 100644
index 000000000000..1f5d7ac82e97
--- /dev/null
+++ b/arch/ia64/xen/xencomm.c
@@ -0,0 +1,105 @@
1/*
2 * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <linux/mm.h>
20
21static unsigned long kernel_virtual_offset;
22static int is_xencomm_initialized;
23
24/* for xen early printk. It uses console io hypercall which uses xencomm.
25 * However early printk may use it before xencomm initialization.
26 */
27int
28xencomm_is_initialized(void)
29{
30 return is_xencomm_initialized;
31}
32
33void
34xencomm_initialize(void)
35{
36 kernel_virtual_offset = KERNEL_START - ia64_tpa(KERNEL_START);
37 is_xencomm_initialized = 1;
38}
39
40/* Translate virtual address to physical address. */
41unsigned long
42xencomm_vtop(unsigned long vaddr)
43{
44 struct page *page;
45 struct vm_area_struct *vma;
46
47 if (vaddr == 0)
48 return 0UL;
49
50 if (REGION_NUMBER(vaddr) == 5) {
51 pgd_t *pgd;
52 pud_t *pud;
53 pmd_t *pmd;
54 pte_t *ptep;
55
56 /* On ia64, TASK_SIZE refers to current. It is not initialized
57 during boot.
58 Furthermore the kernel is relocatable and __pa() doesn't
59 work on addresses. */
60 if (vaddr >= KERNEL_START
61 && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE))
62 return vaddr - kernel_virtual_offset;
63
64 /* In kernel area -- virtually mapped. */
65 pgd = pgd_offset_k(vaddr);
66 if (pgd_none(*pgd) || pgd_bad(*pgd))
67 return ~0UL;
68
69 pud = pud_offset(pgd, vaddr);
70 if (pud_none(*pud) || pud_bad(*pud))
71 return ~0UL;
72
73 pmd = pmd_offset(pud, vaddr);
74 if (pmd_none(*pmd) || pmd_bad(*pmd))
75 return ~0UL;
76
77 ptep = pte_offset_kernel(pmd, vaddr);
78 if (!ptep)
79 return ~0UL;
80
81 return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK);
82 }
83
84 if (vaddr > TASK_SIZE) {
85 /* percpu variables */
86 if (REGION_NUMBER(vaddr) == 7 &&
87 REGION_OFFSET(vaddr) >= (1ULL << IA64_MAX_PHYS_BITS))
88 ia64_tpa(vaddr);
89
90 /* kernel address */
91 return __pa(vaddr);
92 }
93
94 /* XXX double-check (lack of) locking */
95 vma = find_extend_vma(current->mm, vaddr);
96 if (!vma)
97 return ~0UL;
98
99 /* We assume the page is modified. */
100 page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
101 if (!page)
102 return ~0UL;
103
104 return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
105}
diff --git a/arch/ia64/xen/xenivt.S b/arch/ia64/xen/xenivt.S
new file mode 100644
index 000000000000..3e71d50584d9
--- /dev/null
+++ b/arch/ia64/xen/xenivt.S
@@ -0,0 +1,52 @@
1/*
2 * arch/ia64/xen/ivt.S
3 *
4 * Copyright (C) 2005 Hewlett-Packard Co
5 * Dan Magenheimer <dan.magenheimer@hp.com>
6 *
7 * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
8 * VA Linux Systems Japan K.K.
9 * pv_ops.
10 */
11
12#include <asm/asmmacro.h>
13#include <asm/kregs.h>
14#include <asm/pgtable.h>
15
16#include "../kernel/minstate.h"
17
18 .section .text,"ax"
19GLOBAL_ENTRY(xen_event_callback)
20 mov r31=pr // prepare to save predicates
21 ;;
22 SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3
23 ;;
24 movl r3=XSI_PSR_IC
25 mov r14=1
26 ;;
27 st4 [r3]=r14
28 ;;
29 adds r3=8,r2 // set up second base pointer for SAVE_REST
30 srlz.i // ensure everybody knows psr.ic is back on
31 ;;
32 SAVE_REST
33 ;;
341:
35 alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group
36 add out0=16,sp // pass pointer to pt_regs as first arg
37 ;;
38 br.call.sptk.many b0=xen_evtchn_do_upcall
39 ;;
40 movl r20=XSI_PSR_I_ADDR
41 ;;
42 ld8 r20=[r20]
43 ;;
44 adds r20=-1,r20 // vcpu_info->evtchn_upcall_pending
45 ;;
46 ld1 r20=[r20]
47 ;;
48 cmp.ne p6,p0=r20,r0 // if there are pending events,
49 (p6) br.spnt.few 1b // call evtchn_do_upcall again.
50 br.sptk.many xen_leave_kernel // we know ia64_leave_kernel is
51 // paravirtualized as xen_leave_kernel
52END(xen_event_callback)
diff --git a/arch/ia64/xen/xensetup.S b/arch/ia64/xen/xensetup.S
new file mode 100644
index 000000000000..28fed1fcc079
--- /dev/null
+++ b/arch/ia64/xen/xensetup.S
@@ -0,0 +1,83 @@
1/*
2 * Support routines for Xen
3 *
4 * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer@hp.com>
5 */
6
7#include <asm/processor.h>
8#include <asm/asmmacro.h>
9#include <asm/pgtable.h>
10#include <asm/system.h>
11#include <asm/paravirt.h>
12#include <asm/xen/privop.h>
13#include <linux/elfnote.h>
14#include <linux/init.h>
15#include <xen/interface/elfnote.h>
16
17 .section .data.read_mostly
18 .align 8
19 .global xen_domain_type
20xen_domain_type:
21 data4 XEN_NATIVE_ASM
22 .previous
23
24 __INIT
25ENTRY(startup_xen)
26 // Calculate load offset.
27 // The constant, LOAD_OFFSET, can't be used because the boot
28 // loader doesn't always load to the LMA specified by the vmlinux.lds.
29 mov r9=ip // must be the first instruction to make sure
30 // that r9 = the physical address of startup_xen.
31 // Usually r9 = startup_xen - LOAD_OFFSET
32 movl r8=startup_xen
33 ;;
34 sub r9=r9,r8 // Usually r9 = -LOAD_OFFSET.
35
36 mov r10=PARAVIRT_HYPERVISOR_TYPE_XEN
37 movl r11=_start
38 ;;
39 add r11=r11,r9
40 movl r8=hypervisor_type
41 ;;
42 add r8=r8,r9
43 mov b0=r11
44 ;;
45 st8 [r8]=r10
46 br.cond.sptk.many b0
47 ;;
48END(startup_xen)
49
50 ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
51 ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6")
52 ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0")
53 ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, data8.ua startup_xen - LOAD_OFFSET)
54
55#define isBP p3 // are we the Bootstrap Processor?
56
57 .text
58
59GLOBAL_ENTRY(xen_setup_hook)
60 mov r8=XEN_PV_DOMAIN_ASM
61(isBP) movl r9=xen_domain_type;;
62(isBP) st4 [r9]=r8
63 movl r10=xen_ivt;;
64
65 mov cr.iva=r10
66
67 /* Set xsi base. */
68#define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600
69(isBP) mov r2=FW_HYPERCALL_SET_SHARED_INFO_VA
70(isBP) movl r28=XSI_BASE;;
71(isBP) break 0x1000;;
72
73 /* setup pv_ops */
74(isBP) mov r4=rp
75 ;;
76(isBP) br.call.sptk.many rp=xen_setup_pv_ops
77 ;;
78(isBP) mov rp=r4
79 ;;
80
81 br.ret.sptk.many rp
82 ;;
83END(xen_setup_hook)