#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/cpumask.h>
#include <asm/processor.h>
MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
#define REG_NORTHBRIDGE_CAP 0xe8
#define REG_PROCESSOR_TDP 0x1b8
#define REG_TDP_RUNNING_AVERAGE 0xe0
#define REG_TDP_LIMIT3 0xe8
#define FAM15H_MIN_NUM_ATTRS 2
#define FAM15H_NUM_GROUPS 2
#define MAX_INTERVAL 1000
#define MSR_F15H_CU_PWR_ACCUMULATOR 0xc001007a
#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b
#define MSR_F15H_PTSC 0xc0010280
#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F4 0x15b4
struct fam15h_power_data {
unsigned int tdp_to_watts;
unsigned int processor_pwr_watts;
unsigned int cpu_pwr_sample_ratio;
const struct attribute_group *groups[FAM15H_NUM_GROUPS];
struct attribute_group group;
u64 cu_acc_power[MAX_CUS];
u64 cpu_sw_pwr_ptsc[MAX_CUS];
unsigned long power_period;
static bool is_carrizo_or_later(void)
return boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60;
static ssize_t power1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
u32 val, tdp_limit, running_avg_range;
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);
if (is_carrizo_or_later()) {
running_avg_capture = val >> 4;
running_avg_capture = sign_extend32(running_avg_capture, 27);