Merge branches 'acpica', 'bgrt', 'bz-11533', 'cpuidle', 'ec', 'hotplug', 'misc', 'red-hat-bz-727865', 'thermal', 'throttling', 'turbostat' and 'video' into release

Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
45 changed files with 1212 additions and 491 deletions

View File

@ -1,3 +1,23 @@
What: /sys/firmware/acpi/bgrt/
Date: January 2012
Contact: Matthew Garrett <mjg@redhat.com>
Description:
The BGRT is an ACPI 5.0 feature that allows the OS
to obtain a copy of the firmware boot splash and
some associated metadata. This is intended to be used
by boot splash applications in order to interact with
the firmware boot splash in order to avoid jarring
transitions.
image: The image bitmap. Currently a 32-bit BMP.
status: 1 if the image is valid, 0 if firmware invalidated it.
type: 0 indicates image is in BMP format.
version: The version of the BGRT. Currently 1.
xoffset: The number of pixels between the left of the screen
and the left edge of the image.
yoffset: The number of pixels between the top of the screen
and the top edge of the image.
What: /sys/firmware/acpi/interrupts/ What: /sys/firmware/acpi/interrupts/
Date: February 2008 Date: February 2008
Contact: Len Brown <lenb@kernel.org> Contact: Len Brown <lenb@kernel.org>

View File

@ -36,6 +36,7 @@ drwxr-xr-x 2 root root 0 Feb 8 10:42 state3
/sys/devices/system/cpu/cpu0/cpuidle/state0: /sys/devices/system/cpu/cpu0/cpuidle/state0:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
@ -45,6 +46,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state1: /sys/devices/system/cpu/cpu0/cpuidle/state1:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
@ -54,6 +56,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state2: /sys/devices/system/cpu/cpu0/cpuidle/state2:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
@ -63,6 +66,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state3: /sys/devices/system/cpu/cpu0/cpuidle/state3:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
@ -72,6 +76,7 @@ total 0
* desc : Small description about the idle state (string) * desc : Small description about the idle state (string)
* disable : Option to disable this idle state (bool)
* latency : Latency to exit out of this idle state (in microseconds) * latency : Latency to exit out of this idle state (in microseconds)
* name : Name of the idle state (string) * name : Name of the idle state (string)
* power : Power consumed while in this idle state (in milliwatts) * power : Power consumed while in this idle state (in milliwatts)

View File

@ -0,0 +1,29 @@
#ifndef __ASM_ARM_CPUIDLE_H
#define __ASM_ARM_CPUIDLE_H
#ifdef CONFIG_CPU_IDLE
extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
#else
static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) { return -ENODEV; }
#endif
/* Common ARM WFI state */
#define ARM_CPUIDLE_WFI_STATE_PWR(p) {\
.enter = arm_cpuidle_simple_enter,\
.exit_latency = 1,\
.target_residency = 1,\
.power_usage = p,\
.flags = CPUIDLE_FLAG_TIME_VALID,\
.name = "WFI",\
.desc = "ARM WFI",\
}
/*
* in case power_specified == 1, give a default WFI power value needed
* by some governors
*/
#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX)
#endif

View File

@ -21,7 +21,7 @@ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_OC_ETM) += etm.o obj-$(CONFIG_OC_ETM) += etm.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_ARCH_ACORN) += ecard.o
obj-$(CONFIG_FIQ) += fiq.o fiqasm.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o

21
arch/arm/kernel/cpuidle.c Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright 2012 Linaro Ltd.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/cpuidle.h>
#include <asm/proc-fns.h>
int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
cpu_do_idle();
return index;
}

View File

@ -17,9 +17,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/cpuidle.h> #include <linux/cpuidle.h>
#include <asm/proc-fns.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/export.h> #include <linux/export.h>
#include <asm/proc-fns.h>
#include <asm/cpuidle.h>
#include "pm.h" #include "pm.h"
@ -27,66 +28,46 @@
static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device); static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
static struct cpuidle_driver at91_idle_driver = {
.name = "at91_idle",
.owner = THIS_MODULE,
};
/* Actual code that puts the SoC in different idle states */ /* Actual code that puts the SoC in different idle states */
static int at91_enter_idle(struct cpuidle_device *dev, static int at91_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
int index) int index)
{ {
struct timeval before, after;
int idle_time;
u32 saved_lpr; u32 saved_lpr;
local_irq_disable(); __asm__("b 1f; .align 5; 1:\n"
do_gettimeofday(&before); " mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */
if (index == 0)
/* Wait for interrupt state */ saved_lpr = sdram_selfrefresh_enable();
cpu_do_idle(); cpu_do_idle();
else if (index == 1) { sdram_selfrefresh_disable(saved_lpr);
asm("b 1f; .align 5; 1:");
asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */
saved_lpr = sdram_selfrefresh_enable();
cpu_do_idle();
sdram_selfrefresh_disable(saved_lpr);
}
do_gettimeofday(&after);
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
dev->last_residency = idle_time;
return index; return index;
} }
static struct cpuidle_driver at91_idle_driver = {
.name = "at91_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = at91_enter_idle,
.exit_latency = 10,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "RAM_SR",
.desc = "WFI and DDR Self Refresh",
},
.state_count = AT91_MAX_STATES,
};
/* Initialize CPU idle by registering the idle states */ /* Initialize CPU idle by registering the idle states */
static int at91_init_cpuidle(void) static int at91_init_cpuidle(void)
{ {
struct cpuidle_device *device; struct cpuidle_device *device;
struct cpuidle_driver *driver = &at91_idle_driver;
device = &per_cpu(at91_cpuidle_device, smp_processor_id()); device = &per_cpu(at91_cpuidle_device, smp_processor_id());
device->state_count = AT91_MAX_STATES; device->state_count = AT91_MAX_STATES;
driver->state_count = AT91_MAX_STATES;
/* Wait for interrupt state */
driver->states[0].enter = at91_enter_idle;
driver->states[0].exit_latency = 1;
driver->states[0].target_residency = 10000;
driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[0].name, "WFI");
strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and RAM self refresh state */
driver->states[1].enter = at91_enter_idle;
driver->states[1].exit_latency = 10;
driver->states[1].target_residency = 10000;
driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[1].name, "RAM_SR");
strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
cpuidle_register_driver(&at91_idle_driver); cpuidle_register_driver(&at91_idle_driver);

View File

@ -18,6 +18,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/export.h> #include <linux/export.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/cpuidle.h>
#include <mach/cpuidle.h> #include <mach/cpuidle.h>
#include <mach/ddr2.h> #include <mach/ddr2.h>
@ -30,12 +31,43 @@ struct davinci_ops {
u32 flags; u32 flags;
}; };
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
if (ops && ops->enter)
ops->enter(ops->flags);
index = cpuidle_wrap_enter(dev, drv, index,
arm_cpuidle_simple_enter);
if (ops && ops->exit)
ops->exit(ops->flags);
return index;
}
/* fields in davinci_ops.flags */ /* fields in davinci_ops.flags */
#define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0) #define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0)
static struct cpuidle_driver davinci_idle_driver = { static struct cpuidle_driver davinci_idle_driver = {
.name = "cpuidle-davinci", .name = "cpuidle-davinci",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = davinci_enter_idle,
.exit_latency = 10,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "DDR SR",
.desc = "WFI and DDR Self Refresh",
},
.state_count = DAVINCI_CPUIDLE_MAX_STATES,
}; };
static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
@ -77,41 +109,10 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
}, },
}; };
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
struct timeval before, after;
int idle_time;
local_irq_disable();
do_gettimeofday(&before);
if (ops && ops->enter)
ops->enter(ops->flags);
/* Wait for interrupt state */
cpu_do_idle();
if (ops && ops->exit)
ops->exit(ops->flags);
do_gettimeofday(&after);
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
dev->last_residency = idle_time;
return index;
}
static int __init davinci_cpuidle_probe(struct platform_device *pdev) static int __init davinci_cpuidle_probe(struct platform_device *pdev)
{ {
int ret; int ret;
struct cpuidle_device *device; struct cpuidle_device *device;
struct cpuidle_driver *driver = &davinci_idle_driver;
struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
@ -123,27 +124,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ddr2_reg_base = pdata->ddr2_ctlr_base; ddr2_reg_base = pdata->ddr2_ctlr_base;
/* Wait for interrupt state */
driver->states[0].enter = davinci_enter_idle;
driver->states[0].exit_latency = 1;
driver->states[0].target_residency = 10000;
driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[0].name, "WFI");
strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and DDR self refresh state */
driver->states[1].enter = davinci_enter_idle;
driver->states[1].exit_latency = 10;
driver->states[1].target_residency = 10000;
driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[1].name, "DDR SR");
strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
if (pdata->ddr2_pdown) if (pdata->ddr2_pdown)
davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]); cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
device->state_count = DAVINCI_CPUIDLE_MAX_STATES; device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
ret = cpuidle_register_driver(&davinci_idle_driver); ret = cpuidle_register_driver(&davinci_idle_driver);
if (ret) { if (ret) {

View File

@ -20,77 +20,47 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/export.h> #include <linux/export.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/cpuidle.h>
#include <mach/kirkwood.h> #include <mach/kirkwood.h>
#define KIRKWOOD_MAX_STATES 2 #define KIRKWOOD_MAX_STATES 2
static struct cpuidle_driver kirkwood_idle_driver = {
.name = "kirkwood_idle",
.owner = THIS_MODULE,
};
static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Actual code that puts the SoC in different idle states */ /* Actual code that puts the SoC in different idle states */
static int kirkwood_enter_idle(struct cpuidle_device *dev, static int kirkwood_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
int index) int index)
{ {
struct timeval before, after; writel(0x7, DDR_OPERATION_BASE);
int idle_time; cpu_do_idle();
local_irq_disable();
do_gettimeofday(&before);
if (index == 0)
/* Wait for interrupt state */
cpu_do_idle();
else if (index == 1) {
/*
* Following write will put DDR in self refresh.
* Note that we have 256 cycles before DDR puts it
* self in self-refresh, so the wait-for-interrupt
* call afterwards won't get the DDR from self refresh
* mode.
*/
writel(0x7, DDR_OPERATION_BASE);
cpu_do_idle();
}
do_gettimeofday(&after);
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
/* Update last residency */
dev->last_residency = idle_time;
return index; return index;
} }
static struct cpuidle_driver kirkwood_idle_driver = {
.name = "kirkwood_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = kirkwood_enter_idle,
.exit_latency = 10,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "DDR SR",
.desc = "WFI and DDR Self Refresh",
},
.state_count = KIRKWOOD_MAX_STATES,
};
static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Initialize CPU idle by registering the idle states */ /* Initialize CPU idle by registering the idle states */
static int kirkwood_init_cpuidle(void) static int kirkwood_init_cpuidle(void)
{ {
struct cpuidle_device *device; struct cpuidle_device *device;
struct cpuidle_driver *driver = &kirkwood_idle_driver;
device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
device->state_count = KIRKWOOD_MAX_STATES; device->state_count = KIRKWOOD_MAX_STATES;
driver->state_count = KIRKWOOD_MAX_STATES;
/* Wait for interrupt state */
driver->states[0].enter = kirkwood_enter_idle;
driver->states[0].exit_latency = 1;
driver->states[0].target_residency = 10000;
driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[0].name, "WFI");
strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and DDR self refresh state */
driver->states[1].enter = kirkwood_enter_idle;
driver->states[1].exit_latency = 10;
driver->states[1].target_residency = 10000;
driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
strcpy(driver->states[1].name, "DDR SR");
strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
cpuidle_register_driver(&kirkwood_idle_driver); cpuidle_register_driver(&kirkwood_idle_driver);
if (cpuidle_register_device(device)) { if (cpuidle_register_device(device)) {

View File

@ -87,29 +87,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
return 0; return 0;
} }
/** static int __omap3_enter_idle(struct cpuidle_device *dev,
* omap3_enter_idle - Programs OMAP3 to enter the specified state
* @dev: cpuidle device
* @drv: cpuidle driver
* @index: the index of state to be entered
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
*/
static int omap3_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
int index) int index)
{ {
struct omap3_idle_statedata *cx = struct omap3_idle_statedata *cx =
cpuidle_get_statedata(&dev->states_usage[index]); cpuidle_get_statedata(&dev->states_usage[index]);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state; u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
int idle_time;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
local_irq_disable();
local_fiq_disable(); local_fiq_disable();
pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(mpu_pd, mpu_state);
@ -148,21 +133,28 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
} }
return_sleep_time: return_sleep_time:
getnstimeofday(&ts_postidle);
ts_idle = timespec_sub(ts_postidle, ts_preidle);
local_irq_enable();
local_fiq_enable(); local_fiq_enable();
idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
USEC_PER_SEC;
/* Update cpuidle counters */
dev->last_residency = idle_time;
return index; return index;
} }
/**
* omap3_enter_idle - Programs OMAP3 to enter the specified state
* @dev: cpuidle device
* @drv: cpuidle driver
* @index: the index of state to be entered
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
*/
static inline int omap3_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
return cpuidle_wrap_enter(dev, drv, index, __omap3_enter_idle);
}
/** /**
* next_valid_state - Find next valid C-state * next_valid_state - Find next valid C-state
* @dev: cpuidle device * @dev: cpuidle device

View File

@ -62,15 +62,9 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
{ {
struct omap4_idle_statedata *cx = struct omap4_idle_statedata *cx =
cpuidle_get_statedata(&dev->states_usage[index]); cpuidle_get_statedata(&dev->states_usage[index]);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 cpu1_state; u32 cpu1_state;
int idle_time;
int cpu_id = smp_processor_id(); int cpu_id = smp_processor_id();
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
local_irq_disable();
local_fiq_disable(); local_fiq_disable();
/* /*
@ -128,26 +122,17 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
if (index > 0) if (index > 0)
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
getnstimeofday(&ts_postidle);
ts_idle = timespec_sub(ts_postidle, ts_preidle);
local_irq_enable();
local_fiq_enable(); local_fiq_enable();
idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
USEC_PER_SEC;
/* Update cpuidle counters */
dev->last_residency = idle_time;
return index; return index;
} }
DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
struct cpuidle_driver omap4_idle_driver = { struct cpuidle_driver omap4_idle_driver = {
.name = "omap4_idle", .name = "omap4_idle",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.en_core_tk_irqen = 1,
}; };
static inline void _fill_cstate(struct cpuidle_driver *drv, static inline void _fill_cstate(struct cpuidle_driver *drv,

View File

@ -14,6 +14,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/cpuidle.h>
#include <asm/io.h> #include <asm/io.h>
static void shmobile_enter_wfi(void) static void shmobile_enter_wfi(void)
@ -29,37 +30,19 @@ static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
int index) int index)
{ {
ktime_t before, after;
before = ktime_get();
local_irq_disable();
local_fiq_disable();
shmobile_cpuidle_modes[index](); shmobile_cpuidle_modes[index]();
local_irq_enable();
local_fiq_enable();
after = ktime_get();
dev->last_residency = ktime_to_ns(ktime_sub(after, before)) >> 10;
return index; return index;
} }
static struct cpuidle_device shmobile_cpuidle_dev; static struct cpuidle_device shmobile_cpuidle_dev;
static struct cpuidle_driver shmobile_cpuidle_driver = { static struct cpuidle_driver shmobile_cpuidle_driver = {
.name = "shmobile_cpuidle", .name = "shmobile_cpuidle",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.states[0] = { .en_core_tk_irqen = 1,
.name = "C1", .states[0] = ARM_CPUIDLE_WFI_STATE,
.desc = "WFI", .safe_state_index = 0, /* C1 */
.exit_latency = 1, .state_count = 1,
.target_residency = 1 * 2,
.flags = CPUIDLE_FLAG_TIME_VALID,
},
.safe_state_index = 0, /* C1 */
.state_count = 1,
}; };
void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv); void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);

