diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/genapic_flat.c | 96 |
1 files changed, 82 insertions, 14 deletions
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index 00f3fa6df714..282846965080 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c | |||
@@ -20,6 +20,46 @@ | |||
20 | #include <asm/smp.h> | 20 | #include <asm/smp.h> |
21 | #include <asm/ipi.h> | 21 | #include <asm/ipi.h> |
22 | 22 | ||
23 | /* | ||
24 | * The following permit choosing broadcast IPI shortcut v.s sending IPI only | ||
25 | * to online cpus via the send_IPI_mask varient. | ||
26 | * The mask version is my preferred option, since it eliminates a lot of | ||
27 | * other extra code that would need to be written to cleanup intrs sent | ||
28 | * to a CPU while offline. | ||
29 | * | ||
30 | * Sending broadcast introduces lots of trouble in CPU hotplug situations. | ||
31 | * These IPI's are delivered to cpu's irrespective of their offline status | ||
32 | * and could pickup stale intr data when these CPUS are turned online. | ||
33 | * | ||
34 | * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with | ||
35 | * the idea of not using broadcast IPI's anymore. Hence the run time check | ||
36 | * is introduced, on his request so we can choose an alternate mechanism. | ||
37 | * | ||
38 | * Initial wacky performance tests that collect cycle counts show | ||
39 | * no increase in using mask v.s broadcast version. In fact they seem | ||
40 | * identical in terms of cycle counts. | ||
41 | * | ||
42 | * if we need to use broadcast, we need to do the following. | ||
43 | * | ||
44 | * cli; | ||
45 | * hold call_lock; | ||
46 | * clear any pending IPI, just ack and clear all pending intr | ||
47 | * set cpu_online_map; | ||
48 | * release call_lock; | ||
49 | * sti; | ||
50 | * | ||
51 | * The complicated dummy irq processing shown above is not required if | ||
52 | * we didnt sent IPI's to wrong CPU's in the first place. | ||
53 | * | ||
54 | * - Ashok Raj <ashok.raj@intel.com> | ||
55 | */ | ||
56 | #ifdef CONFIG_HOTPLUG_CPU | ||
57 | #define DEFAULT_SEND_IPI (1) | ||
58 | #else | ||
59 | #define DEFAULT_SEND_IPI (0) | ||
60 | #endif | ||
61 | |||
62 | static int no_broadcast=DEFAULT_SEND_IPI; | ||
23 | 63 | ||
24 | static cpumask_t flat_target_cpus(void) | 64 | static cpumask_t flat_target_cpus(void) |
25 | { | 65 | { |
@@ -79,28 +119,37 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) | |||
79 | local_irq_restore(flags); | 119 | local_irq_restore(flags); |
80 | } | 120 | } |
81 | 121 | ||
82 | static void flat_send_IPI_allbutself(int vector) | 122 | static inline void __local_flat_send_IPI_allbutself(int vector) |
83 | { | 123 | { |
84 | cpumask_t mask; | 124 | if (no_broadcast) { |
85 | /* | 125 | cpumask_t mask = cpu_online_map; |
86 | * if there are no other CPUs in the system then | 126 | int this_cpu = get_cpu(); |
87 | * we get an APIC send error if we try to broadcast. | ||
88 | * thus we have to avoid sending IPIs in this case. | ||
89 | */ | ||
90 | int this_cpu = get_cpu(); | ||
91 | |||
92 | mask = cpu_online_map; | ||
93 | cpu_clear(this_cpu, mask); | ||
94 | 127 | ||
95 | if (cpus_weight(mask) >= 1) | 128 | cpu_clear(this_cpu, mask); |
96 | flat_send_IPI_mask(mask, vector); | 129 | flat_send_IPI_mask(mask, vector); |
130 | put_cpu(); | ||
131 | } | ||
132 | else | ||
133 | __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL); | ||
134 | } | ||
97 | 135 | ||
98 | put_cpu(); | 136 | static inline void __local_flat_send_IPI_all(int vector) |
137 | { | ||
138 | if (no_broadcast) | ||
139 | flat_send_IPI_mask(cpu_online_map, vector); | ||
140 | else | ||
141 | __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); | ||
142 | } | ||
143 | |||
144 | static void flat_send_IPI_allbutself(int vector) | ||
145 | { | ||
146 | if (((num_online_cpus()) - 1) >= 1) | ||
147 | __local_flat_send_IPI_allbutself(vector); | ||
99 | } | 148 | } |
100 | 149 | ||
101 | static void flat_send_IPI_all(int vector) | 150 | static void flat_send_IPI_all(int vector) |
102 | { | 151 | { |
103 | flat_send_IPI_mask(cpu_online_map, vector); | 152 | __local_flat_send_IPI_all(vector); |
104 | } | 153 | } |
105 | 154 | ||
106 | static int flat_apic_id_registered(void) | 155 | static int flat_apic_id_registered(void) |
@@ -121,6 +170,16 @@ static unsigned int phys_pkg_id(int index_msb) | |||
121 | return ((ebx >> 24) & 0xFF) >> index_msb; | 170 | return ((ebx >> 24) & 0xFF) >> index_msb; |
122 | } | 171 | } |
123 | 172 | ||
173 | static __init int no_ipi_broadcast(char *str) | ||
174 | { | ||
175 | get_option(&str, &no_broadcast); | ||
176 | printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" : | ||
177 | "IPI Broadcast"); | ||
178 | return 1; | ||
179 | } | ||
180 | |||
181 | __setup("no_ipi_broadcast", no_ipi_broadcast); | ||
182 | |||
124 | struct genapic apic_flat = { | 183 | struct genapic apic_flat = { |
125 | .name = "flat", | 184 | .name = "flat", |
126 | .int_delivery_mode = dest_LowestPrio, | 185 | .int_delivery_mode = dest_LowestPrio, |
@@ -135,3 +194,12 @@ struct genapic apic_flat = { | |||
135 | .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, | 194 | .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, |
136 | .phys_pkg_id = phys_pkg_id, | 195 | .phys_pkg_id = phys_pkg_id, |
137 | }; | 196 | }; |
197 | |||
198 | static int __init print_ipi_mode(void) | ||
199 | { | ||
200 | printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" : | ||
201 | "Shortcut"); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | late_initcall(print_ipi_mode); | ||