mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
Add support for AMD K8 temperature reporting. (#268)
Add various quirks to handle AMD temp sensors erratas
This commit is contained in:
committed by
GitHub
parent
c38b0cbc5f
commit
22663f89bb
@@ -251,6 +251,8 @@ static void global_init(void)
|
||||
|
||||
error_init();
|
||||
|
||||
temperature_init();
|
||||
|
||||
initial_config();
|
||||
|
||||
clear_message_area();
|
||||
|
||||
@@ -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,
|
||||
®[0],
|
||||
&cpuid_info.version.raw[1],
|
||||
®[1],
|
||||
®[2],
|
||||
&cpuid_info.flags.raw[2]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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;
|
||||
uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP);
|
||||
|
||||
} else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily >= 8) {
|
||||
if ((tval >> 19) & 0x01) {
|
||||
cpu_temp_offset = -49.0f;
|
||||
}
|
||||
|
||||
// Grab CPU Temp. for ZEN CPUs using SNM
|
||||
uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP);
|
||||
return cpu_temp_offset + 0.125f * (float)((tval >> 21) & 0x7FF);
|
||||
|
||||
float offset = 0;
|
||||
} else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer)
|
||||
|
||||
if((tval >> 19) & 0x01) {
|
||||
offset = -49.0f;
|
||||
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;
|
||||
}
|
||||
|
||||
return offset + 0.125f * (float)((tval >> 21) & 0x7FF);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user