View File

@ -29,7 +29,6 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
int index) int index)
{ {
unsigned long allowed_mode = SUSP_SH_SLEEP; unsigned long allowed_mode = SUSP_SH_SLEEP;
ktime_t before, after;
int requested_state = index; int requested_state = index;
int allowed_state; int allowed_state;
int k; int k;
@ -47,19 +46,16 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
*/ */
k = min_t(int, allowed_state, requested_state); k = min_t(int, allowed_state, requested_state);
before = ktime_get();
sh_mobile_call_standby(cpuidle_mode[k]); sh_mobile_call_standby(cpuidle_mode[k]);
after = ktime_get();
dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
return k; return k;
} }
static struct cpuidle_device cpuidle_dev; static struct cpuidle_device cpuidle_dev;
static struct cpuidle_driver cpuidle_driver = { static struct cpuidle_driver cpuidle_driver = {
.name = "sh_idle", .name = "sh_idle",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.en_core_tk_irqen = 1,
}; };
void sh_mobile_setup_cpuidle(void) void sh_mobile_setup_cpuidle(void)

View File

@ -642,6 +642,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
kfree(buffer.pointer); kfree(buffer.pointer);
buffer.length = ACPI_ALLOCATE_BUFFER; buffer.length = ACPI_ALLOCATE_BUFFER;
buffer.pointer = NULL; buffer.pointer = NULL;
lapic = NULL;
if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL)) if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
goto out; goto out;
@ -650,7 +651,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
goto free_tmp_map; goto free_tmp_map;
cpumask_copy(tmp_map, cpu_present_mask); cpumask_copy(tmp_map, cpu_present_mask);
acpi_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED); acpi_register_lapic(physid, ACPI_MADT_ENABLED);
/* /*
* If mp_register_lapic successfully generates a new logical cpu * If mp_register_lapic successfully generates a new logical cpu

View File

@ -50,6 +50,7 @@
#include <linux/tboot.h> #include <linux/tboot.h>
#include <linux/stackprotector.h> #include <linux/stackprotector.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/cpuidle.h>
#include <asm/acpi.h> #include <asm/acpi.h>
#include <asm/desc.h> #include <asm/desc.h>
@ -1422,7 +1423,8 @@ void native_play_dead(void)
tboot_shutdown(TB_SHUTDOWN_WFS); tboot_shutdown(TB_SHUTDOWN_WFS);
mwait_play_dead(); /* Only returns on failure */ mwait_play_dead(); /* Only returns on failure */
hlt_play_dead(); if (cpuidle_play_dead())
hlt_play_dead();
} }
#else /* ... !CONFIG_HOTPLUG_CPU */ #else /* ... !CONFIG_HOTPLUG_CPU */

View File

@ -384,6 +384,15 @@ config ACPI_CUSTOM_METHOD
load additional kernel modules after boot, this feature may be used load additional kernel modules after boot, this feature may be used
to override that restriction). to override that restriction).
config ACPI_BGRT
tristate "Boottime Graphics Resource Table support"
default n
help
This driver adds support for exposing the ACPI Boottime Graphics
Resource Table, which allows the operating system to obtain
data from the firmware boot splash. It will appear under
/sys/firmware/acpi/bgrt/ .
source "drivers/acpi/apei/Kconfig" source "drivers/acpi/apei/Kconfig"
endif # ACPI endif # ACPI

View File

@ -62,6 +62,7 @@ obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_HED) += hed.o obj-$(CONFIG_ACPI_HED) += hed.o
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
# processor has its own "processor." module_param namespace # processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o processor-y := processor_driver.o processor_throttling.o

View File

@ -74,8 +74,7 @@ acpi_status acpi_reset(void)
/* Check if the reset register is supported */ /* Check if the reset register is supported */
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || if (!reset_reg->address) {
!reset_reg->address) {
return_ACPI_STATUS(AE_NOT_EXIST); return_ACPI_STATUS(AE_NOT_EXIST);
} }

View File

