Page MenuHomeFreeBSD

D9759.id32630.diff
No OneTemporary

D9759.id32630.diff

Index: sys/dev/amdtemp/amdtemp.c
===================================================================
--- sys/dev/amdtemp/amdtemp.c
+++ sys/dev/amdtemp/amdtemp.c
@@ -1,7 +1,8 @@
/*-
* Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
* Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
- * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org>
+ * Copyright (c) 2009 - 2012 Jung-uk Kim <jkim@FreeBSD.org>
+ * Copyright (c) 2013 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,106 +36,434 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
#include <sys/sysctl.h>
-#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
-#include <machine/cpufunc.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
+#include <machine/cputypes.h>
+#include <machine/pci_cfgreg.h>
#include <dev/pci/pcivar.h>
-#include <x86/pci_cfgreg.h>
+#include <dev/pci/pcireg.h>
-typedef enum {
- CORE0_SENSOR0,
- CORE0_SENSOR1,
- CORE1_SENSOR0,
- CORE1_SENSOR1,
- CORE0,
- CORE1
-} amdsensor_t;
-struct amdtemp_softc {
- device_t sc_dev;
- int sc_ncores;
- int sc_ntemps;
- int sc_flags;
-#define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */
-#define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */
-#define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */
- int32_t sc_offset;
- int32_t (*sc_gettemp)(device_t, amdsensor_t);
- struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
- struct intr_config_hook sc_ich;
-};
+typedef struct pci_io_data_s {
+ uint32_t bus; /* 0xffffffff = amdtemp bus. */
+ uint32_t slot;
+ uint32_t func;
+ uint32_t addr; /* Addr to set addr for read/write data. */
+ uint32_t data; /* Addr for read/write data */
+ uint32_t addr_offset; /* Register offset in this addr space. */
+} pci_io_t, *pci_io_p;
-#define VENDORID_AMD 0x1022
-#define DEVICEID_AMD_MISC0F 0x1103
-#define DEVICEID_AMD_MISC10 0x1203
-#define DEVICEID_AMD_MISC11 0x1303
-#define DEVICEID_AMD_MISC12 0x1403
-#define DEVICEID_AMD_MISC14 0x1703
-#define DEVICEID_AMD_MISC15 0x1603
-#define DEVICEID_AMD_MISC16 0x1533
-#define DEVICEID_AMD_MISC16_M30H 0x1583
-#define DEVICEID_AMD_MISC17 0x141d
+typedef struct amdtemp_softc_s {
+ device_t dev;
+ struct mtx lock; /* Read/write lock for some registers. */
+ uint32_t cpu_ncores;
+ uint32_t flags;
+ uint32_t tts_flags; /* Thermaltrip Status flags. */
+ int32_t tts_temp_offset[4];
+ int32_t rtc_temp_offset;
+ pci_io_t pci_io;
+ struct sysctl_oid *sysctl_cpu[MAXCPU]; /* dev.cpu.X.temperature oids. */
+ struct intr_config_hook sc_ich;
+} amdtemp_softc_t, *amdtemp_softc_p;
+#define AMDTEMP_F_RTC 1 /* Reported Temperature Control. */
+#define AMDTEMP_F_TTS 2 /* Thermaltrip Status. */
+#define AMDTEMP_F_HTC 4 /* Hardware Thermal Control (HTC). */
-static struct amdtemp_product {
- uint16_t amdtemp_vendorid;
- uint16_t amdtemp_deviceid;
-} amdtemp_products[] = {
- { VENDORID_AMD, DEVICEID_AMD_MISC0F },
- { VENDORID_AMD, DEVICEID_AMD_MISC10 },
- { VENDORID_AMD, DEVICEID_AMD_MISC11 },
- { VENDORID_AMD, DEVICEID_AMD_MISC12 },
- { VENDORID_AMD, DEVICEID_AMD_MISC14 },
- { VENDORID_AMD, DEVICEID_AMD_MISC15 },
- { VENDORID_AMD, DEVICEID_AMD_MISC16 },
- { VENDORID_AMD, DEVICEID_AMD_MISC16_M30H },
- { VENDORID_AMD, DEVICEID_AMD_MISC17 },
- { 0, 0 }
+#define AMDTEMP_TTS_F_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */
+#define AMDTEMP_TTS_F_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */
+#define AMDTEMP_TTS_F_OFF28 0x04 /* CurTmp starts at -28C. */
+#define AMDTEMP_TTS_F_NO_SENS 0x08 /* No sensors. */
+
+
+/* D18F3xFC CPUID Family/Model/Stepping */
+#define AMD_REG_CPUID 0xfc
+/* DRAM Configuration High Register */
+#define AMD_REG_DRAM_CONF_HIGH 0x94 /* Function 2 */
+#define AMD_REG_DRAM_MODE_DDR3 0x0100
+
+/* D18F3xA4 Reported Temperature Control Register */
+#define AMD_REG_REPTMP_CTRL 0xa4
+union reg_amd_rep_tmp_ctrl_desc {
+ uint32_t u32;
+ struct reg_amd_rep_tmp_ctrl_bits {
+ uint32_t PerStepTimeUp:5; /* 4:0 rw per 1/8th step time up. */
+ uint32_t TmpMaxDiffUp:2;/* 6:5 rw temperature maximum difference up. */
+ uint32_t TmpSlewDnEn:1; /* 7 rw temperature slew downward enable. */
+ uint32_t PerStepTimeDn:5;/* 12:8 rw per 1/8th step time down. */
+ uint32_t r0:3; /* 15:13 Reserved. */
+ uint32_t CurTmpTjSel:2; /* 17:16 rw Current temperature select. */
+ uint32_t CurTmpTjSlewSel:1;/* 18 rw */
+ uint32_t CurTmpRangeSel:1;/* 19 rw */
+ uint32_t r1:1; /* 20 Reserved. */
+ uint32_t CurTmp:11; /* 31:21 ro/rw current temperature. */
+ } bits;
};
+CTASSERT(sizeof(struct reg_amd_rep_tmp_ctrl_bits) == sizeof(uint32_t));
+/* CurTmpTjSel valid family 10h, 15h, 16h processors. */
-/*
- * Reported Temperature Control Register
+/*
+ * Thermaltrip Status Register
+ * BIOS and Kernel Developer’s Guide for AMD NPT Family 0Fh Processors
+ * 32559 Rev. 3.16 November 2009
*/
-#define AMDTEMP_REPTMP_CTRL 0xa4
+/* D18F3xE4 Thermtrip Status Register */
+#define AMD_REG_THERMTRIP_STAT 0xe4
+union reg_amd_thermtrip_status_desc {
+ uint32_t u32;
+ struct reg_amd_thermtrip_status_bits {
+ uint32_t r0:1; /* 0 Reserved. */
+ uint32_t Thermtp:1; /* 1 ro The processor has entered the THERMTRIP state. */
+ uint32_t ThermSenseCoreSel:1; /* 2 rw */
+ uint32_t ThermtpSense0:1; /* 3 ro */
+ uint32_t ThermtpSense1:1; /* 4 ro */
+ uint32_t ThermtpEn:1; /* 5 ro The THERMTRIP state is supported by the processor. */
+ uint32_t ThermSenseSel:1; /* 6 rw */
+ uint32_t r1:1; /* 7 Reserved. */
+ uint32_t DiodeOffset:6; /* 13:8 ro Thermal diode offset is used to correct the measurement made by an external temperature sensor. */
+ uint32_t CurTmp:10; /* 23:14 ro This field returns the current value of the internal thermal sensor. */
+ uint32_t TjOffset:5; /* 28:24 ro This field is the offset from CurTmp used to normalize to Tcontrol. */
+ uint32_t r2:2; /* 30:29 Reserved. */
+ uint32_t SwThermtp:1; /* 31 rw */
+ } bits;
+};
+CTASSERT(sizeof(struct reg_amd_thermtrip_status_bits) == sizeof(uint32_t));
/*
- * Thermaltrip Status Register (Family 0Fh only)
+ * The default value of the HTC temperature threshold (Tctl_max) is specified
+ * in the AMD Family 14h Processor Power and Thermal Datasheet.
*/
-#define AMDTEMP_THERMTP_STAT 0xe4
-#define AMDTEMP_TTSR_SELCORE 0x04
-#define AMDTEMP_TTSR_SELSENSOR 0x40
+/* D18F3x64 Hardware Thermal Control (HTC) */
+#define AMD_REG_HTC_CTRL 0x64
+union reg_amd_htc_desc {
+ uint32_t u32;
+ struct reg_amd_htc_bits {
+ uint32_t HtcEn:1; /* 0 rw 1=HTC is enabled; the processor is capable of entering the HTC-active state. */
+ uint32_t r0:3; /* 3:1 Reserved. */
+ uint32_t HtcAct:1; /* 4 ro 1=The processor is currently in the HTC-active state. */
+ uint32_t HtcActSts:1; /* 5 ro Read; set-by-hardware; write-1-to-clear. Reset: 0. This bit is set by hardware when the processor enters the HTC-active state. It is cleared by writing a 1 to it. */
+ uint32_t PslApicHiEn:1; /* 6 rw P-state limit higher value change APIC interrupt enable. */
+ uint32_t PslApicLoEn:1; /* 7 rw P-state limit lower value change APIC interrupt enable. */
+ uint32_t r1:8; /* 15:8 Reserved. */
+ uint32_t HtcTmpLmt:7; /* 22:16 rw HTC temperature limit. */
+ uint32_t HtcSlewSel:1; /* 23 rw HTC slew-controlled temperature select. */
+ uint32_t HtcHystLmt:4; /* 27:24 rw HTC hysteresis. The processor exits the HTC active state when the temperature selected by HtcSlewSel is less than the HTC temperature limit (HtcTmpLmt) minus the HTC hysteresis (HtcHystLmt). */
+ uint32_t HtcPstateLimit:3; /* 30:28 rw HTC P-state limit select. */
+ uint32_t HtcLock:1; /* 31 Read; write-1-only. 1=HtcPstateLimit, HtcHystLmt, HtcTmpLmt, and HtcEn are read-only. */
+ } bits;
+};
+CTASSERT(sizeof(struct reg_amd_htc_bits) == sizeof(uint32_t));
-/*
- * DRAM Configuration High Register
- */
-#define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */
-#define AMDTEMP_DRAM_MODE_DDR3 0x0100
+/* For F15h M60h. */
+static pci_io_t pci_io_smu = {
+ 0xffffffff,
+ 0,
+ 0,
+ 0xb8,
+ 0xbc,
+ 0xd8200c00
+};
-/*
- * CPU Family/Model Register
- */
-#define AMDTEMP_CPUID 0xfc
+#define AMDTEMP_ZERO_C_TO_K 2732
+#if __FreeBSD_version < 1200018 /* Since revision 310051. */
+#define AMDTEMP_SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
+ sysctl_add_oid(ctx, parent, nbr, name, (access), \
+ (ptr), (arg), (handler), (fmt), (descr))
+#else
+#define AMDTEMP_SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
+ sysctl_add_oid(ctx, parent, nbr, name, (access), \
+ (ptr), (arg), (handler), (fmt), (descr), NULL)
+#endif
+#define ARG2_GET_REG(__arg) ((__arg) & 0xffff)
+#define ARG2_GET_A1(__arg) (((__arg) >> 16) & 0xff)
+#define ARG2_GET_A2(__arg) (((__arg) >> 24) & 0xff)
+#define MAKE_ARG2(__reg, __a1, __a2) \
+ (((__reg) & 0xff) | (((__a1) & 0xff) << 16) | (((__a2) & 0xff) << 24))
+
+#define AMDTEMP_LOCK(__sc) mtx_lock(&(__sc)->lock)
+#define AMDTEMP_UNLOCK(__sc) mtx_unlock(&(__sc)->lock)
+
+
+typedef struct amdtemp_sysctl_reg_s {
+ uint16_t reg;
+ uint8_t a1;
+ uint8_t a2;
+ uint32_t flags;
+ char *fmt;
+ int (*oid_handler)(SYSCTL_HANDLER_ARGS);
+ char *name;
+ char *descr;
+} sysctl_reg_t, *sysctl_reg_p;
+
+static void amdtemp_sysctl_reg_add(amdtemp_softc_p sc,
+ struct sysctl_oid_list *child,
+ sysctl_reg_p regs);
+static int amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS);
+
+static uint32_t amdtemp_tts_get_temp(amdtemp_softc_p sc,
+ uint32_t reg, uint8_t core, uint8_t sense);
+static int amdtemp_tts_temp_reg_sysctl(SYSCTL_HANDLER_ARGS);
+
+static int amdtemp_htc_temp_sysctl(SYSCTL_HANDLER_ARGS);
+
+static int amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS);
+
+static uint32_t amdtemp_pci_read(amdtemp_softc_p sc, pci_io_p io,
+ uint32_t addr);
+static void amdtemp_pci_write(amdtemp_softc_p sc, pci_io_p io,
+ uint32_t addr, uint32_t data);
+
+
+/* D18F3xE4 Thermtrip Status Register */
+static sysctl_reg_t amdtemp_thermtrip_status_reg_bits[] = {
+ {
+ AMD_REG_THERMTRIP_STAT,
+ 24,
+ 5,
+ (CTLFLAG_RD | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "TjOffset",
+ __DESCR("This field is the offset from CurTmp used to "
+ "normalize to Tcontrol.")
+ }, {
+ AMD_REG_THERMTRIP_STAT,
+ 8,
+ 6,
+ (CTLFLAG_RD | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "DiodeOffset",
+ __DESCR("Thermal diode offset is used to correct the "
+ "measurement made by an external temperature sensor.")
+ }, {
+ AMD_REG_THERMTRIP_STAT,
+ 5,
+ 1,
+ (CTLFLAG_RD | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "enable",
+ __DESCR("The THERMTRIP state is supported by the "
+ "processor.")
+ }, {
+ AMD_REG_THERMTRIP_STAT,
+ 3,
+ 1,
+ (CTLFLAG_RD | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "sense",
+ __DESCR("The processor temperature exceeded the "
+ "THERMTRIP value.")
+ }, {
+ AMD_REG_THERMTRIP_STAT,
+ 1,
+ 1,
+ (CTLFLAG_RD | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "thermtrip",
+ __DESCR("The processor has entered the THERMTRIP state.")
+ },
+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+/* D18F3x64 Hardware Thermal Control (HTC) */
+static sysctl_reg_t amdtemp_htc_reg_bits[] = {
+ {
+ AMD_REG_HTC_CTRL,
+ 16,
+ 7,
+ (CTLFLAG_RD | CTLTYPE_INT),
+ "IK",
+ amdtemp_htc_temp_sysctl,
+ "HtcTmpLmt",
+ __DESCR("HTC temperature limit")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 24,
+ 4,
+ (CTLFLAG_RW | CTLTYPE_INT),
+ "IK",
+ amdtemp_htc_temp_sysctl,
+ "HtcHystLmt",
+ __DESCR("HTC hysteresis. The processor exits the "
+ "HTC active state when the temperature selected by "
+ "HtcSlewSel is less than the HTC temperature limit "
+ "(HtcTmpLmt) minus the HTC hysteresis (HtcHystLmt).")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 0,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcEn",
+ __DESCR("HTC is enabled; the processor is capable of "
+ "entering the HTC-active state.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 31,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcLock",
+ __DESCR("HtcPstateLimit, HtcHystLmt, HtcTmpLmt, and "
+ "HtcEn are read-only.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 23,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcSlewSel",
+ __DESCR("HTC slew-controlled temperature select.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 28,
+ 3,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcPstateLimit",
+ __DESCR("HTC P-state limit select.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 4,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcAct",
+ __DESCR("The processor is currently in the HTC-active "
+ "state.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 5,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "HtcActSts",
+ __DESCR("set-by-hardware; write-1-to-clear. Reset: 0. "
+ "This bit is set by hardware when the processor enters "
+ "the HTC-active state. It is cleared by writing a 1 to "
+ "it.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 6,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "PslApicHiEn",
+ __DESCR("P-state limit higher value change APIC "
+ "interrupt enable.")
+ }, {
+ AMD_REG_HTC_CTRL,
+ 7,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "PslApicLoEn",
+ __DESCR("P-state limit lower value change APIC "
+ "interrupt enable.")
+ },
+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+/* D18F3xA4 Reported Temperature Control Register */
+static sysctl_reg_t amdtemp_reptmp_reg_bits[] = {
+ {
+ AMD_REG_REPTMP_CTRL,
+ 21,
+ 11,
+ (CTLFLAG_RD | CTLTYPE_INT),
+ "IK",
+ amdtemp_rtc_temp_sysctl,
+ "CurTmp",
+ __DESCR("Provides the current control temperature, "
+ "Tctl, after the slew-rate controls have been applied.")
+ }, {
+ AMD_REG_REPTMP_CTRL,
+ 16,
+ 2,
+ (CTLFLAG_RW | CTLTYPE_INT),
+ "IK",
+ amdtemp_rtc_temp_sysctl,
+ "CurTmpTjSel",
+ __DESCR("Specifies a value used to create Tctl.")
+ }, {
+ AMD_REG_REPTMP_CTRL,
+ 7,
+ 1,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "TmpSlewDnEn",
+ __DESCR("Temperature slew downward enable.")
+ }, {
+ AMD_REG_REPTMP_CTRL,
+ 5,
+ 2,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "TmpMaxDiffUp",
+ __DESCR("Specifies the maximum difference, (Tctlm - "
+ "Tctl), when Tctl immediatly updates to Tctlm.")
+ }, {
+ AMD_REG_REPTMP_CTRL,
+ 8,
+ 5,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "PerStepTimeDn",
+ __DESCR("Specifies the time that Tctlm must remain "
+ "below Tctl before applying a 0.125 downward step.")
+ }, {
+ AMD_REG_REPTMP_CTRL,
+ 0,
+ 5,
+ (CTLFLAG_RW | CTLTYPE_UINT),
+ "IU",
+ amdtemp_sysctl_reg_bits,
+ "PerStepTimeUp",
+ __DESCR("Specifies the time that Tctlm must remain "
+ "above Tctl before applying a 0.125 upward step.")
+ },
+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
/*
* Device methods.
*/
-static void amdtemp_identify(driver_t *driver, device_t parent);
+static void amdtemp_identify(driver_t *driver, device_t parent);
static int amdtemp_probe(device_t dev);
static int amdtemp_attach(device_t dev);
+static int amdtemp_detach(device_t dev);
static void amdtemp_intrhook(void *arg);
-static int amdtemp_detach(device_t dev);
-static int amdtemp_match(device_t dev);
-static int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
-static int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor);
-static int amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
+
+
static device_method_t amdtemp_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, amdtemp_identify),
@@ -148,26 +477,42 @@
static driver_t amdtemp_driver = {
"amdtemp",
amdtemp_methods,
- sizeof(struct amdtemp_softc),
+ sizeof(amdtemp_softc_t),
};
-
static devclass_t amdtemp_devclass;
DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
+MODULE_VERSION(amdtemp, 1);
+
static int
-amdtemp_match(device_t dev)
+amdtemp_dev_check(device_t dev)
{
- int i;
- uint16_t vendor, devid;
+ uint32_t cpuid;
- vendor = pci_get_vendor(dev);
- devid = pci_get_device(dev);
-
- for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
- if (vendor == amdtemp_products[i].amdtemp_vendorid &&
- devid == amdtemp_products[i].amdtemp_deviceid)
- return (1);
+ if (resource_disabled("amdtemp", 0))
+ return (ENXIO);
+ /*
+ * Device 18h Function 3 Configuration Registers:
+ * vendor = AMD (0x1022)
+ * class = bridge (0x06000000)
+ * function = 3
+ */
+ if (pci_get_vendor(dev) != CPU_VENDOR_AMD ||
+ pci_get_class(dev) != PCIC_BRIDGE ||
+ pci_get_function(dev) != 3)
+ return (ENXIO);
+ /* Does processor have Temperature sensor / THERMTRIP / HTC ? */
+ if ((amd_pminfo & (AMDPM_TS | AMDPM_TTP | AMDPM_TM)) == 0)
+ return (ENXIO);
+ /* Check minimum cpu family. */
+ cpuid = pci_read_config(dev, AMD_REG_CPUID, 4);
+ if (cpuid != cpu_id) { /* XXX: Ryzen fix. */
+ device_printf(dev, "cpu_id = %x, AMD_REG_CPUID = %x.\n",
+ cpu_id, cpuid);
+ cpuid = cpu_id;
}
+ if (CPUID_TO_FAMILY(cpuid) < 0x0f)
+ return (ENXIO);
return (0);
}
@@ -178,13 +523,13 @@
device_t child;
/* Make sure we're not being doubly invoked. */
- if (device_find_child(parent, "amdtemp", -1) != NULL)
+ if (device_find_child(parent, "amdtemp", -1))
return;
-
- if (amdtemp_match(parent)) {
- child = device_add_child(parent, "amdtemp", -1);
- if (child == NULL)
- device_printf(parent, "add amdtemp child failed\n");
+ if (amdtemp_dev_check(parent))
+ return;
+ child = device_add_child(parent, "amdtemp", -1);
+ if (child == NULL) {
+ device_printf(parent, "add amdtemp child failed.\n");
}
}
@@ -191,30 +536,9 @@
static int
amdtemp_probe(device_t dev)
{
- uint32_t family, model;
- if (resource_disabled("amdtemp", 0))
+ if (amdtemp_dev_check(dev))
return (ENXIO);
-
- family = CPUID_TO_FAMILY(cpu_id);
- model = CPUID_TO_MODEL(cpu_id);
-
- switch (family) {
- case 0x0f:
- if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
- (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
- return (ENXIO);
- break;
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x14:
- case 0x15:
- case 0x16:
- break;
- default:
- return (ENXIO);
- }
device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
return (BUS_PROBE_GENERIC);
@@ -223,29 +547,55 @@
static int
amdtemp_attach(device_t dev)
{
- char tn[32];
- u_int regs[4];
- struct amdtemp_softc *sc = device_get_softc(dev);
- struct sysctl_ctx_list *sysctlctx;
- struct sysctl_oid *sysctlnode;
- uint32_t cpuid, family, model;
- u_int bid;
- int erratum319, unit;
+ amdtemp_softc_p sc = device_get_softc(dev);
+ uint32_t i, cpuid, model, family, regs[4], bid;
+ union reg_amd_rep_tmp_ctrl_desc reg_rtc;
+ union reg_amd_thermtrip_status_desc reg_tts;
+ union reg_amd_htc_desc reg_htc;
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *child, *list;
+ struct sysctl_oid *node, *sub_node;
+ char str[32];
+ int erratum319 = 0;
- erratum319 = 0;
+ sc->dev = dev;
+ /* Find number of cores per package. */
+ sc->cpu_ncores = ((amd_feature2 & AMDID2_CMP) ?
+ ((cpu_procinfo2 & AMDID_CMP_CORES) + 1) : 1);
+ if (sc->cpu_ncores > MAXCPU)
+ return (ENXIO);
+ mtx_init(&sc->lock, device_get_nameunit(dev), "amdtemp", MTX_DEF);
- /*
- * CPUID Register is available from Revision F.
- */
- cpuid = cpu_id;
+ /* Detect supported therm interfaces. */
+ do_cpuid(0x80000001, regs);
+ cpuid = pci_read_config(dev, AMD_REG_CPUID, 4);
+ if (cpuid != cpu_id) /* XXX: Ryzen fix. */
+ cpuid = cpu_id;
+ model = CPUID_TO_MODEL(cpuid);
family = CPUID_TO_FAMILY(cpuid);
- model = CPUID_TO_MODEL(cpuid);
- if (family != 0x0f || model >= 0x40) {
- cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4);
- family = CPUID_TO_FAMILY(cpuid);
- model = CPUID_TO_MODEL(cpuid);
+
+ /* Temperature sensor / Reported Temperature Control. */
+ if (family > 0x0f &&
+ (amd_pminfo & AMDPM_TS)) {
+ sc->flags |= AMDTEMP_F_RTC;
}
+ if (family == 0x15 &&
+ (model >= 0x60 && model <= 0x6f)) { /* Force read via SMU. */
+ sc->pci_io = pci_io_smu;
+ } else if (family == 0x17) { /* XXX force SMU for Ryzen. */
+ sc->pci_io = pci_io_smu;
+ } else if (sc->flags & AMDTEMP_F_RTC) { /* Auto detect. */
+ reg_rtc.u32 = amdtemp_pci_read(sc, &sc->pci_io,
+ AMD_REG_REPTMP_CTRL);
+ if (reg_rtc.bits.CurTmp == 0) { /* Retry with SMU. */
+ reg_rtc.u32 = amdtemp_pci_read(sc, &pci_io_smu,
+ AMD_REG_REPTMP_CTRL);
+ if (reg_rtc.bits.CurTmp)
+ sc->pci_io = pci_io_smu;
+ }
+ }
+ /* ThermalTrip. */
switch (family) {
case 0x0f:
/*
@@ -272,12 +622,21 @@
* XXX According to Linux, CurTmp starts at -28C on
* Socket AM2 Revision G processors, which is not
* documented anywhere.
+ * XXX check TjOffset and DiodeOffset for -49C / -28C
*/
+ if ((amd_pminfo & AMDPM_TTP) == 0) /* No TTP: THERMTRIP */
+ break;
+ reg_tts.u32 = pci_read_config(dev, AMD_REG_THERMTRIP_STAT, 4);
+ if (reg_tts.bits.ThermtpEn == 0)
+ break;
+ if ((model == 0x04 && (cpuid & CPUID_STEPPING) == 0) ||
+ (model == 0x05 && (cpuid & CPUID_STEPPING) <= 1))
+ break; /* No ThermalTrip. */
+ sc->flags |= AMDTEMP_F_TTS;
if (model >= 0x40)
- sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
+ sc->tts_flags |= AMDTEMP_TTS_F_CS_SWAP;
if (model >= 0x60 && model != 0xc1) {
- do_cpuid(0x80000001, regs);
- bid = (regs[1] >> 9) & 0x1f;
+ bid = ((regs[1] >> 9) & 0x1f);
switch (model) {
case 0x68: /* Socket S1g1 */
case 0x6c:
@@ -284,45 +643,137 @@
case 0x7c:
break;
case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
- if (bid != 0x0b && bid != 0x0c)
- sc->sc_flags |=
- AMDTEMP_FLAG_ALT_OFFSET;
+ if (bid != 0x0b && bid != 0x0c) {
+ sc->tts_flags |= AMDTEMP_TTS_F_OFF28;
+ }
break;
case 0x6f: /* Socket AM2 and ASB1 (1 core) */
case 0x7f:
if (bid != 0x07 && bid != 0x09 &&
- bid != 0x0c)
- sc->sc_flags |=
- AMDTEMP_FLAG_ALT_OFFSET;
+ bid != 0x0c) {
+ sc->tts_flags |= AMDTEMP_TTS_F_OFF28;
+ }
break;
default:
- sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET;
+ sc->tts_flags |= AMDTEMP_TTS_F_OFF28;
+ break;
}
- sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
+ sc->tts_flags |= AMDTEMP_TTS_F_CT_10BIT;
}
+ break;
+ default:
+ if ((amd_pminfo & AMDPM_TTP) == 0) /* No TTP: THERMTRIP */
+ break;
+ sc->flags |= AMDTEMP_F_TTS;
+ if (amdtemp_tts_get_temp(sc, AMD_REG_THERMTRIP_STAT, 0, 0) == 2242 &&
+ amdtemp_tts_get_temp(sc, AMD_REG_THERMTRIP_STAT, 0, 1) == 2242)
+ sc->tts_flags |= AMDTEMP_TTS_F_NO_SENS;
+ break;
+ }
- /*
- * There are two sensors per core.
+ /* Hardware Thermal Control (HTC). */
+ if (amd_pminfo & AMDPM_TM) {
+ reg_htc.u32 = amdtemp_pci_read(sc, &sc->pci_io, AMD_REG_HTC_CTRL);
+ if (reg_htc.bits.HtcEn)
+ sc->flags |= AMDTEMP_F_HTC;
+ }
+
+ /* Init sysctl interface. */
+ ctx = device_get_sysctl_ctx(dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+ if (sc->flags & AMDTEMP_F_RTC) { /* Reported Temperature Control */
+ node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rtc",
+ CTLFLAG_RD, NULL, "Reported Temperature Control");
+ list = SYSCTL_CHILDREN(node);
+ amdtemp_sysctl_reg_add(sc, list, amdtemp_reptmp_reg_bits);
+ SYSCTL_ADD_INT(ctx, list, OID_AUTO, "sensor_offset",
+ CTLFLAG_RW, &sc->rtc_temp_offset, 0,
+ "Temperature sensor offset");
+ }
+ if (sc->flags & AMDTEMP_F_TTS) { /* Thermaltrip Status */
+ node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tts",
+ CTLFLAG_RD, NULL, "Thermaltrip Status");
+ list = SYSCTL_CHILDREN(node);
+ amdtemp_sysctl_reg_add(sc, list, amdtemp_thermtrip_status_reg_bits);
+
+ for (i = 0;i < sc->cpu_ncores && i < 2; i ++) {
+ if (sc->tts_flags & AMDTEMP_TTS_F_NO_SENS)
+ break;
+ snprintf(str, sizeof(str), "core%i", i);
+ sub_node = SYSCTL_ADD_NODE(ctx, list, OID_AUTO,
+ str, CTLFLAG_RD, NULL, "CPU core sensors");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node),
+ OID_AUTO, "sensor0",
+ (CTLTYPE_INT | CTLFLAG_RD), sc,
+ MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0),
+ amdtemp_tts_temp_reg_sysctl, "IK",
+ "Sensor 0 temperature");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node),
+ OID_AUTO, "sensor1",
+ (CTLTYPE_INT | CTLFLAG_RD), sc,
+ MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 1),
+ amdtemp_tts_temp_reg_sysctl, "IK",
+ "Sensor 1 temperature");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node),
+ OID_AUTO, "sensor0_offset", CTLFLAG_RW,
+ &sc->tts_temp_offset[((i << 1) | 0)], 0,
+ "Temperature sensor offset");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node),
+ OID_AUTO, "sensor1_offset", CTLFLAG_RW,
+ &sc->tts_temp_offset[((i << 1) | 1)], 0,
+ "Temperature sensor offset");
+ }
+ }
+ if (sc->flags & AMDTEMP_F_HTC) { /* Hardware Thermal Control (HTC) */
+ node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "htc",
+ CTLFLAG_RD, NULL, "Hardware Thermal Control (HTC)");
+ amdtemp_sysctl_reg_add(sc, SYSCTL_CHILDREN(node),
+ amdtemp_htc_reg_bits);
+ }
+
+ /* Verbose staff. */
+ if (bootverbose) {
+ /* CPUID Fn8000_0007_EDX Advanced Power Management Information
+ * 0 TS: Temperature sensor.
+ * 3 TTP: THERMTRIP. Value: Fuse[ThermTripEn].
+ * 4 TM: hardware thermal control (HTC). Value: ~Fuse[HtcDis].
*/
- sc->sc_ntemps = 2;
-
- sc->sc_gettemp = amdtemp_gettemp0f;
- break;
- case 0x10:
+ device_printf(dev, "amdtemp_attach: %d:%d:%d\n",
+ pci_get_bus(dev), pci_get_slot(dev),
+ pci_get_function(dev));
+ if (amd_pminfo & AMDPM_TS) {
+ device_printf(dev, "CPU have TS: Temperature "
+ "sensor.\n");
+ }
+ if (sc->flags & AMDTEMP_F_RTC) {
+ device_printf(dev, "Found: Reported "
+ "Temperature Control (RTC).\n");
+ }
+ if (sc->flags & AMDTEMP_F_TTS) {
+ device_printf(dev, "Found: Thermaltrip Status "
+ "(TTS).\n");
+ }
+ if (amd_pminfo & AMDPM_TM) {
+ device_printf(dev, "Found: Hardware Thermal "
+ "Control (HTC), state: %sabled.\n",
+ ((sc->flags & AMDTEMP_F_HTC) ? "en" : "dis"));
+ }
+ }
+ if (family == 0x10) {
/*
* Erratum 319 Inaccurate Temperature Measurement
- *
* http://support.amd.com/us/Processor_TechDocs/41322.pdf
*/
- do_cpuid(0x80000001, regs);
- switch ((regs[1] >> 28) & 0xf) {
+ switch (((regs[1] >> 28) & 0x0f)) {
case 0: /* Socket F */
erratum319 = 1;
break;
case 1: /* Socket AM2+ or AM3 */
- if ((pci_cfgregread(pci_get_bus(dev),
- pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) &
- AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 ||
+ bid = pci_cfgregread(pci_get_bus(dev),
+ pci_get_slot(dev), 2,
+ AMD_REG_DRAM_CONF_HIGH, 2);
+ if ((bid & AMD_REG_DRAM_MODE_DDR3) ||
+ model > 0x04 ||
(model == 0x04 && (cpuid & CPUID_STEPPING) >= 3))
break;
/* XXX 00100F42h (RB-C2) exists in both formats. */
@@ -329,95 +780,49 @@
erratum319 = 1;
break;
}
- /* FALLTHROUGH */
- case 0x11:
- case 0x12:
- case 0x14:
- case 0x15:
- case 0x16:
- /*
- * There is only one sensor per package.
- */
- sc->sc_ntemps = 1;
-
- sc->sc_gettemp = amdtemp_gettemp;
- break;
+ if (erratum319) {
+ device_printf(dev, "Erratum 319: temperature "
+ "measurement may be inaccurate.\n");
+ }
}
- /* Find number of cores per package. */
- sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
- (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
- if (sc->sc_ncores > MAXCPU)
- return (ENXIO);
-
- if (erratum319)
- device_printf(dev,
- "Erratum 319: temperature measurement may be inaccurate\n");
- if (bootverbose)
- device_printf(dev, "Found %d cores and %d sensors.\n",
- sc->sc_ncores,
- sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
-
/*
- * dev.amdtemp.N tree.
+ * Try to create dev.cpu sysctl entries and setup intrhook function.
+ * This is needed because the cpu driver may be loaded late on boot,
+ * after us.
*/
- unit = device_get_unit(dev);
- snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit);
- TUNABLE_INT_FETCH(tn, &sc->sc_offset);
+ amdtemp_intrhook(sc);
+ if (sc->sysctl_cpu[0] == NULL) {
+ sc->sc_ich.ich_func = amdtemp_intrhook;
+ sc->sc_ich.ich_arg = sc;
+ if (config_intrhook_establish(&sc->sc_ich)) {
+ amdtemp_detach(dev);
+ device_printf(dev, "config_intrhook_establish "
+ "failed!\n");
+ return (ENXIO);
+ }
+ }
- sysctlctx = device_get_sysctl_ctx(dev);
- SYSCTL_ADD_INT(sysctlctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0,
- "Temperature sensor offset");
- sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "core0", CTLFLAG_RD, 0, "Core 0");
+ return (0);
+}
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode),
- OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
- dev, CORE0_SENSOR0, amdtemp_sysctl, "IK",
- "Core 0 / Sensor 0 temperature");
+int
+amdtemp_detach(device_t dev)
+{
+ amdtemp_softc_p sc = device_get_softc(dev);
+ uint32_t i;
- if (sc->sc_ntemps > 1) {
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode),
- OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
- dev, CORE0_SENSOR1, amdtemp_sysctl, "IK",
- "Core 0 / Sensor 1 temperature");
-
- if (sc->sc_ncores > 1) {
- sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1");
-
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode),
- OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
- dev, CORE1_SENSOR0, amdtemp_sysctl, "IK",
- "Core 1 / Sensor 0 temperature");
-
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode),
- OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
- dev, CORE1_SENSOR1, amdtemp_sysctl, "IK",
- "Core 1 / Sensor 1 temperature");
+ for (i = 0; i < sc->cpu_ncores; i ++) {
+ if (sc->sysctl_cpu[i]) {
+ sysctl_remove_oid(sc->sysctl_cpu[i], 1, 0);
}
}
-
- /*
- * Try to create dev.cpu sysctl entries and setup intrhook function.
- * This is needed because the cpu driver may be loaded late on boot,
- * after us.
- */
- amdtemp_intrhook(dev);
- sc->sc_ich.ich_func = amdtemp_intrhook;
- sc->sc_ich.ich_arg = dev;
- if (config_intrhook_establish(&sc->sc_ich) != 0) {
- device_printf(dev, "config_intrhook_establish failed!\n");
- return (ENXIO);
+ /* NewBus removes the dev.amdtemp.N tree by itself. */
+ if (sc->sc_ich.ich_arg) {
+ sc->sc_ich.ich_arg = NULL;
+ config_intrhook_disestablish(&sc->sc_ich);
}
+ mtx_destroy(&sc->lock);
return (0);
}
@@ -425,135 +830,281 @@
void
amdtemp_intrhook(void *arg)
{
- struct amdtemp_softc *sc;
- struct sysctl_ctx_list *sysctlctx;
- device_t dev = (device_t)arg;
- device_t acpi, cpu, nexus;
- amdsensor_t sensor;
- int i;
+ amdtemp_softc_p sc = arg;
+ device_t dev = sc->dev, acpi, cpu, nexus;
+ int (*sysctl_handler)(SYSCTL_HANDLER_ARGS);
+ intptr_t sysctl_arg2;
+ uint32_t i, unit_base;
- sc = device_get_softc(dev);
+ if (sc->sc_ich.ich_arg) {
+ sc->sc_ich.ich_arg = NULL;
+ config_intrhook_disestablish(&sc->sc_ich);
+ }
- /*
- * dev.cpu.N.temperature.
- */
+ /* dev.cpu.N.temperature. */
nexus = device_find_child(root_bus, "nexus", 0);
acpi = device_find_child(nexus, "acpi", 0);
+ /* XXX: cpu_ncores not constant for different CPUs... */
+ unit_base = (device_get_unit(dev) * sc->cpu_ncores);
- for (i = 0; i < sc->sc_ncores; i++) {
- if (sc->sc_sysctl_cpu[i] != NULL)
+ for (i = 0; i < sc->cpu_ncores; i ++) {
+ if (sc->sysctl_cpu[i])
continue;
- cpu = device_find_child(acpi, "cpu",
- device_get_unit(dev) * sc->sc_ncores + i);
- if (cpu != NULL) {
- sysctlctx = device_get_sysctl_ctx(cpu);
-
- sensor = sc->sc_ntemps > 1 ?
- (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0;
- sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
- OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
- dev, sensor, amdtemp_sysctl, "IK",
- "Current temparature");
+ cpu = device_find_child(acpi, "cpu", (unit_base + i));
+ if (cpu == NULL)
+ continue;
+ sysctl_handler = NULL;
+ if (sc->flags & AMDTEMP_F_RTC) {
+ /* Reported Temperature Control */
+ sysctl_handler = amdtemp_rtc_temp_sysctl;
+ sysctl_arg2 = MAKE_ARG2(AMD_REG_REPTMP_CTRL, 21, 11);
+ } else if ((sc->flags & AMDTEMP_F_TTS) &&
+ (sc->tts_flags & AMDTEMP_TTS_F_NO_SENS) == 0) {
+ /* Thermaltrip Status */
+ sysctl_handler = amdtemp_tts_temp_reg_sysctl;
+ sysctl_arg2 = MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0xff);
}
+ if (sysctl_handler == NULL)
+ continue;
+ sc->sysctl_cpu[i] = SYSCTL_ADD_PROC(
+ device_get_sysctl_ctx(cpu),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
+ OID_AUTO, "temperature", (CTLTYPE_INT | CTLFLAG_RD),
+ sc, sysctl_arg2, sysctl_handler, "IK",
+ "Current temperature");
}
- if (sc->sc_ich.ich_arg != NULL)
- config_intrhook_disestablish(&sc->sc_ich);
}
-int
-amdtemp_detach(device_t dev)
+
+/* Sysctl staff. */
+static void
+amdtemp_sysctl_reg_add(amdtemp_softc_p sc,
+ struct sysctl_oid_list *child, sysctl_reg_p regs)
{
- struct amdtemp_softc *sc = device_get_softc(dev);
- int i;
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
+ uint32_t i;
- for (i = 0; i < sc->sc_ncores; i++)
- if (sc->sc_sysctl_cpu[i] != NULL)
- sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
+ for (i = 0; regs[i].oid_handler; i ++) {
+ AMDTEMP_SYSCTL_ADD_PROC(ctx, child, OID_AUTO,
+ regs[i].name, regs[i].flags, sc,
+ MAKE_ARG2(regs[i].reg, regs[i].a1, regs[i].a2),
+ regs[i].oid_handler, regs[i].fmt, regs[i].descr);
+ }
+}
- /* NewBus removes the dev.amdtemp.N tree by itself. */
+static int
+amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS)
+{
+ amdtemp_softc_p sc = arg1;
+ uint32_t i, reg_data, reg_num, bits_off, bits_len, bits_mask = 0;
+ unsigned val;
+ int error;
+ reg_num = ARG2_GET_REG(arg2);
+ bits_off = ARG2_GET_A1(arg2);
+ bits_len = ARG2_GET_A2(arg2);
+ reg_data = amdtemp_pci_read(sc, &sc->pci_io, reg_num);
+
+ for (i = 0; i < bits_len; i ++) {
+ bits_mask |= (((uint32_t)1) << i);
+ }
+
+ val = ((reg_data >> bits_off) & bits_mask);
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || req->newptr == NULL || val == reg_data)
+ return (error);
+ reg_data &= ~(bits_mask << bits_off); /* Clear all bits at offset. */
+ reg_data |= ((val & bits_mask) << bits_off); /* Set value bits. */
+ amdtemp_pci_write(sc, &sc->pci_io, reg_num, reg_data);
+
return (0);
}
+
+/* Thermaltrip Status Register */
+static uint32_t
+amdtemp_tts_get_temp(amdtemp_softc_p sc, uint32_t reg, uint8_t core,
+ uint8_t sense)
+{
+ union reg_amd_thermtrip_status_desc reg_tts;
+ uint32_t val;
+
+ reg_tts.u32 = 0;
+ if ((sc->tts_flags & AMDTEMP_TTS_F_CS_SWAP) == 0) {
+ reg_tts.bits.ThermSenseCoreSel = (core ? 1 : 0);
+ } else { /* Swap. */
+ reg_tts.bits.ThermSenseCoreSel = (core ? 0 : 1);
+ }
+ reg_tts.bits.ThermSenseSel = (sense ? 1 : 0);
+
+ AMDTEMP_LOCK(sc);
+ amdtemp_pci_write(sc, &sc->pci_io, reg, reg_tts.u32);
+ reg_tts.u32 = amdtemp_pci_read(sc, &sc->pci_io, reg);
+ AMDTEMP_UNLOCK(sc);
+
+ val = reg_tts.bits.CurTmp;
+ if ((sc->tts_flags & AMDTEMP_TTS_F_CT_10BIT) == 0) {
+ val &= ~0x00000003; /* Clear first 2 bits. */
+ }
+ val = (AMDTEMP_ZERO_C_TO_K + ((val * 5) / 2) -
+ ((sc->tts_flags & AMDTEMP_TTS_F_OFF28) ? 280 : 490));
+ val += (sc->tts_temp_offset[((2 * reg_tts.bits.ThermSenseCoreSel) +
+ reg_tts.bits.ThermSenseSel)] * 10);
+
+ return (val);
+}
+/* If 0xff == ARG2_GET_A2(arg2) then retun max temp for core. */
static int
-amdtemp_sysctl(SYSCTL_HANDLER_ARGS)
+amdtemp_tts_temp_reg_sysctl(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t)arg1;
- struct amdtemp_softc *sc = device_get_softc(dev);
- amdsensor_t sensor = (amdsensor_t)arg2;
- int32_t auxtemp[2], temp;
+ amdtemp_softc_p sc = arg1;
+ uint32_t reg_num;
+ unsigned val;
int error;
- switch (sensor) {
- case CORE0:
- auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0);
- auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1);
- temp = imax(auxtemp[0], auxtemp[1]);
+ reg_num = ARG2_GET_REG(arg2);
+ if (ARG2_GET_A2(arg2) == 0xff) { /* Core temp max. */
+ val = imax(amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 0),
+ amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 1));
+ } else {
+ val = amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2),
+ ARG2_GET_A2(arg2));
+ }
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ return (0);
+}
+
+
+/* x64 Hardware Thermal Control (HTC) */
+static int
+amdtemp_htc_temp_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ amdtemp_softc_p sc = arg1;
+ union reg_amd_htc_desc reg_htc;
+ uint32_t reg_num, bits_off;
+ unsigned val;
+ int error;
+
+ reg_num = ARG2_GET_REG(arg2);
+ bits_off = ARG2_GET_A1(arg2);
+
+ reg_htc.u32 = amdtemp_pci_read(sc, &sc->pci_io, reg_num);
+ switch (bits_off) {
+ case 16: /* HtcTmpLmt */
+ val = (((reg_htc.bits.HtcTmpLmt * 10) / 2) + 520);
break;
- case CORE1:
- auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0);
- auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1);
- temp = imax(auxtemp[0], auxtemp[1]);
+ case 24: /* HtcHystLmt */
+ val = ((reg_htc.bits.HtcHystLmt * 10) / 2);
break;
- default:
- temp = sc->sc_gettemp(dev, sensor);
- break;
}
- error = sysctl_handle_int(oidp, &temp, 0, req);
+ val += AMDTEMP_ZERO_C_TO_K;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+ /* amdtemp_pci_write(sc, reg_num, &sc->pci_io, reg_htc.u32); */
- return (error);
+ return (0);
}
-#define AMDTEMP_ZERO_C_TO_K 2731
-static int32_t
-amdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
+/* xA4 Reported Temperature Control Register */
+static int
+amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS)
{
- struct amdtemp_softc *sc = device_get_softc(dev);
- uint32_t mask, offset, temp;
+ amdtemp_softc_p sc = arg1;
+ union reg_amd_rep_tmp_ctrl_desc reg_rtc;
+ uint32_t reg_num, bits_off;
+ unsigned val;
+ int error;
- /* Set Sensor/Core selector. */
- temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
- temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR);
- switch (sensor) {
- case CORE0_SENSOR1:
- temp |= AMDTEMP_TTSR_SELSENSOR;
- /* FALLTHROUGH */
- case CORE0_SENSOR0:
- case CORE0:
- if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
- temp |= AMDTEMP_TTSR_SELCORE;
+ reg_num = ARG2_GET_REG(arg2);
+ bits_off = ARG2_GET_A1(arg2);
+
+ AMDTEMP_LOCK(sc);
+ reg_rtc.u32 = amdtemp_pci_read(sc, &sc->pci_io, reg_num);
+ switch (bits_off) {
+ case 16: /* CurTmpTjSel */
+ reg_rtc.bits.CurTmpTjSel = 3;
break;
- case CORE1_SENSOR1:
- temp |= AMDTEMP_TTSR_SELSENSOR;
- /* FALLTHROUGH */
- case CORE1_SENSOR0:
- case CORE1:
- if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
- temp |= AMDTEMP_TTSR_SELCORE;
+ case 21: /* CurTmp */
+ reg_rtc.bits.CurTmpTjSel = 0;
break;
}
- pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1);
+ amdtemp_pci_write(sc, &sc->pci_io, reg_num, reg_rtc.u32);
+ reg_rtc.u32 = amdtemp_pci_read(sc, &sc->pci_io, reg_num);
+ if (bits_off == 16) { /* CurTmpTjSel: switch back to CurTmp. */
+ reg_rtc.bits.CurTmpTjSel = 0;
+ amdtemp_pci_write(sc, &sc->pci_io, reg_num, reg_rtc.u32);
+ }
+ AMDTEMP_UNLOCK(sc);
- mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
- offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49;
- temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
- temp = ((temp >> 14) & mask) * 5 / 2;
- temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10;
+ val = (AMDTEMP_ZERO_C_TO_K + ((reg_rtc.bits.CurTmp * 10) / 8));
+ if (bits_off == 16) { /* CurTmpTjSel */
+ val -= 490;
+ } else {
+ val += (sc->rtc_temp_offset * 10);
+ }
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+ /* amdtemp_pci_write(sc, &sc->pci_io, reg_num, reg_rtc.u32); */
- return (temp);
+ return (0);
}
-static int32_t
-amdtemp_gettemp(device_t dev, amdsensor_t sensor)
+
+static uint32_t
+amdtemp_pci_read(amdtemp_softc_p sc, pci_io_p io, uint32_t addr)
{
- struct amdtemp_softc *sc = device_get_softc(dev);
- uint32_t temp;
+ uint32_t ret, bus;
+ device_t dev;
- temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
- temp = ((temp >> 21) & 0x7ff) * 5 / 4;
- temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10;
+ if (io->addr == 0)
+ return (pci_read_config(sc->dev, addr, 4));
- return (temp);
+ bus = io->bus;
+ if (bus == 0xffffffff)
+ bus = pci_get_bus(sc->dev);
+ dev = pci_find_bsf(bus, io->slot, io->func);
+ if (dev == NULL) {
+ device_printf(sc->dev, "Couldn't find NB PCI device\n");
+ return (0);
+ }
+
+ AMDTEMP_LOCK(sc);
+ pci_write_config(dev, io->addr, (io->addr_offset + addr), 4);
+ ret = pci_read_config(dev, io->data, 4);
+ AMDTEMP_UNLOCK(sc);
+
+ return (ret);
}
+
+static void
+amdtemp_pci_write(amdtemp_softc_p sc, pci_io_p io, uint32_t addr,
+ uint32_t data)
+{
+ uint32_t bus;
+ device_t dev;
+
+ if (io->addr == 0) {
+ pci_write_config(sc->dev, addr, data, 4);
+ return;
+ }
+
+ bus = io->bus;
+ if (bus == 0xffffffff)
+ bus = pci_get_bus(sc->dev);
+ dev = pci_find_bsf(bus, io->slot, io->func);
+ if (dev == NULL) {
+ device_printf(sc->dev, "Couldn't find NB PCI device\n");
+ return;
+ }
+
+ AMDTEMP_LOCK(sc);
+ pci_write_config(dev, io->addr, (io->addr_offset + addr), 4);
+ pci_write_config(dev, io->data, data, 4);
+ AMDTEMP_UNLOCK(sc);
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 24, 10:22 AM (18 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14819627
Default Alt Text
D9759.id32630.diff (40 KB)

Event Timeline