summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/genapic.c
blob: b1c144f73149854da5e9bb277e4309e281b60ba3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * 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/config.h>
#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>

#if defined(CONFIG_ACPI)
#include <acpi/acpi_bus.h>
#endif

/* which logical CPU number maps to which CPU (physical APIC ID) */
u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
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;
extern struct genapic apic_physflat;

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];
	int num_cpus = 0;

#if defined(CONFIG_ACPI)
	/*
	 * 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

	memset(cluster_cnt, 0, sizeof(cluster_cnt));
	for (i = 0; i < NR_CPUS; i++) {
		id = bios_cpu_apicid[i];
		if (id == BAD_APICID)
			continue;
		num_cpus++;
		cluster_cnt[APIC_CLUSTERID(id)]++;
	}

	/* Don't use clustered mode on AMD platforms. */
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
		genapic = &apic_physflat;
#ifndef CONFIG_CPU_HOTPLUG
		/* 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 */
		if (num_cpus <= 8)
			genapic = &apic_flat;
#endif
 		goto print;
 	}

	clusters = 0;
	max_cluster = 0;

	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.)
	 */
	if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster)
		genapic = &apic_flat;
	else
		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);
}
OpenPOWER on IntegriCloud