16e7c1094SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 23c57e89bSClemens Ladisch /* 3d547552aSGuenter Roeck * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h 4d547552aSGuenter Roeck * processor hardware monitoring 53c57e89bSClemens Ladisch * 63c57e89bSClemens Ladisch * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de> 7d547552aSGuenter Roeck * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net> 8c7579389SGuenter Roeck * 9c7579389SGuenter Roeck * Implementation notes: 10c7579389SGuenter Roeck * - CCD1 and CCD2 register address information as well as the calculation to 11c7579389SGuenter Roeck * convert raw register values is from https://github.com/ocerman/zenpower. 12c7579389SGuenter Roeck * The information is not confirmed from chip datasheets, but experiments 13c7579389SGuenter Roeck * suggest that it provides reasonable temperature values. 14b00647c4SGuenter Roeck * - Register addresses to read chip voltage and current are also from 15b00647c4SGuenter Roeck * https://github.com/ocerman/zenpower, and not confirmed from chip 16b00647c4SGuenter Roeck * datasheets. Current calibration is board specific and not typically 17b00647c4SGuenter Roeck * shared by board vendors. For this reason, current values are 18b00647c4SGuenter Roeck * normalized to report 1A/LSB for core current and and 0.25A/LSB for SoC 19b00647c4SGuenter Roeck * current. Reported values can be adjusted using the sensors configuration 20b00647c4SGuenter Roeck * file. 21b00647c4SGuenter Roeck * - It is unknown if the mechanism to read CCD1/CCD2 temperature as well as 22b00647c4SGuenter Roeck * current and voltage information works on higher-end Ryzen CPUs. 23b00647c4SGuenter Roeck * Information reported by Windows tools suggests that additional sensors 24b00647c4SGuenter Roeck * (both temperature and voltage/current) are supported, but their register 25b00647c4SGuenter Roeck * location is currently unknown. 263c57e89bSClemens Ladisch */ 273c57e89bSClemens Ladisch 28a6d210daSGuenter Roeck #include <linux/bitops.h> 299c4a38f1SGuenter Roeck #include <linux/debugfs.h> 303c57e89bSClemens Ladisch #include <linux/err.h> 313c57e89bSClemens Ladisch #include <linux/hwmon.h> 323c57e89bSClemens Ladisch #include <linux/init.h> 333c57e89bSClemens Ladisch #include <linux/module.h> 343c57e89bSClemens Ladisch #include <linux/pci.h> 35dedf7dceSWoods, Brian #include <linux/pci_ids.h> 363b031622SGuenter Roeck #include <asm/amd_nb.h> 373c57e89bSClemens Ladisch #include <asm/processor.h> 383c57e89bSClemens Ladisch 399e581311SAndre Przywara MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor"); 403c57e89bSClemens Ladisch MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); 413c57e89bSClemens Ladisch MODULE_LICENSE("GPL"); 423c57e89bSClemens Ladisch 433c57e89bSClemens Ladisch static bool force; 443c57e89bSClemens Ladisch module_param(force, bool, 0444); 453c57e89bSClemens Ladisch MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); 463c57e89bSClemens Ladisch 47f89ce270SAravind Gopalakrishnan /* Provide lock for writing to NB_SMU_IND_ADDR */ 48f89ce270SAravind Gopalakrishnan static DEFINE_MUTEX(nb_smu_ind_mutex); 49f89ce270SAravind Gopalakrishnan 50ccaf63b4SGuenter Roeck #ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 51ccaf63b4SGuenter Roeck #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3 52ccaf63b4SGuenter Roeck #endif 53ccaf63b4SGuenter Roeck 54c5114a1cSClemens Ladisch /* CPUID function 0x80000001, ebx */ 55a6d210daSGuenter Roeck #define CPUID_PKGTYPE_MASK GENMASK(31, 28) 56c5114a1cSClemens Ladisch #define CPUID_PKGTYPE_F 0x00000000 57c5114a1cSClemens Ladisch #define CPUID_PKGTYPE_AM2R2_AM3 0x10000000 58c5114a1cSClemens Ladisch 59c5114a1cSClemens Ladisch /* DRAM controller (PCI function 2) */ 60c5114a1cSClemens Ladisch #define REG_DCT0_CONFIG_HIGH 0x094 61a6d210daSGuenter Roeck #define DDR3_MODE BIT(8) 62c5114a1cSClemens Ladisch 63c5114a1cSClemens Ladisch /* miscellaneous (PCI function 3) */ 643c57e89bSClemens Ladisch #define REG_HARDWARE_THERMAL_CONTROL 0x64 65a6d210daSGuenter Roeck #define HTC_ENABLE BIT(0) 663c57e89bSClemens Ladisch 673c57e89bSClemens Ladisch #define REG_REPORTED_TEMPERATURE 0xa4 683c57e89bSClemens Ladisch 693c57e89bSClemens Ladisch #define REG_NORTHBRIDGE_CAPABILITIES 0xe8 70a6d210daSGuenter Roeck #define NB_CAP_HTC BIT(10) 713c57e89bSClemens Ladisch 72f89ce270SAravind Gopalakrishnan /* 7340626a1bSGuenter Roeck * For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL 7440626a1bSGuenter Roeck * and REG_REPORTED_TEMPERATURE have been moved to 7540626a1bSGuenter Roeck * D0F0xBC_xD820_0C64 [Hardware Temperature Control] 7640626a1bSGuenter Roeck * D0F0xBC_xD820_0CA4 [Reported Temperature Control] 77f89ce270SAravind Gopalakrishnan */ 7840626a1bSGuenter Roeck #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 79f89ce270SAravind Gopalakrishnan #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 80f89ce270SAravind Gopalakrishnan 819af0a9aeSGuenter Roeck /* F17h M01h Access througn SMN */ 829af0a9aeSGuenter Roeck #define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800 83c7579389SGuenter Roeck #define F17H_M70H_CCD1_TEMP 0x00059954 84c7579389SGuenter Roeck #define F17H_M70H_CCD2_TEMP 0x00059958 859af0a9aeSGuenter Roeck 86b00647c4SGuenter Roeck #define F17H_M01H_SVI 0x0005A000 87b00647c4SGuenter Roeck #define F17H_M01H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0xc) 88b00647c4SGuenter Roeck #define F17H_M01H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10) 89b00647c4SGuenter Roeck 90a6d210daSGuenter Roeck #define CUR_TEMP_SHIFT 21 91a6d210daSGuenter Roeck #define CUR_TEMP_RANGE_SEL_MASK BIT(19) 92a6d210daSGuenter Roeck 93b00647c4SGuenter Roeck #define CFACTOR_ICORE 1000000 /* 1A / LSB */ 94b00647c4SGuenter Roeck #define CFACTOR_ISOC 250000 /* 0.25A / LSB */ 95b00647c4SGuenter Roeck 9668546abfSGuenter Roeck struct k10temp_data { 9768546abfSGuenter Roeck struct pci_dev *pdev; 9840626a1bSGuenter Roeck void (*read_htcreg)(struct pci_dev *pdev, u32 *regval); 9968546abfSGuenter Roeck void (*read_tempreg)(struct pci_dev *pdev, u32 *regval); 1001b50b776SGuenter Roeck int temp_offset; 1011b597889SGuenter Roeck u32 temp_adjust_mask; 102f934c059SGuenter Roeck bool show_tdie; 103c7579389SGuenter Roeck bool show_tccd1; 104c7579389SGuenter Roeck bool show_tccd2; 105b00647c4SGuenter Roeck u32 svi_addr[2]; 106b00647c4SGuenter Roeck bool show_current; 107b00647c4SGuenter Roeck int cfactor[2]; 1081b50b776SGuenter Roeck }; 1091b50b776SGuenter Roeck 1101b50b776SGuenter Roeck struct tctl_offset { 1111b50b776SGuenter Roeck u8 model; 1121b50b776SGuenter Roeck char const *id; 1131b50b776SGuenter Roeck int offset; 1141b50b776SGuenter Roeck }; 1151b50b776SGuenter Roeck 1161b50b776SGuenter Roeck static const struct tctl_offset tctl_offset_table[] = { 117ab5ee246SGuenter Roeck { 0x17, "AMD Ryzen 5 1600X", 20000 }, 1181b50b776SGuenter Roeck { 0x17, "AMD Ryzen 7 1700X", 20000 }, 1191b50b776SGuenter Roeck { 0x17, "AMD Ryzen 7 1800X", 20000 }, 1201b597889SGuenter Roeck { 0x17, "AMD Ryzen 7 2700X", 10000 }, 121cd6a2064SGuenter Roeck { 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */ 122cd6a2064SGuenter Roeck { 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */ 12368546abfSGuenter Roeck }; 12468546abfSGuenter Roeck 125b00647c4SGuenter Roeck static bool is_threadripper(void) 126b00647c4SGuenter Roeck { 127b00647c4SGuenter Roeck return strstr(boot_cpu_data.x86_model_id, "Threadripper"); 128b00647c4SGuenter Roeck } 129b00647c4SGuenter Roeck 130b00647c4SGuenter Roeck static bool is_epyc(void) 131b00647c4SGuenter Roeck { 132b00647c4SGuenter Roeck return strstr(boot_cpu_data.x86_model_id, "EPYC"); 133b00647c4SGuenter Roeck } 134b00647c4SGuenter Roeck 13540626a1bSGuenter Roeck static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval) 13640626a1bSGuenter Roeck { 13740626a1bSGuenter Roeck pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval); 13840626a1bSGuenter Roeck } 13940626a1bSGuenter Roeck 14068546abfSGuenter Roeck static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval) 14168546abfSGuenter Roeck { 14268546abfSGuenter Roeck pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval); 14368546abfSGuenter Roeck } 14468546abfSGuenter Roeck 14568546abfSGuenter Roeck static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn, 14668546abfSGuenter Roeck unsigned int base, int offset, u32 *val) 147f89ce270SAravind Gopalakrishnan { 148f89ce270SAravind Gopalakrishnan mutex_lock(&nb_smu_ind_mutex); 149f89ce270SAravind Gopalakrishnan pci_bus_write_config_dword(pdev->bus, devfn, 15068546abfSGuenter Roeck base, offset); 151f89ce270SAravind Gopalakrishnan pci_bus_read_config_dword(pdev->bus, devfn, 15268546abfSGuenter Roeck base + 4, val); 153f89ce270SAravind Gopalakrishnan mutex_unlock(&nb_smu_ind_mutex); 154f89ce270SAravind Gopalakrishnan } 155f89ce270SAravind Gopalakrishnan 15640626a1bSGuenter Roeck static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval) 15740626a1bSGuenter Roeck { 15840626a1bSGuenter Roeck amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8, 15940626a1bSGuenter Roeck F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET, regval); 16040626a1bSGuenter Roeck } 16140626a1bSGuenter Roeck 16268546abfSGuenter Roeck static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval) 16368546abfSGuenter Roeck { 16468546abfSGuenter Roeck amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8, 16568546abfSGuenter Roeck F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval); 16668546abfSGuenter Roeck } 16768546abfSGuenter Roeck 1689af0a9aeSGuenter Roeck static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) 1699af0a9aeSGuenter Roeck { 1703b031622SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(pdev), 1719af0a9aeSGuenter Roeck F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); 1729af0a9aeSGuenter Roeck } 1739af0a9aeSGuenter Roeck 174d547552aSGuenter Roeck static long get_raw_temp(struct k10temp_data *data) 1753c57e89bSClemens Ladisch { 176f934c059SGuenter Roeck u32 regval; 177d547552aSGuenter Roeck long temp; 1783c57e89bSClemens Ladisch 17968546abfSGuenter Roeck data->read_tempreg(data->pdev, ®val); 180a6d210daSGuenter Roeck temp = (regval >> CUR_TEMP_SHIFT) * 125; 1811b597889SGuenter Roeck if (regval & data->temp_adjust_mask) 1821b597889SGuenter Roeck temp -= 49000; 183f934c059SGuenter Roeck return temp; 184f934c059SGuenter Roeck } 185f934c059SGuenter Roeck 186d547552aSGuenter Roeck const char *k10temp_temp_label[] = { 187d547552aSGuenter Roeck "Tdie", 188d547552aSGuenter Roeck "Tctl", 189c7579389SGuenter Roeck "Tccd1", 190c7579389SGuenter Roeck "Tccd2", 191d547552aSGuenter Roeck }; 192d547552aSGuenter Roeck 193b00647c4SGuenter Roeck const char *k10temp_in_label[] = { 194b00647c4SGuenter Roeck "Vcore", 195b00647c4SGuenter Roeck "Vsoc", 196b00647c4SGuenter Roeck }; 197b00647c4SGuenter Roeck 198b00647c4SGuenter Roeck const char *k10temp_curr_label[] = { 199b00647c4SGuenter Roeck "Icore", 200b00647c4SGuenter Roeck "Isoc", 201b00647c4SGuenter Roeck }; 202b00647c4SGuenter Roeck 203d547552aSGuenter Roeck static int k10temp_read_labels(struct device *dev, 204d547552aSGuenter Roeck enum hwmon_sensor_types type, 205d547552aSGuenter Roeck u32 attr, int channel, const char **str) 206d547552aSGuenter Roeck { 207b00647c4SGuenter Roeck switch (type) { 208b00647c4SGuenter Roeck case hwmon_temp: 209d547552aSGuenter Roeck *str = k10temp_temp_label[channel]; 210b00647c4SGuenter Roeck break; 211b00647c4SGuenter Roeck case hwmon_in: 212b00647c4SGuenter Roeck *str = k10temp_in_label[channel]; 213b00647c4SGuenter Roeck break; 214b00647c4SGuenter Roeck case hwmon_curr: 215b00647c4SGuenter Roeck *str = k10temp_curr_label[channel]; 216b00647c4SGuenter Roeck break; 217b00647c4SGuenter Roeck default: 218b00647c4SGuenter Roeck return -EOPNOTSUPP; 219b00647c4SGuenter Roeck } 220d547552aSGuenter Roeck return 0; 221d547552aSGuenter Roeck } 222d547552aSGuenter Roeck 223b00647c4SGuenter Roeck static int k10temp_read_curr(struct device *dev, u32 attr, int channel, 224b00647c4SGuenter Roeck long *val) 225b00647c4SGuenter Roeck { 226b00647c4SGuenter Roeck struct k10temp_data *data = dev_get_drvdata(dev); 227b00647c4SGuenter Roeck u32 regval; 228b00647c4SGuenter Roeck 229b00647c4SGuenter Roeck switch (attr) { 230b00647c4SGuenter Roeck case hwmon_curr_input: 231b00647c4SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(data->pdev), 232b00647c4SGuenter Roeck data->svi_addr[channel], ®val); 233b00647c4SGuenter Roeck *val = DIV_ROUND_CLOSEST(data->cfactor[channel] * 234b00647c4SGuenter Roeck (regval & 0xff), 235b00647c4SGuenter Roeck 1000); 236b00647c4SGuenter Roeck break; 237b00647c4SGuenter Roeck default: 238b00647c4SGuenter Roeck return -EOPNOTSUPP; 239b00647c4SGuenter Roeck } 240b00647c4SGuenter Roeck return 0; 241b00647c4SGuenter Roeck } 242b00647c4SGuenter Roeck 243b00647c4SGuenter Roeck static int k10temp_read_in(struct device *dev, u32 attr, int channel, long *val) 244b00647c4SGuenter Roeck { 245b00647c4SGuenter Roeck struct k10temp_data *data = dev_get_drvdata(dev); 246b00647c4SGuenter Roeck u32 regval; 247b00647c4SGuenter Roeck 248b00647c4SGuenter Roeck switch (attr) { 249b00647c4SGuenter Roeck case hwmon_in_input: 250b00647c4SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(data->pdev), 251b00647c4SGuenter Roeck data->svi_addr[channel], ®val); 252b00647c4SGuenter Roeck regval = (regval >> 16) & 0xff; 253b00647c4SGuenter Roeck *val = DIV_ROUND_CLOSEST(155000 - regval * 625, 100); 254b00647c4SGuenter Roeck break; 255b00647c4SGuenter Roeck default: 256b00647c4SGuenter Roeck return -EOPNOTSUPP; 257b00647c4SGuenter Roeck } 258b00647c4SGuenter Roeck return 0; 259b00647c4SGuenter Roeck } 260b00647c4SGuenter Roeck 261b00647c4SGuenter Roeck static int k10temp_read_temp(struct device *dev, u32 attr, int channel, 262b00647c4SGuenter Roeck long *val) 263f934c059SGuenter Roeck { 264f934c059SGuenter Roeck struct k10temp_data *data = dev_get_drvdata(dev); 2653c57e89bSClemens Ladisch u32 regval; 2663c57e89bSClemens Ladisch 267d547552aSGuenter Roeck switch (attr) { 268d547552aSGuenter Roeck case hwmon_temp_input: 269d547552aSGuenter Roeck switch (channel) { 270d547552aSGuenter Roeck case 0: /* Tdie */ 271d547552aSGuenter Roeck *val = get_raw_temp(data) - data->temp_offset; 272d547552aSGuenter Roeck if (*val < 0) 273d547552aSGuenter Roeck *val = 0; 274d547552aSGuenter Roeck break; 275d547552aSGuenter Roeck case 1: /* Tctl */ 276d547552aSGuenter Roeck *val = get_raw_temp(data); 277d547552aSGuenter Roeck if (*val < 0) 278d547552aSGuenter Roeck *val = 0; 279d547552aSGuenter Roeck break; 280c7579389SGuenter Roeck case 2: /* Tccd1 */ 281c7579389SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(data->pdev), 282c7579389SGuenter Roeck F17H_M70H_CCD1_TEMP, ®val); 283c7579389SGuenter Roeck *val = (regval & 0xfff) * 125 - 305000; 284c7579389SGuenter Roeck break; 285c7579389SGuenter Roeck case 3: /* Tccd2 */ 286c7579389SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(data->pdev), 287c7579389SGuenter Roeck F17H_M70H_CCD2_TEMP, ®val); 288c7579389SGuenter Roeck *val = (regval & 0xfff) * 125 - 305000; 289c7579389SGuenter Roeck break; 290d547552aSGuenter Roeck default: 291d547552aSGuenter Roeck return -EOPNOTSUPP; 292d547552aSGuenter Roeck } 293d547552aSGuenter Roeck break; 294d547552aSGuenter Roeck case hwmon_temp_max: 295d547552aSGuenter Roeck *val = 70 * 1000; 296d547552aSGuenter Roeck break; 297d547552aSGuenter Roeck case hwmon_temp_crit: 29840626a1bSGuenter Roeck data->read_htcreg(data->pdev, ®val); 299d547552aSGuenter Roeck *val = ((regval >> 16) & 0x7f) * 500 + 52000; 300d547552aSGuenter Roeck break; 301d547552aSGuenter Roeck case hwmon_temp_crit_hyst: 302d547552aSGuenter Roeck data->read_htcreg(data->pdev, ®val); 303d547552aSGuenter Roeck *val = (((regval >> 16) & 0x7f) 304d547552aSGuenter Roeck - ((regval >> 24) & 0xf)) * 500 + 52000; 305d547552aSGuenter Roeck break; 306d547552aSGuenter Roeck default: 307d547552aSGuenter Roeck return -EOPNOTSUPP; 308d547552aSGuenter Roeck } 309d547552aSGuenter Roeck return 0; 3103c57e89bSClemens Ladisch } 3113c57e89bSClemens Ladisch 312b00647c4SGuenter Roeck static int k10temp_read(struct device *dev, enum hwmon_sensor_types type, 313b00647c4SGuenter Roeck u32 attr, int channel, long *val) 314b00647c4SGuenter Roeck { 315b00647c4SGuenter Roeck switch (type) { 316b00647c4SGuenter Roeck case hwmon_temp: 317b00647c4SGuenter Roeck return k10temp_read_temp(dev, attr, channel, val); 318b00647c4SGuenter Roeck case hwmon_in: 319b00647c4SGuenter Roeck return k10temp_read_in(dev, attr, channel, val); 320b00647c4SGuenter Roeck case hwmon_curr: 321b00647c4SGuenter Roeck return k10temp_read_curr(dev, attr, channel, val); 322b00647c4SGuenter Roeck default: 323b00647c4SGuenter Roeck return -EOPNOTSUPP; 324b00647c4SGuenter Roeck } 325b00647c4SGuenter Roeck } 326b00647c4SGuenter Roeck 327d547552aSGuenter Roeck static umode_t k10temp_is_visible(const void *_data, 328d547552aSGuenter Roeck enum hwmon_sensor_types type, 329d547552aSGuenter Roeck u32 attr, int channel) 3303e3e1022SGuenter Roeck { 331d547552aSGuenter Roeck const struct k10temp_data *data = _data; 33268546abfSGuenter Roeck struct pci_dev *pdev = data->pdev; 33340626a1bSGuenter Roeck u32 reg; 33440626a1bSGuenter Roeck 335d547552aSGuenter Roeck switch (type) { 336d547552aSGuenter Roeck case hwmon_temp: 337d547552aSGuenter Roeck switch (attr) { 338d547552aSGuenter Roeck case hwmon_temp_input: 339c7579389SGuenter Roeck switch (channel) { 340c7579389SGuenter Roeck case 0: /* Tdie, or Tctl if we don't show it */ 341c7579389SGuenter Roeck break; 342c7579389SGuenter Roeck case 1: /* Tctl */ 343c7579389SGuenter Roeck if (!data->show_tdie) 344d547552aSGuenter Roeck return 0; 345f934c059SGuenter Roeck break; 346c7579389SGuenter Roeck case 2: /* Tccd1 */ 347c7579389SGuenter Roeck if (!data->show_tccd1) 348c7579389SGuenter Roeck return 0; 349c7579389SGuenter Roeck break; 350c7579389SGuenter Roeck case 3: /* Tccd2 */ 351c7579389SGuenter Roeck if (!data->show_tccd2) 352c7579389SGuenter Roeck return 0; 353c7579389SGuenter Roeck break; 354c7579389SGuenter Roeck default: 355c7579389SGuenter Roeck return 0; 356c7579389SGuenter Roeck } 357c7579389SGuenter Roeck break; 358d547552aSGuenter Roeck case hwmon_temp_max: 35970831c8aSGuenter Roeck if (channel || data->show_tdie) 360d547552aSGuenter Roeck return 0; 361d547552aSGuenter Roeck break; 362d547552aSGuenter Roeck case hwmon_temp_crit: 363d547552aSGuenter Roeck case hwmon_temp_crit_hyst: 364d547552aSGuenter Roeck if (channel || !data->read_htcreg) 36540626a1bSGuenter Roeck return 0; 3663e3e1022SGuenter Roeck 367d547552aSGuenter Roeck pci_read_config_dword(pdev, 368d547552aSGuenter Roeck REG_NORTHBRIDGE_CAPABILITIES, 36940626a1bSGuenter Roeck ®); 37040626a1bSGuenter Roeck if (!(reg & NB_CAP_HTC)) 37140626a1bSGuenter Roeck return 0; 37240626a1bSGuenter Roeck 37340626a1bSGuenter Roeck data->read_htcreg(data->pdev, ®); 37440626a1bSGuenter Roeck if (!(reg & HTC_ENABLE)) 3753e3e1022SGuenter Roeck return 0; 376f934c059SGuenter Roeck break; 377d547552aSGuenter Roeck case hwmon_temp_label: 378c7579389SGuenter Roeck /* No labels if we don't show the die temperature */ 379f934c059SGuenter Roeck if (!data->show_tdie) 380f934c059SGuenter Roeck return 0; 381c7579389SGuenter Roeck switch (channel) { 382c7579389SGuenter Roeck case 0: /* Tdie */ 383c7579389SGuenter Roeck case 1: /* Tctl */ 384c7579389SGuenter Roeck break; 385c7579389SGuenter Roeck case 2: /* Tccd1 */ 386c7579389SGuenter Roeck if (!data->show_tccd1) 387c7579389SGuenter Roeck return 0; 388c7579389SGuenter Roeck break; 389c7579389SGuenter Roeck case 3: /* Tccd2 */ 390c7579389SGuenter Roeck if (!data->show_tccd2) 391c7579389SGuenter Roeck return 0; 392c7579389SGuenter Roeck break; 393c7579389SGuenter Roeck default: 394c7579389SGuenter Roeck return 0; 395c7579389SGuenter Roeck } 396f934c059SGuenter Roeck break; 397d547552aSGuenter Roeck default: 398d547552aSGuenter Roeck return 0; 3993e3e1022SGuenter Roeck } 400d547552aSGuenter Roeck break; 401b00647c4SGuenter Roeck case hwmon_in: 402b00647c4SGuenter Roeck case hwmon_curr: 403b00647c4SGuenter Roeck if (!data->show_current) 404b00647c4SGuenter Roeck return 0; 405b00647c4SGuenter Roeck break; 406d547552aSGuenter Roeck default: 407d547552aSGuenter Roeck return 0; 4083e3e1022SGuenter Roeck } 409d547552aSGuenter Roeck return 0444; 410d547552aSGuenter Roeck } 4113c57e89bSClemens Ladisch 4126c931ae1SBill Pemberton static bool has_erratum_319(struct pci_dev *pdev) 4133c57e89bSClemens Ladisch { 414c5114a1cSClemens Ladisch u32 pkg_type, reg_dram_cfg; 415c5114a1cSClemens Ladisch 416c5114a1cSClemens Ladisch if (boot_cpu_data.x86 != 0x10) 417c5114a1cSClemens Ladisch return false; 418c5114a1cSClemens Ladisch 4193c57e89bSClemens Ladisch /* 420c5114a1cSClemens Ladisch * Erratum 319: The thermal sensor of Socket F/AM2+ processors 421c5114a1cSClemens Ladisch * may be unreliable. 4223c57e89bSClemens Ladisch */ 423c5114a1cSClemens Ladisch pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK; 424c5114a1cSClemens Ladisch if (pkg_type == CPUID_PKGTYPE_F) 425c5114a1cSClemens Ladisch return true; 426c5114a1cSClemens Ladisch if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3) 427c5114a1cSClemens Ladisch return false; 428c5114a1cSClemens Ladisch 429eefc2d9eSJean Delvare /* DDR3 memory implies socket AM3, which is good */ 430c5114a1cSClemens Ladisch pci_bus_read_config_dword(pdev->bus, 431c5114a1cSClemens Ladisch PCI_DEVFN(PCI_SLOT(pdev->devfn), 2), 432c5114a1cSClemens Ladisch REG_DCT0_CONFIG_HIGH, ®_dram_cfg); 433eefc2d9eSJean Delvare if (reg_dram_cfg & DDR3_MODE) 434eefc2d9eSJean Delvare return false; 435eefc2d9eSJean Delvare 436eefc2d9eSJean Delvare /* 437eefc2d9eSJean Delvare * Unfortunately it is possible to run a socket AM3 CPU with DDR2 438eefc2d9eSJean Delvare * memory. We blacklist all the cores which do exist in socket AM2+ 439eefc2d9eSJean Delvare * format. It still isn't perfect, as RB-C2 cores exist in both AM2+ 440eefc2d9eSJean Delvare * and AM3 formats, but that's the best we can do. 441eefc2d9eSJean Delvare */ 442eefc2d9eSJean Delvare return boot_cpu_data.x86_model < 4 || 443b399151cSJia Zhang (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); 4443c57e89bSClemens Ladisch } 4453c57e89bSClemens Ladisch 4469c4a38f1SGuenter Roeck #ifdef CONFIG_DEBUG_FS 4479c4a38f1SGuenter Roeck 4489c4a38f1SGuenter Roeck static void k10temp_smn_regs_show(struct seq_file *s, struct pci_dev *pdev, 4499c4a38f1SGuenter Roeck u32 addr, int count) 4509c4a38f1SGuenter Roeck { 4519c4a38f1SGuenter Roeck u32 reg; 4529c4a38f1SGuenter Roeck int i; 4539c4a38f1SGuenter Roeck 4549c4a38f1SGuenter Roeck for (i = 0; i < count; i++) { 4559c4a38f1SGuenter Roeck if (!(i & 3)) 4569c4a38f1SGuenter Roeck seq_printf(s, "0x%06x: ", addr + i * 4); 4579c4a38f1SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(pdev), addr + i * 4, ®); 4589c4a38f1SGuenter Roeck seq_printf(s, "%08x ", reg); 4599c4a38f1SGuenter Roeck if ((i & 3) == 3) 4609c4a38f1SGuenter Roeck seq_puts(s, "\n"); 4619c4a38f1SGuenter Roeck } 4629c4a38f1SGuenter Roeck } 4639c4a38f1SGuenter Roeck 4649c4a38f1SGuenter Roeck static int svi_show(struct seq_file *s, void *unused) 4659c4a38f1SGuenter Roeck { 4669c4a38f1SGuenter Roeck struct k10temp_data *data = s->private; 4679c4a38f1SGuenter Roeck 4689c4a38f1SGuenter Roeck k10temp_smn_regs_show(s, data->pdev, F17H_M01H_SVI, 32); 4699c4a38f1SGuenter Roeck return 0; 4709c4a38f1SGuenter Roeck } 4719c4a38f1SGuenter Roeck DEFINE_SHOW_ATTRIBUTE(svi); 4729c4a38f1SGuenter Roeck 4739c4a38f1SGuenter Roeck static int thm_show(struct seq_file *s, void *unused) 4749c4a38f1SGuenter Roeck { 4759c4a38f1SGuenter Roeck struct k10temp_data *data = s->private; 4769c4a38f1SGuenter Roeck 4779c4a38f1SGuenter Roeck k10temp_smn_regs_show(s, data->pdev, 4789c4a38f1SGuenter Roeck F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, 256); 4799c4a38f1SGuenter Roeck return 0; 4809c4a38f1SGuenter Roeck } 4819c4a38f1SGuenter Roeck DEFINE_SHOW_ATTRIBUTE(thm); 4829c4a38f1SGuenter Roeck 4839c4a38f1SGuenter Roeck static void k10temp_debugfs_cleanup(void *ddir) 4849c4a38f1SGuenter Roeck { 4859c4a38f1SGuenter Roeck debugfs_remove_recursive(ddir); 4869c4a38f1SGuenter Roeck } 4879c4a38f1SGuenter Roeck 4889c4a38f1SGuenter Roeck static void k10temp_init_debugfs(struct k10temp_data *data) 4899c4a38f1SGuenter Roeck { 4909c4a38f1SGuenter Roeck struct dentry *debugfs; 4919c4a38f1SGuenter Roeck char name[32]; 4929c4a38f1SGuenter Roeck 4939c4a38f1SGuenter Roeck /* Only show debugfs data for Family 17h/18h CPUs */ 4949c4a38f1SGuenter Roeck if (!data->show_tdie) 4959c4a38f1SGuenter Roeck return; 4969c4a38f1SGuenter Roeck 4979c4a38f1SGuenter Roeck scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev)); 4989c4a38f1SGuenter Roeck 4999c4a38f1SGuenter Roeck debugfs = debugfs_create_dir(name, NULL); 5009c4a38f1SGuenter Roeck if (debugfs) { 5019c4a38f1SGuenter Roeck debugfs_create_file("svi", 0444, debugfs, data, &svi_fops); 5029c4a38f1SGuenter Roeck debugfs_create_file("thm", 0444, debugfs, data, &thm_fops); 5039c4a38f1SGuenter Roeck devm_add_action_or_reset(&data->pdev->dev, 5049c4a38f1SGuenter Roeck k10temp_debugfs_cleanup, debugfs); 5059c4a38f1SGuenter Roeck } 5069c4a38f1SGuenter Roeck } 5079c4a38f1SGuenter Roeck 5089c4a38f1SGuenter Roeck #else 5099c4a38f1SGuenter Roeck 5109c4a38f1SGuenter Roeck static void k10temp_init_debugfs(struct k10temp_data *data) 5119c4a38f1SGuenter Roeck { 5129c4a38f1SGuenter Roeck } 5139c4a38f1SGuenter Roeck 5149c4a38f1SGuenter Roeck #endif 5159c4a38f1SGuenter Roeck 516d547552aSGuenter Roeck static const struct hwmon_channel_info *k10temp_info[] = { 517d547552aSGuenter Roeck HWMON_CHANNEL_INFO(temp, 518d547552aSGuenter Roeck HWMON_T_INPUT | HWMON_T_MAX | 519d547552aSGuenter Roeck HWMON_T_CRIT | HWMON_T_CRIT_HYST | 520d547552aSGuenter Roeck HWMON_T_LABEL, 521c7579389SGuenter Roeck HWMON_T_INPUT | HWMON_T_LABEL, 522c7579389SGuenter Roeck HWMON_T_INPUT | HWMON_T_LABEL, 523d547552aSGuenter Roeck HWMON_T_INPUT | HWMON_T_LABEL), 524b00647c4SGuenter Roeck HWMON_CHANNEL_INFO(in, 525b00647c4SGuenter Roeck HWMON_I_INPUT | HWMON_I_LABEL, 526b00647c4SGuenter Roeck HWMON_I_INPUT | HWMON_I_LABEL), 527b00647c4SGuenter Roeck HWMON_CHANNEL_INFO(curr, 528b00647c4SGuenter Roeck HWMON_C_INPUT | HWMON_C_LABEL, 529b00647c4SGuenter Roeck HWMON_C_INPUT | HWMON_C_LABEL), 530d547552aSGuenter Roeck NULL 531d547552aSGuenter Roeck }; 532d547552aSGuenter Roeck 533d547552aSGuenter Roeck static const struct hwmon_ops k10temp_hwmon_ops = { 534d547552aSGuenter Roeck .is_visible = k10temp_is_visible, 535d547552aSGuenter Roeck .read = k10temp_read, 536d547552aSGuenter Roeck .read_string = k10temp_read_labels, 537d547552aSGuenter Roeck }; 538d547552aSGuenter Roeck 539d547552aSGuenter Roeck static const struct hwmon_chip_info k10temp_chip_info = { 540d547552aSGuenter Roeck .ops = &k10temp_hwmon_ops, 541d547552aSGuenter Roeck .info = k10temp_info, 542d547552aSGuenter Roeck }; 543d547552aSGuenter Roeck 544d547552aSGuenter Roeck static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) 5453c57e89bSClemens Ladisch { 546c5114a1cSClemens Ladisch int unreliable = has_erratum_319(pdev); 5473e3e1022SGuenter Roeck struct device *dev = &pdev->dev; 54868546abfSGuenter Roeck struct k10temp_data *data; 5493e3e1022SGuenter Roeck struct device *hwmon_dev; 5501b50b776SGuenter Roeck int i; 5513c57e89bSClemens Ladisch 5523e3e1022SGuenter Roeck if (unreliable) { 5533e3e1022SGuenter Roeck if (!force) { 5543e3e1022SGuenter Roeck dev_err(dev, 5553c57e89bSClemens Ladisch "unreliable CPU thermal sensor; monitoring disabled\n"); 5563e3e1022SGuenter Roeck return -ENODEV; 5573c57e89bSClemens Ladisch } 5583e3e1022SGuenter Roeck dev_warn(dev, 5593c57e89bSClemens Ladisch "unreliable CPU thermal sensor; check erratum 319\n"); 5603c57e89bSClemens Ladisch } 5613c57e89bSClemens Ladisch 56268546abfSGuenter Roeck data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 56368546abfSGuenter Roeck if (!data) 56468546abfSGuenter Roeck return -ENOMEM; 56568546abfSGuenter Roeck 56668546abfSGuenter Roeck data->pdev = pdev; 56768546abfSGuenter Roeck 56853dfa008SGuenter Roeck if (boot_cpu_data.x86 == 0x15 && 56953dfa008SGuenter Roeck ((boot_cpu_data.x86_model & 0xf0) == 0x60 || 57053dfa008SGuenter Roeck (boot_cpu_data.x86_model & 0xf0) == 0x70)) { 57140626a1bSGuenter Roeck data->read_htcreg = read_htcreg_nb_f15; 57268546abfSGuenter Roeck data->read_tempreg = read_tempreg_nb_f15; 573d93217d8SPu Wen } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) { 574c7579389SGuenter Roeck u32 regval; 575c7579389SGuenter Roeck 576a6d210daSGuenter Roeck data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK; 5779af0a9aeSGuenter Roeck data->read_tempreg = read_tempreg_nb_f17; 578f934c059SGuenter Roeck data->show_tdie = true; 579c7579389SGuenter Roeck 580c7579389SGuenter Roeck switch (boot_cpu_data.x86_model) { 581c7579389SGuenter Roeck case 0x1: /* Zen */ 582c7579389SGuenter Roeck case 0x8: /* Zen+ */ 583c7579389SGuenter Roeck case 0x11: /* Zen APU */ 584c7579389SGuenter Roeck case 0x18: /* Zen+ APU */ 585b00647c4SGuenter Roeck data->show_current = !is_threadripper() && !is_epyc(); 586b00647c4SGuenter Roeck data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0; 587b00647c4SGuenter Roeck data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1; 588b00647c4SGuenter Roeck data->cfactor[0] = CFACTOR_ICORE; 589b00647c4SGuenter Roeck data->cfactor[1] = CFACTOR_ISOC; 590c7579389SGuenter Roeck break; 591c7579389SGuenter Roeck case 0x31: /* Zen2 Threadripper */ 592c7579389SGuenter Roeck case 0x71: /* Zen2 */ 593b00647c4SGuenter Roeck data->show_current = !is_threadripper() && !is_epyc(); 594b00647c4SGuenter Roeck data->cfactor[0] = CFACTOR_ICORE; 595b00647c4SGuenter Roeck data->cfactor[1] = CFACTOR_ISOC; 596b00647c4SGuenter Roeck data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE1; 597b00647c4SGuenter Roeck data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE0; 598c7579389SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(pdev), 599c7579389SGuenter Roeck F17H_M70H_CCD1_TEMP, ®val); 600c7579389SGuenter Roeck if (regval & 0xfff) 601c7579389SGuenter Roeck data->show_tccd1 = true; 602c7579389SGuenter Roeck 603c7579389SGuenter Roeck amd_smn_read(amd_pci_dev_to_node_id(pdev), 604c7579389SGuenter Roeck F17H_M70H_CCD2_TEMP, ®val); 605c7579389SGuenter Roeck if (regval & 0xfff) 606c7579389SGuenter Roeck data->show_tccd2 = true; 607c7579389SGuenter Roeck break; 608c7579389SGuenter Roeck } 6091b597889SGuenter Roeck } else { 61040626a1bSGuenter Roeck data->read_htcreg = read_htcreg_pci; 61168546abfSGuenter Roeck data->read_tempreg = read_tempreg_pci; 6121b597889SGuenter Roeck } 61368546abfSGuenter Roeck 6141b50b776SGuenter Roeck for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) { 6151b50b776SGuenter Roeck const struct tctl_offset *entry = &tctl_offset_table[i]; 6161b50b776SGuenter Roeck 6171b50b776SGuenter Roeck if (boot_cpu_data.x86 == entry->model && 6181b50b776SGuenter Roeck strstr(boot_cpu_data.x86_model_id, entry->id)) { 6191b50b776SGuenter Roeck data->temp_offset = entry->offset; 6201b50b776SGuenter Roeck break; 6211b50b776SGuenter Roeck } 6221b50b776SGuenter Roeck } 6231b50b776SGuenter Roeck 624d547552aSGuenter Roeck hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data, 625d547552aSGuenter Roeck &k10temp_chip_info, 626d547552aSGuenter Roeck NULL); 6279c4a38f1SGuenter Roeck if (IS_ERR(hwmon_dev)) 6289c4a38f1SGuenter Roeck return PTR_ERR(hwmon_dev); 6299c4a38f1SGuenter Roeck 6309c4a38f1SGuenter Roeck k10temp_init_debugfs(data); 6319c4a38f1SGuenter Roeck 6329c4a38f1SGuenter Roeck return 0; 6333c57e89bSClemens Ladisch } 6343c57e89bSClemens Ladisch 635cd9bb056SJingoo Han static const struct pci_device_id k10temp_id_table[] = { 6363c57e89bSClemens Ladisch { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, 6373c57e89bSClemens Ladisch { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, 638aa4790a6SClemens Ladisch { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, 6399e581311SAndre Przywara { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, 64024214449SBorislav Petkov { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, 641d303b1b5SPhil Pokorny { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, 642f89ce270SAravind Gopalakrishnan { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) }, 643ccaf63b4SGuenter Roeck { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) }, 64430b146d1SWei Hu { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, 645ec015950SAravind Gopalakrishnan { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, 6469af0a9aeSGuenter Roeck { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, 6473b031622SGuenter Roeck { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, 648210ba120SWoods, Brian { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, 64912163cfbSMarcel Bocu { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, 650d93217d8SPu Wen { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, 6513c57e89bSClemens Ladisch {} 6523c57e89bSClemens Ladisch }; 6533c57e89bSClemens Ladisch MODULE_DEVICE_TABLE(pci, k10temp_id_table); 6543c57e89bSClemens Ladisch 6553c57e89bSClemens Ladisch static struct pci_driver k10temp_driver = { 6563c57e89bSClemens Ladisch .name = "k10temp", 6573c57e89bSClemens Ladisch .id_table = k10temp_id_table, 6583c57e89bSClemens Ladisch .probe = k10temp_probe, 6593c57e89bSClemens Ladisch }; 6603c57e89bSClemens Ladisch 661f71f5a55SAxel Lin module_pci_driver(k10temp_driver); 662