Skip to contentSkip to conversation

ACPI_NUMA for SRAT/SLIT table parsing

PATCH New Erich Focht 1 participant 1 message Aug 9, 2002 ACPI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ACPI_NUMA for SRAT/SLIT table parsing

The attached patch implements the parsing of the ACPI SRAT (Static Resource Affinity Table) and SLIT (System Locality Information Table) which are meanwhile the standard for providing NUMA information on IA64 platforms and started to spread on IA32, too. The patch consists of an architecture independent part (posted by Tak Kouchi on the acpi and discontig mailing lists) and the architecture-dependent functions used for setting up the NUMA structures needed for initialising and running discontigmem on IA64. CONFIG_ACPI_NUMA controls the usage of this path.

The arch-dependent part could well be used by other architectures, too, which might need SRAT/SLIT tables in near future. It does not depend on discontigmem any more and can be used separately e.g for setting up the NUMA tables needed with a config_nonlinear patch or with a NUMA scheduler. It is absolutely necessary for the IA64 discontigmem.

I'm interested in comments, opinions, usage on other architectures... Please consider the inclusion in 2.5.X. A BK changeset against the latest 2.5.30 which can be "bk received" can be downloaded from
http://home.arcor.de/efocht/disc/acpi_numa-2.5.30.bkpatch

Thanks,
Erich

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.470 -> 1.471
# include/linux/acpi.h 1.9 -> 1.10
# arch/ia64/kernel/setup.c 1.16 -> 1.17
# arch/ia64/mm/Makefile 1.1 -> 1.2
# include/asm-ia64/acpi.h 1.2 -> 1.3
# drivers/acpi/tables.c 1.5 -> 1.6
# arch/ia64/kernel/acpi.c 1.12 -> 1.13
# drivers/acpi/Config.in 1.5 -> 1.6

#	               (new)	        -> 1.1     include/asm-ia64/numa.h
#	               (new)	        -> 1.1     arch/ia64/mm/numa.c

#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/08/09 [email protected] 1.471
# Added ACPI SRAT (Static Resource Affinity Table) and SLIT # (System Locality Information Table) parsing code as suggested

# by Tak Kouchi. Tables are parsed if CONFIG_ACPI_NUMA=y.
# 
# The ACPI SRAT and SLIT parsing routines are actually quite
# arch-independent, but currently this setup is used only on IA64.
# The NUMA related variables touched are:
#  node_memblk : physical memory blocks, node to which they belong
#  node_cpuid : hardware cpu IDs and nodes to which they belong
#  numa_slit : locality matrix with "distances" between nodes.
# 
# This setup is needed for CONFIG_DISCONTIGMEM on IA64 but can be
# used for other NUMA purposes, too.
# --------------------------------------------
#
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Fri Aug  9 17:58:36 2002
+++ b/arch/ia64/kernel/acpi.c	Fri Aug  9 17:58:36 2002
@@ -8,6 +8,9 @@
  *  Copyright (C) 2000 Intel Corp.
  *  Copyright (C) 2000,2001 J.I. Lee <[email protected]>
  *  Copyright (C) 2001 Paul Diefenbaugh <[email protected]>
+ *  Copyright (C) 2001 Jenna Hall <[email protected]>
+ *  Copyright (C) 2001 Takayoshi Kochi <[email protected]>
+ *  Copyright (C) 2002 Erich Focht <[email protected]>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -43,6 +46,7 @@
 #include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <asm/numa.h>

#define PREFIX "ACPI: "
@@ -441,6 +445,168 @@
return 0;
}

