Mon Apr 20 11:03:02 2020 UTC ()
Update to support Family 15h Model 60 temperature sensors.

Changes based on FreeBSD amdtemp driver changes by Conrad Meyer.

XXX: Some code duplication between this driver and amdtemp as
     parts of the 15h refresh code share more in common with
     older CPUs while accessing the device more like 17h.


(simonb)
diff -r1.6 -r1.7 src/sys/arch/x86/pci/amdsmn.c
diff -r1.9 -r1.10 src/sys/arch/x86/pci/amdzentemp.c

cvs diff -r1.6 -r1.7 src/sys/arch/x86/pci/amdsmn.c (expand / switch to context diff)
--- src/sys/arch/x86/pci/amdsmn.c 2019/08/06 05:32:44 1.6
+++ src/sys/arch/x86/pci/amdsmn.c 2020/04/20 11:03:02 1.7
@@ -1,7 +1,7 @@
-/*	$NetBSD: amdsmn.c,v 1.6 2019/08/06 05:32:44 msaitoh Exp $	*/
+/*	$NetBSD: amdsmn.c,v 1.7 2020/04/20 11:03:02 simonb Exp $	*/
 
 /*-
- * Copyright (c) 2017 Conrad Meyer <cem@FreeBSD.org>
+ * Copyright (c) 2017, 2019 Conrad Meyer <cem@FreeBSD.org>
  * All rights reserved.
  *
  * NetBSD port by Ian Clark <mrrooster@gmail.com>
@@ -29,10 +29,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdsmn.c,v 1.6 2019/08/06 05:32:44 msaitoh Exp $ ");
+__KERNEL_RCSID(0, "$NetBSD: amdsmn.c,v 1.7 2020/04/20 11:03:02 simonb Exp $ ");
 
 /*
- * Driver for the AMD Family 17h CPU System Management Network.
+ * Driver for the AMD Family 15h (model 60+) and 17h CPU
+ * System Management Network.
  */
 
 #include <sys/param.h>
@@ -52,11 +53,15 @@
 #include "amdsmn.h"
 #include "ioconf.h"
 
-#define	SMN_ADDR_REG	0x60
-#define	SMN_DATA_REG	0x64
+#define	F15H_SMN_ADDR_REG	0xb8
+#define	F15H_SMN_DATA_REG	0xbc
+#define	F17H_SMN_ADDR_REG	0x60
+#define	F17H_SMN_DATA_REG	0x64
 
 struct amdsmn_softc {
 	kmutex_t smn_lock;
+	uint8_t smn_addr_reg;
+	uint8_t smn_data_reg;
 	struct pci_attach_args pa;
 	pci_chipset_tag_t pc;
 	pcitag_t pcitag;
@@ -64,10 +69,29 @@
 
 static const struct pciid {
 	uint16_t	amdsmn_deviceid;
+	uint8_t		amdsmn_addr_reg;
+	uint8_t		amdsmn_data_reg;
 } amdsmn_ids[] = {
-	{ PCI_PRODUCT_AMD_F17_RC },
-	{ PCI_PRODUCT_AMD_F17_1X_RC },
-	{ PCI_PRODUCT_AMD_F17_7X_RC },
+	{
+		.amdsmn_deviceid = PCI_PRODUCT_AMD_F15_60_RC,
+		.amdsmn_addr_reg = F15H_SMN_ADDR_REG,
+		.amdsmn_data_reg = F15H_SMN_DATA_REG,
+	},
+	{
+		.amdsmn_deviceid = PCI_PRODUCT_AMD_F17_RC,
+		.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
+		.amdsmn_data_reg = F17H_SMN_DATA_REG,
+	},
+	{
+		.amdsmn_deviceid = PCI_PRODUCT_AMD_F17_1X_RC,
+		.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
+		.amdsmn_data_reg = F17H_SMN_DATA_REG,
+	},
+	{
+		.amdsmn_deviceid = PCI_PRODUCT_AMD_F17_7X_RC,
+		.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
+		.amdsmn_data_reg = F17H_SMN_DATA_REG,
+	},
 };
 
 static int amdsmn_match(device_t, cfdata_t, void *);
@@ -110,12 +134,21 @@
 	struct amdsmn_softc *sc = device_private(self);
 	struct pci_attach_args *pa = aux;
 	int flags = 0;
+	int i;
 
 	mutex_init(&sc->smn_lock, MUTEX_DEFAULT, IPL_NONE);
 	sc->pa = *pa;
 	sc->pc = pa->pa_pc;
 	sc->pcitag = pa->pa_tag;
-	aprint_normal(": AMD Family 17h System Management Network\n");
+
+	for (i = 0; i < __arraycount(amdsmn_ids); i++)
+		if (PCI_PRODUCT(pa->pa_id) == amdsmn_ids[i].amdsmn_deviceid) {
+			sc->smn_addr_reg = amdsmn_ids[i].amdsmn_addr_reg;
+			sc->smn_data_reg = amdsmn_ids[i].amdsmn_data_reg;
+		}
+
+	// aprint_normal(": AMD Family 17h System Management Network\n");
+	aprint_normal(": AMD System Management Network\n");
 	amdsmn_rescan(self, "amdsmnbus", &flags);
 }
 