@ -363,10 +363,6 @@ static void acpi_tb_convert_fadt(void)
u32 address32; u32 address32;
u32 i; u32 i;
/* Update the local FADT table header length */
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
/* /*
* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary.
* Later code will always use the X 64-bit field. Also, check for an * Later code will always use the X 64-bit field. Also, check for an
@ -408,6 +404,10 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.boot_flags = 0; acpi_gbl_FADT.boot_flags = 0;
} }
/* Update the local FADT table header length */
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
/* /*
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
* generic address structures as necessary. Later code will always use * generic address structures as necessary. Later code will always use

175
drivers/acpi/bgrt.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright 2012 Red Hat, Inc <mjg@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
static struct acpi_table_bgrt *bgrt_tab;
static struct kobject *bgrt_kobj;
struct bmp_header {
u16 id;
u32 size;
} __attribute ((packed));
static struct bmp_header bmp_header;
static ssize_t show_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version);
}
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t show_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status);
}
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
static ssize_t show_type(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type);
}
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static ssize_t show_xoffset(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x);
}
static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL);
static ssize_t show_yoffset(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y);
}
static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
static ssize_t show_image(struct file *file, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
int size = attr->size;
void __iomem *image = attr->private;
if (off >= size) {
count = 0;
} else {
if (off + count > size)
count = size - off;
memcpy_fromio(buf, image+off, count);
}
return count;
}
static struct bin_attribute image_attr = {
.attr = {
.name = "image",
.mode = S_IRUGO,
},
.read = show_image,
};
static struct attribute *bgrt_attributes[] = {
&dev_attr_version.attr,
&dev_attr_status.attr,
&dev_attr_type.attr,
&dev_attr_xoffset.attr,
&dev_attr_yoffset.attr,
NULL,
};
static struct attribute_group bgrt_attribute_group = {
.attrs = bgrt_attributes,
};
static int __init bgrt_init(void)
{
acpi_status status;
int ret;
void __iomem *bgrt;
if (acpi_disabled)
return -ENODEV;
status = acpi_get_table("BGRT", 0,
(struct acpi_table_header **)&bgrt_tab);
if (ACPI_FAILURE(status))
return -ENODEV;
sysfs_bin_attr_init(&image_attr);
bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header));
if (!bgrt) {
ret = -EINVAL;
goto out_err;
}
memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header));
image_attr.size = bmp_header.size;
iounmap(bgrt);
image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size);
if (!image_attr.private) {
ret = -EINVAL;
goto out_err;
}
bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
if (!bgrt_kobj) {
ret = -EINVAL;
goto out_iounmap;
}
ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group);
if (ret)
goto out_kobject;
ret = sysfs_create_bin_file(bgrt_kobj, &image_attr);
if (ret)
goto out_group;
return 0;
out_group:
sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
out_kobject:
kobject_put(bgrt_kobj);
out_iounmap:
iounmap(image_attr.private);
out_err:
return ret;
}
static void __exit bgrt_exit(void)
{
iounmap(image_attr.private);
sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
sysfs_remove_bin_file(bgrt_kobj, &image_attr);
}
module_init(bgrt_init);
module_exit(bgrt_exit);
MODULE_AUTHOR("Matthew Garrett");
MODULE_DESCRIPTION("BGRT boot graphic support");
MODULE_LICENSE("GPL");

View File

@ -1010,6 +1010,7 @@ static int __init acpi_bus_init(void)
} }
struct kobject *acpi_kobj; struct kobject *acpi_kobj;
EXPORT_SYMBOL_GPL(acpi_kobj);
static int __init acpi_init(void) static int __init acpi_init(void)
{ {

View File

@ -812,10 +812,10 @@ static int acpi_ec_add(struct acpi_device *device)
first_ec = ec; first_ec = ec;
device->driver_data = ec; device->driver_data = ec;
WARN(!request_region(ec->data_addr, 1, "EC data"), ret = !!request_region(ec->data_addr, 1, "EC data");
"Could not request EC data io port 0x%lx", ec->data_addr); WARN(!ret, "Could not request EC data io port 0x%lx", ec->data_addr);
WARN(!request_region(ec->command_addr, 1, "EC cmd"), ret = !!request_region(ec->command_addr, 1, "EC cmd");
"Could not request EC cmd io port 0x%lx", ec->command_addr); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr); ec->gpe, ec->command_addr, ec->data_addr);

View File

@ -95,8 +95,8 @@ static int suspend_nvs_register(unsigned long start, unsigned long size)
{ {
struct nvs_page *entry, *next; struct nvs_page *entry, *next;
pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n", pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
start, size); start, start + size - 1, size);
while (size > 0) { while (size > 0) {
unsigned int nr_bytes; unsigned int nr_bytes;

View File

@ -347,7 +347,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
unsigned long pfn; unsigned long pfn;
pfn = pg_off >> PAGE_SHIFT; pfn = pg_off >> PAGE_SHIFT;
if (page_is_ram(pfn)) if (should_use_kmap(pfn))
kunmap(pfn_to_page(pfn)); kunmap(pfn_to_page(pfn));
else else
iounmap(vaddr); iounmap(vaddr);
@ -604,7 +604,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
acpi_irq_handler = handler; acpi_irq_handler = handler;
acpi_irq_context = context; acpi_irq_context = context;
if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { if (request_threaded_irq(irq, NULL, acpi_irq, IRQF_SHARED, "acpi",
acpi_irq)) {
printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
acpi_irq_handler = NULL; acpi_irq_handler = NULL;
return AE_NOT_ACQUIRED; return AE_NOT_ACQUIRED;

View File

@ -68,6 +68,7 @@
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81
#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
#define ACPI_PROCESSOR_DEVICE_HID "ACPI0007"
#define ACPI_PROCESSOR_LIMIT_USER 0 #define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1 #define ACPI_PROCESSOR_LIMIT_THERMAL 1
@ -88,7 +89,7 @@ static int acpi_processor_start(struct acpi_processor *pr);
static const struct acpi_device_id processor_device_ids[] = { static const struct acpi_device_id processor_device_ids[] = {
{ACPI_PROCESSOR_OBJECT_HID, 0}, {ACPI_PROCESSOR_OBJECT_HID, 0},
{"ACPI0007", 0}, {ACPI_PROCESSOR_DEVICE_HID, 0},
{"", 0}, {"", 0},
}; };
MODULE_DEVICE_TABLE(acpi, processor_device_ids); MODULE_DEVICE_TABLE(acpi, processor_device_ids);
@ -535,8 +536,8 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
return -ENOMEM; return -ENOMEM;
if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
kfree(pr); result = -ENOMEM;
return -ENOMEM; goto err_free_pr;
} }
pr->handle = device->handle; pr->handle = device->handle;
@ -576,7 +577,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
dev = get_cpu_device(pr->id); dev = get_cpu_device(pr->id);
if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) { if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) {
result = -EFAULT; result = -EFAULT;
goto err_free_cpumask; goto err_clear_processor;
} }
/* /*
@ -594,9 +595,15 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
err_remove_sysfs: err_remove_sysfs:
sysfs_remove_link(&device->dev.kobj, "sysdev"); sysfs_remove_link(&device->dev.kobj, "sysdev");
err_clear_processor:
/*
* processor_device_array is not cleared to allow checks for buggy BIOS
*/
per_cpu(processors, pr->id) = NULL;
err_free_cpumask: err_free_cpumask:
free_cpumask_var(pr->throttling.shared_cpu_map); free_cpumask_var(pr->throttling.shared_cpu_map);
err_free_pr:
kfree(pr);
return result; return result;
} }
@ -741,20 +748,46 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
return; return;
} }
static acpi_status is_processor_device(acpi_handle handle)
{
struct acpi_device_info *info;
char *hid;
acpi_status status;
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status))
return status;
if (info->type == ACPI_TYPE_PROCESSOR) {
kfree(info);
return AE_OK; /* found a processor object */
}
if (!(info->valid & ACPI_VALID_HID)) {
kfree(info);
return AE_ERROR;
}
hid = info->hardware_id.string;
if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
kfree(info);
return AE_ERROR;
}
kfree(info);
return AE_OK; /* found a processor device object */
}
static acpi_status static acpi_status
processor_walk_namespace_cb(acpi_handle handle, processor_walk_namespace_cb(acpi_handle handle,
u32 lvl, void *context, void **rv) u32 lvl, void *context, void **rv)
{ {
acpi_status status; acpi_status status;
int *action = context; int *action = context;
acpi_object_type type = 0;
status = acpi_get_type(handle, &type); status = is_processor_device(handle);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return (AE_OK); return AE_OK; /* not a processor; continue to walk */
if (type != ACPI_TYPE_PROCESSOR)
return (AE_OK);
switch (*action) { switch (*action) {
case INSTALL_NOTIFY_HANDLER: case INSTALL_NOTIFY_HANDLER:
@ -772,7 +805,8 @@ processor_walk_namespace_cb(acpi_handle handle,
break; break;
} }
return (AE_OK); /* found a processor; skip walking underneath */
return AE_CTRL_DEPTH;
} }
static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
@ -830,7 +864,7 @@ void acpi_processor_install_hotplug_notify(void)
{ {
#ifdef CONFIG_ACPI_HOTPLUG_CPU #ifdef CONFIG_ACPI_HOTPLUG_CPU
int action = INSTALL_NOTIFY_HANDLER; int action = INSTALL_NOTIFY_HANDLER;
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, acpi_walk_namespace(ACPI_TYPE_ANY,
ACPI_ROOT_OBJECT, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ACPI_UINT32_MAX,
processor_walk_namespace_cb, NULL, &action, NULL); processor_walk_namespace_cb, NULL, &action, NULL);
@ -843,7 +877,7 @@ void acpi_processor_uninstall_hotplug_notify(void)
{ {
#ifdef CONFIG_ACPI_HOTPLUG_CPU #ifdef CONFIG_ACPI_HOTPLUG_CPU
int action = UNINSTALL_NOTIFY_HANDLER; int action = UNINSTALL_NOTIFY_HANDLER;
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, acpi_walk_namespace(ACPI_TYPE_ANY,
ACPI_ROOT_OBJECT, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ACPI_UINT32_MAX,
processor_walk_namespace_cb, NULL, &action, NULL); processor_walk_namespace_cb, NULL, &action, NULL);

View File

@ -770,6 +770,35 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
return index; return index;
} }
/**
* acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining)
* @dev: the target CPU
* @index: the index of suggested state
*/
static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
{
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
ACPI_FLUSH_CPU_CACHE();
while (1) {
if (cx->entry_method == ACPI_CSTATE_HALT)
halt();
else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
inb(cx->address);
/* See comment in acpi_idle_do_entry() */
inl(acpi_gbl_FADT.xpm_timer_block.address);
} else
return -ENODEV;
}
/* Never reached */
return 0;
}
/** /**
* acpi_idle_enter_simple - enters an ACPI state without BM handling * acpi_idle_enter_simple - enters an ACPI state without BM handling
* @dev: the target CPU * @dev: the target CPU
@ -1077,12 +1106,14 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
state->flags |= CPUIDLE_FLAG_TIME_VALID; state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1; state->enter = acpi_idle_enter_c1;
state->enter_dead = acpi_idle_play_dead;
drv->safe_state_index = count; drv->safe_state_index = count;
break; break;
case ACPI_STATE_C2: case ACPI_STATE_C2:
state->flags |= CPUIDLE_FLAG_TIME_VALID; state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple; state->enter = acpi_idle_enter_simple;
state->enter_dead = acpi_idle_play_dead;
drv->safe_state_index = count; drv->safe_state_index = count;
break; break;
@ -1159,8 +1190,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
* to make the code that updates C-States be called once. * to make the code that updates C-States be called once.
*/ */
if (smp_processor_id() == 0 && if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
cpuidle_get_driver() == &acpi_idle_driver) {
cpuidle_pause_and_lock(); cpuidle_pause_and_lock();
/* Protect against cpu-hotplug */ /* Protect against cpu-hotplug */

View File

@ -57,6 +57,27 @@ ACPI_MODULE_NAME("processor_thermal");
static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
static unsigned int acpi_thermal_cpufreq_is_init = 0; static unsigned int acpi_thermal_cpufreq_is_init = 0;
#define reduction_pctg(cpu) \
per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
/*
* Emulate "per package data" using per cpu data (which should really be
* provided elsewhere)
*
* Note we can lose a CPU on cpu hotunplug, in this case we forget the state
* temporarily. Fortunately that's not a big issue here (I hope)
*/
static int phys_package_first_cpu(int cpu)
{
int i;
int id = topology_physical_package_id(cpu);
for_each_online_cpu(i)
if (topology_physical_package_id(i) == id)
return i;
return 0;
}
static int cpu_has_cpufreq(unsigned int cpu) static int cpu_has_cpufreq(unsigned int cpu)
{ {
struct cpufreq_policy policy; struct cpufreq_policy policy;
@ -76,7 +97,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
max_freq = ( max_freq = (
policy->cpuinfo.max_freq * policy->cpuinfo.max_freq *
(100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) (100 - reduction_pctg(policy->cpu) * 20)
) / 100; ) / 100;
cpufreq_verify_within_limits(policy, 0, max_freq); cpufreq_verify_within_limits(policy, 0, max_freq);
@ -102,16 +123,28 @@ static int cpufreq_get_cur_state(unsigned int cpu)
if (!cpu_has_cpufreq(cpu)) if (!cpu_has_cpufreq(cpu))
return 0; return 0;
return per_cpu(cpufreq_thermal_reduction_pctg, cpu); return reduction_pctg(cpu);
} }
static int cpufreq_set_cur_state(unsigned int cpu, int state) static int cpufreq_set_cur_state(unsigned int cpu, int state)
{ {
int i;
if (!cpu_has_cpufreq(cpu)) if (!cpu_has_cpufreq(cpu))
return 0; return 0;
per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; reduction_pctg(cpu) = state;
cpufreq_update_policy(cpu);
/*
* Update all the CPUs in the same package because they all
* contribute to the temperature and often share the same
* frequency.
*/
for_each_online_cpu(i) {
if (topology_physical_package_id(i) ==
topology_physical_package_id(cpu))
cpufreq_update_policy(i);
}
return 0; return 0;
} }
@ -119,10 +152,6 @@ void acpi_thermal_cpufreq_init(void)
{ {
int i; int i;
for (i = 0; i < nr_cpu_ids; i++)
if (cpu_present(i))
per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;
i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
if (!i) if (!i)

View File

@ -769,7 +769,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
u64 *value) u64 *value)
{ {
u32 bit_width, bit_offset; u32 bit_width, bit_offset;
u64 ptc_value; u32 ptc_value;
u64 ptc_mask; u64 ptc_mask;
struct acpi_processor_throttling *throttling; struct acpi_processor_throttling *throttling;
int ret = -1; int ret = -1;
@ -777,12 +777,11 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
throttling = &pr->throttling; throttling = &pr->throttling;
switch (throttling->status_register.space_id) { switch (throttling->status_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_SYSTEM_IO:
ptc_value = 0;
bit_width = throttling->status_register.bit_width; bit_width = throttling->status_register.bit_width;
bit_offset = throttling->status_register.bit_offset; bit_offset = throttling->status_register.bit_offset;
acpi_os_read_port((acpi_io_address) throttling->status_register. acpi_os_read_port((acpi_io_address) throttling->status_register.
address, (u32 *) &ptc_value, address, &ptc_value,
(u32) (bit_width + bit_offset)); (u32) (bit_width + bit_offset));
ptc_mask = (1 << bit_width) - 1; ptc_mask = (1 << bit_width) - 1;
*value = (u64) ((ptc_value >> bit_offset) & ptc_mask); *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);

View File

@ -23,8 +23,7 @@ void acpi_reboot(void)
/* Is the reset register supported? The spec says we should be /* Is the reset register supported? The spec says we should be
* checking the bit width and bit offset, but Windows ignores * checking the bit width and bit offset, but Windows ignores
* these fields */ * these fields */
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) /* Ignore also acpi_gbl_FADT.flags.ACPI_FADT_RESET_REGISTER */
return;
reset_value = acpi_gbl_FADT.reset_value; reset_value = acpi_gbl_FADT.reset_value;

View File

@ -880,7 +880,6 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
int j; int j;
device->power.flags.power_resources = 1; device->power.flags.power_resources = 1;
ps->flags.valid = 1;
for (j = 0; j < ps->resources.count; j++) for (j = 0; j < ps->resources.count; j++)
acpi_bus_add_power_resource(ps->resources.handles[j]); acpi_bus_add_power_resource(ps->resources.handles[j]);
} }
@ -888,10 +887,8 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
/* Evaluate "_PSx" to see if we can do explicit sets */ /* Evaluate "_PSx" to see if we can do explicit sets */
object_name[2] = 'S'; object_name[2] = 'S';
status = acpi_get_handle(device->handle, object_name, &handle); status = acpi_get_handle(device->handle, object_name, &handle);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status))
ps->flags.explicit_set = 1; ps->flags.explicit_set = 1;
ps->flags.valid = 1;
}
/* State is valid if we have some power control */ /* State is valid if we have some power control */
if (ps->resources.count || ps->flags.explicit_set) if (ps->resources.count || ps->flags.explicit_set)

