lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20190624150758.6695-16-rrichter@marvell.com>
Date:   Mon, 24 Jun 2019 15:09:25 +0000
From:   Robert Richter <rrichter@...vell.com>
To:     Borislav Petkov <bp@...en8.de>, James Morse <james.morse@....com>,
        "Mauro Carvalho Chehab" <mchehab@...nel.org>
CC:     "linux-edac@...r.kernel.org" <linux-edac@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        Robert Richter <rrichter@...vell.com>
Subject: [PATCH v2 15/24] EDAC, ghes: Extract numa node information for each
 dimm

In a later patch we want to have one mc device per node. This patch
extracts the numa node information for each dimm. This is done by
collecting the physical address ranges from the DMI table (Memory
Array Mapped Address - Type 19 of SMBIOS spec). The node information
for a physical address is already know to a numa aware system (e.g. by
using the ACPI _PXM method or the ACPI SRAT table), so based on the PA
we can assign the node id to the dimms.

A fallback that disables numa is implemented in case the node
information is inconsistent.

E.g., on a ThunderX2 system the following node mappings are found
based on the DMI table:

EDAC DEBUG: mem_info_setup: DIMM0: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM1: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM2: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM3: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM4: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM5: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM6: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM7: Found mem range [0x0000008800000000-0x0000009ffcffffff] on node 0
EDAC DEBUG: mem_info_setup: DIMM8: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM9: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM10: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM11: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM12: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM13: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM14: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1
EDAC DEBUG: mem_info_setup: DIMM15: Found mem range [0x0000009ffd000000-0x000000bffcffffff] on node 1

Signed-off-by: Robert Richter <rrichter@...vell.com>
---
 drivers/edac/ghes_edac.c | 98 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index 44bfb499b147..793362bea044 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -65,14 +65,32 @@ struct memdev_dmi_entry {
 	u16 conf_mem_clk_speed;
 } __attribute__((__packed__));
 
+/* Memory Array Mapped Address - Type 19 of SMBIOS spec */
+struct memarr_dmi_entry {
+	u8		type;
+	u8		length;
+	u16		handle;
+	u32		start;
+	u32		end;
+	u16		phys_mem_array_handle;
+	u8		partition_width;
+	u64		ext_start;
+	u64		ext_end;
+} __attribute__((__packed__));
+
 struct ghes_dimm_info {
 	struct dimm_info dimm_info;
 	int		idx;
+	int		numa_node;
+	phys_addr_t	start;
+	phys_addr_t	end;
+	u16		phys_handle;
 };
 
 struct ghes_mem_info {
-	int num_dimm;
+	int		num_dimm;
 	struct ghes_dimm_info *dimms;
+	int		dimms_per_node[MAX_NUMNODES];
 };
 
 static struct ghes_mem_info mem_info;
@@ -108,12 +126,52 @@ static int ghes_dimm_info_init(int num)
 
 	for_each_dimm(dimm) {
 		dimm->idx	= idx;
+		dimm->numa_node	= NUMA_NO_NODE;
 		idx++;
 	}
 
 	return 0;
 }
 
+static void ghes_edac_set_nid(const struct dmi_header *dh, void *arg)
+{
+	struct memarr_dmi_entry *entry = (struct memarr_dmi_entry *)dh;
+	struct ghes_dimm_info *dimm;
+	phys_addr_t start, end;
+	int nid;
+
+	if (dh->type != DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR)
+		return;
+
+	/* only support SMBIOS 2.7+ */
+	if (entry->length < sizeof(*entry))
+		return;
+
+	if (entry->start == 0xffffffff)
+		start = entry->ext_start;
+	else
+		start = entry->start;
+	if (entry->end == 0xffffffff)
+		end = entry->ext_end;
+	else
+		end = entry->end;
+
+	if (!pfn_valid(PHYS_PFN(start)))
+		return;
+
+	nid = pfn_to_nid(PHYS_PFN(start));
+	if (nid < 0 || nid >= MAX_NUMNODES || !node_possible(nid))
+		nid = NUMA_NO_NODE;
+
+	for_each_dimm(dimm) {
+		if (entry->phys_mem_array_handle == dimm->phys_handle) {
+			dimm->numa_node	= nid;
+			dimm->start	= start;
+			dimm->end	= end;
+		}
+	}
+}
+
 static int get_dimm_smbios_index(u16 handle)
 {
 	struct mem_ctl_info *mci = ghes_pvt->mci;
@@ -135,6 +193,8 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
 		struct dimm_info *dimm = &mi->dimm_info;
 		u16 rdr_mask = BIT(7) | BIT(13);
 
+		mi->phys_handle = entry->phys_mem_array_handle;
+
 		if (entry->size == 0xffff) {
 			pr_info("Can't get DIMM%i size\n", mi->idx);
 			dimm->nr_pages = MiB_TO_PAGES(32);/* Unknown */
@@ -224,8 +284,23 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
 	}
 }
 
+static void mem_info_disable_numa(void)
+{
+	struct ghes_dimm_info *dimm;
+
+	for_each_dimm(dimm) {
+		if (dimm->numa_node != NUMA_NO_NODE)
+			mem_info.dimms_per_node[dimm->numa_node] = 0;
+		dimm->numa_node = 0;
+	}
+
+	mem_info.dimms_per_node[0] = mem_info.num_dimm;
+}
+
 static int mem_info_setup(void)
 {
+	struct ghes_dimm_info *dimm;
+	bool enable_numa = true;
 	int num = 0;
 	int idx = 0;
 	int ret;
@@ -238,6 +313,25 @@ static int mem_info_setup(void)
 		return ret;
 
 	dmi_walk(ghes_edac_dmidecode, &idx);
+	dmi_walk(ghes_edac_set_nid, NULL);
+
+	for_each_dimm(dimm) {
+		if (dimm->numa_node == NUMA_NO_NODE)
+			enable_numa = false;
+		else
+			mem_info.dimms_per_node[dimm->numa_node]++;
+
+		edac_dbg(1, "DIMM%i: Found mem range [%pa-%pa] on node %d\n",
+			dimm->idx, &dimm->start, &dimm->end, dimm->numa_node);
+	}
+
+	if (enable_numa)
+		return 0;
+
+	/* something went wrong, disable numa */
+	if (num_possible_nodes() > 1)
+		pr_warn("Can't get numa info, disabling numa\n");
+	mem_info_disable_numa();
 
 	return 0;
 }
@@ -258,6 +352,8 @@ static int mem_info_setup_fake(void)
 	dimm->dtype = DEV_UNKNOWN;
 	dimm->edac_mode = EDAC_SECDED;
 
+	mem_info_disable_numa();
+
 	return 0;
 }
 
-- 
2.20.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