2 * Copyright 2004 James Cleverdon, IBM.
3 * Subject to the GNU Public License, v.2
5 * Xen APIC subarch code. Maximum 8 CPUs, logical delivery.
7 * Hacked for x86-64 by James Cleverdon from i386 architecture code by
8 * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
11 * Hacked to pieces for Xen by Chris Wright.
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
24 #include <asm/apicdef.h>
25 #include <asm/genapic.h>
27 #include <xen/evtchn.h>
29 DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
31 static inline void __send_IPI_one(unsigned int cpu, int vector)
33 int irq = per_cpu(ipi_to_irq, cpu)[vector];
35 notify_remote_via_irq(irq);
38 void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
44 __send_IPI_one(smp_processor_id(), vector);
46 case APIC_DEST_ALLBUT:
47 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
48 if (cpu == smp_processor_id())
50 if (cpu_isset(cpu, cpu_online_map)) {
51 __send_IPI_one(cpu, vector);
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);
63 printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
69 static cpumask_t xen_target_cpus(void)
71 return cpu_online_map;
74 static cpumask_t xen_vector_allocation_domain(int cpu)
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.
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.
84 cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
89 * Set up the logical destination ID.
90 * Do nothing, not called now.
92 static void xen_init_apic_ldr(void)
94 Dprintk("%s\n", __FUNCTION__);
98 static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
100 unsigned long mask = cpus_addr(cpumask)[0];
104 Dprintk("%s\n", __FUNCTION__);
105 local_irq_save(flags);
106 WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
108 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
109 if (cpu_isset(cpu, cpumask)) {
110 __send_IPI_one(cpu, vector);
113 local_irq_restore(flags);
116 static void xen_send_IPI_allbutself(int vector)
118 #ifdef CONFIG_HOTPLUG_CPU
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.
128 Dprintk("%s\n", __FUNCTION__);
129 if (hotplug || vector == NMI_VECTOR) {
130 cpumask_t allbutme = cpu_online_map;
132 cpu_clear(smp_processor_id(), allbutme);
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);
141 static void xen_send_IPI_all(int vector)
143 Dprintk("%s\n", __FUNCTION__);
144 if (vector == NMI_VECTOR)
145 xen_send_IPI_mask(cpu_online_map, vector);
147 xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
150 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
151 static int xen_apic_id_registered(void)
154 Dprintk("%s\n", __FUNCTION__);
155 return physid_isset(smp_processor_id(), phys_cpu_present_map);
159 static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
161 Dprintk("%s\n", __FUNCTION__);
162 return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
165 static unsigned int phys_pkg_id(int index_msb)
168 Dprintk("%s\n", __FUNCTION__);
170 return ((ebx >> 24) & 0xFF) >> index_msb;
173 struct genapic apic_xen = {
175 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
176 .int_delivery_mode = dest_LowestPrio,
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,
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,