[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-edac
Subject:    [PATCH] x86/AMD: Save and use node_id directly
From:       Yazen Ghannam <Yazen.Ghannam () amd ! com>
Date:       2017-02-15 16:11:58
Message-ID: 1487175118-2235-1-git-send-email-Yazen.Ghannam () amd ! com
[Download RAW message or body]

For the past few generations, AMD hardware has provided a node_id either
through an MSR (Fam10h) or CPUID (TOPOEXT:Fam15h,16h,17h). This value
represents the physical node (die) that a CPU is on. There is a Northbridge
or Data Fabric for each node, so we need the node_id to interact with the
correct NB/DF of a CPU. This is independent of scheduling, NUMA, etc.

We've used amd_get_nb_id() to return the node_id of a CPU based on the
assumption that the NB id is the same as the Last Level Cache id and that
the Last Level Cache id is the same as the Node id. This is not defined in
the hardware but the assumption worked for older systems. This breaks on
Fam17h since the Node id is not equal to the Last Level Cache id. The same
assumption is used in srat_detect_node().

So save the node_id in struct cpuinfo_x86 and read it directly when needed.
This way the value provided by hardware is used and we make no assumptions.
Also, remove amd_get_nb_id() since it's not needed anymore. This maintains
the same behavior for older systems and should work for systems in the
foreseeable future.

Signed-off-by: Yazen Ghannam <Yazen.Ghannam@amd.com>
---
 arch/x86/events/amd/core.c            |  2 +-
 arch/x86/include/asm/processor.h      |  2 +-
 arch/x86/kernel/amd_nb.c              |  4 ++--
 arch/x86/kernel/cpu/amd.c             | 23 ++++++-----------------
 arch/x86/kernel/cpu/intel_cacheinfo.c |  5 +----
 arch/x86/kernel/cpu/mcheck/mce_amd.c  |  4 ++--
 arch/x86/ras/mce_amd_inj.c            |  4 ++--
 drivers/edac/amd64_edac.c             |  4 ++--
 drivers/edac/mce_amd.c                |  8 ++------
 9 files changed, 19 insertions(+), 37 deletions(-)

diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c
index afb222b..f0ab33f 100644
--- a/arch/x86/events/amd/core.c
+++ b/arch/x86/events/amd/core.c
@@ -391,7 +391,7 @@ static void amd_pmu_cpu_starting(int cpu)
 	if (!x86_pmu.amd_nb_constraints)
 		return;
 
-	nb_id = amd_get_nb_id(cpu);
+	nb_id = cpu_data(cpu).node_id;
 	WARN_ON_ONCE(nb_id == BAD_APICID);
 
 	for_each_online_cpu(i) {
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e6cfe7b..ace1bd3 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -105,6 +105,7 @@ struct cpuinfo_x86 {
 	/* CPUID returned core id bits: */
 	__u8			x86_coreid_bits;
 	__u8			cu_id;
+	__u8			node_id;
 	/* Max extended CPUID function supported: */
 	__u32			extended_cpuid_level;
 	/* Maximum supported CPUID level, -1=no CPUID: */
@@ -892,7 +893,6 @@ static inline int mpx_disable_management(void)
 }
 #endif /* CONFIG_X86_INTEL_MPX */
 
-extern u16 amd_get_nb_id(int cpu);
 extern u32 amd_get_nodes_per_socket(void);
 
 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 458da85..c32f610 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -294,7 +294,7 @@ struct resource *amd_get_mmconfig_range(struct resource *res)
 
 int amd_get_subcaches(int cpu)
 {
-	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
+	struct pci_dev *link = node_to_amd_nb(cpu_data(cpu).node_id)->link;
 	unsigned int mask;
 
 	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
@@ -308,7 +308,7 @@ int amd_get_subcaches(int cpu)
 int amd_set_subcaches(int cpu, unsigned long mask)
 {
 	static unsigned int reset, ban;
-	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
+	struct amd_northbridge *nb = node_to_amd_nb(cpu_data(cpu).node_id);
 	unsigned int reg;
 	int cuid;
 
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 35a5d5d..c98d3a9 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -305,7 +305,6 @@ static int nearby_node(int apicid)
 #ifdef CONFIG_SMP
 static void amd_get_topology(struct cpuinfo_x86 *c)
 {
-	u8 node_id;
 	int cpu = smp_processor_id();
 
 	/* get information required for multi-node processors */
@@ -314,7 +313,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
 
 		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
 
-		node_id  = ecx & 0xff;
+		c->node_id  = ecx & 0xff;
 		smp_num_siblings = ((ebx >> 8) & 0xff) + 1;
 
 		if (c->x86 == 0x15)
@@ -340,16 +339,16 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
 				per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
 			} else {
 				/* LLC is at the node level. */
-				per_cpu(cpu_llc_id, cpu) = node_id;
+				per_cpu(cpu_llc_id, cpu) = c->node_id;
 			}
 		}
 	} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
 		u64 value;
 
 		rdmsrl(MSR_FAM10H_NODE_ID, value);
-		node_id = value & 7;
+		c->node_id = value & 7;
 
-		per_cpu(cpu_llc_id, cpu) = node_id;
+		per_cpu(cpu_llc_id, cpu) = c->node_id;
 	} else
 		return;
 
@@ -382,21 +381,11 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
 	/* Convert the initial APIC ID into the socket ID */
 	c->phys_proc_id = c->initial_apicid >> bits;
 	/* use socket ID also for last level cache */
-	per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
+	per_cpu(cpu_llc_id, cpu) = c->node_id = c->phys_proc_id;
 	amd_get_topology(c);
 #endif
 }
 
