Subject: Re: Athlon 64 X2 is "Unknown"
To: None <current-users@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: current-users
Date: 01/14/2007 16:08:20
In article <20061206094800.GB2121@serpens.de>
zza@serpens.de wrote:

> My dual core Athlon X2 64 is "identified" as
> "AMD Unknown K7 (Athlon) (686-class)". How can I fix this?

How about the attached patch?
(though I'm not sure if it's really worth
 because we also have cpu_brand_string already)
---
Izumi Tsutsui


Index: arch/i386/i386/identcpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/identcpu.c,v
retrieving revision 1.52
diff -u -r1.52 identcpu.c
--- arch/i386/i386/identcpu.c	1 Jan 2007 20:56:58 -0000	1.52
+++ arch/i386/i386/identcpu.c	14 Jan 2007 06:52:35 -0000
@@ -148,6 +148,7 @@
 static void intel_family_new_probe(struct cpu_info *);
 
 static const char *intel_family6_name(struct cpu_info *);
+static const char *amd_amd64_name(struct cpu_info *);
 
 static void transmeta_cpu_info(struct cpu_info *);
 
@@ -339,7 +340,7 @@
 			{
 				0, 0, 0, 0, 0, 0, 0, 0,
 				0, 0, 0, 0, 0, 0, 0, 0,
-				"Unknown K7 (Athlon)"	/* Default */
+				"Unknown K8 (Athlon)"	/* Default */
 			},
 			NULL,
 			amd_family6_probe,
@@ -739,6 +740,126 @@
 	return ret;
 }
 
+/*
+ * Identify AMD64 CPU names from cpuid.
+ *
+ * Based on "Revision Guide for AMD Athlon 64 and AMD Opteron Processors"
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf
+ */
+const char *
+amd_amd64_name(struct cpu_info *ci)
+{
+	int extfamily, extmodel, model;
+	const char *ret = NULL;
+
+	model = CPUID2MODEL(ci->ci_signature);
+	extfamily = CPUID2EXTFAMILY(ci->ci_signature);
+	extmodel  = CPUID2EXTMODEL(ci->ci_signature);
+
+	if (extfamily == 0x00) {
+		switch (model) {
+		case 0x1:
+			switch (extmodel) {
+			case 0x2:	/* rev JH-E1/E6 */
+				ret = "Dual-Core Opteron";
+				break;
+			}
+			break;
+		case 0x3:
+			switch (extmodel) {
+			case 0x2:	/* rev JH-E6 (Toledo) */
+				ret = "Dual-Core Opteron or Athlon 64 X2";
+				break;
+			}
+			break;
+		case 0x4:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-B0/C0/CG (ClawHammer) */
+			case 0x1:	/* rev SH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev SH-E5 (Lancaster?) */
+				ret = "Mobile Athlon 64 or Turion 64";
+				break;
+			}
+			break;
+		case 0x5:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-B0/B3/C0/CG (SledgeHammer?) */
+				ret = "Opteron or Athlon 64 FX";
+				break;
+			case 0x1:	/* rev SH-D0 */
+			case 0x2:	/* rev SH-E4 */
+				ret = "Opteron";
+				break;
+			}
+			break;
+		case 0x7:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-CG (ClawHammer) */
+			case 0x1:	/* rev SH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev DH-E4, SH-E4 */
+				ret = "Athlon 64 or Athlon 64 FX or Opteron";
+				break;
+			}
+			break;
+		case 0x8:
+			switch (extmodel) {
+			case 0x0:	/* rev CH-CG */
+			case 0x1:	/* rev CH-D0 */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		case 0xb:
+			switch (extmodel) {
+			case 0x0:	/* rev CH-CG */
+			case 0x1:	/* rev CH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev BH-E4 (Manchester) */
+				ret = "Athlon 64 X2";
+				break;
+			}
+			break;
+		case 0xc:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle) */
+			case 0x1:	/* rev DH-D0 (Winchester) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			case 0x2:	/* rev DH-E3/E6 */
+				ret = "Sempron";
+				break;
+			}
+			break;
+		case 0xe:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle?) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		case 0xf:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle) */
+			case 0x1:	/* rev DH-D0 (Winchester) */
+			case 0x2:	/* rev DH-E3/E6 (Venice) */
+			case 0x4:	/* rev F2 (socekt AM2) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		default:
+			ret = "Unknown AMD64 CPU";
+		}
+	}
+
+	return ret;
+}
+
 static void
 cpu_probe_base_features(struct cpu_info *ci)
 {
@@ -1365,17 +1486,30 @@
 					     i386_intel_brand[ci->ci_brand_id];
 			}
 
-			if (vendor == CPUVENDOR_AMD && family == 6 &&
-			    model >= 6) {
-				if (ci->ci_brand_id == 1)
-					/* 
-					 * It's Duron. We override the 
-					 * name, since it might have been 
-					 * misidentified as Athlon.
+			if (vendor == CPUVENDOR_AMD) {
+				if (family == 6 && model >= 6) {
+					if (ci->ci_brand_id == 1)
+						/* 
+						 * It's Duron. We override the 
+						 * name, since it might have
+						 * been misidentified as Athlon.
+						 */
+						name =
+						    amd_brand[ci->ci_brand_id];
+					else
+						brand = amd_brand_name;
+				}
+				if (CPUID2FAMILY(ci->ci_signature) == 0xf) {
+					/*
+					 * Identify AMD64 CPU names.
+					 * Note family value is clipped by
+					 * CPU_MAXFAMILY.
 					 */
-					name = amd_brand[ci->ci_brand_id];
-				else
-					brand = amd_brand_name;
+					const char *tmp;
+					tmp = amd_amd64_name(ci);
+					if (tmp != NULL)
+						name = tmp;
+				}
 			}
 			
 			if (vendor == CPUVENDOR_IDT && family >= 6)
Index: arch/x86/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/specialreg.h,v
retrieving revision 1.13
diff -u -r1.13 specialreg.h
--- arch/x86/include/specialreg.h	11 Jan 2007 17:24:30 -0000	1.13
+++ arch/x86/include/specialreg.h	14 Jan 2007 06:52:35 -0000
@@ -169,9 +169,13 @@
 
 #define CPUID2_FLAGS "\20\1SSE3\4MONITOR\5DS-CPL\6VMX\10EST\11TM2\13CID\17xTPR"
 
-#define CPUID2FAMILY(cpuid)	(((cpuid) >> 8) & 15)
-#define CPUID2MODEL(cpuid)	(((cpuid) >> 4) & 15)
-#define CPUID2STEPPING(cpuid)	((cpuid) & 15)
+#define CPUID2FAMILY(cpuid)	(((cpuid) >> 8) & 0xf)
+#define CPUID2MODEL(cpuid)	(((cpuid) >> 4) & 0xf)
+#define CPUID2STEPPING(cpuid)	((cpuid) & 0xf)
+
+/* Extended family and model are defined on amd64 processors */
+#define CPUID2EXTFAMILY(cpuid)	(((cpuid) >> 20) & 0xff)
+#define CPUID2EXTMODEL(cpuid)	(((cpuid) >> 16) & 0xf)
 
 #define CPUID(code, eax, ebx, ecx, edx)                         \
 	__asm("cpuid"                                           \