Module Name: src
Committed By: snj
Date: Tue Jun 16 02:23:31 UTC 2009
Modified Files:
src/sys/arch/x86/include [netbsd-5]: specialreg.h
src/sys/arch/x86/x86 [netbsd-5]: cpu_topology.c
Log Message:
Pull up following revision(s) (requested by rmind in ticket #789):
sys/arch/x86/include/specialreg.h: revision 1.36
sys/arch/x86/x86/cpu_topology.c: revision 1.2
Add CPU topology detection support for AMD processors.
Tested on the following AMD CPUs:
- Family 15, model 65
- Family 15, model 67
- Family 15, model 75
- Family 16, model 2
- Family 17, model 3
Reviewed (slightly older version of patch) by <yamt>.
To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.31.4.1 src/sys/arch/x86/include/specialreg.h
cvs rdiff -u -r1.2.2.2 -r1.2.2.3 src/sys/arch/x86/x86/cpu_topology.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/x86/include/specialreg.h
diff -u src/sys/arch/x86/include/specialreg.h:1.31 src/sys/arch/x86/include/specialreg.h:1.31.4.1
--- src/sys/arch/x86/include/specialreg.h:1.31 Tue Oct 14 15:49:04 2008
+++ src/sys/arch/x86/include/specialreg.h Tue Jun 16 02:23:31 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: specialreg.h,v 1.31 2008/10/14 15:49:04 cegger Exp $ */
+/* $NetBSD: specialreg.h,v 1.31.4.1 2009/06/16 02:23:31 snj Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@@ -410,6 +410,7 @@
#define MSR_NB_CFG 0xc001001f
#define NB_CFG_DISIOREQLOCK 0x0000000000000004ULL
#define NB_CFG_DISDATMSK 0x0000001000000000ULL
+#define NB_CFG_INITAPICCPUIDLO (1ULL << 54)
#define MSR_LS_CFG 0xc0011020
#define LS_CFG_DIS_LS2_SQUISH 0x02000000
Index: src/sys/arch/x86/x86/cpu_topology.c
diff -u src/sys/arch/x86/x86/cpu_topology.c:1.2.2.2 src/sys/arch/x86/x86/cpu_topology.c:1.2.2.3
--- src/sys/arch/x86/x86/cpu_topology.c:1.2.2.2 Tue Jun 16 02:19:44 2009
+++ src/sys/arch/x86/x86/cpu_topology.c Tue Jun 16 02:23:31 2009
@@ -1,7 +1,8 @@
-/* $NetBSD: cpu_topology.c,v 1.2.2.2 2009/06/16 02:19:44 snj Exp $ */
+/* $NetBSD: cpu_topology.c,v 1.2.2.3 2009/06/16 02:23:31 snj Exp $ */
/*-
- * Copyright (c)2008 YAMAMOTO Takashi,
+ * Copyright (c) 2009 Mindaugas Rasiukevicius <rmind at NetBSD org>,
+ * Copyright (c) 2008 YAMAMOTO Takashi,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,8 +27,16 @@
* SUCH DAMAGE.
*/
+/*
+ * x86 CPU topology detection.
+ *
+ * References:
+ * - 53668.pdf (7.10.2), 276613.pdf
+ * - 31116.pdf, 41256.pdf, 25481.pdf
+ */
+
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu_topology.c,v 1.2.2.2 2009/06/16 02:19:44 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu_topology.c,v 1.2.2.3 2009/06/16 02:23:31 snj Exp $");
#include <sys/param.h>
#include <sys/bitops.h>
@@ -42,49 +51,123 @@
void
x86_cpu_toplogy(struct cpu_info *ci)
{
- u_int lp_max = 1; /* logical processors per package */
- u_int smt_max; /* smt per core */
- u_int core_max = 1; /* core per package */
- int smt_bits, core_bits;
- uint32_t descs[4];
+ u_int lp_max; /* Logical processors per package */
+ u_int core_max; /* Core per package */
+ int n, cpu_family, apic_id, smt_bits, core_bits = 0;
+ uint32_t descs[4], lextmode;
+
+ apic_id = ci->ci_initapicid;
+ cpu_family = CPUID2FAMILY(ci->ci_signature);
+
+ /* Initial values. */
+ ci->ci_packageid = apic_id;
+ ci->ci_coreid = 0;
+ ci->ci_smtid = 0;
- if (cpu_vendor != CPUVENDOR_INTEL ||
- CPUID2FAMILY(ci->ci_signature) < 6)
+ switch (cpu_vendor) {
+ case CPUVENDOR_INTEL:
+ if (cpu_family < 6)
+ return;
+ break;
+ case CPUVENDOR_AMD:
+ if (cpu_family < 0xf)
+ return;
+ break;
+ default:
return;
+ }
/* Determine the extended feature flags. */
x86_cpuid(0x80000000, descs);
- if (descs[0] >= 0x80000001) {
+ lextmode = descs[0];
+ if (lextmode >= 0x80000001) {
x86_cpuid(0x80000001, descs);
- ci->ci_feature3_flags |= descs[3]; /* %edx */
+ ci->ci_feature3_flags |= descs[3]; /* edx */
}
- /* Determine topology. 253668.pdf 7.10.2. */
- ci->ci_packageid = ci->ci_initapicid;
- ci->ci_coreid = 0;
- ci->ci_smtid = 0;
+ /* Check for HTT support. See notes below regarding AMD. */
if ((ci->ci_feature_flags & CPUID_HTT) != 0) {
+ /* Maximum number of LPs sharing a cache (ebx[23:16]). */
x86_cpuid(1, descs);
lp_max = (descs[1] >> 16) & 0xff;
+ } else {
+ lp_max = 1;
}
- x86_cpuid(0, descs);
- if (descs[0] >= 4) {
- x86_cpuid2(4, 0, descs);
- core_max = (descs[0] >> 26) + 1;
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_INTEL:
+ /* Check for leaf 4 support. */
+ x86_cpuid(0, descs);
+ if (descs[0] >= 4) {
+ /* Maximum number of Cores per package (eax[31:26]). */
+ x86_cpuid2(4, 0, descs);
+ core_max = (descs[0] >> 26) + 1;
+ } else {
+ core_max = 1;
+ }
+ break;
+ case CPUVENDOR_AMD:
+ /* In a case of AMD, HTT flag means CMP support. */
+ if ((ci->ci_feature_flags & CPUID_HTT) == 0) {
+ core_max = 1;
+ break;
+ }
+ /* Legacy Method, LPs represent Cores. */
+ if (cpu_family < 0x10 || lextmode < 0x80000008) {
+ core_max = lp_max;
+ break;
+ }
+ /* Number of Cores (NC) per package (ecx[7:0]). */
+ x86_cpuid(0x80000008, descs);
+ core_max = (descs[2] & 0xff) + 1;
+ /* Amount of bits representing Core ID (ecx[15:12]). */
+ n = (descs[2] >> 12) & 0x0f;
+ if (n != 0) {
+ /*
+ * Extended Method.
+ * core_bits = 2 ^ n (power of two)
+ */
+ core_bits = 1 << n;
+ }
+ break;
+ default:
+ core_max = 1;
}
+
KASSERT(lp_max >= core_max);
- smt_max = lp_max / core_max;
- smt_bits = ilog2(smt_max - 1) + 1;
- core_bits = ilog2(core_max - 1) + 1;
+ smt_bits = ilog2((lp_max / core_max) - 1) + 1;
+ if (core_bits == 0) {
+ core_bits = ilog2(core_max - 1) + 1;
+ }
+
+ /*
+ * Family 0xf and 0x10 processors may have different structure of
+ * APIC ID. Detect that via special MSR register and move the bits,
+ * if necessary (ref: InitApicIdCpuIdLo).
+ */
+ if (cpu_vendor == CPUVENDOR_AMD && cpu_family < 0x11) { /* XXX */
+ const uint64_t reg = rdmsr(MSR_NB_CFG);
+ if ((reg & NB_CFG_INITAPICCPUIDLO) == 0) {
+ /*
+ * 0xf: { CoreId, NodeId[2:0] }
+ * 0x10: { CoreId[1:0], 000b, NodeId[2:0] }
+ */
+ const u_int node_id = apic_id & __BITS(0, 2);
+ apic_id = (cpu_family == 0xf) ?
+ (apic_id >> core_bits) | (node_id << core_bits) :
+ (apic_id >> 5) | (node_id << 2);
+ }
+ }
+
if (smt_bits + core_bits) {
- ci->ci_packageid = ci->ci_initapicid >> (smt_bits + core_bits);
+ ci->ci_packageid = apic_id >> (smt_bits + core_bits);
}
if (core_bits) {
u_int core_mask = __BITS(smt_bits, smt_bits + core_bits - 1);
- ci->ci_coreid = __SHIFTOUT(ci->ci_initapicid, core_mask);
+ ci->ci_coreid = __SHIFTOUT(apic_id, core_mask);
}
if (smt_bits) {
u_int smt_mask = __BITS(0, smt_bits - 1);
- ci->ci_smtid = __SHIFTOUT(ci->ci_initapicid, smt_mask);
+ ci->ci_smtid = __SHIFTOUT(apic_id, smt_mask);
}
}