diff options
author | Ondrej Čerman | 2019-11-02 23:22:20 +0100 |
---|---|---|
committer | Ondrej Čerman | 2019-11-02 23:22:20 +0100 |
commit | d22dd2a43818810bbc8d77a3ff2673bd6d6fb24e (patch) | |
tree | 9f56a9be12e6e1462ca4e3a8e9b5eaab5f9095f1 | |
parent | 71f658f6c3faf2932b2b6c7bb162140ed2094530 (diff) |
Added fallback method (from k10temp) for reading data from SMN
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | zenpower.c | 29 |
3 files changed, 28 insertions, 5 deletions
@@ -1,4 +1,4 @@ -VERSION := 0.1.4 +VERSION := 0.1.5 TARGET := $(shell uname -r) DKMS_ROOT_PATH := /usr/src/zenpower-$(VERSION) @@ -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 @@ -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> // @@ -51,6 +51,7 @@ struct zenpower_data { u32 svi_soc_addr; int temp_offset; bool zen2; + bool kernel_smn_support; }; 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 */ }; +static DEFINE_MUTEX(nb_smu_ind_mutex); + static umode_t zenpower_is_visible(struct kobject *kobj, 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); 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); @@ -310,11 +314,21 @@ 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; @@ -329,7 +343,16 @@ 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; + + 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) { data->zen2 = true; |