-u16 amd_get_nb_id(int cpu)
-{
-	u16 id = 0;
-#ifdef CONFIG_SMP
-	id = per_cpu(cpu_llc_id, cpu);
-#endif
-	return id;
-}
-EXPORT_SYMBOL_GPL(amd_get_nb_id);
-
 u32 amd_get_nodes_per_socket(void)
 {
 	return nodes_per_socket;
@@ -412,7 +401,7 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
 
 	node = numa_cpu_node(cpu);
 	if (node == NUMA_NO_NODE)
-		node = per_cpu(cpu_llc_id, cpu);
+		node = c->node_id;
 
 	/*
 	 * On multi-fabric platform (e.g. Numascale NumaChip) a
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index c55fb2c..04b276f 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -569,14 +569,11 @@ cache_get_priv_group(struct cacheinfo *this_leaf)
 
 static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
 {
-	int node;
-
 	/* only for L3, and not in virtualized environments */
 	if (index < 3)
 		return;
 
-	node = amd_get_nb_id(smp_processor_id());
-	this_leaf->nb = node_to_amd_nb(node);
+	this_leaf->nb = node_to_amd_nb(cpu_data(smp_processor_id()).node_id);
 	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
 		amd_calc_l3_indices(this_leaf->nb);
 }
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 524cc57..6aabdfd 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -1191,7 +1191,7 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank)
 		return -ENODEV;
 
 	if (is_shared_bank(bank)) {
-		nb = node_to_amd_nb(amd_get_nb_id(cpu));
+		nb = node_to_amd_nb(cpu_data(cpu).node_id);
 
 		/* threshold descriptor already initialized on this node? */
 		if (nb && nb->bank4) {
@@ -1298,7 +1298,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
 			 * the last CPU on this node using the shared bank is
 			 * going away, remove that bank now.
 			 */
-			nb = node_to_amd_nb(amd_get_nb_id(cpu));
+			nb = node_to_amd_nb(cpu_data(cpu).node_id);
 			nb->bank4 = NULL;
 		}
 	}
diff --git a/arch/x86/ras/mce_amd_inj.c b/arch/x86/ras/mce_amd_inj.c
index 8730c28..f960d30 100644
--- a/arch/x86/ras/mce_amd_inj.c
+++ b/arch/x86/ras/mce_amd_inj.c
@@ -312,8 +312,8 @@ static void do_inject(void)
 	if (static_cpu_has(X86_FEATURE_AMD_DCM) &&
 	    b == 4 &&
 	    boot_cpu_data.x86 < 0x17) {
-		toggle_nb_mca_mst_cpu(amd_get_nb_id(cpu));
-		cpu = get_nbc_for_node(amd_get_nb_id(cpu));
+		toggle_nb_mca_mst_cpu(cpu_data(cpu).node_id);
+		cpu = get_nbc_for_node(cpu_data(cpu).node_id);
 	}
 
 	get_online_cpus();
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 82dab16..3067647 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1081,7 +1081,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
 /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
 static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
 {
-	u16 mce_nid = amd_get_nb_id(m->extcpu);
+	u16 mce_nid = cpu_data(m->extcpu).node_id;
 	struct mem_ctl_info *mci;
 	u8 start_bit = 1;
 	u8 end_bit   = 47;
@@ -2868,7 +2868,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
 	int cpu;
 
 	for_each_online_cpu(cpu)
-		if (amd_get_nb_id(cpu) == nid)
+		if (cpu_data(cpu).node_id == nid)
 			cpumask_set_cpu(cpu, mask);
 }
 
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 9d9193c..5fa3960 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -745,7 +745,7 @@ static void decode_mc3_mce(struct mce *m)
 static void decode_mc4_mce(struct mce *m)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
-	int node_id = amd_get_nb_id(m->extcpu);
+	int node_id = cpu_data(m->extcpu).node_id;
 	u16 ec = EC(m->status);
 	u8 xec = XEC(m->status, 0x1f);
 	u8 offset = 0;
@@ -878,12 +878,8 @@ static void decode_smca_errors(struct mce *m)
 		pr_cont("%s.\n", smca_mce_descs[bank_type].descs[xec]);
 	}
 
-	/*
-	 * amd_get_nb_id() returns the last level cache id.
-	 * The last level cache on Fam17h is 1 level below the node.
-	 */
 	if (bank_type == SMCA_UMC && xec == 0 && decode_dram_ecc)
-		decode_dram_ecc(amd_get_nb_id(m->extcpu) >> 1, m);
+		decode_dram_ecc(cpu_data(m->extcpu).node_id, m);
 }
 
 static inline void amd_decode_err_code(u16 ec)
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic