Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
srat.c
Go to the documentation of this file.
1 /*
2  * ACPI 3.0 based NUMA setup
3  * Copyright 2004 Andi Kleen, SuSE Labs.
4  *
5  * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
6  *
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.
10  */
11 
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>
20 #include <linux/mm.h>
21 #include <asm/proto.h>
22 #include <asm/numa.h>
23 #include <asm/e820.h>
24 #include <asm/apic.h>
25 #include <asm/uv/uv.h>
26 
27 int acpi_numa __initdata;
28 
29 static __init int setup_node(int pxm)
30 {
31  return acpi_map_pxm_to_node(pxm);
32 }
33 
34 static __init void bad_srat(void)
35 {
36  printk(KERN_ERR "SRAT: SRAT not used.\n");
37  acpi_numa = -1;
38 }
39 
40 static __init inline int srat_disabled(void)
41 {
42  return acpi_numa < 0;
43 }
44 
45 /* Callback for SLIT parsing */
47 {
48  int i, j;
49 
50  for (i = 0; i < slit->locality_count; i++)
51  for (j = 0; j < slit->locality_count; j++)
53  slit->entry[slit->locality_count * i + j]);
54 }
55 
56 /* Callback for Proximity Domain -> x2APIC mapping */
57 void __init
59 {
60  int pxm, node;
61  int apic_id;
62 
63  if (srat_disabled())
64  return;
65  if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
66  bad_srat();
67  return;
68  }
69  if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
70  return;
71  pxm = pa->proximity_domain;
72  apic_id = pa->apic_id;
73  if (!apic->apic_id_valid(apic_id)) {
74  printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n",
75  pxm, apic_id);
76  return;
77  }
78  node = setup_node(pxm);
79  if (node < 0) {
80  printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
81  bad_srat();
82  return;
83  }
84 
85  if (apic_id >= MAX_LOCAL_APIC) {
86  printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
87  return;
88  }
89  set_apicid_to_node(apic_id, node);
90  node_set(node, numa_nodes_parsed);
91  acpi_numa = 1;
92  printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
93  pxm, apic_id, node);
94 }
95 
96 /* Callback for Proximity Domain -> LAPIC mapping */
97 void __init
99 {
100  int pxm, node;
101  int apic_id;
102 
103  if (srat_disabled())
104  return;
105  if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
106  bad_srat();
107  return;
108  }
109  if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
110  return;
111  pxm = pa->proximity_domain_lo;
112  if (acpi_srat_revision >= 2)
113  pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
114  node = setup_node(pxm);
115  if (node < 0) {
116  printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
117  bad_srat();
118  return;
119  }
120 
121  if (get_uv_system_type() >= UV_X2APIC)
122  apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
123  else
124  apic_id = pa->apic_id;
125 
126  if (apic_id >= MAX_LOCAL_APIC) {
127  printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
128  return;
129  }
130 
131  set_apicid_to_node(apic_id, node);
132  node_set(node, numa_nodes_parsed);
133  acpi_numa = 1;
134  printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
135  pxm, apic_id, node);
136 }
137 
138 #ifdef CONFIG_MEMORY_HOTPLUG
139 static inline int save_add_info(void) {return 1;}
140 #else
141 static inline int save_add_info(void) {return 0;}
142 #endif
143 
144 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
145 int __init
147 {
148  u64 start, end;
149  int node, pxm;
150 
151  if (srat_disabled())
152  return -1;
153  if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
154  bad_srat();
155  return -1;
156  }
157  if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
158  return -1;
159 
160  if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
161  return -1;
162  start = ma->base_address;
163  end = start + ma->length;
164  pxm = ma->proximity_domain;
165  if (acpi_srat_revision <= 1)
166  pxm &= 0xff;
167  node = setup_node(pxm);
168  if (node < 0) {
169  printk(KERN_ERR "SRAT: Too many proximity domains.\n");
170  bad_srat();
171  return -1;
172  }
173 
174  if (numa_add_memblk(node, start, end) < 0) {
175  bad_srat();
176  return -1;
177  }
178 
179  node_set(node, numa_nodes_parsed);
180 
181  printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
182  node, pxm,
183  (unsigned long long) start, (unsigned long long) end - 1);
184  return 0;
185 }
186 
188 
190 {
191  int ret;
192 
193  ret = acpi_numa_init();
194  if (ret < 0)
195  return ret;
196  return srat_disabled() ? -EINVAL : 0;
197 }