aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/genapic_64.c
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2008-03-28 15:12:16 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-17 11:41:33 -0400
commitac23d4ee3f84de33c16ed7e68f9adee2386e74fb (patch)
tree296346293480fb5d67a15d7552bf41bd0cadd4cf /arch/x86/kernel/genapic_64.c
parent570da318cf0e3053e62030253494c410a18d4be7 (diff)
x86: support for new UV apic
UV supports really big systems. So big, in fact, that the APICID register does not contain enough bits to contain an APICID that is unique across all cpus. The UV BIOS supports 3 APICID modes: - legacy mode. This mode uses the old APIC mode where APICID is in bits [31:24] of the APICID register. - x2apic mode. This mode is whitebox-compatible. APICIDs are unique across all cpus. Standard x2apic APIC operations (Intel-defined) can be used for IPIs. The node identifier fits within the Intel-defined portion of the APICID register. - x2apic-uv mode. In this mode, the APICIDs on each node have unique IDs, but IDs on different node are not unique. For example, if each mode has 32 cpus, the APICIDs on each node might be 0 - 31. Every node has the same set of IDs. The UV hub is used to route IPIs/interrupts to the correct node. Traditional APIC operations WILL NOT WORK. In x2apic-uv mode, the ACPI tables all contain a full unique ID (note: exact bit layout still changing but the following is close): nnnnnnnnnnlc0cch n = unique node number l = socket number on board c = core h = hyperthread Only the "lc0cch" bits are written to the APICID register. The remaining bits are supplied by having the get_apic_id() function "OR" the extra bits into the value read from the APICID register. (Hmmm.. why not keep the ENTIRE APICID register in per-cpu data....) The x2apic-uv mode is recognized by the MADT table containing: oem_id = "SGI" oem_table_id = "UV-X" Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/genapic_64.c')
-rw-r--r--arch/x86/kernel/genapic_64.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c
index 4cc1c218ae4c..910a4a777a4c 100644
--- a/arch/x86/kernel/genapic_64.c
+++ b/arch/x86/kernel/genapic_64.c
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/ctype.h> 16#include <linux/ctype.h>
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/hardirq.h>
18 19
19#include <asm/smp.h> 20#include <asm/smp.h>
20#include <asm/ipi.h> 21#include <asm/ipi.h>
@@ -32,6 +33,7 @@ void *x86_cpu_to_apicid_early_ptr;
32#endif 33#endif
33DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID; 34DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID;
34EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid); 35EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid);
36DEFINE_PER_CPU(int, x2apic_extra_bits);
35 37
36struct genapic __read_mostly *genapic = &apic_flat; 38struct genapic __read_mostly *genapic = &apic_flat;
37 39
@@ -42,6 +44,9 @@ static enum uv_system_type uv_system_type;
42 */ 44 */
43void __init setup_apic_routing(void) 45void __init setup_apic_routing(void)
44{ 46{
47 if (uv_system_type == UV_NON_UNIQUE_APIC)
48 genapic = &apic_x2apic_uv_x;
49 else
45#ifdef CONFIG_ACPI 50#ifdef CONFIG_ACPI
46 /* 51 /*
47 * Quirk: some x86_64 machines can only use physical APIC mode 52 * Quirk: some x86_64 machines can only use physical APIC mode
@@ -82,6 +87,19 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
82 return 0; 87 return 0;
83} 88}
84 89
90unsigned int read_apic_id(void)
91{
92 unsigned int id;
93
94 WARN_ON(preemptible());
95 id = apic_read(APIC_ID);
96 if (uv_system_type >= UV_X2APIC)
97 id |= __get_cpu_var(x2apic_extra_bits);
98 else
99 id = (id >> 24) & 0xFFu;;
100 return id;
101}
102
85enum uv_system_type get_uv_system_type(void) 103enum uv_system_type get_uv_system_type(void)
86{ 104{
87 return uv_system_type; 105 return uv_system_type;