2 * ACPI 3.0 based NUMA setup
3 * Copyright 2004 Andi Kleen, SuSE Labs.
5 * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
7 * Called from acpi_numa_init while reading the SRAT and SLIT tables.
8 * Assumes all memory regions belonging to a single proximity domain
9 * are in one chunk. Holes between them will be included in the node.
12 #include <linux/kernel.h>
13 #include <linux/acpi.h>
14 #include <linux/mmzone.h>
15 #include <linux/bitmap.h>
16 #include <linux/module.h>
17 #include <linux/topology.h>
18 #include <linux/bootmem.h>
19 #include <linux/memblock.h>
21 #include <asm/proto.h>
25 #include <asm/uv/uv.h>
27 int acpi_numa __initdata
;
29 static struct bootnode nodes_add
[MAX_NUMNODES
];
31 static __init
int setup_node(int pxm
)
33 return acpi_map_pxm_to_node(pxm
);
36 static __init
void bad_srat(void)
38 printk(KERN_ERR
"SRAT: SRAT not used.\n");
40 memset(nodes_add
, 0, sizeof(nodes_add
));
43 static __init
inline int srat_disabled(void)
48 /* Callback for SLIT parsing */
49 void __init
acpi_numa_slit_init(struct acpi_table_slit
*slit
)
53 for (i
= 0; i
< slit
->locality_count
; i
++)
54 for (j
= 0; j
< slit
->locality_count
; j
++)
55 numa_set_distance(pxm_to_node(i
), pxm_to_node(j
),
56 slit
->entry
[slit
->locality_count
* i
+ j
]);
59 /* Callback for Proximity Domain -> x2APIC mapping */
61 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity
*pa
)
68 if (pa
->header
.length
< sizeof(struct acpi_srat_x2apic_cpu_affinity
)) {
72 if ((pa
->flags
& ACPI_SRAT_CPU_ENABLED
) == 0)
74 pxm
= pa
->proximity_domain
;
75 node
= setup_node(pxm
);
77 printk(KERN_ERR
"SRAT: Too many proximity domains %x\n", pxm
);
82 apic_id
= pa
->apic_id
;
83 if (apic_id
>= MAX_LOCAL_APIC
) {
84 printk(KERN_INFO
"SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm
, apic_id
, node
);
87 set_apicid_to_node(apic_id
, node
);
88 node_set(node
, numa_nodes_parsed
);
90 printk(KERN_INFO
"SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
94 /* Callback for Proximity Domain -> LAPIC mapping */
96 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity
*pa
)
103 if (pa
->header
.length
!= sizeof(struct acpi_srat_cpu_affinity
)) {
107 if ((pa
->flags
& ACPI_SRAT_CPU_ENABLED
) == 0)
109 pxm
= pa
->proximity_domain_lo
;
110 node
= setup_node(pxm
);
112 printk(KERN_ERR
"SRAT: Too many proximity domains %x\n", pxm
);
117 if (get_uv_system_type() >= UV_X2APIC
)
118 apic_id
= (pa
->apic_id
<< 8) | pa
->local_sapic_eid
;
120 apic_id
= pa
->apic_id
;
122 if (apic_id
>= MAX_LOCAL_APIC
) {
123 printk(KERN_INFO
"SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm
, apic_id
, node
);
127 set_apicid_to_node(apic_id
, node
);
128 node_set(node
, numa_nodes_parsed
);
130 printk(KERN_INFO
"SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
134 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
135 static inline int save_add_info(void) {return 1;}
137 static inline int save_add_info(void) {return 0;}
141 * This code supports one contiguous hot add area per node
144 update_nodes_add(int node
, unsigned long start
, unsigned long end
)
146 unsigned long s_pfn
= start
>> PAGE_SHIFT
;
147 unsigned long e_pfn
= end
>> PAGE_SHIFT
;
149 struct bootnode
*nd
= &nodes_add
[node
];
151 /* I had some trouble with strange memory hotadd regions breaking
152 the boot. Be very strict here and reject anything unexpected.
153 If you want working memory hotadd write correct SRATs.
155 The node size check is a basic sanity check to guard against
157 if ((signed long)(end
- start
) < NODE_MIN_SIZE
) {
158 printk(KERN_ERR
"SRAT: Hotplug area too small\n");
162 /* This check might be a bit too strict, but I'm keeping it for now. */
163 if (absent_pages_in_range(s_pfn
, e_pfn
) != e_pfn
- s_pfn
) {
165 "SRAT: Hotplug area %lu -> %lu has existing memory\n",
172 if (nd
->start
== nd
->end
) {
177 if (nd
->start
== end
) {
181 if (nd
->end
== start
) {
186 printk(KERN_ERR
"SRAT: Hotplug zone not continuous. Partly ignored\n");
190 node_set(node
, numa_nodes_parsed
);
191 printk(KERN_INFO
"SRAT: hot plug zone found %Lx - %Lx\n",
196 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
198 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity
*ma
)
200 unsigned long start
, end
;
205 if (ma
->header
.length
!= sizeof(struct acpi_srat_mem_affinity
)) {
209 if ((ma
->flags
& ACPI_SRAT_MEM_ENABLED
) == 0)
212 if ((ma
->flags
& ACPI_SRAT_MEM_HOT_PLUGGABLE
) && !save_add_info())
214 start
= ma
->base_address
;
215 end
= start
+ ma
->length
;
216 pxm
= ma
->proximity_domain
;
217 node
= setup_node(pxm
);
219 printk(KERN_ERR
"SRAT: Too many proximity domains.\n");
224 if (numa_add_memblk(node
, start
, end
) < 0) {
229 printk(KERN_INFO
"SRAT: Node %u PXM %u %lx-%lx\n", node
, pxm
,
232 if (ma
->flags
& ACPI_SRAT_MEM_HOT_PLUGGABLE
)
233 update_nodes_add(node
, start
, end
);
236 void __init
acpi_numa_arch_fixup(void) {}
238 int __init
x86_acpi_numa_init(void)
242 ret
= acpi_numa_init();
245 return srat_disabled() ? -EINVAL
: 0;
248 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
249 int memory_add_physaddr_to_nid(u64 start
)
254 if (nodes_add
[i
].start
<= start
&& nodes_add
[i
].end
> start
)
259 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid
);