summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2015-05-08 00:56:56 +0000
committeradrian <adrian@FreeBSD.org>2015-05-08 00:56:56 +0000
commit2cad336903136efb1928d24e584acc71e5ce5905 (patch)
tree3dff867c952f9c6dfb76911b755cda68bf3f67d0
parent2a9a342fe4ad4a95e3cf3a60682ea2b4a954b8f6 (diff)
downloadFreeBSD-src-2cad336903136efb1928d24e584acc71e5ce5905.zip
FreeBSD-src-2cad336903136efb1928d24e584acc71e5ce5905.tar.gz
Add initial memory locality cost awareness to the VM, and include
a basic ACPI SLIT table parser. For now this just exports the map via sysctl; it'll eventually be useful to userland when there's more useful NUMA support in -HEAD. * Add an optional mem_locality map; * add a mapping function taking from/to domain and returning the relative cost, or -1 if it's not available; * Add a very basic SLIT parser to x86 ACPI. Differential Revision: https://reviews.freebsd.org/D2460 Reviewed by: rpaulo, stas, jhb Sponsored by: Norse Corp, Inc (hardware, coding); Dell (hardware)
-rw-r--r--sys/vm/vm_phys.c47
-rw-r--r--sys/vm/vm_phys.h1
-rw-r--r--sys/x86/acpica/srat.c126
3 files changed, 168 insertions, 6 deletions
diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c
index 5c33be4..71fadd7 100644
--- a/sys/vm/vm_phys.c
+++ b/sys/vm/vm_phys.c
@@ -71,6 +71,7 @@ _Static_assert(sizeof(long) * NBBY >= VM_PHYSSEG_MAX,
"Too many physsegs.");
struct mem_affinity *mem_affinity;
+int *mem_locality;
int vm_ndomains = 1;
@@ -140,6 +141,10 @@ static int sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS);
SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD,
NULL, 0, sysctl_vm_phys_segs, "A", "Phys Seg Info");
+static int sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS);
+SYSCTL_OID(_vm, OID_AUTO, phys_locality, CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, sysctl_vm_phys_locality, "A", "Phys Locality Info");
+
SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD,
&vm_ndomains, 0, "Number of physical memory domains available.");
@@ -297,6 +302,48 @@ sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS)
return (error);
}
+/*
+ * Return affinity, or -1 if there's no affinity information.
+ */
+static int
+vm_phys_mem_affinity(int f, int t)
+{
+
+ if (mem_locality == NULL)
+ return (-1);
+ if (f >= vm_ndomains || t >= vm_ndomains)
+ return (-1);
+ return (mem_locality[f * vm_ndomains + t]);
+}
+
+/*
+ * Outputs the VM locality table.
+ */
+static int
+sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sbuf;
+ int error, i, j;
+
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error != 0)
+ return (error);
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+
+ sbuf_printf(&sbuf, "\n");
+
+ for (i = 0; i < vm_ndomains; i++) {
+ sbuf_printf(&sbuf, "%d: ", i);
+ for (j = 0; j < vm_ndomains; j++) {
+ sbuf_printf(&sbuf, "%d ", vm_phys_mem_affinity(i, j));
+ }
+ sbuf_printf(&sbuf, "\n");
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ return (error);
+}
+
static void
vm_freelist_add(struct vm_freelist *fl, vm_page_t m, int order, int tail)
{
diff --git a/sys/vm/vm_phys.h b/sys/vm/vm_phys.h
index 8f3e847..153ef94 100644
--- a/sys/vm/vm_phys.h
+++ b/sys/vm/vm_phys.h
@@ -61,6 +61,7 @@ struct vm_phys_seg {
};
extern struct mem_affinity *mem_affinity;
+int *mem_locality;
extern int vm_ndomains;
extern struct vm_phys_seg vm_phys_segs[];
extern int vm_phys_nsegs;
diff --git a/sys/x86/acpica/srat.c b/sys/x86/acpica/srat.c
index 8d2a741..e908279 100644
--- a/sys/x86/acpica/srat.c
+++ b/sys/x86/acpica/srat.c
@@ -64,9 +64,97 @@ static vm_paddr_t srat_physaddr;
static int vm_domains[VM_PHYSSEG_MAX];
+static ACPI_TABLE_SLIT *slit;
+static vm_paddr_t slit_physaddr;
+static int vm_locality_table[MAXMEMDOM * MAXMEMDOM];
+
static void srat_walk_table(acpi_subtable_handler *handler, void *arg);
/*
+ * SLIT parsing.
+ */
+
+static void
+slit_parse_table(ACPI_TABLE_SLIT *s)
+{
+ int i, j;
+ int i_domain, j_domain;
+ int offset = 0;
+ uint8_t e;
+
+ /*
+ * This maps the SLIT data into the VM-domain centric view.
+ * There may be sparse entries in the PXM namespace, so
+ * remap them to a VM-domain ID and if it doesn't exist,
+ * skip it.
+ *
+ * It should result in a packed 2d array of VM-domain
+ * locality information entries.
+ */
+
+ if (bootverbose)
+ printf("SLIT.Localities: %d\n", (int) s->LocalityCount);
+ for (i = 0; i < s->LocalityCount; i++) {
+ i_domain = acpi_map_pxm_to_vm_domainid(i);
+ if (i_domain < 0)
+ continue;
+
+ if (bootverbose)
+ printf("%d: ", i);
+ for (j = 0; j < s->LocalityCount; j++) {
+ j_domain = acpi_map_pxm_to_vm_domainid(j);
+ if (j_domain < 0)
+ continue;
+ e = s->Entry[i * s->LocalityCount + j];
+ if (bootverbose)
+ printf("%d ", (int) e);
+ /* 255 == "no locality information" */
+ if (e == 255)
+ vm_locality_table[offset] = -1;
+ else
+ vm_locality_table[offset] = e;
+ offset++;
+ }
+ if (bootverbose)
+ printf("\n");
+ }
+}
+
+/*
+ * Look for an ACPI System Locality Distance Information Table ("SLIT")
+ */
+static int
+parse_slit(void)
+{
+
+ if (resource_disabled("slit", 0)) {
+ return (-1);
+ }
+
+ slit_physaddr = acpi_find_table(ACPI_SIG_SLIT);
+ if (slit_physaddr == 0) {
+ return (-1);
+ }
+
+ /*
+ * Make a pass over the table to populate the cpus[] and
+ * mem_info[] tables.
+ */
+ slit = acpi_map_table(slit_physaddr, ACPI_SIG_SLIT);
+ slit_parse_table(slit);
+ acpi_unmap_table(slit);
+ slit = NULL;
+
+ /* Tell the VM about it! */
+ mem_locality = vm_locality_table;
+ return (0);
+}
+
+/*
+ * SRAT parsing.
+ */
+
+/*
* Returns true if a memory range overlaps with at least one range in
* phys_avail[].
*/
@@ -301,17 +389,17 @@ renumber_domains(void)
/*
* Look for an ACPI System Resource Affinity Table ("SRAT")
*/
-static void
-parse_srat(void *dummy)
+static int
+parse_srat(void)
{
int error;
if (resource_disabled("srat", 0))
- return;
+ return (-1);
srat_physaddr = acpi_find_table(ACPI_SIG_SRAT);
if (srat_physaddr == 0)
- return;
+ return (-1);
/*
* Make a pass over the table to populate the cpus[] and
@@ -325,13 +413,39 @@ parse_srat(void *dummy)
if (error || check_domains() != 0 || check_phys_avail() != 0 ||
renumber_domains() != 0) {
srat_physaddr = 0;
- return;
+ return (-1);
}
/* Point vm_phys at our memory affinity table. */
mem_affinity = mem_info;
+
+ return (0);
+}
+
+static void
+init_mem_locality(void)
+{
+ int i;
+
+ /*
+ * For now, assume 255 == "no locality information for
+ * this pairing.
+ */
+ for (i = 0; i < MAXMEMDOM * MAXMEMDOM; i++)
+ vm_locality_table[i] = -1;
+}
+
+static void
+parse_acpi_tables(void *dummy)
+{
+
+ if (parse_srat() < 0)
+ return;
+ init_mem_locality();
+ (void) parse_slit();
}
-SYSINIT(parse_srat, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_srat, NULL);
+SYSINIT(parse_acpi_tables, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_acpi_tables,
+ NULL);
static void
srat_walk_table(acpi_subtable_handler *handler, void *arg)
OpenPOWER on IntegriCloud