From 6c1caca70063aa707ba809a6b4695d0f0c5646f1 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Thu, 27 Feb 2020 15:57:13 -0800 Subject: Update to internal 2020-02-27 Signed-off-by: Jason M. Bills --- .../linux-aspeed/0090-peci-cpupower-driver-1.patch | 405 +++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch') diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch new file mode 100644 index 000000000..475e9611f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch @@ -0,0 +1,405 @@ +From e40f7d10d5306c075e2fc7e538ce1efc70eeb448 Mon Sep 17 00:00:00 2001 +From: ZhikuiRen +Date: Thu, 9 Jan 2020 10:48:00 -0800 +Subject: [PATCH] Add peci-cpupower driver + +peci-cpupower reads CPU energy counter through peci +and computes average power in mW since last read. + +Signed-off-by: ZhikuiRen +--- + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/peci-cpupower.rst | 52 ++++++++ + arch/arm/configs/aspeed_g5_defconfig | 1 + + drivers/hwmon/Kconfig | 14 +++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/peci-cpupower.c | 231 ++++++++++++++++++++++++++++++++++ + drivers/mfd/intel-peci-client.c | 1 + + include/uapi/linux/peci-ioctl.h | 1 + + 8 files changed, 302 insertions(+) + create mode 100644 Documentation/hwmon/peci-cpupower.rst + create mode 100644 drivers/hwmon/peci-cpupower.c + +diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst +index 7d894c9..0bde0ef 100644 +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -130,6 +130,7 @@ Hardware Monitoring Kernel Drivers + pcf8591 + peci-cputemp + peci-dimmtemp ++ peci-cpupower + pmbus + powr1220 + pxe1610 +diff --git a/Documentation/hwmon/peci-cpupower.rst b/Documentation/hwmon/peci-cpupower.rst +new file mode 100644 +index 0000000..4d7bd61 +--- /dev/null ++++ b/Documentation/hwmon/peci-cpupower.rst +@@ -0,0 +1,52 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver peci-cpupower ++========================== ++ ++:Copyright: |copy| 2018-2020 Intel Corporation ++ ++Supported chips: ++ One of Intel server CPUs listed below which is connected to a PECI bus. ++ * Intel Xeon E5/E7 v3 server processors ++ Intel Xeon E5-14xx v3 family ++ Intel Xeon E5-24xx v3 family ++ Intel Xeon E5-16xx v3 family ++ Intel Xeon E5-26xx v3 family ++ Intel Xeon E5-46xx v3 family ++ Intel Xeon E7-48xx v3 family ++ Intel Xeon E7-88xx v3 family ++ * Intel Xeon E5/E7 v4 server processors ++ Intel Xeon E5-16xx v4 family ++ Intel Xeon E5-26xx v4 family ++ Intel Xeon E5-46xx v4 family ++ Intel Xeon E7-48xx v4 family ++ Intel Xeon E7-88xx v4 family ++ * Intel Xeon Scalable server processors ++ Intel Xeon D family ++ Intel Xeon Bronze family ++ Intel Xeon Silver family ++ Intel Xeon Gold family ++ Intel Xeon Platinum family ++ ++ Addresses scanned: PECI client address 0x30 - 0x37 ++ Datasheet: Available from http://www.intel.com/design/literature.htm ++ ++Author: ++ Zhikui Ren ++ ++Description ++----------- ++ ++This driver implements a generic PECI hwmon feature which provides ++average power consumption readings of the CPU package based on energy counter ++accessible using the PECI Client Command Suite via the processor PECI client. ++ ++Power values are average power since last measure given in milli Watt and ++will be measurable only when the target CPU is powered on. ++ ++``sysfs`` interface ++------------------- ++======================= ======================================================= ++power1_average Provides average power since last read in milli Watt. ++power1_label Provides string "Average Power". ++======================= ======================================================= +diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig +index 1e589a0..0e50040 100644 +--- a/arch/arm/configs/aspeed_g5_defconfig ++++ b/arch/arm/configs/aspeed_g5_defconfig +@@ -177,6 +177,7 @@ CONFIG_SENSORS_OCC_P8_I2C=y + CONFIG_SENSORS_OCC_P9_SBE=y + CONFIG_SENSORS_PECI_CPUTEMP=y + CONFIG_SENSORS_PECI_DIMMTEMP=y ++CONFIG_SENSORS_PECI_CPUPOWER=y + CONFIG_PMBUS=y + CONFIG_SENSORS_ADM1275=y + CONFIG_SENSORS_IBM_CFFPS=y +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 8312b37..07d8826 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1361,6 +1361,20 @@ config SENSORS_PECI_DIMMTEMP + This driver can also be built as a module. If so, the module + will be called peci-dimmtemp. + ++config SENSORS_PECI_CPUPOWER ++ tristate "PECI CPU power monitoring support" ++ depends on PECI ++ select MFD_INTEL_PECI_CLIENT ++ help ++ If you say yes here you get support for the generic Intel PECI ++ cputemp driver which provides average engergy ++ readings of the CPU package using ++ the PECI Client Command Suite via the processor PECI client. ++ Check Documentation/hwmon/peci-cpupower for details. ++ ++ This driver can also be built as a module. If so, the module ++ will be called peci-cpupower. ++ + source "drivers/hwmon/pmbus/Kconfig" + + config SENSORS_PWM_FAN +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index e74ea92..fab43fd 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -144,6 +144,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o + obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o + obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o + obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o ++obj-$(CONFIG_SENSORS_PECI_CPUPOWER) += peci-cpupower.o + obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o + obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o +diff --git a/drivers/hwmon/peci-cpupower.c b/drivers/hwmon/peci-cpupower.c +new file mode 100644 +index 0000000..6907696 +--- /dev/null ++++ b/drivers/hwmon/peci-cpupower.c +@@ -0,0 +1,231 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2020 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "peci-hwmon.h" ++ ++#define POWER_DEFAULT_CHANNEL_NUMS 1 ++ ++struct peci_cpupower { ++ struct peci_client_manager *mgr; ++ struct device *dev; ++ char name[PECI_NAME_SIZE]; ++ const struct cpu_gen_info *gen_info; ++ struct peci_sensor_data energy; ++ long avg_power_val; ++ u64 core_mask; ++ u32 power_config[POWER_DEFAULT_CHANNEL_NUMS + 1]; ++ uint config_idx; ++ struct hwmon_channel_info power_info; ++ const struct hwmon_channel_info *info[2]; ++ struct hwmon_chip_info chip; ++}; ++ ++enum cpupower_channels { ++ average_power, ++}; ++ ++static const u32 config_table[POWER_DEFAULT_CHANNEL_NUMS] = { ++ /* average power */ ++ HWMON_P_LABEL | HWMON_P_AVERAGE, ++}; ++ ++static const char *cpupower_label[POWER_DEFAULT_CHANNEL_NUMS] = { ++ "Average Power", ++}; ++ ++static int get_average_power(struct peci_cpupower *priv) ++{ ++ u8 pkg_cfg[4]; ++ int ret; ++ ++ if (!peci_sensor_need_update(&priv->energy)) ++ return 0; ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_TDP_UNITS, ++ PECI_PKG_ID_PKG_ENERGY_STATUS, ++ pkg_cfg); ++ ++ u32 power_unit = ((le32_to_cpup((__le32 *)pkg_cfg)) & 0x1f00) >> 8; ++ ++ dev_dbg(priv->dev, "cpupower units %d (1J/pow(2, unit))\n", ++ power_unit); ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_ENERGY_COUNTER, ++ PECI_PKG_ID_PKG_ENERGY_STATUS, ++ pkg_cfg); ++ if (!ret) { ++ u32 energy_cnt = le32_to_cpup((__le32 *)pkg_cfg); ++ ulong jif = jiffies; ++ ulong elapsed = (jif - priv->energy.last_updated); ++ long power_val = 0; ++ /* ++ * Don't calculate average power for first counter read or ++ * counter wrapped around or last counter read was more than ++ * 60 minutes ago (jiffies did not wrap and power calculation ++ * does not overflow or underflow ++ */ ++ if (priv->energy.last_updated > 0 && ++ energy_cnt > priv->energy.value && ++ (elapsed < (HZ * 3600))) { ++ power_val = (long)(energy_cnt - priv->energy.value) ++ / elapsed * HZ; ++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, raw powerValue %d scale to %d mW\n", ++ (long)(energy_cnt - priv->energy.value), ++ elapsed, power_val, ++ power_val >> (power_unit - 10)); ++ } else { ++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, skipping calculate power, try agin\n", ++ (long)(energy_cnt - priv->energy.value), ++ elapsed); ++ ret = -EAGAIN; ++ } ++ ++ priv->energy.value = energy_cnt; ++ priv->avg_power_val = power_val >> ((power_unit - 10)); ++ peci_sensor_mark_updated(&priv->energy); ++ ++ dev_dbg(priv->dev, "energy counter 0x%8x, average power %dmW, jif %u, HZ is %d jiffies\n", ++ priv->energy.value, priv->avg_power_val, ++ jif, HZ); ++ } ++ return ret; ++} ++ ++static int cpupower_read_string(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ if (attr != hwmon_power_label) ++ return -EOPNOTSUPP; ++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS) ++ return -EOPNOTSUPP; ++ *str = cpupower_label[channel]; ++ ++ return 0; ++} ++ ++static int cpupower_read(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct peci_cpupower *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS || ++ !(priv->power_config[channel] & BIT(attr))) ++ return -EOPNOTSUPP; ++ ++ switch (attr) { ++ case hwmon_power_average: ++ switch (channel) { ++ case average_power: ++ ret = get_average_power(priv); ++ if (ret) ++ break; ++ ++ *val = priv->avg_power_val; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} ++ ++static umode_t cpupower_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct peci_cpupower *priv = data; ++ ++ if (channel < POWER_DEFAULT_CHANNEL_NUMS || ++ (priv->power_config[channel] & BIT(attr))) ++ return 0444; ++ ++ return 0; ++} ++ ++static const struct hwmon_ops cpupower_ops = { ++ .is_visible = cpupower_is_visible, ++ .read_string = cpupower_read_string, ++ .read = cpupower_read, ++}; ++ ++static int peci_cpupower_probe(struct platform_device *pdev) ++{ ++ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); ++ struct device *dev = &pdev->dev; ++ struct peci_cpupower *priv; ++ struct device *hwmon_dev; ++ ++ if ((mgr->client->adapter->cmd_mask & ++ (BIT(PECI_CMD_RD_PKG_CFG))) != ++ (BIT(PECI_CMD_RD_PKG_CFG))) { ++ return -ENODEV; ++ } ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ priv->mgr = mgr; ++ priv->dev = dev; ++ priv->gen_info = mgr->gen_info; ++ ++ snprintf(priv->name, PECI_NAME_SIZE, "peci_cpupower.cpu%d", ++ mgr->client->addr - PECI_BASE_ADDR); ++ ++ priv->power_config[priv->config_idx++] = config_table[average_power]; ++ ++ priv->chip.ops = &cpupower_ops; ++ priv->chip.info = priv->info; ++ ++ priv->info[0] = &priv->power_info; ++ ++ priv->power_info.type = hwmon_power; ++ priv->power_info.config = priv->power_config; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, ++ priv->name, ++ priv, ++ &priv->chip, ++ NULL); ++ ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name); ++ ++ return 0; ++} ++ ++static const struct platform_device_id peci_cpupower_ids[] = { ++ { .name = "peci-cpupower", .driver_data = 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(platform, peci_cpupower_ids); ++ ++static struct platform_driver peci_cpupower_driver = { ++ .probe = peci_cpupower_probe, ++ .id_table = peci_cpupower_ids, ++ .driver = { .name = KBUILD_MODNAME, }, ++}; ++module_platform_driver(peci_cpupower_driver); ++ ++MODULE_AUTHOR("Zhikui Ren "); ++MODULE_DESCRIPTION("PECI cpupower driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c +index 9751b04..0c62ad6 100644 +--- a/drivers/mfd/intel-peci-client.c ++++ b/drivers/mfd/intel-peci-client.c +@@ -21,6 +21,7 @@ + static struct mfd_cell peci_functions[] = { + { .name = "peci-cputemp", }, + { .name = "peci-dimmtemp", }, ++ { .name = "peci-cpupower", }, + }; + + static const struct cpu_gen_info cpu_gen_info_table[] = { +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index 843930f..d16f7c9 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -231,6 +231,7 @@ struct peci_rd_pkg_cfg_msg { + #define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ + #define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ + #define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ ++#define PECI_PKG_ID_PKG_ENERGY_STATUS 0x00ff /* Average Energy */ + + __u8 rx_len; + __u8 cc; +-- +2.7.4 + -- cgit v1.2.3