blob: 0b3603adf56d4e4f35aa4a5eb22dc97cb72243ed [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/threads.h>
12#include <linux/cpumask.h>
13#include <linux/string.h>
14#include <linux/kernel.h>
15#include <linux/ctype.h>
16#include <linux/init.h>
17#include <linux/module.h>
18
19#include <asm/smp.h>
20#include <asm/ipi.h>
21
Len Brown76f58582005-08-24 12:10:49 -040022#if defined(CONFIG_ACPI)
Jason Davis90660ec2005-04-16 15:24:53 -070023#include <acpi/acpi_bus.h>
24#endif
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/* which logical CPU number maps to which CPU (physical APIC ID) */
Ravikiran G Thirumalai6c231b72005-09-06 15:17:45 -070027u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
Linus Torvalds1da177e2005-04-16 15:20:36 -070028EXPORT_SYMBOL(x86_cpu_to_apicid);
29u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
30
31extern struct genapic apic_cluster;
32extern struct genapic apic_flat;
Andi Kleenf8d31192005-07-28 21:15:42 -070033extern struct genapic apic_physflat;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35struct genapic *genapic = &apic_flat;
Siddha, Suresh B9899f822006-12-07 02:14:10 +010036struct genapic *genapic_force;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38/*
39 * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
40 */
41void __init clustered_apic_check(void)
42{
43 long i;
44 u8 clusters, max_cluster;
45 u8 id;
46 u8 cluster_cnt[NUM_APIC_CLUSTERS];
Andi Kleen70556462005-09-12 18:49:24 +020047 int max_apic = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Siddha, Suresh B9899f822006-12-07 02:14:10 +010049 /* genapic selection can be forced because of certain quirks.
50 */
51 if (genapic_force) {
52 genapic = genapic_force;
53 goto print;
54 }
55
Len Brown76f58582005-08-24 12:10:49 -040056#if defined(CONFIG_ACPI)
Jason Davis90660ec2005-04-16 15:24:53 -070057 /*
58 * Some x86_64 machines use physical APIC mode regardless of how many
59 * procs/clusters are present (x86_64 ES7000 is an example).
60 */
Alexey Starikovskiycee324b2007-02-02 19:48:22 +030061 if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
62 if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
Jason Davis90660ec2005-04-16 15:24:53 -070063 genapic = &apic_cluster;
64 goto print;
65 }
66#endif
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 memset(cluster_cnt, 0, sizeof(cluster_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 for (i = 0; i < NR_CPUS; i++) {
70 id = bios_cpu_apicid[i];
Andi Kleenf8d31192005-07-28 21:15:42 -070071 if (id == BAD_APICID)
72 continue;
Andi Kleen70556462005-09-12 18:49:24 +020073 if (id > max_apic)
74 max_apic = id;
Andi Kleenf8d31192005-07-28 21:15:42 -070075 cluster_cnt[APIC_CLUSTERID(id)]++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
77
Andi Kleenf8d31192005-07-28 21:15:42 -070078 /* Don't use clustered mode on AMD platforms. */
79 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
80 genapic = &apic_physflat;
Andi Kleen016102d2005-09-12 18:49:24 +020081#ifndef CONFIG_HOTPLUG_CPU
Andi Kleenf8d31192005-07-28 21:15:42 -070082 /* In the CPU hotplug case we cannot use broadcast mode
83 because that opens a race when a CPU is removed.
84 Stay at physflat mode in this case.
85 It is bad to do this unconditionally though. Once
86 we have ACPI platform support for CPU hotplug
87 we should detect hotplug capablity from ACPI tables and
88 only do this when really needed. -AK */
Andi Kleen70556462005-09-12 18:49:24 +020089 if (max_apic <= 8)
Andi Kleenf8d31192005-07-28 21:15:42 -070090 genapic = &apic_flat;
91#endif
92 goto print;
93 }
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 clusters = 0;
96 max_cluster = 0;
Andi Kleenf8d31192005-07-28 21:15:42 -070097
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
99 if (cluster_cnt[i] > 0) {
100 ++clusters;
101 if (cluster_cnt[i] > max_cluster)
102 max_cluster = cluster_cnt[i];
103 }
104 }
105
106 /*
107 * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
108 * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
109 * else physical mode.
110 * (We don't use lowest priority delivery + HW APIC IRQ steering, so
111 * can ignore the clustered logical case and go straight to physical.)
112 */
Andi Kleen5bf97e02005-09-12 18:49:24 +0200113 if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
114#ifdef CONFIG_HOTPLUG_CPU
115 /* Don't use APIC shortcuts in CPU hotplug to avoid races */
116 genapic = &apic_physflat;
117#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 genapic = &apic_flat;
Andi Kleen5bf97e02005-09-12 18:49:24 +0200119#endif
120 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 genapic = &apic_cluster;
122
123print:
124 printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
125}
126
127/* Same for both flat and clustered. */
128
129void send_IPI_self(int vector)
130{
131 __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
132}