>From 9d9f2b330ad635dff9aa141cd96bde2907385032 Mon Sep 17 00:00:00 2001 From: Philby John <pjohn@xxxxxxxxxx> Date: Thu, 7 Jun 2012 12:09:31 +0530 Subject: [PATCH] Octeon 6xxx: Add Power Throttling support for CN6xxx and above This patch adds the sysfs primitives for power throttling. Octeon2 supports dynamic power control which aids to cut down power consumption. The code exposes a "percentage" power throttling limiter by means of /sys interface for each available cpu. Setting this value to 0 will set power consumption to a minimum as it will only execute a couple instructions every PERIOD as set in the PowThrottle register. If set to 100% for that particular cpu, it will consume maximum power. Signed-off-by: Philby John <pjohn@xxxxxxxxxx> --- arch/mips/cavium-octeon/Kconfig | 12 ++ arch/mips/cavium-octeon/Makefile | 1 + arch/mips/cavium-octeon/octeon_pwr_throtl.c | 177 +++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 0 deletions(-) create mode 100644 arch/mips/cavium-octeon/octeon_pwr_throtl.c diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index f9e275a..7a7f7e7 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -97,5 +97,17 @@ config SWIOTLB select IOMMU_HELPER select NEED_SG_DMA_LENGTH +config CAVIUM_POWER_THROTTLING + bool "Enable support for power throttling on Octeon 63xx and above" + depends on CPU_CAVIUM_OCTEON + default n + help + On Octeon 6xxx and above dynamic power can be controlled + by setting the PowThrottle registers for each cpu. This could be + beneficial for lower power consumption requirements. + + If your application makes extensive use of high-energy instructions + (such as Octeon cryptographic accleration) it's better to leave this + option disabled as it may have slight impact on performance. endif # CPU_CAVIUM_OCTEON diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 19eb043..912f9bb 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -15,3 +15,4 @@ obj-y += octeon-memcpy.o obj-y += executive/ obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_CAVIUM_POWER_THROTTLING) += octeon_pwr_throtl.o diff --git a/arch/mips/cavium-octeon/octeon_pwr_throtl.c b/arch/mips/cavium-octeon/octeon_pwr_throtl.c new file mode 100644 index 0000000..6348cc1 --- /dev/null +++ b/arch/mips/cavium-octeon/octeon_pwr_throtl.c @@ -0,0 +1,177 @@ +/* + * octeon_pwr_throtl.c - interface for controlling power throttling on Octeon + * based platforms 6xxx and above. + * Octeon2 supports dynamic power control which aids to cut down power + * consumption. The code exposes a "percentage" power throttling limiter by + * means of /sys interface for each available cpu. Setting this value to 0 + * will set power consumption to a minimum as it will only execute a couple + * instructions every PERIOD as set in the PowThrottle register. + * If set to 100% for that particular cpu; will consume maximum power. + * + * Copyright (C) 2012 MontaVista LLC. + * Author: Philby John <pjohn@xxxxxxxxxx> + * Credits: This driver is derived from Dmitriy Zavin's (dmitriyz@xxxxxxxxxx) + * thermal throttle event support code. + */ + +#include <linux/interrupt.h> +#include <linux/notifier.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/percpu.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/cpu.h> +#include <linux/mutex.h> + +#include <asm/processor.h> +#include <asm/octeon/cvmx-power-throttle.h> + +#define define_pwr_throttle_one_rw(_name) \ + static DEVICE_ATTR(_name, 0644, power_throt_show_##_name, \ + power_throt_store_##_name) \ + +#define define_pwr_throttle_show_func(name) \ + \ +static ssize_t power_throt_show_##name( \ + struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + unsigned int cpu = dev->id; \ + ssize_t ret; \ + \ + preempt_disable(); /* CPU hotplug */ \ + if (cpu_online(cpu)) \ + ret = sprintf(buf, "%d\n", \ + cvmx_power_throttle_get_powlim(cpu)); \ + else \ + ret = 0; \ + preempt_enable(); \ + \ + return ret; \ +} + +#define define_pwr_throttle_store_func(name) \ + \ +static ssize_t power_throt_store_##name( \ + struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, \ + size_t size) \ +{ \ + unsigned int cpu = dev->id; \ + unsigned long val; \ + int error; \ + \ + error = kstrtoul(buf, 0, &val); \ + if (error) \ + return error; \ + \ + preempt_disable(); \ + cvmx_power_throttle(val, cpu); \ + preempt_enable(); \ + \ + return size; \ +} + +define_pwr_throttle_store_func(percentage); +define_pwr_throttle_show_func(percentage); +define_pwr_throttle_one_rw(percentage); + +static struct attribute *pwr_throttle_attrs[] = { + &dev_attr_percentage.attr, + NULL +}; + +static struct attribute_group pwr_throttle_attr_group = { + .attrs = pwr_throttle_attrs, + .name = "power_throttle" +}; + +#ifdef CONFIG_SYSFS + +/* Mutex protecting device creation against CPU hotplug: */ +static DEFINE_MUTEX(pwr_throttl_cpu_lock); + +static __cpuinit int power_throttle_add_dev(struct device *dev) +{ + int err; + + err = sysfs_create_group(&dev->kobj, &pwr_throttle_attr_group); + if (err) + return err; + err = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_percentage.attr, + pwr_throttle_attr_group.name); + return err; +} + +static __cpuinit void power_throttle_remove_dev(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &pwr_throttle_attr_group); +} + +static __cpuinit int +power_throttle_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct device *dev; + int err = 0; + + dev = get_cpu_device(cpu); + + switch (action) { + case CPU_ONLINE: + case CPU_DOWN_FAILED: + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + mutex_lock(&pwr_throttl_cpu_lock); + err = power_throttle_add_dev(dev); + mutex_unlock(&pwr_throttl_cpu_lock); + WARN_ON(err); + break; + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + case CPU_DEAD: + case CPU_DEAD_FROZEN: + case CPU_DOWN_PREPARE: + mutex_lock(&pwr_throttl_cpu_lock); + power_throttle_remove_dev(dev); + mutex_unlock(&pwr_throttl_cpu_lock); + break; + } + return err ? NOTIFY_BAD : NOTIFY_OK; +} + +static struct notifier_block power_throttle_cpu_notifier = { + .notifier_call = power_throttle_cpu_callback, +}; + +static __init int power_throtl_init(void) +{ + unsigned int cpu = 0; + int err; + + register_hotcpu_notifier(&power_throttle_cpu_notifier); + +#ifdef CONFIG_HOTPLUG_CPU + mutex_lock(&pwr_throttl_cpu_lock); +#endif + /* connect live CPUs to sysfs */ + for_each_online_cpu(cpu) { + err = power_throttle_add_dev(get_cpu_device(cpu)); + WARN_ON(err); + cvmx_init_throttle_feedback(cpu); + } +#ifdef CONFIG_HOTPLUG_CPU + mutex_unlock(&pwr_throttl_cpu_lock); +#endif + return 0; +} +device_initcall(power_throtl_init); + +#endif -- 1.6.3.3.338.ge89ce