+#ifdef CONFIG_ACPI_NUMA
+
+#define SRAT_DEBUG
+#define SLIT_DEBUG
+
+#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)
+
+static int __initdata srat_num_cpus = 0; /* number of cpus */
+static u32 __initdata pxm_flag[PXM_FLAG_LEN] = { [0 ... PXM_FLAG_LEN-1] = 0};
+#define PXM_BIT_SET(bit) (set_bit(bit,(void *)pxm_flag))
+#define PXM_BIT_CLEAR(bit) (clear_bit(bit,(void *)pxm_flag))
+#define PXM_BIT_TEST(bit) (test_bit(bit,(void *)pxm_flag))
+/* maps to convert between proximity domain and logical node ID */ +int pxm_to_nid_map[MAX_PXM_DOMAINS] = { [0 ... MAX_PXM_DOMAINS-1] = -1}; +int nid_to_pxm_map[NR_NODES] = { [0 ... NR_NODES-1] = -1};
+
+/*
+ * ACPI 2.0 SLIT (System Locality Information Table)
+ * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/
+ */
+void __init
+acpi_numa_slit_init (struct acpi_table_slit *slit)
+{
+ int i, j, node_from, node_to;
+ u32 len;
+
+ len = sizeof(struct acpi_table_header) + 8
+ + slit->localities * slit->localities;
+ if (slit->header.length != len) {
+ printk("ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n",
+ len, slit->header.length);
+ memset(numa_slit, 10, sizeof(numa_slit));
+ return;
+ }
+
+ memset(numa_slit, -1, sizeof(numa_slit));
+ for (i=0; i<slit->localities; i++) {
+ if (!PXM_BIT_TEST(i))
+ continue;
+ node_from = pxm_to_nid_map[i];
+ for (j=0; j<slit->localities; j++) {
+ if (!PXM_BIT_TEST(j))
+ continue;
+ node_to = pxm_to_nid_map[j];
+ node_distance(node_from, node_to) =
+ slit->entry[i*slit->localities + j];
+ }
+ }
+
+#ifdef SLIT_DEBUG
+ printk("ACPI 2.0 SLIT locality table:\n");
+ for (i = 0; i < numnodes; i++) {
+ for (j = 0; j < numnodes; j++)
+ printk("%03d ", node_distance(i,j));
+ printk("\n");
+ }
+#endif
+}
+
+void __init
+acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa) +{
+ /* record this node in proximity bitmap */
+ PXM_BIT_SET(pa->proximity_domain);
+
+ node_cpuid[srat_num_cpus].phys_id = (pa->apic_id << 8) | (pa->lsapic_eid);
+ /* nid should be overridden as logical node id later */
+ node_cpuid[srat_num_cpus].nid = pa->proximity_domain;
+ srat_num_cpus++;
+
+#ifdef SRAT_DEBUG
+ printk("CPU %x in proximity domain %x %s\n",
+ pa->apic_id, pa->proximity_domain,
+ pa->flags.enabled ? "enabled" : "disabled");
+#endif
+}
+
+void __init
+acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma) +{
+ unsigned long paddr, size;
+ u8 pxm;
+ struct node_memblk_s *p, *q, *pend;
+
+ pxm = ma->proximity_domain;
+
+ /* record this node in proximity bitmap */
+ PXM_BIT_SET(pxm);
+
+ /* fill node memory chunk structure */
+ paddr = ma->base_addr_hi;
+ paddr = (paddr << 32) | ma->base_addr_lo;
+ size = ma->length_hi;
+ size = (size << 32) | ma->length_lo;
+
+ if (num_memblks >= NR_MEMBLKS) {
+ printk("Too many mem chunks in SRAT. Ignoring %ld MBytes at %lx\n",
+ size/(1024*1024), paddr);
+ return;
+ }
+
+ /* Insertion sort based on base address */
+ pend = &node_memblk[num_memblks];
+ for (p = &node_memblk[0]; p < pend; p++) {
+ if (paddr < p->start_paddr)
+ break;
+ }
+ if (p < pend) {
+ for (q = pend; q >= p; q--)
+ *(q + 1) = *q;
+ }
+ p->start_paddr = paddr;
+ p->size = size;
+ p->nid = pxm;
+ num_memblks++;
+
+#ifdef SRAT_DEBUG
+ printk("Memory range 0x%lx to 0x%lx (type %x) in proximity domain %x %s\n",

+	       paddr, paddr + size - 1,
+	       ma->memory_type, ma->proximity_domain,
+	       ma->flags.enabled ? (ma->flags.hot_pluggable ? 
+				    "enabled and removable" : "enabled" )
+	       : "disabled");

+#endif
+}
+
+void __init
+acpi_numa_arch_fixup(void)
+{
+ int i, j;
+
+ /* calculate total number of nodes in system from PXM bitmap */
+ numnodes = 0; /* init total nodes in system */
+ for (i = 0; i < MAX_PXM_DOMAINS; i++) {
+ if (PXM_BIT_TEST(i)) {
+ pxm_to_nid_map[i] = numnodes;
+ nid_to_pxm_map[numnodes++] = i;
+ }
+ }
+
+ /* set logical node id in memory chunk structure */
+ for (i = 0; i < num_memblks; i++)
+ node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid];
+
+ /* assign memory bank numbers for each chunk on each node */
+ for (i = 0; i < numnodes; i++) {
+ int bank;
+
+ bank = 0;
+ for (j = 0; j < num_memblks; j++)
+ if (node_memblk[j].nid == i)
+ node_memblk[j].bank = bank++;
+ }
+
+ /* set logical node id in cpu structure */
+ for (i = 0; i < srat_num_cpus; i++)
+ node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid];
+
+ printk("Number of logical nodes in system = %d\n", numnodes);
+ printk("Number of memory chunks in system = %d\n", num_memblks);
+}
+#endif /* CONFIG_ACPI_NUMA */