View File

@ -941,13 +941,13 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
if (!tz) if (!tz)
return -EINVAL; return -EINVAL;
/* Get temperature [_TMP] (required) */ /* Get trip points [_CRT, _PSV, etc.] (required) */
result = acpi_thermal_get_temperature(tz); result = acpi_thermal_get_trip_points(tz);
if (result) if (result)
return result; return result;
/* Get trip points [_CRT, _PSV, etc.] (required) */ /* Get temperature [_TMP] (required) */
result = acpi_thermal_get_trip_points(tz); result = acpi_thermal_get_temperature(tz);
if (result) if (result)
return result; return result;

View File

@ -548,27 +548,27 @@ acpi_video_device_EDID(struct acpi_video_device *device,
* 1. The system BIOS should NOT automatically control the brightness * 1. The system BIOS should NOT automatically control the brightness
* level of the LCD when the power changes from AC to DC. * level of the LCD when the power changes from AC to DC.
* Return Value: * Return Value:
* -1 wrong arg. * -EINVAL wrong arg.
*/ */
static int static int
acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
{ {
u64 status = 0; acpi_status status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER }; union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 }; struct acpi_object_list args = { 1, &arg0 };
if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) { if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
status = -1; return -EINVAL;
goto Failed;
}
arg0.integer.value = (lcd_flag << 2) | bios_flag; arg0.integer.value = (lcd_flag << 2) | bios_flag;
video->dos_setting = arg0.integer.value; video->dos_setting = arg0.integer.value;
acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL); status = acpi_evaluate_object(video->device->handle, "_DOS",
&args, NULL);
if (ACPI_FAILURE(status))
return -EIO;
Failed: return 0;
return status;
} }
/* /*
@ -1343,15 +1343,17 @@ static int
acpi_video_bus_get_devices(struct acpi_video_bus *video, acpi_video_bus_get_devices(struct acpi_video_bus *video,
struct acpi_device *device) struct acpi_device *device)
{ {
int status = 0; int status;
struct acpi_device *dev; struct acpi_device *dev;
acpi_video_device_enumerate(video); status = acpi_video_device_enumerate(video);
if (status)
return status;
list_for_each_entry(dev, &device->children, node) { list_for_each_entry(dev, &device->children, node) {
status = acpi_video_bus_get_one_device(dev, video); status = acpi_video_bus_get_one_device(dev, video);
if (ACPI_FAILURE(status)) { if (status) {
printk(KERN_WARNING PREFIX printk(KERN_WARNING PREFIX
"Can't attach device\n"); "Can't attach device\n");
continue; continue;
@ -1653,15 +1655,20 @@ static int acpi_video_bus_add(struct acpi_device *device)
mutex_init(&video->device_list_lock); mutex_init(&video->device_list_lock);
INIT_LIST_HEAD(&video->video_device_list); INIT_LIST_HEAD(&video->video_device_list);
acpi_video_bus_get_devices(video, device); error = acpi_video_bus_get_devices(video, device);
acpi_video_bus_start_devices(video); if (error)
goto err_free_video;
video->input = input = input_allocate_device(); video->input = input = input_allocate_device();
if (!input) { if (!input) {
error = -ENOMEM; error = -ENOMEM;
goto err_stop_video; goto err_put_video;
} }
error = acpi_video_bus_start_devices(video);
if (error)
goto err_free_input_dev;
snprintf(video->phys, sizeof(video->phys), snprintf(video->phys, sizeof(video->phys),
"%s/video/input0", acpi_device_hid(video->device)); "%s/video/input0", acpi_device_hid(video->device));
@ -1682,7 +1689,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
error = input_register_device(input); error = input_register_device(input);
if (error) if (error)
goto err_free_input_dev; goto err_stop_video;
printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
@ -1692,14 +1699,19 @@ static int acpi_video_bus_add(struct acpi_device *device)
video->pm_nb.notifier_call = acpi_video_resume; video->pm_nb.notifier_call = acpi_video_resume;
video->pm_nb.priority = 0; video->pm_nb.priority = 0;
register_pm_notifier(&video->pm_nb); error = register_pm_notifier(&video->pm_nb);
if (error)
goto err_unregister_input_dev;
return 0; return 0;
err_free_input_dev: err_unregister_input_dev:
input_free_device(input); input_unregister_device(input);
err_stop_video: err_stop_video:
acpi_video_bus_stop_devices(video); acpi_video_bus_stop_devices(video);
err_free_input_dev:
input_free_device(input);
err_put_video:
acpi_video_bus_put_devices(video); acpi_video_bus_put_devices(video);
kfree(video->attached_array); kfree(video->attached_array);
err_free_video: err_free_video:

View File

@ -53,6 +53,52 @@ static void cpuidle_kick_cpus(void) {}
static int __cpuidle_register_device(struct cpuidle_device *dev); static int __cpuidle_register_device(struct cpuidle_device *dev);
static inline int cpuidle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct cpuidle_state *target_state = &drv->states[index];
return target_state->enter(dev, drv, index);
}
static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
}
typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
static cpuidle_enter_t cpuidle_enter_ops;
/**
* cpuidle_play_dead - cpu off-lining
*
* Only returns in case of an error
*/
int cpuidle_play_dead(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_driver *drv = cpuidle_get_driver();
int i, dead_state = -1;
int power_usage = -1;
/* Find lowest-power state that supports long-term idle */
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
if (s->power_usage < power_usage && s->enter_dead) {
power_usage = s->power_usage;
dead_state = i;
}
}
if (dead_state != -1)
return drv->states[dead_state].enter_dead(dev, dead_state);
return -ENODEV;
}
/** /**
* cpuidle_idle_call - the main idle loop * cpuidle_idle_call - the main idle loop
* *
@ -63,7 +109,6 @@ int cpuidle_idle_call(void)
{ {
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_driver *drv = cpuidle_get_driver(); struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_state *target_state;
int next_state, entered_state; int next_state, entered_state;
if (off) if (off)
@ -92,12 +137,10 @@ int cpuidle_idle_call(void)
return 0; return 0;
} }
target_state = &drv->states[next_state];
trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_power_start(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle(next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu);
entered_state = target_state->enter(dev, drv, next_state); entered_state = cpuidle_enter_ops(dev, drv, next_state);
trace_power_end(dev->cpu); trace_power_end(dev->cpu);
trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@ -110,6 +153,8 @@ int cpuidle_idle_call(void)
dev->states_usage[entered_state].time += dev->states_usage[entered_state].time +=
(unsigned long long)dev->last_residency; (unsigned long long)dev->last_residency;
dev->states_usage[entered_state].usage++; dev->states_usage[entered_state].usage++;
} else {
dev->last_residency = 0;
} }
/* give the governor an opportunity to reflect on the outcome */ /* give the governor an opportunity to reflect on the outcome */
@ -164,6 +209,37 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
/**
* cpuidle_wrap_enter - performs timekeeping and irqen around enter function
* @dev: pointer to a valid cpuidle_device object
* @drv: pointer to a valid cpuidle_driver object
* @index: index of the target cpuidle state.
*/
int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index))
{
ktime_t time_start, time_end;
s64 diff;
time_start = ktime_get();
index = enter(dev, drv, index);
time_end = ktime_get();
local_irq_enable();
diff = ktime_to_us(ktime_sub(time_end, time_start));
if (diff > INT_MAX)
diff = INT_MAX;
dev->last_residency = (int) diff;
return index;
}
#ifdef CONFIG_ARCH_HAS_CPU_RELAX #ifdef CONFIG_ARCH_HAS_CPU_RELAX
static int poll_idle(struct cpuidle_device *dev, static int poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) struct cpuidle_driver *drv, int index)
@ -197,6 +273,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
state->power_usage = -1; state->power_usage = -1;
state->flags = 0; state->flags = 0;
state->enter = poll_idle; state->enter = poll_idle;
state->disable = 0;
} }
#else #else
static void poll_idle_init(struct cpuidle_driver *drv) {} static void poll_idle_init(struct cpuidle_driver *drv) {}
@ -212,13 +289,14 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
int cpuidle_enable_device(struct cpuidle_device *dev) int cpuidle_enable_device(struct cpuidle_device *dev)
{ {
int ret, i; int ret, i;
struct cpuidle_driver *drv = cpuidle_get_driver();
if (dev->enabled) if (dev->enabled)
return 0; return 0;
if (!cpuidle_get_driver() || !cpuidle_curr_governor) if (!drv || !cpuidle_curr_governor)
return -EIO; return -EIO;
if (!dev->state_count) if (!dev->state_count)
return -EINVAL; dev->state_count = drv->state_count;
if (dev->registered == 0) { if (dev->registered == 0) {
ret = __cpuidle_register_device(dev); ret = __cpuidle_register_device(dev);
@ -226,13 +304,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret; return ret;
} }
poll_idle_init(cpuidle_get_driver()); cpuidle_enter_ops = drv->en_core_tk_irqen ?
cpuidle_enter_tk : cpuidle_enter;
poll_idle_init(drv);
if ((ret = cpuidle_add_state_sysfs(dev))) if ((ret = cpuidle_add_state_sysfs(dev)))
return ret; return ret;
if (cpuidle_curr_governor->enable && if (cpuidle_curr_governor->enable &&
(ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) (ret = cpuidle_curr_governor->enable(drv, dev)))
goto fail_sysfs; goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) { for (i = 0; i < dev->state_count; i++) {

View File

@ -47,7 +47,7 @@ static void __cpuidle_register_driver(struct cpuidle_driver *drv)
*/ */
int cpuidle_register_driver(struct cpuidle_driver *drv) int cpuidle_register_driver(struct cpuidle_driver *drv)
{ {
if (!drv) if (!drv || !drv->state_count)
return -EINVAL; return -EINVAL;
if (cpuidle_disabled()) if (cpuidle_disabled())

View File

@ -236,7 +236,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{ {
struct menu_device *data = &__get_cpu_var(menu_devices); struct menu_device *data = &__get_cpu_var(menu_devices);
int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
unsigned int power_usage = -1; int power_usage = -1;
int i; int i;
int multiplier; int multiplier;
struct timespec t; struct timespec t;
@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* We want to default to C1 (hlt), not to busy polling * We want to default to C1 (hlt), not to busy polling
* unless the timer is happening really really soon. * unless the timer is happening really really soon.
*/ */
if (data->expected_us > 5) if (data->expected_us > 5 &&
drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
data->last_state_idx = CPUIDLE_DRIVER_STATE_START; data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
/* /*
@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i]; struct cpuidle_state *s = &drv->states[i];
if (s->disable)
continue;
if (s->target_residency > data->predicted_us) if (s->target_residency > data->predicted_us)
continue; continue;
if (s->exit_latency > latency_req) if (s->exit_latency > latency_req)

View File

@ -11,6 +11,7 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/capability.h>
#include "cpuidle.h" #include "cpuidle.h"
@ -222,6 +223,9 @@ struct cpuidle_state_attr {
#define define_one_state_ro(_name, show) \ #define define_one_state_ro(_name, show) \
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
#define define_one_state_rw(_name, show, store) \
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
#define define_show_state_function(_name) \ #define define_show_state_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \ static ssize_t show_state_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, char *buf) \ struct cpuidle_state_usage *state_usage, char *buf) \
@ -229,6 +233,24 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
return sprintf(buf, "%u\n", state->_name);\ return sprintf(buf, "%u\n", state->_name);\
} }
#define define_store_state_function(_name) \
static ssize_t store_state_##_name(struct cpuidle_state *state, \
const char *buf, size_t size) \
{ \
long value; \
int err; \
if (!capable(CAP_SYS_ADMIN)) \
return -EPERM; \
err = kstrtol(buf, 0, &value); \
if (err) \
return err; \
if (value) \
state->disable = 1; \
else \
state->disable = 0; \
return size; \
}
#define define_show_state_ull_function(_name) \ #define define_show_state_ull_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \ static ssize_t show_state_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, char *buf) \ struct cpuidle_state_usage *state_usage, char *buf) \
@ -251,6 +273,8 @@ define_show_state_ull_function(usage)
define_show_state_ull_function(time) define_show_state_ull_function(time)
define_show_state_str_function(name) define_show_state_str_function(name)
define_show_state_str_function(desc) define_show_state_str_function(desc)
define_show_state_function(disable)
define_store_state_function(disable)
define_one_state_ro(name, show_state_name); define_one_state_ro(name, show_state_name);
define_one_state_ro(desc, show_state_desc); define_one_state_ro(desc, show_state_desc);
@ -258,6 +282,7 @@ define_one_state_ro(latency, show_state_exit_latency);
define_one_state_ro(power, show_state_power_usage); define_one_state_ro(power, show_state_power_usage);
define_one_state_ro(usage, show_state_usage); define_one_state_ro(usage, show_state_usage);
define_one_state_ro(time, show_state_time); define_one_state_ro(time, show_state_time);
define_one_state_rw(disable, show_state_disable, store_state_disable);
static struct attribute *cpuidle_state_default_attrs[] = { static struct attribute *cpuidle_state_default_attrs[] = {
&attr_name.attr, &attr_name.attr,
@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
&attr_power.attr, &attr_power.attr,
&attr_usage.attr, &attr_usage.attr,
&attr_time.attr, &attr_time.attr,
&attr_disable.attr,
NULL NULL
}; };
@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
return ret; return ret;
} }
static ssize_t cpuidle_state_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t size)
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
if (cattr->store)
ret = cattr->store(state, buf, size);
return ret;
}
static const struct sysfs_ops cpuidle_state_sysfs_ops = { static const struct sysfs_ops cpuidle_state_sysfs_ops = {
.show = cpuidle_state_show, .show = cpuidle_state_show,
.store = cpuidle_state_store,
}; };
static void cpuidle_state_sysfs_release(struct kobject *kobj) static void cpuidle_state_sysfs_release(struct kobject *kobj)

View File

@ -609,25 +609,16 @@ static bool mcp_exceeded(struct ips_driver *ips)
bool ret = false; bool ret = false;
u32 temp_limit; u32 temp_limit;
u32 avg_power; u32 avg_power;
const char *msg = "MCP limit exceeded: ";
spin_lock_irqsave(&ips->turbo_status_lock, flags); spin_lock_irqsave(&ips->turbo_status_lock, flags);
temp_limit = ips->mcp_temp_limit * 100; temp_limit = ips->mcp_temp_limit * 100;
if (ips->mcp_avg_temp > temp_limit) { if (ips->mcp_avg_temp > temp_limit)
dev_info(&ips->dev->dev,
"%sAvg temp %u, limit %u\n", msg, ips->mcp_avg_temp,
temp_limit);
ret = true; ret = true;
}
avg_power = ips->cpu_avg_power + ips->mch_avg_power; avg_power = ips->cpu_avg_power + ips->mch_avg_power;
if (avg_power > ips->mcp_power_limit) { if (avg_power > ips->mcp_power_limit)
dev_info(&ips->dev->dev,
"%sAvg power %u, limit %u\n", msg, avg_power,
ips->mcp_power_limit);
ret = true; ret = true;
}
spin_unlock_irqrestore(&ips->turbo_status_lock, flags); spin_unlock_irqrestore(&ips->turbo_status_lock, flags);

View File

@ -321,9 +321,14 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp)
{ {
struct acpi_device *acpi = to_acpi_device(dev); struct acpi_device *acpi = to_acpi_device(dev);
struct pnp_dev *pnp = _pnp; struct pnp_dev *pnp = _pnp;
struct device *physical_device;
physical_device = acpi_get_physical_device(acpi->handle);
if (physical_device)
put_device(physical_device);
/* true means it matched */ /* true means it matched */
return !acpi_get_physical_device(acpi->handle) return !physical_device
&& compare_pnp_id(pnp->id, acpi_device_hid(acpi)); && compare_pnp_id(pnp->id, acpi_device_hid(acpi));
} }

View File

@ -18,3 +18,11 @@ config THERMAL_HWMON
depends on THERMAL depends on THERMAL
depends on HWMON=y || HWMON=THERMAL depends on HWMON=y || HWMON=THERMAL
default y default y
config SPEAR_THERMAL
bool "SPEAr thermal sensor driver"
depends on THERMAL
depends on PLAT_SPEAR
help
Enable this to plug the SPEAr thermal sensor driver into the Linux
thermal framework

View File

@ -3,3 +3,4 @@
# #
obj-$(CONFIG_THERMAL) += thermal_sys.o obj-$(CONFIG_THERMAL) += thermal_sys.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o

View File

@ -0,0 +1,206 @@
/*
* SPEAr thermal driver.
*
* Copyright (C) 2011-2012 ST Microelectronics
* Author: Vincenzo Frascino <vincenzo.frascino@st.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_data/spear_thermal.h>
#include <linux/thermal.h>
#define MD_FACTOR 1000
/* SPEAr Thermal Sensor Dev Structure */
struct spear_thermal_dev {
/* pointer to base address of the thermal sensor */
void __iomem *thermal_base;
/* clk structure */
struct clk *clk;
/* pointer to thermal flags */
unsigned int flags;
};
static inline int thermal_get_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
{
struct spear_thermal_dev *stdev = thermal->devdata;
/*
* Data are ready to be read after 628 usec from POWERDOWN signal
* (PDN) = 1
*/
*temp = (readl_relaxed(stdev->thermal_base) & 0x7F) * MD_FACTOR;
return 0;
}
static struct thermal_zone_device_ops ops = {
.get_temp = thermal_get_temp,
};
#ifdef CONFIG_PM
static int spear_thermal_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
struct spear_thermal_dev *stdev = spear_thermal->devdata;
unsigned int actual_mask = 0;
/* Disable SPEAr Thermal Sensor */
actual_mask = readl_relaxed(stdev->thermal_base);
writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
clk_disable(stdev->clk);
dev_info(dev, "Suspended.\n");
return 0;
}
static int spear_thermal_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
struct spear_thermal_dev *stdev = spear_thermal->devdata;
unsigned int actual_mask = 0;
int ret = 0;
ret = clk_enable(stdev->clk);
if (ret) {
dev_err(&pdev->dev, "Can't enable clock\n");
return ret;
}
/* Enable SPEAr Thermal Sensor */
actual_mask = readl_relaxed(stdev->thermal_base);
writel_relaxed(actual_mask | stdev->flags, stdev->thermal_base);
dev_info(dev, "Resumed.\n");
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
spear_thermal_resume);
static int spear_thermal_probe(struct platform_device *pdev)
{
struct thermal_zone_device *spear_thermal = NULL;
struct spear_thermal_dev *stdev;
struct spear_thermal_pdata *pdata;
int ret = 0;
struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!stres) {
dev_err(&pdev->dev, "memory resource missing\n");
return -ENODEV;
}
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "platform data is NULL\n");
return -EINVAL;
}
stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
if (!stdev) {
dev_err(&pdev->dev, "kzalloc fail\n");
return -ENOMEM;
}
/* Enable thermal sensor */
stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start,
resource_size(stres));
if (!stdev->thermal_base) {
dev_err(&pdev->dev, "ioremap failed\n");
return -ENOMEM;
}
stdev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(stdev->clk)) {
dev_err(&pdev->dev, "Can't get clock\n");
return PTR_ERR(stdev->clk);
}
ret = clk_enable(stdev->clk);
if (ret) {
dev_err(&pdev->dev, "Can't enable clock\n");
goto put_clk;
}
stdev->flags = pdata->thermal_flags;
writel_relaxed(stdev->flags, stdev->thermal_base);
spear_thermal = thermal_zone_device_register("spear_thermal", 0,
stdev, &ops, 0, 0, 0, 0);
if (IS_ERR(spear_thermal)) {
dev_err(&pdev->dev, "thermal zone device is NULL\n");
ret = PTR_ERR(spear_thermal);
goto disable_clk;
}
platform_set_drvdata(pdev, spear_thermal);
dev_info(&spear_thermal->device, "Thermal Sensor Loaded at: 0x%p.\n",
stdev->thermal_base);
return 0;
disable_clk:
clk_disable(stdev->clk);
put_clk:
clk_put(stdev->clk);
return ret;
}
static int spear_thermal_exit(struct platform_device *pdev)
{
unsigned int actual_mask = 0;
struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
struct spear_thermal_dev *stdev = spear_thermal->devdata;
thermal_zone_device_unregister(spear_thermal);
platform_set_drvdata(pdev, NULL);
/* Disable SPEAr Thermal Sensor */
actual_mask = readl_relaxed(stdev->thermal_base);
writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
clk_disable(stdev->clk);
clk_put(stdev->clk);
return 0;
}
static struct platform_driver spear_thermal_driver = {
.probe = spear_thermal_probe,
.remove = spear_thermal_exit,
.driver = {
.name = "spear_thermal",
.owner = THIS_MODULE,
.pm = &spear_thermal_pm_ops,
},
};
module_platform_driver(spear_thermal_driver);
MODULE_AUTHOR("Vincenzo Frascino <vincenzo.frascino@st.com>");
MODULE_DESCRIPTION("SPEAr thermal driver");
MODULE_LICENSE("GPL");

