Added fallback method (from k10temp) for reading data from SMN

This commit is contained in:
Ondrej Čerman 2019-11-02 23:22:20 +01:00
parent 71f658f6c3
commit d22dd2a438
3 changed files with 28 additions and 5 deletions

View file

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

View file

@ -1,7 +1,7 @@
# Zenpower # Zenpower
Zenpower is Linux kernel driver for reading temperature, voltage(SVI2), current(SVI2) and power(SVI2) for AMD Zen family CPUs. 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/ 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 ## Installation

View file

@ -7,7 +7,7 @@
MODULE_DESCRIPTION("AMD ZEN family CPU Sensors Driver"); MODULE_DESCRIPTION("AMD ZEN family CPU Sensors Driver");
MODULE_AUTHOR("Ondrej Čerman"); MODULE_AUTHOR("Ondrej Čerman");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.4"); MODULE_VERSION("0.1.5");
// based on k10temp - GPL - (c) 2009 Clemens Ladisch <clemens@ladisch.de> // based on k10temp - GPL - (c) 2009 Clemens Ladisch <clemens@ladisch.de>
// //
@ -51,6 +51,7 @@ struct zenpower_data {
u32 svi_soc_addr; u32 svi_soc_addr;
int temp_offset; int temp_offset;
bool zen2; bool zen2;
bool kernel_smn_support;
}; };
struct tctl_offset { struct tctl_offset {
@ -68,6 +69,8 @@ static const struct tctl_offset tctl_offset_table[] = {
{ 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */ { 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, static umode_t zenpower_is_visible(struct kobject *kobj,
struct attribute *attr, int index) struct attribute *attr, int index)
{ {
@ -226,6 +229,7 @@ static ssize_t debug_data_show(struct device *dev,
struct zenpower_data *data = dev_get_drvdata(dev); struct zenpower_data *data = dev_get_drvdata(dev);
u32 smndata; u32 smndata;
len += sprintf(buf, "kernel_smn_support = %d\n", data->kernel_smn_support);
for (i = 0; i < ARRAY_SIZE(debug_addrs_arr); i++){ for (i = 0; i < ARRAY_SIZE(debug_addrs_arr); i++){
data->read_amdsmn_addr(data->pdev, debug_addrs_arr[i], &smndata); data->read_amdsmn_addr(data->pdev, debug_addrs_arr[i], &smndata);
len += sprintf(buf + len, "%08x = %08x\n", debug_addrs_arr[i], smndata); len += sprintf(buf + len, "%08x = %08x\n", debug_addrs_arr[i], smndata);
@ -310,11 +314,21 @@ static const struct attribute_group zenpower_group = {
__ATTRIBUTE_GROUPS(zenpower); __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); 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) static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -329,7 +343,16 @@ static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
data->zen2 = false; data->zen2 = false;
data->pdev = pdev; data->pdev = pdev;
data->read_amdsmn_addr = read_amdsmn_addr; data->read_amdsmn_addr = nb_index_read;
data->kernel_smn_support = false;
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 && boot_cpu_data.x86_model == 0x71) { if (boot_cpu_data.x86 == 0x17 && boot_cpu_data.x86_model == 0x71) {
data->zen2 = true; data->zen2 = true;