int __init
acpi_find_rsdp (unsigned long *rsdp_phys)
@@ -528,11 +694,6 @@
acpi_boot_init (char *cmdline)
{
int result = 0;
-
- /* Initialize the ACPI boot-time table parser */
- result = acpi_table_init(cmdline);
- if (0 != result)
- return result;

/*
* MADT

arch/ia64/kernel/setup.c +10 -0
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
@@ -297,6 +297,16 @@
 
 	efi_init();
 
+#ifdef CONFIG_ACPI_BOOT
+	/* Initialize the ACPI boot-time table parser */
+	acpi_table_init(*cmdline_p);
+
+#ifdef CONFIG_ACPI_NUMA
+	acpi_numa_init();
+#endif
+
+#endif /* CONFIG_APCI_BOOT */
+
 	find_memory();
 
 #if 0
arch/ia64/mm/Makefile +1 -0
diff -Nru a/arch/ia64/mm/Makefile b/arch/ia64/mm/Makefile
@@ -10,5 +10,6 @@
 O_TARGET := mm.o
 
 obj-y	 := init.o fault.o tlb.o extable.o
+obj-$(CONFIG_NUMA) += numa.o
 
 include $(TOPDIR)/Rules.make
arch/ia64/mm/numa.c new file +46 -0

46 lines not on this page · raw message

drivers/acpi/Config.in +4 -0
diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in
@@ -58,6 +58,7 @@
     define_bool CONFIG_ACPI_FAN		n
     define_bool CONFIG_ACPI_PROCESSOR	n
     define_bool CONFIG_ACPI_THERMAL	n
+    define_bool CONFIG_ACPI_NUMA	y
     endmenu
   fi
 
@@ -78,6 +79,9 @@
     tristate     '  Fan'		CONFIG_ACPI_FAN
     tristate     '  Processor'		CONFIG_ACPI_PROCESSOR
     dep_tristate '  Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
+    if [ "$CONFIG_NUMA" = "y" ]; then
+       bool         '  NUMA support' 	CONFIG_ACPI_NUMA
+    fi
     bool         '  Debug Statements' 	CONFIG_ACPI_DEBUG
     endmenu
   fi
drivers/acpi/tables.c +186 -9

239 lines not on this page · raw message

include/asm-ia64/acpi.h +6 -6
diff -Nru a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
@@ -33,17 +33,17 @@
 #define __acpi_map_table(phys_addr, size) __va(phys_addr)
 
 const char *acpi_get_sysname (void);
-int acpi_boot_init (char *cdline);
 int acpi_find_rsdp (unsigned long *phys_addr);
 int acpi_request_vector (u32 int_type);
 int acpi_get_prt (struct pci_vector_struct **vectors, int *count);
 int acpi_get_interrupt_model(int *type);
 
-#ifdef CONFIG_DISCONTIGMEM
-#define NODE_ARRAY_INDEX(x)	((x) / 8)	/* 8 bits/char */
-#define NODE_ARRAY_OFFSET(x)	((x) % 8)	/* 8 bits/char */
-#define MAX_PXM_DOMAINS		(256)
-#endif /* CONFIG_DISCONTIGMEM */
+#ifdef CONFIG_ACPI_NUMA
+/* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
+#define MAX_PXM_DOMAINS (256)
+extern int pxm_to_nid_map[MAX_PXM_DOMAINS];
+extern int nid_to_pxm_map[NR_NODES];
+#endif
 
 #endif /*__KERNEL__*/
 
include/asm-ia64/numa.h new file +64 -0

64 lines not on this page · raw message

include/linux/acpi.h +10 -1
diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h
@@ -336,12 +336,21 @@
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 unsigned long acpi_find_rsdp (void);
 int acpi_boot_init (char *cmdline);
+int acpi_numa_init (void);
 
 int acpi_table_init (char *cmdline);
 int acpi_table_parse (enum acpi_table_id, acpi_table_handler);
-int acpi_table_parse_madt (enum acpi_table_id, acpi_madt_entry_handler);
+int acpi_table_parse_madt (enum acpi_madt_entry_id, acpi_madt_entry_handler);
+int acpi_table_parse_srat (enum acpi_srat_entry_id, acpi_madt_entry_handler);
 void acpi_table_print (struct acpi_table_header *, unsigned long);
 void acpi_table_print_madt_entry (acpi_table_entry_header *);
+void acpi_table_print_srat_entry (acpi_table_entry_header *);
+
+/* the following four functions are architecture-dependent */
+extern void __init acpi_numa_slit_init (struct acpi_table_slit *slit);
+extern void __init acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa);
+extern void __init acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
+extern void __init acpi_numa_arch_fixup(void);
 
 extern int acpi_mp_config;