Add support for AMD K8 temperature reporting. (#268)

Add various quirks to handle AMD temp sensors erratas
This commit is contained in:
Sam Demeulemeester
2023-02-13 22:29:17 +01:00
committed by GitHub
parent c38b0cbc5f
commit 22663f89bb
8 changed files with 150 additions and 21 deletions

View File

@@ -251,6 +251,8 @@ static void global_init(void)
error_init();
temperature_init();
initial_config();
clear_message_area();

View File

@@ -36,7 +36,7 @@ void cpuid_init(void)
// Get the processor family information & feature flags.
if (cpuid_info.max_cpuid >= 1) {
cpuid(0x1, 0,
&cpuid_info.version.raw,
&cpuid_info.version.raw[0],
&cpuid_info.proc_info.raw,
&cpuid_info.flags.raw[1],
&cpuid_info.flags.raw[0]
@@ -65,8 +65,8 @@ void cpuid_init(void)
if (cpuid_info.max_xcpuid >= 0x80000001) {
cpuid(0x80000001, 0,
&reg[0],
&cpuid_info.version.raw[1],
&reg[1],
&reg[2],
&cpuid_info.flags.raw[2]
);
}

View File

@@ -29,7 +29,7 @@ typedef enum {
*/
typedef union {
uint32_t raw;
uint32_t raw[2];
struct {
uint32_t stepping : 4;
uint32_t model : 4;
@@ -39,6 +39,7 @@ typedef union {
uint32_t extendedModel : 4;
uint32_t extendedFamily : 8;
uint32_t : 4;
uint32_t extendedBrandID : 32; // AMD Only
};
} cpuid_version_t;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2004-2022 Samuel Demeulemeester
// Copyright (C) 2004-2023 Sam Demeulemeester
//
// ------------------------
// This file is used to detect quirks on specific hardware
@@ -13,6 +13,9 @@
#include "pci.h"
#include "unistd.h"
#include "cpuinfo.h"
#include "cpuid.h"
#include "config.h"
#include "temperature.h"
quirk_t quirk;
@@ -64,6 +67,38 @@ static void get_m1541_l2_cache_size(void)
if (reg == 0b10) { l2_cache = 1024; }
}
static void disable_temp_reporting(void)
{
enable_temperature = false;
}
static void amd_k8_revfg_temp(void)
{
uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8);
// For Rev F & G, switch sensor if no temperature is reported
if (!((rtcr >> 16) & 0xFF)) {
pci_config_write8(0, 24, 3, AMD_TEMP_REG_K8, rtcr | 0x04);
}
// K8 Rev G Desktop requires an additional offset.
if (cpuid_info.version.extendedModel < 6 && cpuid_info.version.extendedModel > 7) // Not Rev G
return;
if (cpuid_info.version.extendedModel == 6 && cpuid_info.version.extendedModel < 9) // Not Desktop
return;
uint16_t brandID = (cpuid_info.version.extendedBrandID >> 9) & 0x1f;
if (cpuid_info.version.model == 0xF && (brandID == 0x7 || brandID == 0x9 || brandID == 0xC)) // Mobile (Single Core)
return;
if (cpuid_info.version.model == 0xB && brandID > 0xB) // Mobile (Dual Core)
return;
cpu_temp_offset = 21.0f;
}
// ---------------------
// -- Public function --
// ---------------------
@@ -115,4 +150,53 @@ void quirks_init(void)
quirk.process = NULL;
}
}
// ------------------------------------------------------
// -- Early AMD K8 doesn't support temperature reading --
// ------------------------------------------------------
// The on-die temperature diode on SH-B0/B3 stepping does not work.
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
&& cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel == 0) { // Early K8
if ((cpuid_info.version.model == 4 && cpuid_info.version.stepping == 0) || // SH-B0 ClawHammer (Athlon 64)
(cpuid_info.version.model == 5 && cpuid_info.version.stepping <= 1)) { // SH-B0/B3 SledgeHammer (Opteron)
quirk.id = QUIRK_K8_BSTEP_NOTEMP;
quirk.type |= QUIRK_TYPE_TEMP;
quirk.process = disable_temp_reporting;
}
}
// ---------------------------------------------------
// -- Late AMD K8 (rev F/G) temp sensor workaround --
// ---------------------------------------------------
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
&& cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel >= 4) { // Later K8
quirk.id = QUIRK_K8_REVFG_TEMP;
quirk.type |= QUIRK_TYPE_TEMP;
quirk.process = amd_k8_revfg_temp;
}
// ------------------------------------------------
// -- AMD K10 CPUs Temp workaround (Errata #319) --
// ------------------------------------------------
// Some AMD K10 CPUs on Socket AM2+/F have buggued thermal diode leading
// to inaccurate temperature measurements. Affected steppings: DR-BA/B2/B3, RB-C2 & HY-D0.
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
&& cpuid_info.version.extendedFamily == 1 && cpuid_info.version.extendedModel == 0) { // AMD K10
uint8_t pkg_type = (cpuid_info.version.extendedBrandID >> 28) & 0x0F;
uint32_t dct0_high = pci_config_read32(0, 24, 2, 0x94); // 0x94[8] = 1 for DDR3
if (pkg_type == 0b0000 || (pkg_type == 0b0001 && (((dct0_high >> 8) & 1) == 0))) { // Socket F or AM2+ (exclude AM3)
if (cpuid_info.version.model < 4 || // DR-BA, DR-B2 & DR-B3
(cpuid_info.version.model == 4 && cpuid_info.version.stepping <= 2) || // RB-C2
cpuid_info.version.model == 8) { // HY-D0
quirk.id = QUIRK_AMD_ERRATA_319;
quirk.type |= QUIRK_TYPE_TEMP;
quirk.process = disable_temp_reporting;
}
}
}
}

