FreeBSD Bugzilla – Attachment 149000 Details for
Bug 194792
[amdtemp] [patch] all cpu support
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
amdtemp.patch (text/plain), 46.71 KB, created by
Ivan Rozhuk
on 2014-11-03 20:26:51 UTC
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Ivan Rozhuk
Created:
2014-11-03 20:26:51 UTC
Size:
46.71 KB
patch
obsolete
>--- /usr/src/sys/dev/amdtemp/amdtemp.c_orig 2014-10-22 19:36:20.000000000 +0400 >+++ /usr/src/sys/dev/amdtemp/amdtemp.c 2014-11-03 22:42:36.000000000 +0300 >@@ -1,7 +1,8 @@ > /*- > * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> > * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> >- * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org> >+ * Copyright (c) 2009-2011 Jung-uk Kim <jkim@FreeBSD.org> >+ * Copyright (c) 2013 - 2014 Rozhuk Ivan <rozhuk.im@gmail.com> > * All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >@@ -27,97 +28,311 @@ > */ > > /* >- * Driver for the AMD CPU on-die thermal sensors for Family 0Fh/10h/11h procs. >+ * Driver for the AMD CPU on-die thermal sensors. > * Initially based on the k8temp Linux driver. > */ > > #include <sys/cdefs.h> >-__FBSDID("$FreeBSD: stable/9/sys/dev/amdtemp/amdtemp.c 263870 2014-03-28 08:58:51Z brueffer $"); >+__FBSDID("$FreeBSD$"); >+ >+#define CTASSERT(x) > > #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 <dev/pci/pcireg.h> >+ > >-typedef enum { >- SENSOR0_CORE0, >- SENSOR0_CORE1, >- SENSOR1_CORE0, >- SENSOR1_CORE1, >- CORE0, >- CORE1 >-} amdsensor_t; > > struct amdtemp_softc { >- device_t sc_dev; >- int sc_ncores; >- int sc_ntemps; >- int sc_flags; >-#define AMDTEMP_FLAG_DO_QUIRK 0x01 /* DiodeOffset may be incorrect. */ >-#define AMDTEMP_FLAG_DO_ZERO 0x02 /* DiodeOffset starts from 0C. */ >-#define AMDTEMP_FLAG_DO_SIGN 0x04 /* DiodeOffsetSignBit is present. */ >-#define AMDTEMP_FLAG_CS_SWAP 0x08 /* ThermSenseCoreSel is inverted. */ >-#define AMDTEMP_FLAG_CT_10BIT 0x10 /* CurTmp is 10-bit wide. */ >- int32_t (*sc_gettemp)(device_t, amdsensor_t); >- struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; >- struct intr_config_hook sc_ich; >-}; >- >-#define VENDORID_AMD 0x1022 >-#define DEVICEID_AMD_MISC0F 0x1103 >-#define DEVICEID_AMD_MISC10 0x1203 >-#define DEVICEID_AMD_MISC11 0x1303 >-#define DEVICEID_AMD_MISC16 0x1533 >- >-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_MISC16 }, >- { 0, 0 } >+ 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; >+ int32_t tsi_temp_offset[8]; >+ struct sysctl_oid *sysctl_cpu[MAXCPU]; /* dev.cpu.X.temperature oids. */ >+ struct intr_config_hook sc_ich; > }; >+#define AMDTEMP_F_TTS 1 /* Thermaltrip Status. */ >+#define AMDTEMP_F_HTC 2 /* Hardware Thermal Control (HTC). */ >+#define AMDTEMP_F_RTC 4 /* Reported Temperature Control. */ >+#define AMDTEMP_F_TSI 8 /* TSI via CPU registers. */ >+#define AMDTEMP_F_SBTSI 16 /* TSI via SMBus. */ > >-/* >- * Reported Temperature Control Register (Family 10h/11h only) >+#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_LOCK(sc) mtx_lock(&(sc)->lock) >+#define AMDTEMP_UNLOCK(sc) mtx_unlock(&(sc)->lock) >+ >+ >+/* D18F3xFC CPUID Family/Model/Stepping */ >+#define AMD_REG_CPUID 0xfc >+ >+/* >+ * 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 */ >+ } __packed bits; >+}; >+ >+ >+/* DRAM Configuration High Register */ >+#define AMD_REG_DRAM_CONF_HIGH 0x94 /* Function 2 */ >+#define AMD_REG_DRAM_MODE_DDR3 0x0100 > > /* >- * Thermaltrip Status Register >+ * 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 /* Family 0Fh only */ >-#define AMDTEMP_TTSR_SELSENSOR 0x40 /* Family 0Fh only */ >+/* 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. */ >+ } __packed bits; >+}; > >+ >+/* 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. */ >+ } __packed bits; >+}; >+/* CurTmpTjSel valid family 10h, 15h, 16h processors. */ >+ >+ >+/* SB-TSI */ >+#define AMD_REG_SBI_CTRL 0x1e4 /* SBI Control */ >+union reg_amd_sbi_ctrl_desc { >+ uint32_t u32; >+ struct reg_amd_sbi_ctrl_bits { >+ uint32_t r0:1; /* 0 Reserved. */ >+ uint32_t SbRmiDis:1; /* 1 ro SMBus-based sideband remote management interface disable. */ >+ uint32_t r1:1; /* 2 Reserved. */ >+ uint32_t SbTsiDis:1; /* 3 ro SMBus-based sideband temperature sensor interface disable. */ >+ uint32_t SbiAddr:3; /* 6:4 rw SMBus-based sideband interface address. */ >+ uint32_t r2:1; /* 7 Reserved. */ >+ uint32_t LvtOffset:4; /* 11:8 rw local vector table offset. */ >+ uint32_t r3:19; /* 30:12 Reserved. */ >+ uint32_t SbiRegWrDn:1; /* 31 ro SBI register write complete. */ >+ } __packed bits; >+}; > /* >- * CPU Family/Model Register >+ * AMD Family 10h Processor BKDG: SbRmiDis (bit offset: 1) + SbTsiDis (bit offset: 3) >+ * AMD Family 11h Processor BKDG: SbTsiDis (bit offset: 1) >+ * AMD Family 12h Processor BKDG: SbTsiDis (bit offset: 1) >+ * BKDG for AMD Family 14h Models 00h-0Fh Processors: SbTsiDis (bit offset: 1) >+ * BKDG for AMD Family 15h Models 00h-0Fh Processors: SbRmiDis, no TSI >+ * BKDG for AMD Family 16h Models 00h-0Fh Processors: ??? 48751 Rev 3.00 - May 30, 2013 > */ >-#define AMDTEMP_CPUID 0xfc >+#define AMD_REG_SBI_ADDR 0x1e8 /* SBI Address */ >+#define AMD_REG_SBI_ADDR_MASK 0x07 >+#define AMD_REG_SBI_DATA 0x1ec /* SBI Data */ >+#define AMD_SBI_WRITE_TIMEOUT 100 /* XXX should be increased? */ >+ >+/* SB-TSI registers. */ >+#define SB_TSI_REG_CPU_TEMP_HB 0x01 /* CPU Temperature High Byte Register. */ >+#define SB_TSI_REG_STATUS 0x02 /* SB-TSI Status Register. */ >+#define SB_TSI_REG_CFG 0x03 /* SB-TSI Configuration Register. */ >+#define SB_TSI_REG_UPD_RATE 0x04 /* Update Rate Register. */ >+#define SB_TSI_REG_HIGH_TEMP_THB 0x07 /* High Temperature Threshold High Byte Register. */ >+#define SB_TSI_REG_LOW_TEMP_THB 0x08 /* Low Temperature Threshold High Byte Register.*/ >+#define SB_TSI_REG_CFG2 0x09 /* SB-TSI Configuration Register. */ >+#define SB_TSI_REG_CPU_TEMP_LB 0x10 /* CPU Temperature Low Byte Register. */ >+#define SB_TSI_REG_CPU_TEMP_OFF_HB 0x11 /* CPU Temperature Offset High Byte Register. */ >+#define SB_TSI_REG_CPU_TEMP_OFF_LB 0x12 /* CPU Temperature Offset Low Byte Register. */ >+#define SB_TSI_REG_HIGH_TEMP_TLB 0x13 /* High Temperature Threshold Low Byte Register. */ >+#define SB_TSI_REG_LOW_TEMP_TLB 0x14 /* Low Temperature Threshold Low Byte Register. */ >+#define SB_TSI_REG_TIMEOUT_CFG 0x22 /* Timeout Configuration Register. */ >+#define SB_TSI_REG_ALERT_THRESHOLD 0x32 /* Alert Threshold Register. */ >+#define SB_TSI_REG_ALERT_CFG 0xbf /* Alert Configuration Register. */ >+#define SB_TSI_REG_MANUFACTURE_ID 0xfe /* Manufacture ID Register. */ >+#define SB_TSI_REG_REVISION 0xff /* SB-TSI Revision Register. */ >+ >+ >+ >+#define AMDTEMP_ZERO_C_TO_K 2732 >+ >+ >+#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)) >+ >+struct amdtemp_sysctl_reg { >+ uint16_t reg; >+ uint8_t a1; >+ uint8_t a2; >+ uint32_t flags; >+ char *fmt; >+ int (*oid_handler)(SYSCTL_HANDLER_ARGS); >+ char *name; >+ char *descr; >+}; >+ >+static void amdtemp_sysctl_reg_add(struct amdtemp_softc *sc, >+ struct sysctl_oid_list *child, struct amdtemp_sysctl_reg *regs); >+static void amdtemp_sysctl_reg_add2(struct amdtemp_softc *sc, >+ struct sysctl_oid_list *child, struct amdtemp_sysctl_reg *regs, >+ uint32_t a2); >+static int amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS); >+ >+static uint32_t amdtemp_tts_get_temp(struct amdtemp_softc *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 void amdtemp_sbi_set_addr(struct amdtemp_softc *sc, uint32_t sbi_addr); >+static uint32_t amdtemp_sbi_read(struct amdtemp_softc *sc, uint32_t sbi_addr, >+ uint32_t reg_addr); >+static int amdtemp_sbi_write(struct amdtemp_softc *sc, uint32_t sbi_addr, >+ uint32_t reg_addr, uint8_t data); >+static int amdtemp_tsi_reg_sysctl(SYSCTL_HANDLER_ARGS); >+static int amdtemp_tsi_temp_reg_sysctl(SYSCTL_HANDLER_ARGS); >+ >+ >+/* D18F3xE4 Thermtrip Status Register */ >+static struct amdtemp_sysctl_reg amdtemp_thermtrip_status_reg_bits[] = { >+ { AMD_REG_THERMTRIP_STAT, 24, 5, (CTLFLAG_RD | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "TjOffset", "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", "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, "ThermtpEn", "The THERMTRIP state is supported by the processor." }, >+ { AMD_REG_THERMTRIP_STAT, 1, 1, (CTLFLAG_RD | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "Thermtrip", "The processor has entered the THERMTRIP state." }, >+ >+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL } >+}; >+ >+/* D18F3x64 Hardware Thermal Control (HTC) */ >+static struct amdtemp_sysctl_reg amdtemp_htc_reg_bits[] = { >+ { AMD_REG_HTC_CTRL, 16, 7, (CTLFLAG_RD | CTLTYPE_INT), "IK", amdtemp_htc_temp_sysctl, "HtcTmpLmt", "HTC temperature limit" }, >+ { AMD_REG_HTC_CTRL, 24, 4, (CTLFLAG_RW | CTLTYPE_INT), "IK", amdtemp_htc_temp_sysctl, "HtcHystLmt", "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", "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", "HtcPstateLimit, HtcHystLmt, HtcTmpLmt, and HtcEn are read-only." }, >+ { AMD_REG_HTC_CTRL, 23, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "HtcSlewSel", "HTC slew-controlled temperature select." }, >+ { AMD_REG_HTC_CTRL, 28, 3, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "HtcPstateLimit", "HTC P-state limit select." }, >+ { AMD_REG_HTC_CTRL, 4, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "HtcAct", "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", "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", "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", "P-state limit lower value change APIC interrupt enable." }, >+ >+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL } >+}; >+ >+/* D18F3xA4 Reported Temperature Control Register */ >+static struct amdtemp_sysctl_reg amdtemp_reptmp_reg_bits[] = { >+ { AMD_REG_REPTMP_CTRL, 21,11, (CTLFLAG_RD | CTLTYPE_INT), "IK", amdtemp_rtc_temp_sysctl, "CurTmp", "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", "Specifies a value used to create Tctl." }, >+ //{ AMD_REG_REPTMP_CTRL, 18, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "CurTmpTjSlewSel", "" }, >+ //{ AMD_REG_REPTMP_CTRL, 19, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "CurTmpRangeSel", "" }, >+ { AMD_REG_REPTMP_CTRL, 7, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "TmpSlewDnEn", "Temperature slew downward enable." }, >+ { AMD_REG_REPTMP_CTRL, 5, 2, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_sysctl_reg_bits, "TmpMaxDiffUp", "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", "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", "Specifies the time that Tctlm must remain above Tctl before applying a 0.125 upward step." }, >+ >+ { 0, 0, 0, 0, NULL, NULL, NULL, NULL } >+}; >+ >+/* SB-TSI registers. */ >+static struct amdtemp_sysctl_reg amdtemp_tsi_regs[] = { >+ { SB_TSI_REG_CPU_TEMP_LB, SB_TSI_REG_CPU_TEMP_HB, 0, (CTLFLAG_RD | CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, "cpu_temperature", "CPU Temperature" }, >+ { SB_TSI_REG_HIGH_TEMP_TLB, SB_TSI_REG_HIGH_TEMP_THB, 0, (CTLFLAG_RD | CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, "high_temperature_threshold", "High Temperature Threshold" }, >+ { SB_TSI_REG_LOW_TEMP_TLB, SB_TSI_REG_LOW_TEMP_THB, 0, (CTLFLAG_RD | CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, "low_temperature_threshold", "Low Temperature Threshold" }, >+ >+ { SB_TSI_REG_CPU_TEMP_OFF_HB, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "cpu_temperature_offset_hi", "CPU Temperature Offset High Byte" }, >+ { SB_TSI_REG_CPU_TEMP_OFF_LB, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "cpu_temperature_offset_lo", "CPU Temperature Offset Low Byte" }, >+ >+ { SB_TSI_REG_STATUS, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "status", "SB-TSI Status" }, >+ { SB_TSI_REG_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "cfg3", "SB-TSI Configuration Register 0x03" }, >+ { SB_TSI_REG_CFG2, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "cfg9", "SB-TSI Configuration Register 0x09" }, >+ { SB_TSI_REG_UPD_RATE, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "upd_rate", "Update Rate" }, >+ { SB_TSI_REG_TIMEOUT_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "timeout_cfg", "Timeout Configuration" }, >+ { SB_TSI_REG_ALERT_THRESHOLD, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "alert_threshold", "Alert Threshold" }, >+ { SB_TSI_REG_ALERT_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "alert_cfg", "Alert Configuration" }, >+ { SB_TSI_REG_MANUFACTURE_ID, 0, 0, (CTLFLAG_RD | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "manufacture_id", "Manufacture ID" }, >+ { SB_TSI_REG_REVISION, 0, 0, (CTLFLAG_RD | CTLTYPE_UINT), "IU", amdtemp_tsi_reg_sysctl, "revision", "SB-TSI Revision" }, >+ >+ { 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 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 void amdtemp_intrhook(void *arg); >+ >+ > > static device_method_t amdtemp_methods[] = { > /* Device interface */ >@@ -126,7 +341,7 @@ > DEVMETHOD(device_attach, amdtemp_attach), > DEVMETHOD(device_detach, amdtemp_detach), > >- {0, 0} >+ DEVMETHOD_END > }; > > static driver_t amdtemp_driver = { >@@ -134,112 +349,90 @@ > amdtemp_methods, > sizeof(struct amdtemp_softc), > }; >- > 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) >-{ >- int i; >- uint16_t vendor, devid; >- >- 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); >- } >+amdtemp_dev_check(device_t dev) { >+ uint32_t cpuid; > >+ if (resource_disabled("amdtemp", 0)) >+ return (ENXIO); >+ /* >+ * Device 18h Function 3 Configuration Registers: >+ * vendor = AMD (0x1022) >+ * class = bridge (0x06000000) >+ * function = 3 >+ */ >+ if (CPU_VENDOR_AMD != pci_get_vendor(dev) || >+ PCIC_BRIDGE != pci_get_class(dev) || >+ 3 != pci_get_function(dev)) >+ return (ENXIO); >+ /* Is processor have Temperature sensor / THERMTRIP / HTC ? */ >+ if (0 == (amd_pminfo & (AMDPM_TS | AMDPM_TTP | AMDPM_TM))) >+ return (ENXIO); >+ /* Check minimum cpu family. */ >+ cpuid = pci_read_config(dev, AMD_REG_CPUID, 4); >+ if (CPUID_TO_FAMILY(cpuid) < 0x0f) >+ return (ENXIO); > return (0); > } > > static void >-amdtemp_identify(driver_t *driver, device_t parent) >-{ >+amdtemp_identify(driver_t *driver, device_t parent) { > device_t child; > > /* Make sure we're not being doubly invoked. */ > if (device_find_child(parent, "amdtemp", -1) != NULL) > return; >- >- if (amdtemp_match(parent)) { >- child = device_add_child(parent, "amdtemp", -1); >- if (child == NULL) >- device_printf(parent, "add amdtemp child failed\n"); >- } >+ if (0 != amdtemp_dev_check(parent)) >+ return; >+ child = device_add_child(parent, "amdtemp", -1); >+ if (child == NULL) >+ device_printf(parent, "add amdtemp child failed\n"); > } > > static int >-amdtemp_probe(device_t dev) >-{ >- uint32_t family, model; >+amdtemp_probe(device_t dev) { > >- if (resource_disabled("amdtemp", 0)) >+ if (0 != 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 0x16: >- break; >- default: >- return (ENXIO); >- } > device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); > > return (BUS_PROBE_GENERIC); > } > > static int >-amdtemp_attach(device_t dev) >-{ >+amdtemp_attach(device_t dev) { > struct amdtemp_softc *sc = device_get_softc(dev); >- struct sysctl_ctx_list *sysctlctx; >- struct sysctl_oid *sysctlnode; >- uint32_t regs[4]; >- uint32_t cpuid, family, model; >- >- /* >- * Errata #154: Incorect Diode Offset >- */ >- if (cpu_id == 0x20f32) { >- do_cpuid(0x80000001, regs); >- if ((regs[1] & 0xfff) == 0x2c) >- sc->sc_flags |= AMDTEMP_FLAG_DO_QUIRK; >- } >+ uint32_t i, cpuid, model; >+ union reg_amd_thermtrip_status_desc reg_tts; >+ union reg_amd_htc_desc reg_htc; >+ union reg_amd_sbi_ctrl_desc reg_sbi; >+ struct sysctl_ctx_list *ctx; >+ struct sysctl_oid_list *child, *list; >+ struct sysctl_oid *node, *sub_node; >+ char str[32]; >+ int tsi_ok = 0, erratum319 = 0; >+ u_int regs[4], bid; > >- /* >- * CPUID Register is available from Revision F. >- */ >- family = CPUID_TO_FAMILY(cpu_id); >- model = CPUID_TO_MODEL(cpu_id); >- if (family != 0x0f || model >= 0x40) { >- cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); >- family = CPUID_TO_FAMILY(cpuid); >- model = CPUID_TO_MODEL(cpuid); >- } >+ sc->dev = dev; >+ /* Find number of cores per package. */ >+ sc->cpu_ncores = (((amd_feature2 & AMDID2_CMP) != 0) ? >+ ((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); > >- switch (family) { >+ cpuid = pci_read_config(dev, AMD_REG_CPUID, 4); >+ model = CPUID_TO_MODEL(cpuid); >+ switch (CPUID_TO_FAMILY(cpuid)) { > case 0x0f: > /* > * Thermaltrip Status Register > * >- * - DiodeOffsetSignBit >- * >- * Revision D & E: bit 24 >- * Other: N/A >- * > * - ThermSenseCoreSel > * > * Revision F & G: 0 - Core1, 1 - Core0 >@@ -257,260 +450,543 @@ > * ThermSenseCoreSel work in undocumented cases as well. > * In fact, the Linux driver suggests it may not work but > * we just assume it does until we find otherwise. >+ * >+ * 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 (model < 0x40) { >- sc->sc_flags |= AMDTEMP_FLAG_DO_ZERO; >- if (model >= 0x10) >- sc->sc_flags |= AMDTEMP_FLAG_DO_SIGN; >- } else { >- sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; >- if (model >= 0x60 && model != 0xc1) >- sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; >+ if (0 == (amd_pminfo & AMDPM_TTP)) /* No TTP: THERMTRIP */ >+ break; >+ reg_tts.u32 = pci_read_config(dev, AMD_REG_THERMTRIP_STAT, 4); >+ if (0 == reg_tts.bits.ThermtpEn) >+ 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->tts_flags |= AMDTEMP_TTS_F_CS_SWAP; >+ if (model >= 0x60 && model != 0xc1) { >+ do_cpuid(0x80000001, regs); >+ bid = ((regs[1] >> 9) & 0x1f); >+ switch (model) { >+ case 0x68: /* Socket S1g1 */ >+ case 0x6c: >+ case 0x7c: >+ break; >+ case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ >+ 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->tts_flags |= AMDTEMP_TTS_F_OFF28; >+ break; >+ default: >+ sc->tts_flags |= AMDTEMP_TTS_F_OFF28; >+ } >+ sc->tts_flags |= AMDTEMP_TTS_F_CT_10BIT; > } >- >+ break; >+ case 0x10: >+ sc->flags |= AMDTEMP_F_RTC; >+ reg_sbi.u32 = pci_read_config(dev, AMD_REG_SBI_CTRL, 4); >+ if (0 == reg_sbi.bits.SbTsiDis) >+ sc->flags |= AMDTEMP_F_TSI; > /* >- * There are two sensors per core. >+ * Erratum 319 Inaccurate Temperature Measurement >+ * http://support.amd.com/us/Processor_TechDocs/41322.pdf > */ >- sc->sc_ntemps = 2; >- >- sc->sc_gettemp = amdtemp_gettemp0f; >+ do_cpuid(0x80000001, regs); >+ switch ((regs[1] >> 28) & 0xf) { >+ 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, >+ AMD_REG_DRAM_CONF_HIGH, 2) & AMD_REG_DRAM_MODE_DDR3) != 0 || >+ model > 0x04 || >+ (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) >+ break; >+ /* XXX 00100F42h (RB-C2) exists in both formats. */ >+ erratum319 = 1; >+ break; >+ } > break; >- case 0x10: > 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; >+ default: >+ sc->flags |= AMDTEMP_F_RTC; >+ reg_sbi.u32 = pci_read_config(dev, AMD_REG_SBI_CTRL, 4); >+ if (0 == reg_sbi.bits.SbRmiDis || /* = SbTsiDis */ >+ 0 == reg_sbi.bits.SbTsiDis) >+ sc->flags |= AMDTEMP_F_TSI; >+ /* XXX TODO: read TSI via SMBus. */ > break; > } >- >- /* 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 (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. >- */ >- sysctlctx = device_get_sysctl_ctx(dev); >- sysctlnode = SYSCTL_ADD_NODE(sysctlctx, >- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, >- "sensor0", CTLFLAG_RD, 0, "Sensor 0"); >- >- SYSCTL_ADD_PROC(sysctlctx, >- SYSCTL_CHILDREN(sysctlnode), >- OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, >- dev, SENSOR0_CORE0, amdtemp_sysctl, "IK", >- "Sensor 0 / Core 0 temperature"); >- >- if (sc->sc_ntemps > 1) { >- if (sc->sc_ncores > 1) >- SYSCTL_ADD_PROC(sysctlctx, >- SYSCTL_CHILDREN(sysctlnode), >- OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, >- dev, SENSOR0_CORE1, amdtemp_sysctl, "IK", >- "Sensor 0 / Core 1 temperature"); >- >- sysctlnode = SYSCTL_ADD_NODE(sysctlctx, >- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, >- "sensor1", CTLFLAG_RD, 0, "Sensor 1"); >- >- SYSCTL_ADD_PROC(sysctlctx, >- SYSCTL_CHILDREN(sysctlnode), >- OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, >- dev, SENSOR1_CORE0, amdtemp_sysctl, "IK", >- "Sensor 1 / Core 0 temperature"); >- >- if (sc->sc_ncores > 1) >- SYSCTL_ADD_PROC(sysctlctx, >- SYSCTL_CHILDREN(sysctlnode), >- OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, >- dev, SENSOR1_CORE1, amdtemp_sysctl, "IK", >- "Sensor 1 / Core 1 temperature"); >+ if (0 != (amd_pminfo & AMDPM_TM)) { /* Hardware Thermal Control (HTC) */ >+ reg_htc.u32 = pci_read_config(dev, AMD_REG_HTC_CTRL, 4); >+ if (0 != reg_htc.bits.HtcEn) >+ sc->flags |= AMDTEMP_F_HTC; >+ } >+ >+ ctx = device_get_sysctl_ctx(dev); >+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); >+ if (0 != (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 ++) { >+ 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 (0 != (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); >+ } >+ if (0 != (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 (0 != (sc->flags & AMDTEMP_F_TSI)) { /* Temperature Sensor Interface */ >+ for (i = 0; i < 8; i ++) { >+ if (0 == amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION)) >+ continue; >+ if (0 == tsi_ok) { /* First time add node. */ >+ node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tsi", >+ CTLFLAG_RD, NULL, "Temperature Sensor Interface"); >+ list = SYSCTL_CHILDREN(node); >+ tsi_ok ++; >+ } >+ snprintf(str, sizeof(str), "sensor%i", i); >+ sub_node = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, str, >+ CTLFLAG_RD, NULL, "TSI sensor"); >+ amdtemp_sysctl_reg_add2(sc, SYSCTL_CHILDREN(sub_node), >+ amdtemp_tsi_regs, i); >+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO, >+ "sensor_offset", CTLFLAG_RW, &sc->tsi_temp_offset[i], 0, >+ "Temperature sensor offset"); >+ } >+ if (0 == tsi_ok) /* Unset flag if no TSI sensors found. */ >+ sc->flags &= ~AMDTEMP_F_TSI; >+ } >+ >+ 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]. >+ */ >+ if (0 != (amd_pminfo & AMDPM_TS)) >+ device_printf(dev, "CPU have TS: Temperature sensor\n"); >+ if (0 != (sc->flags & AMDTEMP_F_TTS)) >+ device_printf(dev, "Found: Thermaltrip Status (TTS)\n"); >+ if (0 != (sc->flags & AMDTEMP_F_RTC)) >+ device_printf(dev, "Found: Reported Temperature Control (RTC)\n"); >+ if (0 != (sc->flags & AMDTEMP_F_TSI)) >+ device_printf(dev, "Found: Temperature Sensor Interface via CPU registers (TSI)\n"); >+ if ((amd_pminfo & AMDPM_TM) != 0) >+ device_printf(dev, "Found: Hardware Thermal Control (HTC)\n"); >+ } >+ if (erratum319) >+ device_printf(dev, >+ "Erratum 319: temperature measurement may be inaccurate\n"); > /* > * 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); >+ amdtemp_intrhook(sc); >+ if (NULL == sc->sysctl_cpu[0]) { >+ sc->sc_ich.ich_func = amdtemp_intrhook; >+ sc->sc_ich.ich_arg = sc; >+ if (config_intrhook_establish(&sc->sc_ich) != 0) { >+ amdtemp_detach(dev); >+ device_printf(dev, "config_intrhook_establish failed!\n"); >+ return (ENXIO); >+ } > } >+ return (0); >+} >+ >+int >+amdtemp_detach(device_t dev) { >+ struct amdtemp_softc *sc = device_get_softc(dev); >+ uint32_t i; >+ >+ for (i = 0; i < sc->cpu_ncores; i++) >+ if (sc->sysctl_cpu[i] != NULL) >+ sysctl_remove_oid(sc->sysctl_cpu[i], 1, 0); >+ /* NewBus removes the dev.amdtemp.N tree by itself. */ >+ if (sc->sc_ich.ich_arg != NULL) { >+ sc->sc_ich.ich_arg = NULL; >+ config_intrhook_disestablish(&sc->sc_ich); >+ } >+ mtx_destroy(&sc->lock); > > return (0); > } > > 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_intrhook(void *arg) { >+ struct amdtemp_softc *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 != NULL) { >+ 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] != NULL) >+ continue; >+ cpu = device_find_child(acpi, "cpu", (unit_base + i)); >+ if (cpu == NULL) > 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) : SENSOR0_CORE0; >- 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"); >+ sysctl_handler = NULL; >+ if (0 != (sc->flags & AMDTEMP_F_TSI)) { >+ /* Temperature Sensor Interface */ >+ if (0 == amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION)) >+ continue; >+ sysctl_handler = amdtemp_tsi_temp_reg_sysctl; >+ sysctl_arg2 = MAKE_ARG2(SB_TSI_REG_CPU_TEMP_LB, >+ SB_TSI_REG_CPU_TEMP_HB, i); >+ } else if (0 != (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 (0 != (sc->flags & AMDTEMP_F_TTS)) { >+ /* Thermaltrip Status */ >+ sysctl_handler = amdtemp_tts_temp_reg_sysctl; >+ sysctl_arg2 = MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0xff); > } >+ if (NULL == sysctl_handler) >+ 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 temparature"); > } >- if (sc->sc_ich.ich_arg != NULL) >- config_intrhook_disestablish(&sc->sc_ich); > } > >-int >-amdtemp_detach(device_t dev) >-{ >- struct amdtemp_softc *sc = device_get_softc(dev); >- int 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); >+/* Sysctl staff. */ >+static void >+amdtemp_sysctl_reg_add(struct amdtemp_softc *sc, struct sysctl_oid_list *child, >+ struct amdtemp_sysctl_reg *regs) { >+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); >+ uint32_t i; >+ >+ for (i = 0; NULL != regs[i].oid_handler; i ++) { >+ 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 void >+amdtemp_sysctl_reg_add2(struct amdtemp_softc *sc, struct sysctl_oid_list *child, >+ struct amdtemp_sysctl_reg *regs, uint32_t a2) { >+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); >+ uint32_t i; >+ >+ for (i = 0; NULL != regs[i].oid_handler; i ++) { >+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, regs[i].name, >+ regs[i].flags, sc, >+ MAKE_ARG2(regs[i].reg, regs[i].a1, a2), >+ regs[i].oid_handler, regs[i].fmt, regs[i].descr); >+ } >+} >+ >+static int >+amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *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 = pci_read_config(sc->dev, reg_num, 4); >+ >+ 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 (0 != error || NULL == req->newptr || 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 >+ pci_write_config(sc->dev, reg_num, reg_data, 4); > > return (0); > } > >+ >+/* Thermaltrip Status Register */ >+static uint32_t >+amdtemp_tts_get_temp(struct amdtemp_softc *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 (0 == (sc->tts_flags & AMDTEMP_TTS_F_CS_SWAP)) >+ reg_tts.bits.ThermSenseCoreSel = ((0 != core) ? 1 : 0); >+ else /* Swap. */ >+ reg_tts.bits.ThermSenseCoreSel = ((0 != core) ? 0 : 1); >+ reg_tts.bits.ThermSenseSel = ((0 != sense) ? 1 : 0); >+ >+ AMDTEMP_LOCK(sc); >+ pci_write_config(sc->dev, reg, reg_tts.u32, 4); >+ reg_tts.u32 = pci_read_config(sc->dev, reg, 4); >+ AMDTEMP_UNLOCK(sc); >+ >+ val = reg_tts.bits.CurTmp; >+ if (0 == (sc->tts_flags & AMDTEMP_TTS_F_CT_10BIT)) >+ val &= ~3; /* Clear first 2 bits. */ >+ val = (AMDTEMP_ZERO_C_TO_K + ((val * 5) / 2) - >+ ((0 != (sc->tts_flags & AMDTEMP_TTS_F_OFF28)) ? 280 : 490)); >+ val += (sc->tts_temp_offset[((reg_tts.bits.ThermSenseCoreSel << 1) | >+ 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) >-{ >- 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_tts_temp_reg_sysctl(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *sc = arg1; >+ uint32_t reg_num; >+ unsigned val; > int error; > >- switch (sensor) { >- case CORE0: >- auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0); >- auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0); >- temp = imax(auxtemp[0], auxtemp[1]); >- break; >- case CORE1: >- auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1); >- auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1); >- temp = imax(auxtemp[0], auxtemp[1]); >+ reg_num = ARG2_GET_REG(arg2); >+ if (0xff == ARG2_GET_A2(arg2)) { >+ 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 (0 != error || NULL == req->newptr) >+ return (error); >+ return (0); >+} >+ >+ >+/* D18F3x64 Hardware Thermal Control (HTC) */ >+static int >+amdtemp_htc_temp_sysctl(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *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 = pci_read_config(sc->dev, reg_num, 4); >+ switch (bits_off) { >+ case 16: /* HtcTmpLmt */ >+ val = (((reg_htc.bits.HtcTmpLmt * 10) / 2) + 520); > break; >- default: >- temp = sc->sc_gettemp(dev, sensor); >+ case 24: /* HtcHystLmt */ >+ val = ((reg_htc.bits.HtcHystLmt * 10) / 2); > break; > } >- error = sysctl_handle_int(oidp, &temp, 0, req); >- >- return (error); >+ val += AMDTEMP_ZERO_C_TO_K; >+ error = sysctl_handle_int(oidp, &val, 0, req); >+ if (0 != error || NULL == req->newptr) >+ return (error); >+ //pci_write_config(sc->dev, reg_num, reg_htc.u32, 4); >+ return (0); > } > >-#define AMDTEMP_ZERO_C_TO_K 2732 > >-static int32_t >-amdtemp_gettemp0f(device_t dev, amdsensor_t sensor) >-{ >- struct amdtemp_softc *sc = device_get_softc(dev); >- uint32_t mask, temp; >- int32_t diode_offset, offset; >- uint8_t cfg, sel; >- >- /* Set Sensor/Core selector. */ >- sel = 0; >- switch (sensor) { >- case SENSOR1_CORE0: >- sel |= AMDTEMP_TTSR_SELSENSOR; >- /* FALLTHROUGH */ >- case SENSOR0_CORE0: >- case CORE0: >- if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) >- sel |= AMDTEMP_TTSR_SELCORE; >+/* D18F3xA4 Reported Temperature Control Register */ >+static int >+amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *sc = arg1; >+ union reg_amd_rep_tmp_ctrl_desc reg_rtc; >+ uint32_t reg_num, bits_off; >+ unsigned val; >+ int error; >+ >+ reg_num = ARG2_GET_REG(arg2); >+ bits_off = ARG2_GET_A1(arg2); >+ >+ AMDTEMP_LOCK(sc); >+ reg_rtc.u32 = pci_read_config(sc->dev, reg_num, 4); >+ switch (bits_off) { >+ case 16: /* CurTmpTjSel */ >+ reg_rtc.bits.CurTmpTjSel = 3; > break; >- case SENSOR1_CORE1: >- sel |= AMDTEMP_TTSR_SELSENSOR; >- /* FALLTHROUGH */ >- case SENSOR0_CORE1: >- case CORE1: >- if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) >- sel |= AMDTEMP_TTSR_SELCORE; >+ case 21: /* CurTmp */ >+ reg_rtc.bits.CurTmpTjSel = 0; > break; > } >- cfg = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); >- cfg &= ~(AMDTEMP_TTSR_SELSENSOR | AMDTEMP_TTSR_SELCORE); >- pci_write_config(dev, AMDTEMP_THERMTP_STAT, cfg | sel, 1); >- >- /* CurTmp starts from -49C. */ >- offset = AMDTEMP_ZERO_C_TO_K - 490; >- >- /* Adjust offset if DiodeOffset is set and valid. */ >- temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); >- diode_offset = (temp >> 8) & 0x3f; >- if ((sc->sc_flags & AMDTEMP_FLAG_DO_ZERO) != 0) { >- if ((sc->sc_flags & AMDTEMP_FLAG_DO_SIGN) != 0 && >- ((temp >> 24) & 0x1) != 0) >- diode_offset *= -1; >- if ((sc->sc_flags & AMDTEMP_FLAG_DO_QUIRK) != 0 && >- ((temp >> 25) & 0xf) <= 2) >- diode_offset += 10; >- offset += diode_offset * 10; >- } else if (diode_offset != 0) >- offset += (diode_offset - 11) * 10; >- >- mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; >- temp = ((temp >> 14) & mask) * 5 / 2 + offset; >- >- return (temp); >-} >- >-static int32_t >-amdtemp_gettemp(device_t dev, amdsensor_t sensor) >-{ >- uint32_t temp; >- int32_t diode_offset, offset; >- >- /* CurTmp starts from 0C. */ >- offset = AMDTEMP_ZERO_C_TO_K; >- >- /* Adjust offset if DiodeOffset is set and valid. */ >- temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); >- diode_offset = (temp >> 8) & 0x7f; >- if (diode_offset > 0 && diode_offset < 0x40) >- offset += (diode_offset - 11) * 10; >+ pci_write_config(sc->dev, reg_num, reg_rtc.u32, 4); >+ reg_rtc.u32 = pci_read_config(sc->dev, reg_num, 4); >+ if (bits_off == 16) { /* CurTmpTjSel: switch back to CurTmp. */ >+ reg_rtc.bits.CurTmpTjSel = 0; >+ pci_write_config(sc->dev, reg_num, reg_rtc.u32, 4); >+ } >+ AMDTEMP_UNLOCK(sc); >+ >+ val = (AMDTEMP_ZERO_C_TO_K + ((reg_rtc.bits.CurTmp * 10) / 8)); >+ if (16 == bits_off) /* CurTmpTjSel */ >+ val -= 490; >+ else >+ val += (sc->rtc_temp_offset * 10); >+ error = sysctl_handle_int(oidp, &val, 0, req); >+ if (0 != error || NULL == req->newptr) >+ return (error); >+ //pci_write_config(sc->dev, reg_num, reg_rtc.u32, 4); >+ return (0); >+} >+ >+ >+/* Set SMBus-based sideband interface address: 0-7. */ >+static void >+amdtemp_sbi_set_addr(struct amdtemp_softc *sc, uint32_t sbi_addr) { >+ union reg_amd_sbi_ctrl_desc reg_sbi; >+ >+ sbi_addr &= AMD_REG_SBI_ADDR_MASK; >+ reg_sbi.u32 = pci_read_config(sc->dev, AMD_REG_SBI_CTRL, 4); >+ if (reg_sbi.bits.SbiAddr == sbi_addr) /* Is address allready set? */ >+ return; >+ reg_sbi.bits.SbiAddr = sbi_addr; >+ pci_write_config(sc->dev, AMD_REG_SBI_CTRL, reg_sbi.u32, 4); >+} >+ >+static uint32_t >+amdtemp_sbi_read(struct amdtemp_softc *sc, uint32_t sbi_addr, uint32_t reg_addr) { >+ uint32_t ret; >+ >+ AMDTEMP_LOCK(sc); >+ amdtemp_sbi_set_addr(sc, sbi_addr); >+ pci_write_config(sc->dev, AMD_REG_SBI_ADDR, reg_addr, 4); >+ ret = pci_read_config(sc->dev, AMD_REG_SBI_DATA, 4); >+ AMDTEMP_UNLOCK(sc); >+ >+ return (ret); >+} >+ >+static int >+amdtemp_sbi_write(struct amdtemp_softc *sc, uint32_t sbi_addr, uint32_t reg_addr, >+ uint8_t data) { >+ union reg_amd_sbi_ctrl_desc reg_sbi; >+ uint32_t data32 = data; >+ >+ AMDTEMP_LOCK(sc); >+ amdtemp_sbi_set_addr(sc, sbi_addr); >+ pci_write_config(sc->dev, AMD_REG_SBI_ADDR, reg_addr, 4); >+ pci_write_config(sc->dev, AMD_REG_SBI_DATA, data32, 4); >+ /* Wait write. */ >+ data32 = AMD_SBI_WRITE_TIMEOUT; >+ while (data32 --) { >+ reg_sbi.u32 = pci_read_config(sc->dev, AMD_REG_SBI_CTRL, 4); >+ if (0 != reg_sbi.bits.SbiRegWrDn) >+ break; >+ DELAY(100); >+ } >+ AMDTEMP_UNLOCK(sc); >+ >+ if (data32 == 0) { >+ device_printf(sc->dev, "timeout waiting for SBI write.\n"); >+ return (1); >+ } >+ return (0); >+} > >- temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); >- temp = ((temp >> 21) & 0x7ff) * 5 / 4 + offset; >+static int >+amdtemp_tsi_reg_sysctl(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *sc = arg1; >+ uint32_t reg_data, reg_addr, sbi_addr; >+ unsigned val; >+ int error; > >- return (temp); >+ reg_addr = ARG2_GET_REG(arg2); >+ sbi_addr = (ARG2_GET_A2(arg2) & AMD_REG_SBI_ADDR_MASK); >+ reg_data = amdtemp_sbi_read(sc, sbi_addr, reg_addr); >+ val = reg_data; >+ >+ error = sysctl_handle_int(oidp, &val, 0, req); >+ if (0 != error || NULL == req->newptr || val == reg_data) >+ return (error); >+ return (amdtemp_sbi_write(sc, sbi_addr, reg_addr, val)); >+} >+ >+static int >+amdtemp_tsi_temp_reg_sysctl(SYSCTL_HANDLER_ARGS) { >+ struct amdtemp_softc *sc = arg1; >+ uint32_t reg_data_lo, reg_data_hi, sbi_addr; >+ unsigned val; >+ int error; >+ >+ sbi_addr = (ARG2_GET_A2(arg2) & AMD_REG_SBI_ADDR_MASK); >+ reg_data_lo = amdtemp_sbi_read(sc, sbi_addr, ARG2_GET_REG(arg2)); >+ reg_data_hi = amdtemp_sbi_read(sc, sbi_addr, ARG2_GET_A1(arg2)); >+ val = (AMDTEMP_ZERO_C_TO_K + (reg_data_hi * 10)); >+ /* Apply offset only to sensor. */ >+ if (SB_TSI_REG_CPU_TEMP_LB == ARG2_GET_REG(arg2)) >+ val += (sc->tsi_temp_offset[sbi_addr] * 10); >+ if (reg_data_lo & 0x80) >+ val += 5; /* 0,5 C */ >+ if (reg_data_lo & 0x40) >+ val += 3; /* 0,25 C */ >+ if (reg_data_lo & 0x20) >+ val += 1; /* 0,125 C */ >+ >+ error = sysctl_handle_int(oidp, &val, 0, req); >+ if (0 != error || NULL == req->newptr) >+ return (error); >+ return (0); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 194792
: 149000