2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2004 James Cleverdon, IBM.
|
|
|
|
* Subject to the GNU Public License, v.2
|
|
|
|
*
|
|
|
|
* Generic APIC sub-arch probe layer.
|
|
|
|
*
|
|
|
|
* Hacked for x86-64 by James Cleverdon from i386 architecture code by
|
|
|
|
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
|
|
|
|
* James Cleverdon.
|
|
|
|
*/
|
|
|
|
#include <linux/threads.h>
|
|
|
|
#include <linux/cpumask.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/ctype.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
|
|
|
|
#include <asm/smp.h>
|
|
|
|
#include <asm/ipi.h>
|
|
|
|
|
2005-08-24 16:10:49 +00:00
|
|
|
#if defined(CONFIG_ACPI)
|
2005-04-16 22:24:53 +00:00
|
|
|
#include <acpi/acpi_bus.h>
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* which logical CPU number maps to which CPU (physical APIC ID) */
|
2005-09-06 22:17:45 +00:00
|
|
|
u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
|
2005-04-16 22:20:36 +00:00
|
|
|
EXPORT_SYMBOL(x86_cpu_to_apicid);
|
|
|
|
u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
|
|
|
|
|
|
|
|
extern struct genapic apic_cluster;
|
|
|
|
extern struct genapic apic_flat;
|
2005-07-29 04:15:42 +00:00
|
|
|
extern struct genapic apic_physflat;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
struct genapic *genapic = &apic_flat;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
|
|
|
|
*/
|
|
|
|
void __init clustered_apic_check(void)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
u8 clusters, max_cluster;
|
|
|
|
u8 id;
|
|
|
|
u8 cluster_cnt[NUM_APIC_CLUSTERS];
|
2005-09-12 16:49:24 +00:00
|
|
|
int max_apic = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2005-08-24 16:10:49 +00:00
|
|
|
#if defined(CONFIG_ACPI)
|
2005-04-16 22:24:53 +00:00
|
|
|
/*
|
|
|
|
* Some x86_64 machines use physical APIC mode regardless of how many
|
|
|
|
* procs/clusters are present (x86_64 ES7000 is an example).
|
|
|
|
*/
|
|
|
|
if (acpi_fadt.revision > FADT2_REVISION_ID)
|
|
|
|
if (acpi_fadt.force_apic_physical_destination_mode) {
|
|
|
|
genapic = &apic_cluster;
|
|
|
|
goto print;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
memset(cluster_cnt, 0, sizeof(cluster_cnt));
|
|
|
|
for (i = 0; i < NR_CPUS; i++) {
|
|
|
|
id = bios_cpu_apicid[i];
|
2005-07-29 04:15:42 +00:00
|
|
|
if (id == BAD_APICID)
|
|
|
|
continue;
|
2005-09-12 16:49:24 +00:00
|
|
|
if (id > max_apic)
|
|
|
|
max_apic = id;
|
2005-07-29 04:15:42 +00:00
|
|
|
cluster_cnt[APIC_CLUSTERID(id)]++;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-07-29 04:15:42 +00:00
|
|
|
/* Don't use clustered mode on AMD platforms. */
|
|
|
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
|
|
|
|
genapic = &apic_physflat;
|
2005-09-12 16:49:24 +00:00
|
|
|
#ifndef CONFIG_HOTPLUG_CPU
|
2005-07-29 04:15:42 +00:00
|
|
|
/* In the CPU hotplug case we cannot use broadcast mode
|
|
|
|
because that opens a race when a CPU is removed.
|
|
|
|
Stay at physflat mode in this case.
|
|
|
|
It is bad to do this unconditionally though. Once
|
|
|
|
we have ACPI platform support for CPU hotplug
|
|
|
|
we should detect hotplug capablity from ACPI tables and
|
|
|
|
only do this when really needed. -AK */
|
2005-09-12 16:49:24 +00:00
|
|
|
if (max_apic <= 8)
|
2005-07-29 04:15:42 +00:00
|
|
|
genapic = &apic_flat;
|
|
|
|
#endif
|
|
|
|
goto print;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
clusters = 0;
|
|
|
|
max_cluster = 0;
|
2005-07-29 04:15:42 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
|
|
|
|
if (cluster_cnt[i] > 0) {
|
|
|
|
++clusters;
|
|
|
|
if (cluster_cnt[i] > max_cluster)
|
|
|
|
max_cluster = cluster_cnt[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
|
|
|
|
* else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
|
|
|
|
* else physical mode.
|
|
|
|
* (We don't use lowest priority delivery + HW APIC IRQ steering, so
|
|
|
|
* can ignore the clustered logical case and go straight to physical.)
|
|
|
|
*/
|
2005-09-12 16:49:24 +00:00
|
|
|
if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
/* Don't use APIC shortcuts in CPU hotplug to avoid races */
|
|
|
|
genapic = &apic_physflat;
|
|
|
|
#else
|
2005-04-16 22:20:36 +00:00
|
|
|
genapic = &apic_flat;
|
2005-09-12 16:49:24 +00:00
|
|
|
#endif
|
|
|
|
} else
|
2005-04-16 22:20:36 +00:00
|
|
|
genapic = &apic_cluster;
|
|
|
|
|
|
|
|
print:
|
|
|
|
printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Same for both flat and clustered. */
|
|
|
|
|
|
|
|
void send_IPI_self(int vector)
|
|
|
|
{
|
|
|
|
__send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
|
|
|
|
}
|