Merge branch 'ver5'

This commit is contained in:
Ondrej Čerman 2019-11-04 16:50:17 +01:00
commit 3406cda35c
3 changed files with 122 additions and 12 deletions

View file

@ -1,4 +1,4 @@
VERSION := 0.1.4
VERSION := 0.1.5
TARGET := $(shell uname -r)
DKMS_ROOT_PATH := /usr/src/zenpower-$(VERSION)

View file

@ -1,7 +1,7 @@
# Zenpower
Zenpower is Linux kernel driver for reading temperature, voltage(SVI2), current(SVI2) and power(SVI2) for AMD Zen family CPUs.
Make sure that your Linux kernel have support for your CPUs as Zenpower is using kernel calls to read values from SMN.
Make sure that your Linux kernel have support for your CPUs as Zenpower is using kernel function `amd_smn_read` to read values from SMN. A fallback method (which may or may not work!) will be used when it is detected that kernel function `amd_smn_read` lacks support for your CPU.
For AMD family 17h Model 70h (Ryzen 3000) CPUs you need kernel version 5.3.4 or newer or kernel with this patch: https://patchwork.kernel.org/patch/11043277/
## Installation

View file

@ -7,7 +7,7 @@
MODULE_DESCRIPTION("AMD ZEN family CPU Sensors Driver");
MODULE_AUTHOR("Ondrej Čerman");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.4");
MODULE_VERSION("0.1.5");
// based on k10temp - GPL - (c) 2009 Clemens Ladisch <clemens@ladisch.de>
//
@ -41,6 +41,8 @@ MODULE_VERSION("0.1.4");
#define F17H_M01H_SVI 0x0005A000
#define F17H_M01H_SVI_TEL_PLANE0 F17H_M01H_SVI + 0xc
#define F17H_M01H_SVI_TEL_PLANE1 F17H_M01H_SVI + 0x10
#define F17H_M70H_CCD1_TEMP 0x00059954
#define F17H_M70H_CCD2_TEMP 0x00059958
#define F17H_TEMP_ADJUST_MASK 0x80000
@ -51,6 +53,9 @@ struct zenpower_data {
u32 svi_soc_addr;
int temp_offset;
bool zen2;
bool kernel_smn_support;
bool amps_visible;
bool ccd1_visible, ccd2_visible;
};
struct tctl_offset {
@ -68,9 +73,29 @@ static const struct tctl_offset tctl_offset_table[] = {
{ 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */
};
static DEFINE_MUTEX(nb_smu_ind_mutex);
static umode_t zenpower_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct zenpower_data *data = dev_get_drvdata(dev);
switch (index) {
case 4 ... 11: // amperage and wattage
if (!data->amps_visible)
return 0;
break;
case 17 ... 18: // CCD1 temperature
if (!data->ccd1_visible)
return 0;
break;
case 19 ... 20: // CCD2 temperature
if (!data->ccd2_visible)
return 0;
break;
}
return attr->mode;
}
@ -107,7 +132,7 @@ static u32 get_soc_current(u32 plane, bool zen2)
return (fc * idd_cor) / 1000;
}
static unsigned int get_raw_temp(struct zenpower_data *data)
static unsigned int get_ctl_temp(struct zenpower_data *data)
{
unsigned int temp;
u32 regval;
@ -119,11 +144,19 @@ static unsigned int get_raw_temp(struct zenpower_data *data)
return temp;
}
static unsigned int get_ccd_temp(struct zenpower_data *data, u32 ccd_addr)
{
u32 regval;
data->read_amdsmn_addr(data->pdev, ccd_addr, &regval);
return (regval & 0xfff) * 125 - 305000;
}
static ssize_t temp1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zenpower_data *data = dev_get_drvdata(dev);
unsigned int temp = get_raw_temp(data);
unsigned int temp = get_ctl_temp(data);
if (temp > data->temp_offset)
temp -= data->temp_offset;
@ -143,7 +176,25 @@ static ssize_t temp2_input_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct zenpower_data *data = dev_get_drvdata(dev);
unsigned int temp = get_raw_temp(data);
unsigned int temp = get_ctl_temp(data);
return sprintf(buf, "%u\n", temp);
}
static ssize_t temp3_input_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct zenpower_data *data = dev_get_drvdata(dev);
unsigned int temp = get_ccd_temp(data, F17H_M70H_CCD1_TEMP);
return sprintf(buf, "%u\n", temp);
}
static ssize_t temp4_input_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct zenpower_data *data = dev_get_drvdata(dev);
unsigned int temp = get_ccd_temp(data, F17H_M70H_CCD2_TEMP);
return sprintf(buf, "%u\n", temp);
}
@ -216,7 +267,7 @@ static ssize_t power2_input_show(struct device *dev,
int static debug_addrs_arr[] = {
F17H_M01H_SVI + 0x8, F17H_M01H_SVI_TEL_PLANE0, F17H_M01H_SVI_TEL_PLANE1,
0x000598BC, 0x0005994C, 0x00059954, 0x00059958, 0x0005995C
0x000598BC, 0x0005994C, F17H_M70H_CCD1_TEMP, F17H_M70H_CCD2_TEMP, 0x0005995C
};
static ssize_t debug_data_show(struct device *dev,
@ -226,6 +277,7 @@ static ssize_t debug_data_show(struct device *dev,
struct zenpower_data *data = dev_get_drvdata(dev);
u32 smndata;
len += sprintf(buf, "kernel_smn_support = %d\n", data->kernel_smn_support);
for (i = 0; i < ARRAY_SIZE(debug_addrs_arr); i++){
data->read_amdsmn_addr(data->pdev, debug_addrs_arr[i], &smndata);
len += sprintf(buf + len, "%08x = %08x\n", debug_addrs_arr[i], smndata);
@ -257,6 +309,10 @@ static ssize_t zen_label_show(struct device *dev,
return sprintf(buf, "Tdie\n");
case 32:
return sprintf(buf, "Tctl\n");
case 33:
return sprintf(buf, "Tccd1\n");
case 34:
return sprintf(buf, "Tccd2\n");
}
return 0;
@ -279,8 +335,13 @@ static DEVICE_ATTR_RO(temp1_max);
static SENSOR_DEVICE_ATTR(temp1_label, 0444, zen_label_show, NULL, 31);
static DEVICE_ATTR_RO(temp2_input);
static SENSOR_DEVICE_ATTR(temp2_label, 0444, zen_label_show, NULL, 32);
static DEVICE_ATTR_RO(temp3_input);
static SENSOR_DEVICE_ATTR(temp3_label, 0444, zen_label_show, NULL, 33);
static DEVICE_ATTR_RO(temp4_input);
static SENSOR_DEVICE_ATTR(temp4_label, 0444, zen_label_show, NULL, 34);
static DEVICE_ATTR_RO(debug_data);
static struct attribute *zenpower_attrs[] = {
&dev_attr_in1_input.attr,
&sensor_dev_attr_in1_label.dev_attr.attr,
@ -299,6 +360,10 @@ static struct attribute *zenpower_attrs[] = {
&sensor_dev_attr_temp1_label.dev_attr.attr,
&dev_attr_temp2_input.attr,
&sensor_dev_attr_temp2_label.dev_attr.attr,
&dev_attr_temp3_input.attr,
&sensor_dev_attr_temp3_label.dev_attr.attr,
&dev_attr_temp4_input.attr,
&sensor_dev_attr_temp4_label.dev_attr.attr,
&dev_attr_debug_data.attr,
NULL
};
@ -310,17 +375,28 @@ static const struct attribute_group zenpower_group = {
__ATTRIBUTE_GROUPS(zenpower);
static void read_amdsmn_addr(struct pci_dev *pdev, u32 address, u32 *regval)
static void kernel_smn_read(struct pci_dev *pdev, u32 address, u32 *regval)
{
amd_smn_read(amd_pci_dev_to_node_id(pdev), address, regval);
}
// fallback method from k10temp
// may return inaccurate results on multi-die chips
static void nb_index_read(struct pci_dev *pdev, u32 address, u32 *regval)
{
mutex_lock(&nb_smu_ind_mutex);
pci_bus_write_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0x60, address);
pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0x64, regval);
mutex_unlock(&nb_smu_ind_mutex);
}
static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
struct zenpower_data *data;
struct device *hwmon_dev;
bool swapped_addr = false;
u32 tmp;
int i;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
@ -329,11 +405,45 @@ static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
data->zen2 = false;
data->pdev = pdev;
data->read_amdsmn_addr = read_amdsmn_addr;
data->read_amdsmn_addr = nb_index_read;
data->kernel_smn_support = false;
data->amps_visible = false;
data->ccd1_visible = false;
data->ccd2_visible = false;
if (boot_cpu_data.x86 == 0x17 && boot_cpu_data.x86_model == 0x71) {
data->zen2 = true;
swapped_addr = true;
for (id = amd_nb_misc_ids; id->vendor; id++) {
if (pdev->vendor == id->vendor && pdev->device == id->device) {
data->kernel_smn_support = true;
data->read_amdsmn_addr = kernel_smn_read;
break;
}
}
if (boot_cpu_data.x86 == 0x17) {
switch (boot_cpu_data.x86_model) {
case 0x1: // Zen
case 0x8: // Zen+
case 0x11: // Zen APU
case 0x18: // Zen+ APU
data->amps_visible = true;
break;
case 0x71: // Zen2
data->amps_visible = true;
data->zen2 = true;
swapped_addr = true;
data->read_amdsmn_addr(pdev, F17H_M70H_CCD1_TEMP, &tmp);
if ((tmp & 0xfff) > 0) {
data->ccd1_visible = true;
}
data->read_amdsmn_addr(pdev, F17H_M70H_CCD2_TEMP, &tmp);
if ((tmp & 0xfff) > 0) {
data->ccd2_visible = true;
}
break;
}
}
#ifdef SWAP_CORE_SOC