This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / x86_64 / kernel / genapic_xen.c
1 /*
2  * Copyright 2004 James Cleverdon, IBM.
3  * Subject to the GNU Public License, v.2
4  *
5  * Xen APIC subarch code.  Maximum 8 CPUs, logical delivery.
6  *
7  * Hacked for x86-64 by James Cleverdon from i386 architecture code by
8  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
9  * James Cleverdon.
10  *
11  * Hacked to pieces for Xen by Chris Wright.
12  */
13 #include <linux/config.h>
14 #include <linux/threads.h>
15 #include <linux/cpumask.h>
16 #include <linux/string.h>
17 #include <linux/kernel.h>
18 #include <linux/ctype.h>
19 #include <linux/init.h>
20 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
21 #include <asm/smp.h>
22 #include <asm/ipi.h>
23 #else
24 #include <asm/apic.h>
25 #include <asm/apicdef.h>
26 #include <asm/genapic.h>
27 #endif
28 #include <xen/evtchn.h>
29
30 DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
31
32 static inline void __send_IPI_one(unsigned int cpu, int vector)
33 {
34         int irq = per_cpu(ipi_to_irq, cpu)[vector];
35         BUG_ON(irq < 0);
36         notify_remote_via_irq(irq);
37 }
38
39 void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
40 {
41         int cpu;
42
43         switch (shortcut) {
44         case APIC_DEST_SELF:
45                 __send_IPI_one(smp_processor_id(), vector);
46                 break;
47         case APIC_DEST_ALLBUT:
48                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
49                         if (cpu == smp_processor_id())
50                                 continue;
51                         if (cpu_isset(cpu, cpu_online_map)) {
52                                 __send_IPI_one(cpu, vector);
53                         }
54                 }
55                 break;
56         case APIC_DEST_ALLINC:
57                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
58                         if (cpu_isset(cpu, cpu_online_map)) {
59                                 __send_IPI_one(cpu, vector);
60                         }
61                 }
62                 break;
63         default:
64                 printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
65                        vector);
66                 break;
67         }
68 }
69
70 static cpumask_t xen_target_cpus(void)
71 {
72         return cpu_online_map;
73 }
74
75 /*
76  * Set up the logical destination ID.
77  * Do nothing, not called now.
78  */
79 static void xen_init_apic_ldr(void)
80 {
81         Dprintk("%s\n", __FUNCTION__);
82         return;
83 }
84
85 static void xen_send_IPI_allbutself(int vector)
86 {
87         /*
88          * if there are no other CPUs in the system then
89          * we get an APIC send error if we try to broadcast.
90          * thus we have to avoid sending IPIs in this case.
91          */
92         Dprintk("%s\n", __FUNCTION__);
93         if (num_online_cpus() > 1)
94                 xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
95 }
96
97 static void xen_send_IPI_all(int vector)
98 {
99         Dprintk("%s\n", __FUNCTION__);
100         xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
101 }
102
103 static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
104 {
105         unsigned long mask = cpus_addr(cpumask)[0];
106         unsigned int cpu;
107         unsigned long flags;
108
109         Dprintk("%s\n", __FUNCTION__);
110         local_irq_save(flags);
111         WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
112
113         for (cpu = 0; cpu < NR_CPUS; ++cpu) {
114                 if (cpu_isset(cpu, cpumask)) {
115                         __send_IPI_one(cpu, vector);
116                 }
117         }
118         local_irq_restore(flags);
119 }
120
121 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
122 static int xen_apic_id_registered(void)
123 {
124         /* better be set */
125         Dprintk("%s\n", __FUNCTION__);
126         return physid_isset(smp_processor_id(), phys_cpu_present_map);
127 }
128 #endif
129
130 static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
131 {
132         Dprintk("%s\n", __FUNCTION__);
133         return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
134 }
135
136 static unsigned int phys_pkg_id(int index_msb)
137 {
138         u32 ebx;
139
140         Dprintk("%s\n", __FUNCTION__);
141         ebx = cpuid_ebx(1);
142         return ((ebx >> 24) & 0xFF) >> index_msb;
143 }
144
145 struct genapic apic_xen =  {
146         .name = "xen",
147 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
148         .int_delivery_mode = dest_LowestPrio,
149 #endif
150         .int_dest_mode = (APIC_DEST_LOGICAL != 0),
151         .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
152         .target_cpus = xen_target_cpus,
153 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
154         .apic_id_registered = xen_apic_id_registered,
155 #endif
156         .init_apic_ldr = xen_init_apic_ldr,
157         .send_IPI_all = xen_send_IPI_all,
158         .send_IPI_allbutself = xen_send_IPI_allbutself,
159         .send_IPI_mask = xen_send_IPI_mask,
160         .cpu_mask_to_apicid = xen_cpu_mask_to_apicid,
161         .phys_pkg_id = phys_pkg_id,
162 };