@@ -146,8 +179,8 @@
 	struct amdsmn_softc *sc = device_private(dev);
 
 	mutex_enter(&sc->smn_lock);
-	pci_conf_write(sc->pc, sc->pcitag, SMN_ADDR_REG, addr);
-	*value = pci_conf_read(sc->pc, sc->pcitag, SMN_DATA_REG);
+	pci_conf_write(sc->pc, sc->pcitag, sc->smn_addr_reg, addr);
+	*value = pci_conf_read(sc->pc, sc->pcitag, sc->smn_data_reg);
 	mutex_exit(&sc->smn_lock);
 
 	return 0;
@@ -159,8 +192,8 @@
 	struct amdsmn_softc *sc = device_private(dev);
 
 	mutex_enter(&sc->smn_lock);
-	pci_conf_write(sc->pc, sc->pcitag, SMN_ADDR_REG, addr);
-	pci_conf_write(sc->pc, sc->pcitag, SMN_DATA_REG, value);
+	pci_conf_write(sc->pc, sc->pcitag, sc->smn_addr_reg, addr);
+	pci_conf_write(sc->pc, sc->pcitag, sc->smn_data_reg, value);
 	mutex_exit(&sc->smn_lock);
 
 	return 0;

cvs diff -r1.9 -r1.10 src/sys/arch/x86/pci/amdzentemp.c (expand / switch to context diff)
--- src/sys/arch/x86/pci/amdzentemp.c 2019/06/16 09:12:51 1.9
+++ src/sys/arch/x86/pci/amdzentemp.c 2020/04/20 11:03:02 1.10
@@ -1,10 +1,13 @@
-/*      $NetBSD: amdzentemp.c,v 1.9 2019/06/16 09:12:51 mlelstv Exp $ */
+/*      $NetBSD: amdzentemp.c,v 1.10 2020/04/20 11:03:02 simonb Exp $ */
 /*      $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $   */
 
 /*
- * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
+ * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org>
+ * All rights reserved.
+ *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Christoph Egger.
  *
@@ -50,7 +53,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.9 2019/06/16 09:12:51 mlelstv Exp $ ");
+__KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.10 2020/04/20 11:03:02 simonb Exp $ ");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -70,17 +73,35 @@
 
 #include "amdsmn.h"
 
-/* Address to query for temp on family 17h */
-#define AMD_17H_CUR_TMP    0x59800
+#define	AMD_CURTMP_RANGE_ADJUST	49000000	/* in microKelvins (ie, 49C) */
+#define	AMD_CURTMP_RANGE_CHECK	__BIT(19)
+#define	F10_TEMP_CURTMP		__BITS(31,21)	/* XXX same as amdtemp.c */
+#define	F15M60_CURTMP_TJSEL	__BITS(17,16)
 
+/*
+ * Reported Temperature, Family 15h, M60+
+ *
+ * Same register bit definitions as other Family 15h CPUs, but access is
+ * indirect via SMN, like Family 17h.
+ */
+#define	AMD_15H_M60H_REPTMP_CTRL	0xd8200ca4
+
+/*
+ * Reported Temperature, Family 17h
+ *
+ * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register
+ * provide the current temp.  bit 19, when clear, means the temp is reported in
+ * a range 0.."225C" (probable typo for 255C), and when set changes the range
+ * to -49..206C.
+ */
+#define	AMD_17H_CUR_TMP			0x59800
+
 struct amdzentemp_softc {
-        pci_chipset_tag_t sc_pc;
-        pcitag_t sc_pcitag;
 	struct sysmon_envsys *sc_sme;
 	device_t sc_smn;
 	envsys_data_t *sc_sensor;
 	size_t sc_sensor_len;
-        size_t sc_numsensors;
+	size_t sc_numsensors;
 	int32_t sc_offset;
 };
 
@@ -89,8 +110,9 @@
 static void amdzentemp_attach(device_t, device_t, void *);
 static int  amdzentemp_detach(device_t, int);
 