View File

@ -23,6 +23,8 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
@ -39,8 +41,6 @@ MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define PREFIX "Thermal: "
struct thermal_cooling_device_instance { struct thermal_cooling_device_instance {
int id; int id;
char name[THERMAL_NAME_LENGTH]; char name[THERMAL_NAME_LENGTH];
@ -60,13 +60,11 @@ static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list); static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock); static DEFINE_MUTEX(thermal_list_lock);
static unsigned int thermal_event_seqnum;
static int get_idr(struct idr *idr, struct mutex *lock, int *id) static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{ {
int err; int err;
again: again:
if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
return -ENOMEM; return -ENOMEM;
@ -152,9 +150,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
if (!tz->ops->set_mode) if (!tz->ops->set_mode)
return -EPERM; return -EPERM;
if (!strncmp(buf, "enabled", sizeof("enabled"))) if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
else if (!strncmp(buf, "disabled", sizeof("disabled"))) else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
else else
result = -EINVAL; result = -EINVAL;
@ -283,8 +281,7 @@ passive_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(type, 0444, type_show, NULL); static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(temp, 0444, temp_show, NULL); static DEVICE_ATTR(temp, 0444, temp_show, NULL);
static DEVICE_ATTR(mode, 0644, mode_show, mode_store); static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \ static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
passive_store);
static struct device_attribute trip_point_attrs[] = { static struct device_attribute trip_point_attrs[] = {
__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
@ -313,22 +310,6 @@ static struct device_attribute trip_point_attrs[] = {
__ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL), __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
}; };
#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \
do { \
result = device_create_file(_dev, \
&trip_point_attrs[_index * 2]); \
if (result) \
break; \
result = device_create_file(_dev, \
&trip_point_attrs[_index * 2 + 1]); \
} while (0)
#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \
do { \
device_remove_file(_dev, &trip_point_attrs[_index * 2]); \
device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \
} while (0)
/* sys I/F for cooling device */ /* sys I/F for cooling device */
#define to_cooling_device(_dev) \ #define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device) container_of(_dev, struct thermal_cooling_device, device)
@ -835,15 +816,14 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
return 0; return 0;
device_remove_file(&tz->device, &dev->attr); device_remove_file(&tz->device, &dev->attr);
remove_symbol_link: remove_symbol_link:
sysfs_remove_link(&tz->device.kobj, dev->name); sysfs_remove_link(&tz->device.kobj, dev->name);
release_idr: release_idr:
release_idr(&tz->idr, &tz->lock, dev->id); release_idr(&tz->idr, &tz->lock, dev->id);
free_mem: free_mem:
kfree(dev); kfree(dev);
return result; return result;
} }
EXPORT_SYMBOL(thermal_zone_bind_cooling_device); EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
/** /**
@ -873,14 +853,13 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
return -ENODEV; return -ENODEV;
unbind: unbind:
device_remove_file(&tz->device, &pos->attr); device_remove_file(&tz->device, &pos->attr);
sysfs_remove_link(&tz->device.kobj, pos->name); sysfs_remove_link(&tz->device.kobj, pos->name);
release_idr(&tz->idr, &tz->lock, pos->id); release_idr(&tz->idr, &tz->lock, pos->id);
kfree(pos); kfree(pos);
return 0; return 0;
} }
EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
static void thermal_release(struct device *dev) static void thermal_release(struct device *dev)
@ -888,7 +867,8 @@ static void thermal_release(struct device *dev)
struct thermal_zone_device *tz; struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
if (!strncmp(dev_name(dev), "thermal_zone", sizeof "thermal_zone" - 1)) { if (!strncmp(dev_name(dev), "thermal_zone",
sizeof("thermal_zone") - 1)) {
tz = to_thermal_zone(dev); tz = to_thermal_zone(dev);
kfree(tz); kfree(tz);
} else { } else {
@ -908,8 +888,9 @@ static struct class thermal_class = {
* @devdata: device private data. * @devdata: device private data.
* @ops: standard thermal cooling devices callbacks. * @ops: standard thermal cooling devices callbacks.
*/ */
struct thermal_cooling_device *thermal_cooling_device_register( struct thermal_cooling_device *
char *type, void *devdata, const struct thermal_cooling_device_ops *ops) thermal_cooling_device_register(char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{ {
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos; struct thermal_zone_device *pos;
@ -974,12 +955,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(
if (!result) if (!result)
return cdev; return cdev;
unregister: unregister:
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
device_unregister(&cdev->device); device_unregister(&cdev->device);
return ERR_PTR(result); return ERR_PTR(result);
} }
EXPORT_SYMBOL(thermal_cooling_device_register); EXPORT_SYMBOL(thermal_cooling_device_register);
/** /**
@ -1024,7 +1004,6 @@ void thermal_cooling_device_unregister(struct
device_unregister(&cdev->device); device_unregister(&cdev->device);
return; return;
} }
EXPORT_SYMBOL(thermal_cooling_device_unregister); EXPORT_SYMBOL(thermal_cooling_device_unregister);
/** /**
@ -1044,8 +1023,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
if (tz->ops->get_temp(tz, &temp)) { if (tz->ops->get_temp(tz, &temp)) {
/* get_temp failed - retry it later */ /* get_temp failed - retry it later */
printk(KERN_WARNING PREFIX "failed to read out thermal zone " pr_warn("failed to read out thermal zone %d\n", tz->id);
"%d\n", tz->id);
goto leave; goto leave;
} }
@ -1060,9 +1038,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
ret = tz->ops->notify(tz, count, ret = tz->ops->notify(tz, count,
trip_type); trip_type);
if (!ret) { if (!ret) {
printk(KERN_EMERG pr_emerg("Critical temperature reached (%ld C), shutting down\n",
"Critical temperature reached (%ld C), shutting down.\n", temp/1000);
temp/1000);
orderly_poweroff(true); orderly_poweroff(true);
} }
} }
@ -1100,7 +1077,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
tz->last_temperature = temp; tz->last_temperature = temp;
leave: leave:
if (tz->passive) if (tz->passive)
thermal_zone_device_set_polling(tz, tz->passive_delay); thermal_zone_device_set_polling(tz, tz->passive_delay);
else if (tz->polling_delay) else if (tz->polling_delay)
@ -1199,7 +1176,12 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
} }
for (count = 0; count < trips; count++) { for (count = 0; count < trips; count++) {
TRIP_POINT_ATTR_ADD(&tz->device, count, result); result = device_create_file(&tz->device,
&trip_point_attrs[count * 2]);
if (result)
break;
result = device_create_file(&tz->device,
&trip_point_attrs[count * 2 + 1]);
if (result) if (result)
goto unregister; goto unregister;
tz->ops->get_trip_type(tz, count, &trip_type); tz->ops->get_trip_type(tz, count, &trip_type);
@ -1235,12 +1217,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
if (!result) if (!result)
return tz; return tz;
unregister: unregister:
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
device_unregister(&tz->device); device_unregister(&tz->device);
return ERR_PTR(result); return ERR_PTR(result);
} }
EXPORT_SYMBOL(thermal_zone_device_register); EXPORT_SYMBOL(thermal_zone_device_register);
/** /**
@ -1279,9 +1260,12 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
if (tz->ops->get_mode) if (tz->ops->get_mode)
device_remove_file(&tz->device, &dev_attr_mode); device_remove_file(&tz->device, &dev_attr_mode);
for (count = 0; count < tz->trips; count++) for (count = 0; count < tz->trips; count++) {
TRIP_POINT_ATTR_REMOVE(&tz->device, count); device_remove_file(&tz->device,
&trip_point_attrs[count * 2]);
device_remove_file(&tz->device,
&trip_point_attrs[count * 2 + 1]);
}
thermal_remove_hwmon_sysfs(tz); thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr); idr_destroy(&tz->idr);
@ -1289,7 +1273,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
device_unregister(&tz->device); device_unregister(&tz->device);
return; return;
} }
EXPORT_SYMBOL(thermal_zone_device_unregister); EXPORT_SYMBOL(thermal_zone_device_unregister);
#ifdef CONFIG_NET #ifdef CONFIG_NET
@ -1312,10 +1295,11 @@ int thermal_generate_netlink_event(u32 orig, enum events event)
void *msg_header; void *msg_header;
int size; int size;
int result; int result;
static unsigned int thermal_event_seqnum;
/* allocate memory */ /* allocate memory */
size = nla_total_size(sizeof(struct thermal_genl_event)) + \ size = nla_total_size(sizeof(struct thermal_genl_event)) +
nla_total_size(0); nla_total_size(0);
skb = genlmsg_new(size, GFP_ATOMIC); skb = genlmsg_new(size, GFP_ATOMIC);
if (!skb) if (!skb)
@ -1331,8 +1315,8 @@ int thermal_generate_netlink_event(u32 orig, enum events event)
} }
/* fill the data */ /* fill the data */
attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \ attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
sizeof(struct thermal_genl_event)); sizeof(struct thermal_genl_event));
if (!attr) { if (!attr) {
nlmsg_free(skb); nlmsg_free(skb);
@ -1359,7 +1343,7 @@ int thermal_generate_netlink_event(u32 orig, enum events event)
result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
if (result) if (result)
printk(KERN_INFO "failed to send netlink event:%d", result); pr_info("failed to send netlink event:%d\n", result);
return result; return result;
} }

