fedora core 6 1.2949 + vserver 2.2.0
[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/threads.h>
14 #include <linux/cpumask.h>
15 #include <linux/string.h>
16 #include <linux/kernel.h>
17 #include <linux/ctype.h>
18 #include <linux/init.h>
19 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
20 #include <asm/smp.h>
21 #include <asm/ipi.h>
22 #else
23 #include <asm/apic.h>
24 #include <asm/apicdef.h>
25 #include <asm/genapic.h>
26 #endif
27 #include <xen/evtchn.h>
28
29 DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
30
31 static inline void __send_IPI_one(unsigned int cpu, int vector)
32 {
33         int irq = per_cpu(ipi_to_irq, cpu)[vector];
34         BUG_ON(irq < 0);
35         notify_remote_via_irq(irq);
36 }
37
38 void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
39 {
40         int cpu;
41
42         switch (shortcut) {
43         case APIC_DEST_SELF:
44                 __send_IPI_one(smp_processor_id(), vector);
45                 break;
46         case APIC_DEST_ALLBUT:
47                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
48                         if (cpu == smp_processor_id())
49                                 continue;
50                         if (cpu_isset(cpu, cpu_online_map)) {
51                                 __send_IPI_one(cpu, vector);
52                         }
53                 }
54                 break;
55         case APIC_DEST_ALLINC:
56                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
57                         if (cpu_isset(cpu, cpu_online_map)) {
58                                 __send_IPI_one(cpu, vector);
59                         }
60                 }
61                 break;
62         default:
63                 printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
64                        vector);
65                 break;
66         }
67 }
68
69 static cpumask_t xen_target_cpus(void)
70 {
71         return cpu_online_map;
72 }
73
74 static cpumask_t xen_vector_allocation_domain(int cpu)
75 {
76         /* Careful. Some cpus do not strictly honor the set of cpus
77          * specified in the interrupt destination when using lowest
78          * priority interrupt delivery mode.
79          *
80          * In particular there was a hyperthreading cpu observed to
81          * deliver interrupts to the wrong hyperthread when only one
82          * hyperthread was specified in the interrupt desitination.
83          */
84         cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
85         return domain;
86 }
87
88 /*
89  * Set up the logical destination ID.
90  * Do nothing, not called now.
91  */
92 static void xen_init_apic_ldr(void)
93 {
94         Dprintk("%s\n", __FUNCTION__);
95         return;
96 }
97
98 static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
99 {
100         unsigned long mask = cpus_addr(cpumask)[0];
101         unsigned int cpu;
102         unsigned long flags;
103
104         Dprintk("%s\n", __FUNCTION__);
105         local_irq_save(flags);
106         WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
107
108         for (cpu = 0; cpu < NR_CPUS; ++cpu) {
109                 if (cpu_isset(cpu, cpumask)) {
110                         __send_IPI_one(cpu, vector);
111                 }
112         }
113         local_irq_restore(flags);
114 }
115
116 static void xen_send_IPI_allbutself(int vector)
117 {
118 #ifdef  CONFIG_HOTPLUG_CPU
119         int hotplug = 1;
120 #else
121         int hotplug = 0;
122 #endif
123         /*
124          * if there are no other CPUs in the system then
125          * we get an APIC send error if we try to broadcast.
126          * thus we have to avoid sending IPIs in this case.
127          */
128         Dprintk("%s\n", __FUNCTION__);
129         if (hotplug || vector == NMI_VECTOR) {
130                 cpumask_t allbutme = cpu_online_map;
131
132                 cpu_clear(smp_processor_id(), allbutme);
133
134                 if (!cpus_empty(allbutme))
135                         xen_send_IPI_mask(allbutme, vector);
136         } else if (num_online_cpus() > 1) {
137                 xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
138         }
139 }
140
141 static void xen_send_IPI_all(int vector)
142 {
143         Dprintk("%s\n", __FUNCTION__);
144         if (vector == NMI_VECTOR)
145                 xen_send_IPI_mask(cpu_online_map, vector);
146         else
147                 xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
148 }
149
150 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
151 static int xen_apic_id_registered(void)
152 {
153         /* better be set */
154         Dprintk("%s\n", __FUNCTION__);
155         return physid_isset(smp_processor_id(), phys_cpu_present_map);
156 }
157 #endif
158
159 static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
160 {
161         Dprintk("%s\n", __FUNCTION__);
162         return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
163 }
164
165 static unsigned int phys_pkg_id(int index_msb)
166 {
167         int ebx;
168         Dprintk("%s\n", __FUNCTION__);
169         ebx = cpuid_ebx(1);
170         return ((ebx >> 24) & 0xFF) >> index_msb;
171 }
172
173 struct genapic apic_xen =  {
174         .name = "xen",
175 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
176         .int_delivery_mode = dest_LowestPrio,
177 #endif
178         .int_dest_mode = (APIC_DEST_LOGICAL != 0),
179         .target_cpus = xen_target_cpus,
180         .vector_allocation_domain = xen_vector_allocation_domain,
181 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
182         .apic_id_registered = xen_apic_id_registered,
183 #endif
184         .init_apic_ldr = xen_init_apic_ldr,
185         .send_IPI_all = xen_send_IPI_all,
186         .send_IPI_allbutself = xen_send_IPI_allbutself,
187         .send_IPI_mask = xen_send_IPI_mask,
188         .cpu_mask_to_apicid = xen_cpu_mask_to_apicid,
189         .phys_pkg_id = phys_pkg_id,
190 };