-static void amdzentemp_family17_init(struct amdzentemp_softc *);
-static void amdzentemp_family17_setup_sensors(struct amdzentemp_softc *, int);
+static void amdzentemp_init(struct amdzentemp_softc *);
+static void amdzentemp_setup_sensors(struct amdzentemp_softc *, int);
+static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *);
 static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *);
 
 CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc),
@@ -114,18 +136,19 @@
 amdzentemp_attach(device_t parent, device_t self, void *aux)
 {
 	struct amdzentemp_softc *sc = device_private(self);
-	struct pci_attach_args *pa = aux;
+	struct cpu_info *ci = curcpu();
+	int family;
 	int error;
 	size_t i;
 
+	family = CPUID_TO_FAMILY(ci->ci_signature);
 	aprint_naive("\n");
-	aprint_normal(": AMD CPU Temperature Sensors (Family17h)");
+	aprint_normal(": AMD CPU Temperature Sensors (Family%xh)",
+	    family);
 
-	sc->sc_pc = pa->pa_pc;
-	sc->sc_pcitag = pa->pa_tag;
 	sc->sc_smn = parent;
 
-	amdzentemp_family17_init(sc);
+	amdzentemp_init(sc);
 
 	aprint_normal("\n");
 
@@ -133,7 +156,7 @@
 	sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors;
 	sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP);
 
-	amdzentemp_family17_setup_sensors(sc, device_unit(self));
+	amdzentemp_setup_sensors(sc, device_unit(self));
 
 	/*
 	 * Set properties in sensors.
@@ -149,7 +172,17 @@
 	sc->sc_sme->sme_name = device_xname(self);
 	sc->sc_sme->sme_cookie = sc;
 
-	sc->sc_sme->sme_refresh = amdzentemp_family17_refresh;
+	switch (family) {
+	case 0x15:
+		sc->sc_sme->sme_refresh = amdzentemp_family15_refresh;
+		break;
+	case 0x17:
+		sc->sc_sme->sme_refresh = amdzentemp_family17_refresh;
+		break;
+	default:
+		/* XXX panic */
+		break;
+	}
 
 	error = sysmon_envsys_register(sc->sc_sme);
 	if (error) {
@@ -189,7 +222,7 @@
 
 
 static void
-amdzentemp_family17_init(struct amdzentemp_softc *sc) 
+amdzentemp_init(struct amdzentemp_softc *sc) 
 {
 
 	sc->sc_numsensors = 1;
@@ -207,7 +240,7 @@
 }
 
 static void
-amdzentemp_family17_setup_sensors(struct amdzentemp_softc *sc, int dv_unit) 
+amdzentemp_setup_sensors(struct amdzentemp_softc *sc, int dv_unit) 
 {
 	sc->sc_sensor[0].units = ENVSYS_STEMP;
 	sc->sc_sensor[0].state = ENVSYS_SVALID;
@@ -218,6 +251,40 @@
 }
 
 static void
+amdzentemp_family15_refresh(struct sysmon_envsys *sme,
+    envsys_data_t *edata) 
+{
+	struct amdzentemp_softc *sc = sme->sme_cookie;
+	uint32_t val, temp;
+	int error;
+	
+	error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val);
+	if (error) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+
+	/* from amdtemp.c:amdtemp_family10_refresh() */
+	temp = __SHIFTOUT(val, F10_TEMP_CURTMP);
+
+	/* From Celsius to micro-Kelvin. */
+	edata->value_cur = (temp * 125000) + 273150000;
+
+	/*
+	 * On Family 15h and higher, if CurTmpTjSel is 11b, the range is
+	 * adjusted down by 49.0 degrees Celsius.  (This adjustment is not
+	 * documented in BKDGs prior to family 15h model 00h.)
+	 *
+	 * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15
+	 *     as well??
+	 */
+	if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3)
+		edata->value_cur -= AMD_CURTMP_RANGE_ADJUST;
+
+	edata->state = ENVSYS_SVALID;
+}
+
+static void
 amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 
 {
 	struct amdzentemp_softc *sc = sme->sme_cookie;
@@ -233,8 +300,8 @@
 	/* From C to uK. */      
 	edata->value_cur = ((temp >> 21) * 125000) + 273150000;
 	/* adjust for possible offset of 49K */
-	if (temp & 0x80000) 
-		edata->value_cur -= 49000000;
+	if (temp & AMD_CURTMP_RANGE_CHECK) 
+		edata->value_cur -= AMD_CURTMP_RANGE_ADJUST;
 	edata->value_cur += sc->sc_offset;
 }
 
@@ -266,4 +333,3 @@
 		return ENOTTY;
 	}
 }
-