--- zzzz-none-000/linux-3.10.107/drivers/hwmon/fam15h_power.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/hwmon/fam15h_power.c 2021-02-04 17:41:59.000000000 +0000 @@ -26,14 +26,12 @@ #include #include #include +#include MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); MODULE_AUTHOR("Andreas Herrmann "); MODULE_LICENSE("GPL"); -/* Family 16h Northbridge's function 4 PCI ID */ -#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 - /* D18F3 */ #define REG_NORTHBRIDGE_CAP 0xe8 @@ -44,11 +42,21 @@ #define REG_TDP_RUNNING_AVERAGE 0xe0 #define REG_TDP_LIMIT3 0xe8 +#define FAM15H_MIN_NUM_ATTRS 2 +#define FAM15H_NUM_GROUPS 2 + +#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b + struct fam15h_power_data { - struct device *hwmon_dev; + struct pci_dev *pdev; unsigned int tdp_to_watts; unsigned int base_tdp; unsigned int processor_pwr_watts; + unsigned int cpu_pwr_sample_ratio; + const struct attribute_group *groups[FAM15H_NUM_GROUPS]; + struct attribute_group group; + /* maximum accumulated power of a compute unit */ + u64 max_cu_acc_power; }; static ssize_t show_power(struct device *dev, @@ -57,13 +65,24 @@ u32 val, tdp_limit, running_avg_range; s32 running_avg_capture; u64 curr_pwr_watts; - struct pci_dev *f4 = to_pci_dev(dev); struct fam15h_power_data *data = dev_get_drvdata(dev); + struct pci_dev *f4 = data->pdev; pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), REG_TDP_RUNNING_AVERAGE, &val); - running_avg_capture = (val >> 4) & 0x3fffff; - running_avg_capture = sign_extend32(running_avg_capture, 21); + + /* + * On Carrizo and later platforms, TdpRunAvgAccCap bit field + * is extended to 4:31 from 4:25. + */ + if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60) { + running_avg_capture = val >> 4; + running_avg_capture = sign_extend32(running_avg_capture, 27); + } else { + running_avg_capture = (val >> 4) & 0x3fffff; + running_avg_capture = sign_extend32(running_avg_capture, 21); + } + running_avg_range = (val & 0xf) + 1; pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), @@ -96,25 +115,38 @@ } static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL); -static ssize_t show_name(struct device *dev, - struct device_attribute *attr, char *buf) +static int fam15h_power_init_attrs(struct pci_dev *pdev, + struct fam15h_power_data *data) { - return sprintf(buf, "fam15h_power\n"); -} -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + int n = FAM15H_MIN_NUM_ATTRS; + struct attribute **fam15h_power_attrs; + struct cpuinfo_x86 *c = &boot_cpu_data; + + if (c->x86 == 0x15 && + (c->x86_model <= 0xf || + (c->x86_model >= 0x60 && c->x86_model <= 0x6f))) + n += 1; + + fam15h_power_attrs = devm_kcalloc(&pdev->dev, n, + sizeof(*fam15h_power_attrs), + GFP_KERNEL); -static struct attribute *fam15h_power_attrs[] = { - &dev_attr_power1_input.attr, - &dev_attr_power1_crit.attr, - &dev_attr_name.attr, - NULL -}; + if (!fam15h_power_attrs) + return -ENOMEM; -static const struct attribute_group fam15h_power_attr_group = { - .attrs = fam15h_power_attrs, -}; + n = 0; + fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr; + if (c->x86 == 0x15 && + (c->x86_model <= 0xf || + (c->x86_model >= 0x60 && c->x86_model <= 0x6f))) + fam15h_power_attrs[n++] = &dev_attr_power1_input.attr; + + data->group.attrs = fam15h_power_attrs; + + return 0; +} -static bool fam15h_power_is_internal_node0(struct pci_dev *f4) +static bool should_load_on_this_node(struct pci_dev *f4) { u32 val; @@ -171,11 +203,12 @@ #define fam15h_power_resume NULL #endif -static void fam15h_power_init_data(struct pci_dev *f4, - struct fam15h_power_data *data) +static int fam15h_power_init_data(struct pci_dev *f4, + struct fam15h_power_data *data) { - u32 val; + u32 val, eax, ebx, ecx, edx; u64 tmp; + int ret; pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val); data->base_tdp = val >> 16; @@ -195,14 +228,41 @@ /* convert to microWatt */ data->processor_pwr_watts = (tmp * 15625) >> 10; + + ret = fam15h_power_init_attrs(f4, data); + if (ret) + return ret; + + cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + + /* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */ + if (!(edx & BIT(12))) + return 0; + + /* + * determine the ratio of the compute unit power accumulator + * sample period to the PTSC counter period by executing CPUID + * Fn8000_0007:ECX + */ + data->cpu_pwr_sample_ratio = ecx; + + if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) { + pr_err("Failed to read max compute unit power accumulator MSR\n"); + return -ENODEV; + } + + data->max_cu_acc_power = tmp; + + return 0; } static int fam15h_power_probe(struct pci_dev *pdev, - const struct pci_device_id *id) + const struct pci_device_id *id) { struct fam15h_power_data *data; struct device *dev = &pdev->dev; - int err; + struct device *hwmon_dev; + int ret; /* * though we ignore every other northbridge, we still have to @@ -211,47 +271,33 @@ */ tweak_runavg_range(pdev); - if (!fam15h_power_is_internal_node0(pdev)) + if (!should_load_on_this_node(pdev)) return -ENODEV; data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL); if (!data) return -ENOMEM; - fam15h_power_init_data(pdev, data); - - dev_set_drvdata(dev, data); - err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_group; - } - - return 0; - -exit_remove_group: - sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group); - return err; -} - -static void fam15h_power_remove(struct pci_dev *pdev) -{ - struct device *dev; - struct fam15h_power_data *data; - - dev = &pdev->dev; - data = dev_get_drvdata(dev); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group); + ret = fam15h_power_init_data(pdev, data); + if (ret) + return ret; + + data->pdev = pdev; + + data->groups[0] = &data->group; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power", + data, + &data->groups[0]); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = { +static const struct pci_device_id fam15h_power_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) }, {} }; MODULE_DEVICE_TABLE(pci, fam15h_power_id_table); @@ -260,7 +306,6 @@ .name = "fam15h_power", .id_table = fam15h_power_id_table, .probe = fam15h_power_probe, - .remove = fam15h_power_remove, .resume = fam15h_power_resume, };