Recent linux kernels suppose that the SRAT table is in rev 2 format
(ACPI 3.0), but some BIOSes still provide SRAT table in rev 1.
The rev 2 of the SRAT extension mainly provides an extension of the
"proximity_domain" item from 8 bits to 32 bits, using a "reserved" field
of the structure.
When the "reserved" field is not null, linux finds a wrong proximity
domain, and numa initialization is wrong.
Following patch tests the SRAT revision to allow a correct initialization:
This patch tests the version of SRAT ACPI table to allow supporting SRAT
rev 1 and SRAT rev 2.
diff -Nru linux-2.6.29-rc7-orig/arch/x86/kernel/acpi/boot.c
linux-2.6.29-rc7-tmp/arch/x86/kernel/acpi/boot.c
--- linux-2.6.29-rc7-orig/arch/x86/kernel/acpi/boot.c 2009-03-12
14:41:38.000000000 +0100
+++ linux-2.6.29-rc7-tmp/arch/x86/kernel/acpi/boot.c 2009-03-16
14:52:07.000000000 +0100
@@ -260,7 +260,8 @@
}
static int __init
-acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned
long end)
+acpi_parse_lapic(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_local_apic *processor = NULL;
@@ -285,7 +286,8 @@
}
static int __init
-acpi_parse_sapic(struct acpi_subtable_header *header, const unsigned
long end)
+acpi_parse_sapic(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_local_sapic *processor = NULL;
@@ -303,8 +305,8 @@
}
static int __init
-acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
- const unsigned long end)
+acpi_parse_lapic_addr_ovr(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
@@ -319,7 +321,8 @@
}
static int __init
-acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const
unsigned long end)
+acpi_parse_lapic_nmi(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
@@ -341,7 +344,8 @@
#ifdef CONFIG_X86_IO_APIC
static int __init
-acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned
long end)
+acpi_parse_ioapic(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_io_apic *ioapic = NULL;
@@ -392,8 +396,8 @@
}
static int __init
-acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
- const unsigned long end)
+acpi_parse_int_src_ovr(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_interrupt_override *intsrc = NULL;
@@ -426,7 +430,8 @@
}
static int __init
-acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned
long end)
+acpi_parse_nmi_src(const struct acpi_subtable_header * const header,
+ const unsigned long end, const int rev)
{
struct acpi_madt_nmi_source *nmi_src = NULL;
diff -Nru linux-2.6.29-rc7-orig/arch/x86/mm/srat_64.c
linux-2.6.29-rc7-tmp/arch/x86/mm/srat_64.c
--- linux-2.6.29-rc7-orig/arch/x86/mm/srat_64.c 2009-03-12
14:41:38.000000000 +0100
+++ linux-2.6.29-rc7-tmp/arch/x86/mm/srat_64.c 2009-03-16
15:25:18.000000000 +0100
@@ -220,7 +220,7 @@
/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
void __init
-acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
+acpi_numa_memory_affinity_init(const struct acpi_srat_mem_affinity *
const ma, const int rev)
{
struct bootnode *nd, oldnode;
unsigned long start, end;
@@ -240,7 +240,18 @@
return;
start = ma->base_address;
end = start + ma->length;
- pxm = ma->proximity_domain;
+ switch (rev){
+ case ACPI_SRAT_MEM_AFF_ACPI2:
+ pxm = ma->_2.proximity_domain;
+ break;
+ case ACPI_SRAT_MEM_AFF_ACPI3:
+ pxm = ma->_3.proximity_domain;
+ break;
+ default:
+ printk(KERN_ERR "SRAT: unknown memory affinity revision
%d+1\n", rev);
+ bad_srat();
+ return;
+ }
node = setup_node(pxm);
if (node < 0) {
printk(KERN_ERR "SRAT: Too many proximity domains.\n");
diff -Nru linux-2.6.29-rc7-orig/drivers/acpi/numa.c
linux-2.6.29-rc7-tmp/drivers/acpi/numa.c
--- linux-2.6.29-rc7-orig/drivers/acpi/numa.c 2009-03-12
14:41:43.000000000 +0100
+++ linux-2.6.29-rc7-tmp/drivers/acpi/numa.c 2009-03-16
15:25:59.000000000 +0100
@@ -88,7 +88,8 @@
#endif /* 0 */
static void __init
-acpi_table_print_srat_entry(struct acpi_subtable_header *header)
+acpi_table_print_srat_entry(const struct acpi_subtable_header * const
header,
+ const int rev)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -116,13 +117,25 @@
case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_srat_mem_affinity *p =
- (struct acpi_srat_mem_affinity *)header;
+ struct acpi_srat_mem_affinity *p = (struct
acpi_srat_mem_affinity *)header;
+ int pxm;
+
+ switch (rev){
+ case ACPI_SRAT_MEM_AFF_ACPI2:
+ pxm = p->_2.proximity_domain;
+ break;
+ case ACPI_SRAT_MEM_AFF_ACPI3:
+ pxm = p->_3.proximity_domain;
+ break;
+ default:
+ printk(KERN_ERR "SRAT: unknown memory affinity revision
%d+1\n", rev);
+ pxm = 0;
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"SRAT Memory (0x%lx length 0x%lx) in proximity
domain %d %s%s\n",
(unsigned long)p->base_address,
(unsigned long)p->length,
- p->proximity_domain,
+ pxm,
(p->flags & ACPI_SRAT_MEM_ENABLED)?
"enabled" : "disabled",
(p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
@@ -181,8 +194,8 @@
}
static int __init
-acpi_parse_processor_affinity(struct acpi_subtable_header * header,
- const unsigned long end)
+acpi_parse_processor_affinity(const struct acpi_subtable_header * const
header,
+ const unsigned long end, const int rev)
{
struct acpi_srat_cpu_affinity *processor_affinity;
@@ -190,7 +203,7 @@
if (!processor_affinity)
return -EINVAL;
- acpi_table_print_srat_entry(header);
+ acpi_table_print_srat_entry(header, rev);
/* let architecture-dependent part to do it */
acpi_numa_processor_affinity_init(processor_affinity);
@@ -199,8 +212,8 @@
}
static int __init
-acpi_parse_memory_affinity(struct acpi_subtable_header * header,
- const unsigned long end)
+acpi_parse_memory_affinity(const struct acpi_subtable_header * const
header,
+ const unsigned long end, const int rev)
{
struct acpi_srat_mem_affinity *memory_affinity;
@@ -208,10 +221,10 @@
if (!memory_affinity)
return -EINVAL;
- acpi_table_print_srat_entry(header);
+ acpi_table_print_srat_entry(header, rev);
/* let architecture-dependent part to do it */
- acpi_numa_memory_affinity_init(memory_affinity);
+ acpi_numa_memory_affinity_init(memory_affinity, rev);
return 0;
}
@@ -239,7 +252,7 @@
int __init acpi_numa_init(void)
{
- /* SRAT: Static Resource Affinity Table */
+ /* SRAT: Static/System Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity, NR_CPUS);
diff -Nru linux-2.6.29-rc7-orig/drivers/acpi/tables.c
linux-2.6.29-rc7-tmp/drivers/acpi/tables.c
--- linux-2.6.29-rc7-orig/drivers/acpi/tables.c 2009-03-12
14:41:43.000000000 +0100
+++ linux-2.6.29-rc7-tmp/drivers/acpi/tables.c 2009-03-16
15:01:05.000000000 +0100
@@ -44,7 +44,7 @@
static int acpi_apic_instance __initdata;
-void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
+void acpi_table_print_madt_entry(const struct acpi_subtable_header *
const header)
{
if (!header)
return;
@@ -206,7 +206,7 @@
table_end) {
if (entry->type == entry_id
&& (!max_entries || count++ < max_entries))
- if (handler(entry, table_end))
+ if (handler(entry, table_end, table_header->revision))
return -EINVAL;
entry = (struct acpi_subtable_header *)
diff -Nru linux-2.6.29-rc7-orig/include/acpi/actbl1.h
linux-2.6.29-rc7-tmp/include/acpi/actbl1.h
--- linux-2.6.29-rc7-orig/include/acpi/actbl1.h 2009-03-12
14:41:40.000000000 +0100
+++ linux-2.6.29-rc7-tmp/include/acpi/actbl1.h 2009-03-16
14:53:14.000000000 +0100
@@ -1193,16 +1193,26 @@
};
/* 1: Memory Affinity */
+#define ACPI_SRAT_MEM_AFF_ACPI2 1
+#define ACPI_SRAT_MEM_AFF_ACPI3 2
struct acpi_srat_mem_affinity {
struct acpi_subtable_header header;
- u32 proximity_domain;
- u16 reserved; /* Reserved, must be zero */
+ union {
+ struct { /* ACPI 2 */
+ u8 proximity_domain;
+ u8 reserved[5]; /* Reserved, must be zero */
+ } _2;
+ struct { /* ACPI 3 */
+ u32 proximity_domain;
+ u16 reserved; /* Reserved, must be zero */
+ } _3;
+ };
u64 base_address;
u64 length;
- u32 reserved1;
+ u32 reserved1;
u32 flags;
- u64 reserved2; /* Reserved, must be zero */
+ u64 reserved2; /* Reserved, must be zero */
};
/* Flags */
diff -Nru linux-2.6.29-rc7-orig/include/linux/acpi.h
linux-2.6.29-rc7-tmp/include/linux/acpi.h
--- linux-2.6.29-rc7-orig/include/linux/acpi.h 2009-03-12
14:41:40.000000000 +0100
+++ linux-2.6.29-rc7-tmp/include/linux/acpi.h 2009-03-16
15:19:07.000000000 +0100
@@ -76,7 +76,8 @@
typedef int (*acpi_table_handler) (struct acpi_table_header *table);
-typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header
*header, const unsigned long end);
+typedef int (*acpi_table_entry_handler) (const struct
acpi_subtable_header * const header,
+ const unsigned long end, const int revision);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
int early_acpi_boot_init(void);
@@ -91,12 +92,12 @@
int entry_id, acpi_table_entry_handler handler, unsigned int
max_entries);
int acpi_table_parse_madt (enum acpi_madt_type id,
acpi_table_entry_handler handler, unsigned int max_entries);
int acpi_parse_mcfg (struct acpi_table_header *header);
-void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
+void acpi_table_print_madt_entry (const struct acpi_subtable_header *
const madt);
/* the following four functions are architecture-dependent */
void acpi_numa_slit_init (struct acpi_table_slit *slit);
void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
+void acpi_numa_memory_affinity_init (const struct
acpi_srat_mem_affinity * const ma, const int rev);
void acpi_numa_arch_fixup(void);
#ifdef CONFIG_ACPI_HOTPLUG_CPU
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html