View File

@ -15,6 +15,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/hrtimer.h>
#define CPUIDLE_STATE_MAX 8 #define CPUIDLE_STATE_MAX 8
#define CPUIDLE_NAME_LEN 16 #define CPUIDLE_NAME_LEN 16
@ -43,12 +44,15 @@ struct cpuidle_state {
unsigned int flags; unsigned int flags;
unsigned int exit_latency; /* in US */ unsigned int exit_latency; /* in US */
unsigned int power_usage; /* in mW */ int power_usage; /* in mW */
unsigned int target_residency; /* in US */ unsigned int target_residency; /* in US */
unsigned int disable;
int (*enter) (struct cpuidle_device *dev, int (*enter) (struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
int index); int index);
int (*enter_dead) (struct cpuidle_device *dev, int index);
}; };
/* Idle State Flags */ /* Idle State Flags */
@ -96,7 +100,6 @@ struct cpuidle_device {
struct list_head device_list; struct list_head device_list;
struct kobject kobj; struct kobject kobj;
struct completion kobj_unregister; struct completion kobj_unregister;
void *governor_data;
}; };
DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@ -118,10 +121,12 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
****************************/ ****************************/
struct cpuidle_driver { struct cpuidle_driver {
char name[CPUIDLE_NAME_LEN]; const char *name;
struct module *owner; struct module *owner;
unsigned int power_specified:1; unsigned int power_specified:1;
/* set to 1 to use the core cpuidle time keeping (for all states). */
unsigned int en_core_tk_irqen:1;
struct cpuidle_state states[CPUIDLE_STATE_MAX]; struct cpuidle_state states[CPUIDLE_STATE_MAX];
int state_count; int state_count;
int safe_state_index; int safe_state_index;
@ -140,6 +145,11 @@ extern void cpuidle_pause_and_lock(void);
extern void cpuidle_resume_and_unlock(void); extern void cpuidle_resume_and_unlock(void);
extern int cpuidle_enable_device(struct cpuidle_device *dev); extern int cpuidle_enable_device(struct cpuidle_device *dev);
extern void cpuidle_disable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev);
extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index));
extern int cpuidle_play_dead(void);
#else #else
static inline void disable_cpuidle(void) { } static inline void disable_cpuidle(void) { }
@ -157,6 +167,12 @@ static inline void cpuidle_resume_and_unlock(void) { }
static inline int cpuidle_enable_device(struct cpuidle_device *dev) static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{return -ENODEV; } {return -ENODEV; }
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index))
{ return -ENODEV; }
static inline int cpuidle_play_dead(void) {return -ENODEV; }
#endif #endif

View File

@ -0,0 +1,26 @@
/*
* SPEAr thermal driver platform data.
*
* Copyright (C) 2011-2012 ST Microelectronics
* Author: Vincenzo Frascino <vincenzo.frascino@st.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef SPEAR_THERMAL_H
#define SPEAR_THERMAL_H
/* SPEAr Thermal Sensor Platform Data */
struct spear_thermal_pdata {
/* flags used to enable thermal sensor */
unsigned int thermal_flags;
};
#endif /* SPEAR_THERMAL_H */

View File

