[PATCH] x86-64: Use physflat on Intel for < 8 CPUs with CPU hotplug
[pandora-kernel.git] / arch / x86_64 / kernel / genapic.c
1 /*
2  * Copyright 2004 James Cleverdon, IBM.
3  * Subject to the GNU Public License, v.2
4  *
5  * Generic APIC sub-arch probe layer.
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 #include <linux/config.h>
12 #include <linux/threads.h>
13 #include <linux/cpumask.h>
14 #include <linux/string.h>
15 #include <linux/kernel.h>
16 #include <linux/ctype.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19
20 #include <asm/smp.h>
21 #include <asm/ipi.h>
22
23 #if defined(CONFIG_ACPI)
24 #include <acpi/acpi_bus.h>
25 #endif
26
27 /* which logical CPU number maps to which CPU (physical APIC ID) */
28 u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
29 EXPORT_SYMBOL(x86_cpu_to_apicid);
30 u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
31
32 extern struct genapic apic_cluster;
33 extern struct genapic apic_flat;
34 extern struct genapic apic_physflat;
35
36 struct genapic *genapic = &apic_flat;
37
38
39 /*
40  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
41  */
42 void __init clustered_apic_check(void)
43 {
44         long i;
45         u8 clusters, max_cluster;
46         u8 id;
47         u8 cluster_cnt[NUM_APIC_CLUSTERS];
48         int max_apic = 0;
49
50 #if defined(CONFIG_ACPI)
51         /*
52          * Some x86_64 machines use physical APIC mode regardless of how many
53          * procs/clusters are present (x86_64 ES7000 is an example).
54          */
55         if (acpi_fadt.revision > FADT2_REVISION_ID)
56                 if (acpi_fadt.force_apic_physical_destination_mode) {
57                         genapic = &apic_cluster;
58                         goto print;
59                 }
60 #endif
61
62         memset(cluster_cnt, 0, sizeof(cluster_cnt));
63         for (i = 0; i < NR_CPUS; i++) {
64                 id = bios_cpu_apicid[i];
65                 if (id == BAD_APICID)
66                         continue;
67                 if (id > max_apic)
68                         max_apic = id;
69                 cluster_cnt[APIC_CLUSTERID(id)]++;
70         }
71
72         /* Don't use clustered mode on AMD platforms. */
73         if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
74                 genapic = &apic_physflat;
75 #ifndef CONFIG_HOTPLUG_CPU
76                 /* In the CPU hotplug case we cannot use broadcast mode
77                    because that opens a race when a CPU is removed.
78                    Stay at physflat mode in this case.
79                    It is bad to do this unconditionally though. Once
80                    we have ACPI platform support for CPU hotplug
81                    we should detect hotplug capablity from ACPI tables and
82                    only do this when really needed. -AK */
83                 if (max_apic <= 8)
84                         genapic = &apic_flat;
85 #endif
86                 goto print;
87         }
88
89         clusters = 0;
90         max_cluster = 0;
91
92         for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
93                 if (cluster_cnt[i] > 0) {
94                         ++clusters;
95                         if (cluster_cnt[i] > max_cluster)
96                                 max_cluster = cluster_cnt[i];
97                 }
98         }
99
100         /*
101          * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
102          * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
103          * else physical mode.
104          * (We don't use lowest priority delivery + HW APIC IRQ steering, so
105          * can ignore the clustered logical case and go straight to physical.)
106          */
107         if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
108 #ifdef CONFIG_HOTPLUG_CPU
109                 /* Don't use APIC shortcuts in CPU hotplug to avoid races */
110                 genapic = &apic_physflat;
111 #else
112                 genapic = &apic_flat;
113 #endif
114         } else
115                 genapic = &apic_cluster;
116
117 print:
118         printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
119 }
120
121 /* Same for both flat and clustered. */
122
123 void send_IPI_self(int vector)
124 {
125         __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
126 }