View File

@@ -19,12 +19,16 @@
#define QUIRK_TYPE_SMBUS (1 << 4)
#define QUIRK_TYPE_TIMER (1 << 5)
#define QUIRK_TYPE_MEM_SIZE (1 << 6)
#define QUIRK_TYPE_TEMP (1 << 7)
typedef enum {
QUIRK_NONE,
QUIRK_TUSL2,
QUIRK_ALI_ALADDIN_V,
QUIRK_X10SDV_NOSMP
QUIRK_X10SDV_NOSMP,
QUIRK_K8_BSTEP_NOTEMP,
QUIRK_K8_REVFG_TEMP,
QUIRK_AMD_ERRATA_319
} quirk_id_t;
typedef struct {

View File

@@ -30,6 +30,9 @@
#define MSR_AMD64_NB_CFG 0xc001001f
#define MSR_AMD64_COFVID_STATUS 0xc0010071
#define MSR_VIA_TEMP_C7 0x1169
#define MSR_VIA_TEMP_NANO 0x1423
#define rdmsr(msr, value1, value2) \
__asm__ __volatile__("rdmsr" \
: "=a" (value1), \

View File

@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2022 Martin Whitaker.
// Copyright (C) 2004-2023 Sam Demeulemeester.
//
// Derived from an extract of memtest86+ init.c:
//
@@ -16,18 +17,32 @@
#include "cpuid.h"
#include "cpuinfo.h"
#include "hwquirks.h"
#include "msr.h"
#include "pci.h"
#include "temperature.h"
//------------------------------------------------------------------------------
// Public Variables
//------------------------------------------------------------------------------
float cpu_temp_offset = 0;
//------------------------------------------------------------------------------
// Public Functions
//------------------------------------------------------------------------------
void temperature_init(void)
{
// Process temperature-related quirks
if (quirk.type & QUIRK_TYPE_TEMP) {
quirk.process();
}
}
int get_cpu_temperature(void)
{
// Intel CPU
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) {
if (cpuid_info.dts_pmp & 1) {
@@ -47,26 +62,32 @@ int get_cpu_temperature(void)
}
// AMD CPU
else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily > 0 && cpuid_info.version.extendedFamily < 8) {
else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF) { // Target only K8 & newer
// Untested yet
uint32_t rtcr = pci_config_read32(0, 24, 3, 0xA4);
int raw_temp = (rtcr >> 21) & 0x7FF;
if (cpuid_info.version.extendedFamily >= 8) { // Target Zen µarch and newer. Use SMN to get temperature.
return raw_temp / 8;
} else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily >= 8) {
// Grab CPU Temp. for ZEN CPUs using SNM
uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP);
float offset = 0;
if((tval >> 19) & 0x01) {
offset = -49.0f;
if ((tval >> 19) & 0x01) {
cpu_temp_offset = -49.0f;
}
return offset + 0.125f * (float)((tval >> 21) & 0x7FF);
return cpu_temp_offset + 0.125f * (float)((tval >> 21) & 0x7FF);
} else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer)
uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10);
int raw_temp = ((rtcr >> 21) & 0x7FF) / 8;
return (raw_temp > 0) ? raw_temp : 0;
} else { // Target K8 (CPUID ExtFamily = 0)
uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8);
int raw_temp = ((rtcr >> 16) & 0xFF) - 49 + cpu_temp_offset;
return (raw_temp > 0) ? raw_temp : 0;
}
}
// VIA/Centaur/Zhaoxin CPU
@@ -76,9 +97,9 @@ int get_cpu_temperature(void)
uint32_t msrl, msrh, msr_temp;
if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) {
msr_temp = 0x1423; // Zhaoxin, Nano
msr_temp = MSR_VIA_TEMP_NANO; // Zhaoxin, Nano
} else if (cpuid_info.version.model == 0xA || cpuid_info.version.model == 0xD) {
msr_temp = 0x1169; // C7 A/D
msr_temp = MSR_VIA_TEMP_C7; // C7 A/D
} else {
return 0;
}

View File

@@ -8,8 +8,22 @@
*
*//*
* Copyright (C) 2020-2022 Martin Whitaker.
* Copyright (C) 2003-2023 Sam Demeulemeester.
*/
#define AMD_TEMP_REG_K8 0xE4
#define AMD_TEMP_REG_K10 0xA4
/**
* Global CPU Temperature offset
*/
extern float cpu_temp_offset;
/**
* Init temperature sensor and compute offsets if needed
*/
void temperature_init(void);
/**
* Returns the current temperature of the CPU. Returns 0 if
* the temperature cannot be read.