@ -4,11 +4,13 @@ turbostat \- Report processor frequency and idle statistics
.SH SYNOPSIS .SH SYNOPSIS
.ft B .ft B
.B turbostat .B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ] .RB [ "\-v" ]
.RB [ "\-M MSR#" ] .RB [ "\-M MSR#" ]
.RB command .RB command
.br .br
.B turbostat .B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ] .RB [ "\-v" ]
.RB [ "\-M MSR#" ] .RB [ "\-M MSR#" ]
.RB [ "\-i interval_sec" ] .RB [ "\-i interval_sec" ]
@ -25,6 +27,8 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs.
on processors that additionally support C-state residency counters. on processors that additionally support C-state residency counters.
.SS Options .SS Options
The \fB-s\fP option prints only a 1-line summary for each sample interval.
.PP
The \fB-v\fP option increases verbosity. The \fB-v\fP option increases verbosity.
.PP .PP
The \fB-M MSR#\fP option dumps the specified MSR, The \fB-M MSR#\fP option dumps the specified MSR,
@ -39,13 +43,14 @@ displays the statistics gathered since it was forked.
.SH FIELD DESCRIPTIONS .SH FIELD DESCRIPTIONS
.nf .nf
\fBpk\fP processor package number. \fBpk\fP processor package number.
\fBcr\fP processor core number. \fBcor\fP processor core number.
\fBCPU\fP Linux CPU (logical processor) number. \fBCPU\fP Linux CPU (logical processor) number.
Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology.
\fB%c0\fP percent of the interval that the CPU retired instructions. \fB%c0\fP percent of the interval that the CPU retired instructions.
\fBGHz\fP average clock rate while the CPU was in c0 state. \fBGHz\fP average clock rate while the CPU was in c0 state.
\fBTSC\fP average GHz that the TSC ran during the entire interval. \fBTSC\fP average GHz that the TSC ran during the entire interval.
\fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states. \fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states.
\fB%pc3, %pc6\fP percentage residency in hardware package idle states. \fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states.
.fi .fi
.PP .PP
.SH EXAMPLE .SH EXAMPLE
@ -53,25 +58,37 @@ Without any parameters, turbostat prints out counters ever 5 seconds.
(override interval with "-i sec" option, or specify a command (override interval with "-i sec" option, or specify a command
for turbostat to fork). for turbostat to fork).
The first row of statistics reflect the average for the entire system. The first row of statistics is a summary for the entire system.
Note that the summary is a weighted average.
Subsequent rows show per-CPU statistics. Subsequent rows show per-CPU statistics.
.nf .nf
[root@x980]# ./turbostat [root@x980]# ./turbostat
cr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07 0.60 1.63 3.38 2.91 0.00 96.49 0.00 76.64
0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07 0 0 0.59 1.62 3.38 4.51 0.00 94.90 0.00 76.64
0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07 0 6 1.13 1.64 3.38 3.97 0.00 94.90 0.00 76.64
1 2 0.10 1.62 3.38 0.29 0.00 99.61 0.00 95.07 1 2 0.08 1.62 3.38 0.07 0.00 99.85 0.00 76.64
1 8 0.11 1.62 3.38 0.28 0.00 99.61 0.00 95.07 1 8 0.03 1.62 3.38 0.12 0.00 99.85 0.00 76.64
2 4 0.01 1.62 3.38 0.01 0.00 99.98 0.00 95.07 2 4 0.01 1.62 3.38 0.06 0.00 99.93 0.00 76.64
2 10 0.01 1.61 3.38 0.02 0.00 99.98 0.00 95.07 2 10 0.04 1.62 3.38 0.02 0.00 99.93 0.00 76.64
8 1 0.07 1.62 3.38 0.15 0.00 99.78 0.00 95.07 8 1 2.85 1.62 3.38 11.71 0.00 85.44 0.00 76.64
8 7 0.03 1.62 3.38 0.19 0.00 99.78 0.00 95.07 8 7 1.98 1.62 3.38 12.58 0.00 85.44 0.00 76.64
9 3 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07 9 3 0.36 1.62 3.38 0.71 0.00 98.93 0.00 76.64
9 9 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07 9 9 0.09 1.62 3.38 0.98 0.00 98.93 0.00 76.64
10 5 0.01 1.62 3.38 0.13 0.00 99.86 0.00 95.07 10 5 0.03 1.62 3.38 0.09 0.00 99.87 0.00 76.64
10 11 0.08 1.62 3.38 0.05 0.00 99.86 0.00 95.07 10 11 0.07 1.62 3.38 0.06 0.00 99.87 0.00 76.64
.fi
.SH SUMMARY EXAMPLE
The "-s" option prints the column headers just once,
and then the one line system summary for each sample interval.
.nf
[root@x980]# ./turbostat -s
%c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
0.61 1.89 3.38 5.95 0.00 93.44 0.00 66.33
0.52 1.62 3.38 6.83 0.00 92.65 0.00 61.11
0.62 1.92 3.38 5.47 0.00 93.91 0.00 67.31
.fi .fi
.SH VERBOSE EXAMPLE .SH VERBOSE EXAMPLE
The "-v" option adds verbosity to the output: The "-v" option adds verbosity to the output:
@ -101,33 +118,33 @@ until ^C while the other CPUs are mostly idle:
.nf .nf
[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
^C
^Ccr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00 8.63 3.64 3.38 14.46 0.49 76.42 0.00 0.00
0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00 0 0 0.34 3.36 3.38 99.66 0.00 0.00 0.00 0.00
0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00 0 6 99.96 3.64 3.38 0.04 0.00 0.00 0.00 0.00
1 2 0.11 3.14 3.38 0.19 3.95 95.75 0.00 0.00 1 2 0.14 3.50 3.38 1.75 2.04 96.07 0.00 0.00
1 8 0.05 2.88 3.38 0.25 3.95 95.75 0.00 0.00 1 8 0.38 3.57 3.38 1.51 2.04 96.07 0.00 0.00
2 4 0.00 3.13 3.38 0.02 0.00 99.98 0.00 0.00 2 4 0.01 2.65 3.38 0.06 0.00 99.93 0.00 0.00
2 10 0.00 3.09 3.38 0.02 0.00 99.98 0.00 0.00 2 10 0.03 2.12 3.38 0.04 0.00 99.93 0.00 0.00
8 1 0.04 3.50 3.38 14.43 0.00 85.54 0.00 0.00 8 1 0.91 3.59 3.38 35.27 0.92 62.90 0.00 0.00
8 7 0.03 2.98 3.38 14.43 0.00 85.54 0.00 0.00 8 7 1.61 3.63 3.38 34.57 0.92 62.90 0.00 0.00
9 3 0.00 3.16 3.38 100.00 0.00 0.00 0.00 0.00 9 3 0.04 3.38 3.38 0.20 0.00 99.76 0.00 0.00
9 9 99.93 3.63 3.38 0.06 0.00 0.00 0.00 0.00 9 9 0.04 3.29 3.38 0.20 0.00 99.76 0.00 0.00
10 5 0.01 2.82 3.38 0.08 0.00 99.91 0.00 0.00 10 5 0.03 3.08 3.38 0.12 0.00 99.85 0.00 0.00
10 11 0.02 3.36 3.38 0.06 0.00 99.91 0.00 0.00 10 11 0.05 3.07 3.38 0.10 0.00 99.85 0.00 0.00
6.950866 sec 4.907015 sec
.fi .fi
Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit Above the cycle soaker drives cpu6 up 3.6 Ghz turbo limit
while the other processors are generally in various states of idle. while the other processors are generally in various states of idle.
Note that cpu3 is an HT sibling sharing core9 Note that cpu0 is an HT sibling sharing core0
with cpu9, and thus it is unable to get to an idle state with cpu6, and thus it is unable to get to an idle state
deeper than c1 while cpu9 is busy. deeper than c1 while cpu6 is busy.
Note that turbostat reports average GHz of 3.61, while Note that turbostat reports average GHz of 3.64, while
the arithmetic average of the GHz column above is 3.24. the arithmetic average of the GHz column above is lower.
This is a weighted average, where the weight is %c0. ie. it is the total number of This is a weighted average, where the weight is %c0. ie. it is the total number of
un-halted cycles elapsed per time divided by the number of CPUs. un-halted cycles elapsed per time divided by the number of CPUs.
.SH NOTES .SH NOTES
@ -167,6 +184,6 @@ http://www.intel.com/products/processor/manuals/
.SH "SEE ALSO" .SH "SEE ALSO"
msr(4), vmstat(8) msr(4), vmstat(8)
.PP .PP
.SH AUTHORS .SH AUTHOR
.nf .nf
Written by Len Brown <len.brown@intel.com> Written by Len Brown <len.brown@intel.com>

View File

@ -2,7 +2,7 @@
* turbostat -- show CPU frequency and C-state residency * turbostat -- show CPU frequency and C-state residency
* on modern Intel turbo-capable processors. * on modern Intel turbo-capable processors.
* *
* Copyright (c) 2010, Intel Corporation. * Copyright (c) 2012 Intel Corporation.
* Len Brown <len.brown@intel.com> * Len Brown <len.brown@intel.com>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -19,6 +19,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
@ -32,6 +33,7 @@
#include <dirent.h> #include <dirent.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <sched.h>
#define MSR_TSC 0x10 #define MSR_TSC 0x10
#define MSR_NEHALEM_PLATFORM_INFO 0xCE #define MSR_NEHALEM_PLATFORM_INFO 0xCE
@ -49,6 +51,7 @@
char *proc_stat = "/proc/stat"; char *proc_stat = "/proc/stat";
unsigned int interval_sec = 5; /* set with -i interval_sec */ unsigned int interval_sec = 5; /* set with -i interval_sec */
unsigned int verbose; /* set with -v */ unsigned int verbose; /* set with -v */
unsigned int summary_only; /* set with -s */
unsigned int skip_c0; unsigned int skip_c0;
unsigned int skip_c1; unsigned int skip_c1;
unsigned int do_nhm_cstates; unsigned int do_nhm_cstates;
@ -68,9 +71,10 @@ unsigned int show_cpu;
int aperf_mperf_unstable; int aperf_mperf_unstable;
int backwards_count; int backwards_count;
char *progname; char *progname;
int need_reinitialize;
int num_cpus; int num_cpus;
cpu_set_t *cpu_mask;
size_t cpu_mask_size;
struct counters { struct counters {
unsigned long long tsc; /* per thread */ unsigned long long tsc; /* per thread */
@ -99,44 +103,76 @@ struct timeval tv_even;
struct timeval tv_odd; struct timeval tv_odd;
struct timeval tv_delta; struct timeval tv_delta;
unsigned long long get_msr(int cpu, off_t offset) /*
* cpu_mask_init(ncpus)
*
* allocate and clear cpu_mask
* set cpu_mask_size
*/
void cpu_mask_init(int ncpus)
{
cpu_mask = CPU_ALLOC(ncpus);
if (cpu_mask == NULL) {
perror("CPU_ALLOC");
exit(3);
}
cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
CPU_ZERO_S(cpu_mask_size, cpu_mask);
}
void cpu_mask_uninit()
{
CPU_FREE(cpu_mask);
cpu_mask = NULL;
cpu_mask_size = 0;
}
int cpu_migrate(int cpu)
{
CPU_ZERO_S(cpu_mask_size, cpu_mask);
CPU_SET_S(cpu, cpu_mask_size, cpu_mask);
if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1)
return -1;
else
return 0;
}
int get_msr(int cpu, off_t offset, unsigned long long *msr)
{ {
ssize_t retval; ssize_t retval;
unsigned long long msr;
char pathname[32]; char pathname[32];
int fd; int fd;
sprintf(pathname, "/dev/cpu/%d/msr", cpu); sprintf(pathname, "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY); fd = open(pathname, O_RDONLY);
if (fd < 0) { if (fd < 0)
perror(pathname); return -1;
need_reinitialize = 1;
return 0;
}
retval = pread(fd, &msr, sizeof msr, offset);
if (retval != sizeof msr) {
fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
cpu, offset, retval);
exit(-2);
}
retval = pread(fd, msr, sizeof *msr, offset);
close(fd); close(fd);
return msr;
if (retval != sizeof *msr)
return -1;
return 0;
} }
void print_header(void) void print_header(void)
{ {
if (show_pkg) if (show_pkg)
fprintf(stderr, "pk"); fprintf(stderr, "pk");
if (show_pkg)
fprintf(stderr, " ");
if (show_core) if (show_core)
fprintf(stderr, " cr"); fprintf(stderr, "cor");
if (show_cpu) if (show_cpu)
fprintf(stderr, " CPU"); fprintf(stderr, " CPU");
if (show_pkg || show_core || show_cpu)
fprintf(stderr, " ");
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %%c0 "); fprintf(stderr, " %%c0");
if (has_aperf) if (has_aperf)
fprintf(stderr, " GHz"); fprintf(stderr, " GHz");
fprintf(stderr, " TSC"); fprintf(stderr, " TSC");
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %%c1"); fprintf(stderr, " %%c1");
@ -147,13 +183,13 @@ void print_header(void)
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %%c7"); fprintf(stderr, " %%c7");
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %%pc2"); fprintf(stderr, " %%pc2");
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %%pc3"); fprintf(stderr, " %%pc3");
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %%pc6"); fprintf(stderr, " %%pc6");
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %%pc7"); fprintf(stderr, " %%pc7");
if (extra_msr_offset) if (extra_msr_offset)
fprintf(stderr, " MSR 0x%x ", extra_msr_offset); fprintf(stderr, " MSR 0x%x ", extra_msr_offset);
@ -187,6 +223,15 @@ void dump_list(struct counters *cnt)
dump_cnt(cnt); dump_cnt(cnt);
} }
/*
* column formatting convention & formats
* package: "pk" 2 columns %2d
* core: "cor" 3 columns %3d
* CPU: "CPU" 3 columns %3d
* GHz: "GHz" 3 columns %3.2
* TSC: "TSC" 3 columns %3.2
* percentage " %pc3" %6.2
*/
void print_cnt(struct counters *p) void print_cnt(struct counters *p)
{ {
double interval_float; double interval_float;
@ -196,39 +241,45 @@ void print_cnt(struct counters *p)
/* topology columns, print blanks on 1st (average) line */ /* topology columns, print blanks on 1st (average) line */
if (p == cnt_average) { if (p == cnt_average) {
if (show_pkg) if (show_pkg)
fprintf(stderr, " ");
if (show_pkg && show_core)
fprintf(stderr, " "); fprintf(stderr, " ");
if (show_core) if (show_core)
fprintf(stderr, " "); fprintf(stderr, " ");
if (show_cpu) if (show_cpu)
fprintf(stderr, " "); fprintf(stderr, " " " ");
} else { } else {
if (show_pkg) if (show_pkg)
fprintf(stderr, "%d", p->pkg); fprintf(stderr, "%2d", p->pkg);
if (show_pkg && show_core)
fprintf(stderr, " ");
if (show_core) if (show_core)
fprintf(stderr, "%4d", p->core); fprintf(stderr, "%3d", p->core);
if (show_cpu) if (show_cpu)
fprintf(stderr, "%4d", p->cpu); fprintf(stderr, " %3d", p->cpu);
} }
/* %c0 */ /* %c0 */
if (do_nhm_cstates) { if (do_nhm_cstates) {
if (show_pkg || show_core || show_cpu)
fprintf(stderr, " ");
if (!skip_c0) if (!skip_c0)
fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc); fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc);
else else
fprintf(stderr, " ****"); fprintf(stderr, " ****");
} }
/* GHz */ /* GHz */
if (has_aperf) { if (has_aperf) {
if (!aperf_mperf_unstable) { if (!aperf_mperf_unstable) {
fprintf(stderr, "%5.2f", fprintf(stderr, " %3.2f",
1.0 * p->tsc / units * p->aperf / 1.0 * p->tsc / units * p->aperf /
p->mperf / interval_float); p->mperf / interval_float);
} else { } else {
if (p->aperf > p->tsc || p->mperf > p->tsc) { if (p->aperf > p->tsc || p->mperf > p->tsc) {
fprintf(stderr, " ****"); fprintf(stderr, " ***");
} else { } else {
fprintf(stderr, "%4.1f*", fprintf(stderr, "%3.1f*",
1.0 * p->tsc / 1.0 * p->tsc /
units * p->aperf / units * p->aperf /
p->mperf / interval_float); p->mperf / interval_float);
@ -241,7 +292,7 @@ void print_cnt(struct counters *p)
if (do_nhm_cstates) { if (do_nhm_cstates) {
if (!skip_c1) if (!skip_c1)
fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc);
else else
fprintf(stderr, " ****"); fprintf(stderr, " ****");
} }
@ -252,13 +303,13 @@ void print_cnt(struct counters *p)
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc);
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc);
if (do_nhm_cstates) if (do_nhm_cstates)
fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc);
if (do_snb_cstates) if (do_snb_cstates)
fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc); fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc);
if (extra_msr_offset) if (extra_msr_offset)
fprintf(stderr, " 0x%016llx", p->extra_msr); fprintf(stderr, " 0x%016llx", p->extra_msr);
putc('\n', stderr); putc('\n', stderr);
@ -267,12 +318,20 @@ void print_cnt(struct counters *p)
void print_counters(struct counters *counters) void print_counters(struct counters *counters)
{ {
struct counters *cnt; struct counters *cnt;
static int printed;
print_header();
if (!printed || !summary_only)
print_header();
if (num_cpus > 1) if (num_cpus > 1)
print_cnt(cnt_average); print_cnt(cnt_average);
printed = 1;
if (summary_only)
return;
for (cnt = counters; cnt != NULL; cnt = cnt->next) for (cnt = counters; cnt != NULL; cnt = cnt->next)
print_cnt(cnt); print_cnt(cnt);
@ -440,31 +499,51 @@ void compute_average(struct counters *delta, struct counters *avg)
free(sum); free(sum);
} }
void get_counters(struct counters *cnt) int get_counters(struct counters *cnt)
{ {
for ( ; cnt; cnt = cnt->next) { for ( ; cnt; cnt = cnt->next) {
cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
if (do_nhm_cstates) if (cpu_migrate(cnt->cpu))
cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY); return -1;
if (do_nhm_cstates)
cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY); if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc))
return -1;
if (has_aperf) {
if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf))
return -1;
if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf))
return -1;
}
if (do_nhm_cstates) {
if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3))
return -1;
if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6))
return -1;
}
if (do_snb_cstates) if (do_snb_cstates)
cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY); if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7))
if (has_aperf) return -1;
cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
if (has_aperf) if (do_nhm_cstates) {
cnt->mperf = get_msr(cnt->cpu, MSR_MPERF); if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3))
if (do_snb_cstates) return -1;
cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY); if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6))
if (do_nhm_cstates) return -1;
cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY); }
if (do_nhm_cstates) if (do_snb_cstates) {
cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY); if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2))
if (do_snb_cstates) return -1;
cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY); if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7))
return -1;
}
if (extra_msr_offset) if (extra_msr_offset)
cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset); if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr))
return -1;
} }
return 0;
} }
void print_nehalem_info(void) void print_nehalem_info(void)
@ -475,7 +554,7 @@ void print_nehalem_info(void)
if (!do_nehalem_platform_info) if (!do_nehalem_platform_info)
return; return;
msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO); get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
ratio = (msr >> 40) & 0xFF; ratio = (msr >> 40) & 0xFF;
fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@ -491,7 +570,7 @@ void print_nehalem_info(void)
if (!do_nehalem_turbo_ratio_limit) if (!do_nehalem_turbo_ratio_limit)
return; return;
msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT); get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
ratio = (msr >> 24) & 0xFF; ratio = (msr >> 24) & 0xFF;
if (ratio) if (ratio)
@ -557,7 +636,8 @@ void insert_counters(struct counters **list,
return; return;
} }
show_cpu = 1; /* there is more than one CPU */ if (!summary_only)
show_cpu = 1; /* there is more than one CPU */
/* /*
* insert on front of list. * insert on front of list.
@ -575,13 +655,15 @@ void insert_counters(struct counters **list,
while (prev->next && (prev->next->pkg < new->pkg)) { while (prev->next && (prev->next->pkg < new->pkg)) {
prev = prev->next; prev = prev->next;
show_pkg = 1; /* there is more than 1 package */ if (!summary_only)
show_pkg = 1; /* there is more than 1 package */
} }
while (prev->next && (prev->next->pkg == new->pkg) while (prev->next && (prev->next->pkg == new->pkg)
&& (prev->next->core < new->core)) { && (prev->next->core < new->core)) {
prev = prev->next; prev = prev->next;
show_core = 1; /* there is more than 1 core */ if (!summary_only)
show_core = 1; /* there is more than 1 core */
} }
while (prev->next && (prev->next->pkg == new->pkg) while (prev->next && (prev->next->pkg == new->pkg)
@ -681,7 +763,7 @@ int get_core_id(int cpu)
} }
/* /*
* run func(index, cpu) on every cpu in /proc/stat * run func(pkg, core, cpu) on every cpu in /proc/stat
*/ */
int for_all_cpus(void (func)(int, int, int)) int for_all_cpus(void (func)(int, int, int))
@ -717,18 +799,18 @@ int for_all_cpus(void (func)(int, int, int))
void re_initialize(void) void re_initialize(void)
{ {
printf("turbostat: topology changed, re-initializing.\n");
free_all_counters(); free_all_counters();
num_cpus = for_all_cpus(alloc_new_counters); num_cpus = for_all_cpus(alloc_new_counters);
need_reinitialize = 0; cpu_mask_uninit();
printf("num_cpus is now %d\n", num_cpus); cpu_mask_init(num_cpus);
printf("turbostat: re-initialized with num_cpus %d\n", num_cpus);
} }
void dummy(int pkg, int core, int cpu) { return; } void dummy(int pkg, int core, int cpu) { return; }
/* /*
* check to see if a cpu came on-line * check to see if a cpu came on-line
*/ */
void verify_num_cpus(void) int verify_num_cpus(void)
{ {
int new_num_cpus; int new_num_cpus;
@ -738,8 +820,9 @@ void verify_num_cpus(void)
if (verbose) if (verbose)
printf("num_cpus was %d, is now %d\n", printf("num_cpus was %d, is now %d\n",
num_cpus, new_num_cpus); num_cpus, new_num_cpus);
need_reinitialize = 1; return -1;
} }
return 0;
} }
void turbostat_loop() void turbostat_loop()
@ -749,25 +832,25 @@ restart:
gettimeofday(&tv_even, (struct timezone *)NULL); gettimeofday(&tv_even, (struct timezone *)NULL);
while (1) { while (1) {
verify_num_cpus(); if (verify_num_cpus()) {
if (need_reinitialize) {
re_initialize(); re_initialize();
goto restart; goto restart;
} }
sleep(interval_sec); sleep(interval_sec);
get_counters(cnt_odd); if (get_counters(cnt_odd)) {
re_initialize();
goto restart;
}
gettimeofday(&tv_odd, (struct timezone *)NULL); gettimeofday(&tv_odd, (struct timezone *)NULL);
compute_delta(cnt_odd, cnt_even, cnt_delta); compute_delta(cnt_odd, cnt_even, cnt_delta);
timersub(&tv_odd, &tv_even, &tv_delta); timersub(&tv_odd, &tv_even, &tv_delta);
compute_average(cnt_delta, cnt_average); compute_average(cnt_delta, cnt_average);
print_counters(cnt_delta); print_counters(cnt_delta);
if (need_reinitialize) { sleep(interval_sec);
if (get_counters(cnt_even)) {
re_initialize(); re_initialize();
goto restart; goto restart;
} }
sleep(interval_sec);
get_counters(cnt_even);
gettimeofday(&tv_even, (struct timezone *)NULL); gettimeofday(&tv_even, (struct timezone *)NULL);
compute_delta(cnt_even, cnt_odd, cnt_delta); compute_delta(cnt_even, cnt_odd, cnt_delta);
timersub(&tv_even, &tv_odd, &tv_delta); timersub(&tv_even, &tv_odd, &tv_delta);
@ -953,6 +1036,7 @@ void turbostat_init()
check_super_user(); check_super_user();
num_cpus = for_all_cpus(alloc_new_counters); num_cpus = for_all_cpus(alloc_new_counters);
cpu_mask_init(num_cpus);
if (verbose) if (verbose)
print_nehalem_info(); print_nehalem_info();
@ -1005,8 +1089,11 @@ void cmdline(int argc, char **argv)
progname = argv[0]; progname = argv[0];
while ((opt = getopt(argc, argv, "+vi:M:")) != -1) { while ((opt = getopt(argc, argv, "+svi:M:")) != -1) {
switch (opt) { switch (opt) {
case 's':
summary_only++;
break;
case 'v': case 'v':
verbose++; verbose++;
break; break;