Changeset View
Standalone View
sys/dev/amdtemp/amdtemp.c
/*- | /*- | ||||
* Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> | * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> | ||||
* Copyright (c) 2009 Norikatsu Shigemura <nork@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. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
Context not available. | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
rpaulo: No can do. | |||||
Done Inline ActionsWithout this build fail. rozhuk.im-gmail.com: Without this build fail.
I dont know how to fix.
Have you any ideas? | |||||
Done Inline ActionsWhat's the build error? rpaulo: What's the build error? | |||||
Done Inline Actions/usr/src/sys/modules/amdtemp/../../dev/amdtemp/amdtemp.c:1077:7: error: static_assert expression is not an integral constant expression regs[i].flags, sc, ^~~~~~~~~~~~~~~~~~ /usr/src/sys/sys/sysctl.h:733:13: note: expanded from macro 'SYSCTL_ADD_PROC' CTASSERT(((access) & CTLTYPE) != 0); \ ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ /usr/src/sys/sys/systm.h:103:36: note: expanded from macro 'CTASSERT' ^ /usr/src/sys/modules/amdtemp/../../dev/amdtemp/amdtemp.c:1093:7: error: static_assert expression is not an integral constant expression regs[i].flags, sc, ^~~~~~~~~~~~~~~~~~ /usr/src/sys/sys/sysctl.h:733:13: note: expanded from macro 'SYSCTL_ADD_PROC' CTASSERT(((access) & CTLTYPE) != 0); \ ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ /usr/src/sys/sys/systm.h:103:36: note: expanded from macro 'CTASSERT' ^ 2 errors generated.
rozhuk.im-gmail.com: /usr/src/sys/modules/amdtemp/../../dev/amdtemp/amdtemp.c:1077:7: error: static_assert… | |||||
Done Inline ActionsChange the code to pass non-variable access controls to sysctl_add_proc. rpaulo: Change the code to pass non-variable access controls to sysctl_add_proc.
Defeating CTASSERT()… | |||||
#include <sys/bus.h> | #include <sys/systm.h> | ||||
#include <sys/conf.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/bus.h> | |||||
#include <sys/resource.h> | |||||
#include <sys/rman.h> | |||||
#include <sys/sysctl.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/md_var.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <machine/cputypes.h> | |||||
#include <machine/pci_cfgreg.h> | |||||
#include <dev/pci/pcivar.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 { | struct amdtemp_softc { | ||||
device_t sc_dev; | device_t dev; | ||||
Not Done Inline Actions{ in line above. rpaulo: { in line above. | |||||
int sc_ncores; | struct mtx lock; /* Read/write lock for some registers. */ | ||||
int sc_ntemps; | uint32_t cpu_ncores; | ||||
int sc_flags; | uint32_t flags; | ||||
#define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ | uint32_t tts_flags; /* Thermaltrip Status flags. */ | ||||
#define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ | int32_t tts_temp_offset[4]; | ||||
#define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */ | int32_t rtc_temp_offset; | ||||
int32_t sc_offset; | int32_t tsi_temp_offset[8]; | ||||
int32_t (*sc_gettemp)(device_t, amdsensor_t); | struct sysctl_oid *sysctl_cpu[MAXCPU]; /* dev.cpu.X.temperature oids. */ | ||||
struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; | struct intr_config_hook sc_ich; | ||||
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. */ | |||||
#define VENDORID_AMD 0x1022 | #define AMDTEMP_TTS_F_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ | ||||
#define DEVICEID_AMD_MISC0F 0x1103 | #define AMDTEMP_TTS_F_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ | ||||
#define DEVICEID_AMD_MISC10 0x1203 | #define AMDTEMP_TTS_F_OFF28 0x04 /* CurTmp starts at -28C. */ | ||||
#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 | |||||
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_LOCK(__sc) mtx_lock(&(__sc)->lock) | ||||
* Reported Temperature Control Register | #define AMDTEMP_UNLOCK(__sc) mtx_unlock(&(__sc)->lock) | ||||
*/ | |||||
#define AMDTEMP_REPTMP_CTRL 0xa4 | |||||
/* | |||||
* Thermaltrip Status Register (Family 0Fh only) | /* 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_THERMTP_STAT 0xe4 | /* D18F3xE4 Thermtrip Status Register */ | ||||
#define AMDTEMP_TTSR_SELCORE 0x04 | #define AMD_REG_THERMTRIP_STAT 0xe4 | ||||
#define AMDTEMP_TTSR_SELSENSOR 0x40 | union reg_amd_thermtrip_status_desc { | ||||
uint32_t u32; | |||||
Not Done Inline Actions{ in line above rpaulo: { in line above | |||||
struct reg_amd_thermtrip_status_bits { | |||||
Not Done Inline Actions{ should be in the line above. rpaulo: { should be in the line above. | |||||
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 */ | |||||
Not Done Inline Actions{ in line above. Please fix all instances. rpaulo: { in line above. Please fix all instances. | |||||
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)); | |||||
Not Done Inline ActionsNo reason for this to be packed, right? rpaulo: No reason for this to be packed, right?
Use a CTASSERT(sizeof(...)) to make sure the size is… | |||||
/* DRAM Configuration High Register */ | |||||
#define AMD_REG_DRAM_CONF_HIGH 0x94 /* Function 2 */ | |||||
#define AMD_REG_DRAM_MODE_DDR3 0x0100 | |||||
/* | /* | ||||
* DRAM Configuration High 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_DRAM_CONF_HIGH 0x94 /* Function 2 */ | /* D18F3x64 Hardware Thermal Control (HTC) */ | ||||
#define AMDTEMP_DRAM_MODE_DDR3 0x0100 | #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)); | |||||
/* 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. */ | |||||
/* SB-TSI */ | |||||
#define AMD_REG_SBI_CTRL 0x1e4 /* SBI Control */ | |||||
union reg_amd_sbi_ctrl_desc { | |||||
Not Done Inline ActionsPlease use C99 initializers here so it is clear what fields the magic numbers are associated with when the structure definition is far away. cem: Please use C99 initializers here so it is clear what fields the magic numbers are associated… | |||||
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. */ | |||||
Not Done Inline ActionsNot 2731? cem: Not 2731? | |||||
Not Done Inline ActionsWhat is 2731? rozhuk.im-gmail.com: What is 2731? | |||||
Not Done Inline Actionsfloor(0°C in deci-Kelvins). See r300421 and r285994. cem: floor(0°C in deci-Kelvins). See r300421 and r285994. | |||||
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. */ | |||||
} bits; | |||||
}; | |||||
CTASSERT(sizeof(struct reg_amd_sbi_ctrl_bits) == sizeof(uint32_t)); | |||||
/* | /* | ||||
* 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; | |||||
}; | |||||
Not Done Inline Actionssysctl naming convention is lowercase cem: sysctl naming convention is lowercase | |||||
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", | |||||
__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, | |||||
"ThermtpEn", | |||||
__DESCR("The THERMTRIP state is supported by the " | |||||
"processor.") | |||||
}, { | |||||
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 struct amdtemp_sysctl_reg 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 struct amdtemp_sysctl_reg 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, | |||||
18, | |||||
1, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_sysctl_reg_bits, | |||||
"CurTmpTjSlewSel", | |||||
__DESCR("") | |||||
}, { | |||||
AMD_REG_REPTMP_CTRL, | |||||
19, | |||||
1, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_sysctl_reg_bits, | |||||
"CurTmpRangeSel", | |||||
__DESCR("") | |||||
},*/ | |||||
{ | |||||
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, | |||||
Not Done Inline ActionsThis change is a style(9) regression from the previous code. cem: This change is a style(9) regression from the previous code. | |||||
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 } | |||||
}; | |||||
/* 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", | |||||
Not Done Inline ActionsThis check seems to defeat the point of trying to read the value from PCI space, doesn't it? cem: This check seems to defeat the point of trying to read the value from PCI space, doesn't it? | |||||
amdtemp_tsi_temp_reg_sysctl, | |||||
"cpu_temperature", | |||||
__DESCR("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", | |||||
__DESCR("High Temperature Threshold") | |||||
}, { | |||||
SB_TSI_REG_LOW_TEMP_TLB, | |||||
SB_TSI_REG_LOW_TEMP_THB, | |||||
0, | |||||
(CTLFLAG_RD | CTLTYPE_INT), | |||||
Not Done Inline ActionsThis change is a style regression from the existing code. cem: This change is a style regression from the existing code. | |||||
Not Done Inline ActionsThis is temporary change for ryzen debug. rozhuk.im-gmail.com: This is temporary change for ryzen debug. | |||||
Not Done Inline ActionsThat doesn't make sense. It doesn't change functionality; it's purely a style change. How does a style change help debug? cem: That doesn't make sense. It doesn't change functionality; it's purely a style change. How… | |||||
"IK", | |||||
amdtemp_tsi_temp_reg_sysctl, | |||||
"low_temperature_threshold", | |||||
__DESCR("Low Temperature Threshold") | |||||
}, | |||||
Not Done Inline ActionsThis change is gratuitous? cem: This change is gratuitous? | |||||
{ | |||||
SB_TSI_REG_CPU_TEMP_OFF_HB, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"cpu_temperature_offset_hi", | |||||
__DESCR("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", | |||||
__DESCR("CPU Temperature Offset Low Byte") | |||||
}, | |||||
{ | |||||
SB_TSI_REG_STATUS, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"status", | |||||
__DESCR("SB-TSI Status") | |||||
}, { | |||||
SB_TSI_REG_CFG, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"cfg3", | |||||
__DESCR("SB-TSI Configuration Register 0x03") | |||||
}, { | |||||
SB_TSI_REG_CFG2, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"cfg9", | |||||
__DESCR("SB-TSI Configuration Register 0x09") | |||||
}, { | |||||
SB_TSI_REG_UPD_RATE, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
Not Done Inline ActionsCan pci_io be set to any other value? cem: Can pci_io be set to any other value? | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"upd_rate", | |||||
__DESCR("Update Rate") | |||||
}, { | |||||
SB_TSI_REG_TIMEOUT_CFG, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"timeout_cfg", | |||||
__DESCR("Timeout Configuration") | |||||
}, { | |||||
SB_TSI_REG_ALERT_THRESHOLD, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"alert_threshold", | |||||
__DESCR("Alert Threshold") | |||||
}, { | |||||
SB_TSI_REG_ALERT_CFG, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RW | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"alert_cfg", | |||||
__DESCR("Alert Configuration") | |||||
}, { | |||||
SB_TSI_REG_MANUFACTURE_ID, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RD | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"manufacture_id", | |||||
__DESCR("Manufacture ID") | |||||
}, { | |||||
SB_TSI_REG_REVISION, | |||||
0, | |||||
0, | |||||
(CTLFLAG_RD | CTLTYPE_UINT), | |||||
"IU", | |||||
amdtemp_tsi_reg_sysctl, | |||||
"revision", | |||||
__DESCR("SB-TSI Revision") | |||||
}, | |||||
{ 0, 0, 0, 0, NULL, NULL, NULL, NULL } | |||||
}; | |||||
Not Done Inline ActionsThis change seems gratuitous? cem: This change seems gratuitous? | |||||
/* | /* | ||||
* Device methods. | * 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_probe(device_t dev); | ||||
static int amdtemp_attach(device_t dev); | static int amdtemp_attach(device_t dev); | ||||
static int amdtemp_detach(device_t dev); | |||||
static void amdtemp_intrhook(void *arg); | 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[] = { | static device_method_t amdtemp_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_identify, amdtemp_identify), | DEVMETHOD(device_identify, amdtemp_identify), | ||||
Context not available. | |||||
amdtemp_methods, | amdtemp_methods, | ||||
sizeof(struct amdtemp_softc), | sizeof(struct amdtemp_softc), | ||||
}; | }; | ||||
static devclass_t amdtemp_devclass; | static devclass_t amdtemp_devclass; | ||||
DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); | DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); | ||||
MODULE_VERSION(amdtemp, 1); | |||||
Not Done Inline ActionsWhat's this number? cem: What's this number? | |||||
static int | static int | ||||
amdtemp_match(device_t dev) | amdtemp_dev_check(device_t dev) | ||||
{ | { | ||||
int i; | uint32_t cpuid; | ||||
uint16_t vendor, devid; | |||||
vendor = pci_get_vendor(dev); | if (resource_disabled("amdtemp", 0)) | ||||
devid = pci_get_device(dev); | 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_TO_FAMILY(cpuid) < 0x0f) | |||||
Not Done Inline ActionsOn my Ryzen 1700X this test fails because CPUID_TO_FAMILY(cpuid) returns zero, causing the driver to fail to attach. If I change this to: if (CPUID_TO_FAMILY(cpu_id) < 0x0f) then the driver attaches. truckman: On my Ryzen 1700X this test fails because CPUID_TO_FAMILY(cpuid) returns zero, causing the… | |||||
return (ENXIO); | |||||
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); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
Not Done Inline Actions*Does rpaulo: *Does | |||||
Context not available. | |||||
device_t child; | device_t child; | ||||
/* Make sure we're not being doubly invoked. */ | /* Make sure we're not being doubly invoked. */ | ||||
if (device_find_child(parent, "amdtemp", -1) != NULL) | if (device_find_child(parent, "amdtemp", -1)) | ||||
return; | return; | ||||
if (amdtemp_dev_check(parent)) | |||||
if (amdtemp_match(parent)) { | return; | ||||
child = device_add_child(parent, "amdtemp", -1); | child = device_add_child(parent, "amdtemp", -1); | ||||
if (child == NULL) | if (child == NULL) { | ||||
device_printf(parent, "add amdtemp child failed\n"); | device_printf(parent, "add amdtemp child failed.\n"); | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
static int | static int | ||||
amdtemp_probe(device_t dev) | amdtemp_probe(device_t dev) | ||||
{ | { | ||||
uint32_t family, model; | |||||
if (resource_disabled("amdtemp", 0)) | if (amdtemp_dev_check(dev)) | ||||
return (ENXIO); | 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"); | device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); | ||||
return (BUS_PROBE_GENERIC); | return (BUS_PROBE_GENERIC); | ||||
Context not available. | |||||
static int | static int | ||||
amdtemp_attach(device_t dev) | amdtemp_attach(device_t dev) | ||||
{ | { | ||||
char tn[32]; | |||||
u_int regs[4]; | |||||
struct amdtemp_softc *sc = device_get_softc(dev); | struct amdtemp_softc *sc = device_get_softc(dev); | ||||
struct sysctl_ctx_list *sysctlctx; | uint32_t i, cpuid, model; | ||||
struct sysctl_oid *sysctlnode; | union reg_amd_thermtrip_status_desc reg_tts; | ||||
uint32_t cpuid, family, model; | union reg_amd_htc_desc reg_htc; | ||||
u_int bid; | union reg_amd_sbi_ctrl_desc reg_sbi; | ||||
int erratum319, unit; | struct sysctl_ctx_list *ctx; | ||||
struct sysctl_oid_list *child, *list; | |||||
struct sysctl_oid *node, *sub_node; | |||||
char str[32]; | |||||
int tsi_ok, erratum319 = 0; | |||||
u_int regs[4], bid; | |||||
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); | |||||
/* | /* Detect supported therm interfaces. */ | ||||
* CPUID Register is available from Revision F. | cpuid = pci_read_config(dev, AMD_REG_CPUID, 4); | ||||
*/ | |||||
cpuid = cpu_id; | |||||
family = CPUID_TO_FAMILY(cpuid); | |||||
model = CPUID_TO_MODEL(cpuid); | model = CPUID_TO_MODEL(cpuid); | ||||
if (family != 0x0f || model >= 0x40) { | switch (CPUID_TO_FAMILY(cpuid)) { | ||||
cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); | |||||
family = CPUID_TO_FAMILY(cpuid); | |||||
model = CPUID_TO_MODEL(cpuid); | |||||
} | |||||
switch (family) { | |||||
case 0x0f: | case 0x0f: | ||||
/* | /* | ||||
* Thermaltrip Status Register | * Thermaltrip Status Register | ||||
Not Done Inline ActionsGratuitous change? cem: Gratuitous change? | |||||
Not Done Inline ActionsGratuitous change? cem: Gratuitous change? | |||||
Context not available. | |||||
* XXX According to Linux, CurTmp starts at -28C on | * XXX According to Linux, CurTmp starts at -28C on | ||||
* Socket AM2 Revision G processors, which is not | * Socket AM2 Revision G processors, which is not | ||||
* documented anywhere. | * documented anywhere. | ||||
* XXX check TjOffset and DiodeOffset for -49C / -28C | |||||
*/ | */ | ||||
if (model >= 0x40) | if ((amd_pminfo & AMDPM_TTP) == 0) /* No TTP: THERMTRIP */ | ||||
sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; | break; | ||||
reg_tts.u32 = pci_read_config(dev, AMD_REG_THERMTRIP_STAT, 4); | |||||
if (reg_tts.bits.ThermtpEn == 0) | |||||
Not Done Inline ActionsGratuitous change? cem: Gratuitous change? | |||||
break; | |||||
if ((model == 0x04 && (cpuid & CPUID_STEPPING) == 0) || | |||||
(model == 0x05 && (cpuid & CPUID_STEPPING) <= 1)) | |||||
break; /* No ThermalTrip. */ | |||||
sc->flags |= AMDTEMP_F_TTS; | |||||
Not Done Inline ActionsI understand why people like the inverted comparison, but it's not the current FreeBSD style. rpaulo: I understand why people like the inverted comparison, but it's not the current FreeBSD style. | |||||
if (model >= 0x40) { | |||||
sc->tts_flags |= AMDTEMP_TTS_F_CS_SWAP; | |||||
} | |||||
if (model >= 0x60 && model != 0xc1) { | if (model >= 0x60 && model != 0xc1) { | ||||
do_cpuid(0x80000001, regs); | do_cpuid(0x80000001, regs); | ||||
bid = (regs[1] >> 9) & 0x1f; | bid = ((regs[1] >> 9) & 0x1f); | ||||
switch (model) { | switch (model) { | ||||
case 0x68: /* Socket S1g1 */ | case 0x68: /* Socket S1g1 */ | ||||
case 0x6c: | case 0x6c: | ||||
Context not available. | |||||
case 0x7c: | case 0x7c: | ||||
break; | break; | ||||
case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ | case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ | ||||
if (bid != 0x0b && bid != 0x0c) | if (bid != 0x0b && bid != 0x0c) { | ||||
sc->sc_flags |= | sc->tts_flags |= AMDTEMP_TTS_F_OFF28; | ||||
AMDTEMP_FLAG_ALT_OFFSET; | } | ||||
break; | break; | ||||
case 0x6f: /* Socket AM2 and ASB1 (1 core) */ | case 0x6f: /* Socket AM2 and ASB1 (1 core) */ | ||||
case 0x7f: | case 0x7f: | ||||
if (bid != 0x07 && bid != 0x09 && | if (bid != 0x07 && bid != 0x09 && | ||||
bid != 0x0c) | bid != 0x0c) { | ||||
sc->sc_flags |= | sc->tts_flags |= AMDTEMP_TTS_F_OFF28; | ||||
AMDTEMP_FLAG_ALT_OFFSET; | } | ||||
break; | break; | ||||
default: | default: | ||||
sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; | sc->tts_flags |= AMDTEMP_TTS_F_OFF28; | ||||
break; | |||||
Not Done Inline ActionsFits in line above. rpaulo: Fits in line above. | |||||
Not Done Inline Actions? rozhuk.im-gmail.com: ? | |||||
Not Done Inline Actionsif (bid != 0x07 && bid !=0x09 ... Use the whole line up to 78 columns. rpaulo: if (bid != 0x07 && bid !=0x09 ...
Use the whole line up to 78 columns. | |||||
} | } | ||||
Not Done Inline Actionsstyle(9) nit: No space between i and ++ cem: style(9) nit: No space between `i` and `++` | |||||
sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; | sc->tts_flags |= AMDTEMP_TTS_F_CT_10BIT; | ||||
Not Done Inline Actionsstyle(9) nit: if (sc->sysctl_cpu[i] != NULL) { cem: style(9) nit: `if (sc->sysctl_cpu[i] != NULL) {` | |||||
} | } | ||||
/* | |||||
* There are two sensors per core. | |||||
*/ | |||||
sc->sc_ntemps = 2; | |||||
sc->sc_gettemp = amdtemp_gettemp0f; | |||||
break; | break; | ||||
case 0x10: | case 0x10: | ||||
sc->flags |= AMDTEMP_F_RTC; | |||||
reg_sbi.u32 = pci_read_config(dev, AMD_REG_SBI_CTRL, 4); | |||||
if (reg_sbi.bits.SbTsiDis == 0) { | |||||
sc->flags |= AMDTEMP_F_TSI; | |||||
Not Done Inline ActionsProbably reverse the order of these two? cem: Probably reverse the order of these two? | |||||
} | |||||
/* | /* | ||||
* Erratum 319 Inaccurate Temperature Measurement | * Erratum 319 Inaccurate Temperature Measurement | ||||
* | |||||
* http://support.amd.com/us/Processor_TechDocs/41322.pdf | * http://support.amd.com/us/Processor_TechDocs/41322.pdf | ||||
*/ | */ | ||||
do_cpuid(0x80000001, regs); | do_cpuid(0x80000001, regs); | ||||
switch ((regs[1] >> 28) & 0xf) { | switch (((regs[1] >> 28) & 0x0f)) { | ||||
rpauloUnsubmitted Done Inline ActionsToo many parentheses. rpaulo: Too many parentheses. | |||||
case 0: /* Socket F */ | case 0: /* Socket F */ | ||||
erratum319 = 1; | erratum319 = 1; | ||||
break; | break; | ||||
case 1: /* Socket AM2+ or AM3 */ | case 1: /* Socket AM2+ or AM3 */ | ||||
if ((pci_cfgregread(pci_get_bus(dev), | if ((pci_cfgregread(pci_get_bus(dev), pci_get_slot(dev), 2, | ||||
pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & | AMD_REG_DRAM_CONF_HIGH, 2) & AMD_REG_DRAM_MODE_DDR3) || | ||||
AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || | model > 0x04 || | ||||
(model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) | (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) | ||||
break; | break; | ||||
/* XXX 00100F42h (RB-C2) exists in both formats. */ | /* XXX 00100F42h (RB-C2) exists in both formats. */ | ||||
Context not available. | |||||
erratum319 = 1; | erratum319 = 1; | ||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | break; | ||||
case 0x11: | case 0x11: | ||||
case 0x12: | case 0x12: | ||||
case 0x14: | case 0x14: | ||||
case 0x15: | case 0x15: | ||||
case 0x16: | case 0x16: | ||||
/* | default: | ||||
Done Inline ActionsSeems like gratuitous changes? And the extra space contradicts style(9). cem: Seems like gratuitous changes? And the extra space contradicts style(9). | |||||
* There is only one sensor per package. | sc->flags |= AMDTEMP_F_RTC; | ||||
*/ | reg_sbi.u32 = pci_read_config(dev, AMD_REG_SBI_CTRL, 4); | ||||
sc->sc_ntemps = 1; | if (reg_sbi.bits.SbRmiDis == 0 || /* = SbTsiDis */ | ||||
reg_sbi.bits.SbTsiDis == 0) { | |||||
sc->sc_gettemp = amdtemp_gettemp; | sc->flags |= AMDTEMP_F_TSI; | ||||
} | |||||
/* XXX TODO: read TSI via SMBus. */ | |||||
break; | break; | ||||
} | } | ||||
/* Hardware Thermal Control (HTC). */ | |||||
if (amd_pminfo & AMDPM_TM) { | |||||
reg_htc.u32 = pci_read_config(dev, AMD_REG_HTC_CTRL, 4); | |||||
if (reg_htc.bits.HtcEn) { | |||||
sc->flags |= AMDTEMP_F_HTC; | |||||
} | |||||
} | |||||
/* Find number of cores per package. */ | /* Init sysctl interface. */ | ||||
sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? | ctx = device_get_sysctl_ctx(dev); | ||||
(cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; | child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | ||||
if (sc->sc_ncores > MAXCPU) | if (sc->flags & AMDTEMP_F_TTS) { /* Thermaltrip Status */ | ||||
return (ENXIO); | node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tts", | ||||
CTLFLAG_RD, NULL, "Thermaltrip Status"); | |||||
if (erratum319) | list = SYSCTL_CHILDREN(node); | ||||
device_printf(dev, | amdtemp_sysctl_reg_add(sc, list, amdtemp_thermtrip_status_reg_bits); | ||||
"Erratum 319: temperature measurement may be inaccurate\n"); | for (i = 0; i < sc->cpu_ncores && i < 2; i ++) { | ||||
if (bootverbose) | snprintf(str, sizeof(str), "core%i", i); | ||||
device_printf(dev, "Found %d cores and %d sensors.\n", | sub_node = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, | ||||
sc->sc_ncores, | str, CTLFLAG_RD, NULL, "CPU core sensors"); | ||||
sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); | SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node), | ||||
OID_AUTO, "sensor0", | |||||
/* | (CTLTYPE_INT | CTLFLAG_RD), sc, | ||||
* dev.amdtemp.N tree. | MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0), | ||||
*/ | amdtemp_tts_temp_reg_sysctl, "IK", | ||||
unit = device_get_unit(dev); | "Sensor 0 temperature"); | ||||
snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); | SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node), | ||||
TUNABLE_INT_FETCH(tn, &sc->sc_offset); | OID_AUTO, "sensor1", | ||||
(CTLTYPE_INT | CTLFLAG_RD), sc, | |||||
sysctlctx = device_get_sysctl_ctx(dev); | MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 1), | ||||
SYSCTL_ADD_INT(sysctlctx, | amdtemp_tts_temp_reg_sysctl, "IK", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | "Sensor 1 temperature"); | ||||
"sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, | SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), | ||||
"Temperature sensor offset"); | OID_AUTO, "sensor0_offset", CTLFLAG_RW, | ||||
sysctlnode = SYSCTL_ADD_NODE(sysctlctx, | &sc->tts_temp_offset[((i << 1) | 0)], 0, | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | "Temperature sensor offset"); | ||||
"core0", CTLFLAG_RD, 0, "Core 0"); | SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), | ||||
OID_AUTO, "sensor1_offset", CTLFLAG_RW, | |||||
SYSCTL_ADD_PROC(sysctlctx, | &sc->tts_temp_offset[((i << 1) | 1)], 0, | ||||
SYSCTL_CHILDREN(sysctlnode), | "Temperature sensor offset"); | ||||
OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, | |||||
dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", | |||||
"Core 0 / Sensor 0 temperature"); | |||||
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"); | |||||
} | } | ||||
} | } | ||||
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)"); | |||||
Done Inline ActionsBetter way to write all these bit comparisons is: if (sc->flags & AMDTEMP_XXX) {...}. No need for comparison with zero and removes the extra parentheses. rpaulo: Better way to write all these bit comparisons is: if (sc->flags & AMDTEMP_XXX) {...}.
No need… | |||||
amdtemp_sysctl_reg_add(sc, SYSCTL_CHILDREN(node), | |||||
amdtemp_htc_reg_bits); | |||||
} | |||||
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_TSI) { /* Temperature Sensor Interface */ | |||||
tsi_ok = 0; | |||||
for (i = 0; i < 8; i ++) { | |||||
if (amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION) == 0) | |||||
continue; | |||||
if (tsi_ok == 0) { /* 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 (tsi_ok == 0) { /* 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 (amd_pminfo & AMDPM_TS) { | |||||
device_printf(dev, "CPU have TS: Temperature " | |||||
"sensor.\n"); | |||||
} | |||||
if (sc->flags & AMDTEMP_F_TTS) { | |||||
device_printf(dev, "Found: Thermaltrip Status " | |||||
"(TTS).\n"); | |||||
} | |||||
if (sc->flags & AMDTEMP_F_RTC) { | |||||
device_printf(dev, "Found: Reported " | |||||
"Temperature Control (RTC).\n"); | |||||
} | |||||
if (sc->flags & AMDTEMP_F_TSI) { | |||||
device_printf(dev, "Found: Temperature Sensor " | |||||
"Interface via CPU registers (TSI).\n"); | |||||
} | |||||
if (amd_pminfo & AMDPM_TM) { | |||||
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. | * Try to create dev.cpu sysctl entries and setup intrhook function. | ||||
* This is needed because the cpu driver may be loaded late on boot, | * This is needed because the cpu driver may be loaded late on boot, | ||||
* after us. | * after us. | ||||
*/ | */ | ||||
amdtemp_intrhook(dev); | amdtemp_intrhook(sc); | ||||
sc->sc_ich.ich_func = amdtemp_intrhook; | if (sc->sysctl_cpu[0] == NULL) { | ||||
sc->sc_ich.ich_arg = dev; | sc->sc_ich.ich_func = amdtemp_intrhook; | ||||
if (config_intrhook_establish(&sc->sc_ich) != 0) { | sc->sc_ich.ich_arg = sc; | ||||
device_printf(dev, "config_intrhook_establish failed!\n"); | if (config_intrhook_establish(&sc->sc_ich)) { | ||||
return (ENXIO); | amdtemp_detach(dev); | ||||
device_printf(dev, "config_intrhook_establish " | |||||
"failed!\n"); | |||||
return (ENXIO); | |||||
} | |||||
} | } | ||||
return (0); | 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]) { | |||||
sysctl_remove_oid(sc->sysctl_cpu[i], 1, 0); | |||||
} | |||||
} | |||||
/* 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); | |||||
} | |||||
void | void | ||||
amdtemp_intrhook(void *arg) | amdtemp_intrhook(void *arg) | ||||
{ | { | ||||
struct amdtemp_softc *sc; | struct amdtemp_softc *sc = arg; | ||||
struct sysctl_ctx_list *sysctlctx; | device_t dev = sc->dev, acpi, cpu, nexus; | ||||
device_t dev = (device_t)arg; | int (*sysctl_handler)(SYSCTL_HANDLER_ARGS); | ||||
device_t acpi, cpu, nexus; | intptr_t sysctl_arg2; | ||||
amdsensor_t sensor; | uint32_t i, unit_base; | ||||
int i; | |||||
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); | nexus = device_find_child(root_bus, "nexus", 0); | ||||
acpi = device_find_child(nexus, "acpi", 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++) { | for (i = 0; i < sc->cpu_ncores; i ++) { | ||||
if (sc->sc_sysctl_cpu[i] != NULL) | if (sc->sysctl_cpu[i]) | ||||
continue; | continue; | ||||
cpu = device_find_child(acpi, "cpu", | cpu = device_find_child(acpi, "cpu", (unit_base + i)); | ||||
device_get_unit(dev) * sc->sc_ncores + i); | if (cpu == NULL) | ||||
if (cpu != NULL) { | continue; | ||||
sysctlctx = device_get_sysctl_ctx(cpu); | sysctl_handler = NULL; | ||||
if ((sc->flags & AMDTEMP_F_TSI) && | |||||
sensor = sc->sc_ntemps > 1 ? | amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION)) { | ||||
(i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; | /* Temperature Sensor Interface */ | ||||
sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, | sysctl_handler = amdtemp_tsi_temp_reg_sysctl; | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), | sysctl_arg2 = MAKE_ARG2(SB_TSI_REG_CPU_TEMP_LB, | ||||
OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, | SB_TSI_REG_CPU_TEMP_HB, i); | ||||
dev, sensor, amdtemp_sysctl, "IK", | } else if (sc->flags & AMDTEMP_F_RTC) { | ||||
"Current temparature"); | /* 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) { | |||||
/* Thermaltrip Status */ | |||||
sysctl_handler = amdtemp_tts_temp_reg_sysctl; | |||||
sysctl_arg2 = MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0xff); | |||||
} | } | ||||
if (sysctl_handler == NULL) | |||||
continue; | |||||
Done Inline Actionsinverted comparison rpaulo: inverted comparison | |||||
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(struct amdtemp_softc *sc, | |||||
struct sysctl_oid_list *child, struct amdtemp_sysctl_reg *regs) | |||||
{ | { | ||||
struct amdtemp_softc *sc = device_get_softc(dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); | ||||
int i; | uint32_t i; | ||||
for (i = 0; i < sc->sc_ncores; i++) | for (i = 0; regs[i].oid_handler; i ++) { | ||||
if (sc->sc_sysctl_cpu[i] != NULL) | sysctl_add_oid(ctx, child, OID_AUTO, regs[i].name, | ||||
sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); | 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; regs[i].oid_handler; i ++) { | |||||
sysctl_add_oid(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 (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. */ | |||||
pci_write_config(sc->dev, reg_num, reg_data, 4); | |||||
return (0); | 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 ((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); | |||||
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 ((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[((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 | 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 = arg1; | ||||
struct amdtemp_softc *sc = device_get_softc(dev); | uint32_t reg_num; | ||||
amdsensor_t sensor = (amdsensor_t)arg2; | unsigned val; | ||||
int32_t auxtemp[2], temp; | |||||
int error; | int error; | ||||
switch (sensor) { | reg_num = ARG2_GET_REG(arg2); | ||||
case CORE0: | if (ARG2_GET_A2(arg2) == 0xff) { | ||||
auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); | val = imax(amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 0), | ||||
auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); | amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 1)); | ||||
temp = imax(auxtemp[0], auxtemp[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); | |||||
} | |||||
/* 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; | break; | ||||
case CORE1: | case 24: /* HtcHystLmt */ | ||||
auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); | val = ((reg_htc.bits.HtcHystLmt * 10) / 2); | ||||
auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); | |||||
temp = imax(auxtemp[0], auxtemp[1]); | |||||
break; | 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); | |||||
/* pci_write_config(sc->dev, reg_num, reg_htc.u32, 4); */ | |||||
return (error); | return (0); | ||||
} | } | ||||
#define AMDTEMP_ZERO_C_TO_K 2731 | |||||
static int32_t | /* D18F3xA4 Reported Temperature Control Register */ | ||||
amdtemp_gettemp0f(device_t dev, amdsensor_t sensor) | static int | ||||
amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | { | ||||
struct amdtemp_softc *sc = device_get_softc(dev); | struct amdtemp_softc *sc = arg1; | ||||
uint32_t mask, offset, temp; | union reg_amd_rep_tmp_ctrl_desc reg_rtc; | ||||
uint32_t reg_num, bits_off; | |||||
unsigned val; | |||||
int error; | |||||
/* Set Sensor/Core selector. */ | reg_num = ARG2_GET_REG(arg2); | ||||
temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); | bits_off = ARG2_GET_A1(arg2); | ||||
temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); | |||||
switch (sensor) { | AMDTEMP_LOCK(sc); | ||||
case CORE0_SENSOR1: | reg_rtc.u32 = pci_read_config(sc->dev, reg_num, 4); | ||||
temp |= AMDTEMP_TTSR_SELSENSOR; | switch (bits_off) { | ||||
/* FALLTHROUGH */ | case 16: /* CurTmpTjSel */ | ||||
case CORE0_SENSOR0: | reg_rtc.bits.CurTmpTjSel = 3; | ||||
case CORE0: | |||||
if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) | |||||
temp |= AMDTEMP_TTSR_SELCORE; | |||||
break; | break; | ||||
case CORE1_SENSOR1: | case 21: /* CurTmp */ | ||||
temp |= AMDTEMP_TTSR_SELSENSOR; | reg_rtc.bits.CurTmpTjSel = 0; | ||||
/* FALLTHROUGH */ | |||||
case CORE1_SENSOR0: | |||||
case CORE1: | |||||
if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) | |||||
temp |= AMDTEMP_TTSR_SELCORE; | |||||
break; | break; | ||||
} | } | ||||
pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); | 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); | |||||
mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; | val = (AMDTEMP_ZERO_C_TO_K + ((reg_rtc.bits.CurTmp * 10) / 8)); | ||||
offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; | if (bits_off == 16) { /* CurTmpTjSel */ | ||||
temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); | val -= 490; | ||||
temp = ((temp >> 14) & mask) * 5 / 2; | } else { | ||||
temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; | val += (sc->rtc_temp_offset * 10); | ||||
} | |||||
error = sysctl_handle_int(oidp, &val, 0, req); | |||||
if (error || req->newptr == NULL) | |||||
return (error); | |||||
/* pci_write_config(sc->dev, reg_num, reg_rtc.u32, 4); */ | |||||
return (temp); | return (0); | ||||
} | } | ||||
static int32_t | |||||
amdtemp_gettemp(device_t dev, amdsensor_t sensor) | /* Set SMBus-based sideband interface address: 0-7. */ | ||||
static void | |||||
amdtemp_sbi_set_addr(struct amdtemp_softc *sc, uint32_t sbi_addr) | |||||
{ | { | ||||
struct amdtemp_softc *sc = device_get_softc(dev); | union reg_amd_sbi_ctrl_desc reg_sbi; | ||||
uint32_t temp; | |||||
temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); | sbi_addr &= AMD_REG_SBI_ADDR_MASK; | ||||
temp = ((temp >> 21) & 0x7ff) * 5 / 4; | reg_sbi.u32 = pci_read_config(sc->dev, AMD_REG_SBI_CTRL, 4); | ||||
temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; | 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); | |||||
} | |||||
return (temp); | static uint32_t | ||||
amdtemp_sbi_read(struct amdtemp_softc *sc, uint32_t sbi_addr, | |||||
uint32_t reg_addr) | |||||
{ | |||||
uint32_t ret; | |||||
if ((sc->flags & AMDTEMP_F_TSI) == 0) | |||||
return (0); | |||||
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 (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); | |||||
} | |||||
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; | |||||
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 (error || req->newptr == NULL || 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 (ARG2_GET_REG(arg2) == SB_TSI_REG_CPU_TEMP_LB) { | |||||
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 (error || req->newptr == NULL) | |||||
return (error); | |||||
return (0); | |||||
} | |||||
Context not available. |
No can do.