1317 lines · 34.5 KB · C
RawDownload
/* * processor_idle - idle state submodule to the ACPI processor driver * *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> *  Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de> *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> *  			- Added processor hotplug support *  Copyright (C) 2005  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> *  			- Added support for C3 on SMP * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or (at *  your option) any later version. * *  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. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/cpufreq.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/acpi.h>#include <linux/dmi.h>#include <linux/moduleparam.h>#include <linux/sched.h>	/* need_resched() */#include <linux/latency.h>#include <linux/clockchips.h> /* * Include the apic definitions for x86 to have the APIC timer related defines * available also for UP (on SMP it gets magically included via linux/smp.h). * asm/acpi.h is not an option, as it would require more include magic. Also * creating an empty asm-ia64/apic.h would just trade pest vs. cholera. */#ifdef CONFIG_X86#include <asm/apic.h>#endif /* * Include the apic definitions for x86 to have the APIC timer related defines * available also for UP (on SMP it gets magically included via linux/smp.h). */#ifdef CONFIG_X86#include <asm/apic.h>#endif #include <asm/io.h>#include <asm/uaccess.h> #include <acpi/acpi_bus.h>#include <acpi/processor.h> #define ACPI_PROCESSOR_COMPONENT        0x01000000#define ACPI_PROCESSOR_CLASS            "processor"#define _COMPONENT              ACPI_PROCESSOR_COMPONENTACPI_MODULE_NAME("processor_idle");#define ACPI_PROCESSOR_FILE_POWER	"power"#define US_TO_PM_TIMER_TICKS(t)		((t * (PM_TIMER_FREQUENCY/1000)) / 1000)#define C2_OVERHEAD			4	/* 1us (3.579 ticks per us) */#define C3_OVERHEAD			4	/* 1us (3.579 ticks per us) */static void (*pm_idle_save) (void) __read_mostly;module_param(max_cstate, uint, 0644); static unsigned int nocst __read_mostly;module_param(nocst, uint, 0000); /* * bm_history -- bit-mask with a bit per jiffy of bus-master activity * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms * 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms * 100 HZ: 0x0000000F: 4 jiffies = 40ms * reduce history for more aggressive entry into C3 */static unsigned int bm_history __read_mostly =    (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));module_param(bm_history, uint, 0644);/* --------------------------------------------------------------------------                                Power Management   -------------------------------------------------------------------------- */ /* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else. * * To skip this limit, boot/load with a large max_cstate limit. */static int set_max_cstate(struct dmi_system_id *id){	if (max_cstate > ACPI_PROCESSOR_MAX_POWER)		return 0; 	printk(KERN_NOTICE PREFIX "%s detected - limiting to C%ld max_cstate."	       " Override with \"processor.max_cstate=%d\"\n", id->ident,	       (long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1); 	max_cstate = (long)id->driver_data; 	return 0;} /* Actually this shouldn't be __cpuinitdata, would be better to fix the   callers to only run once -AK */static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1},	{ set_max_cstate, "IBM ThinkPad R40e", {	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),	  DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1},	{ set_max_cstate, "Medion 41700", {	  DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),	  DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1},	{ set_max_cstate, "Clevo 5600D", {	  DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),	  DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},	 (void *)2},	{},}; static inline u32 ticks_elapsed(u32 t1, u32 t2){	if (t2 >= t1)		return (t2 - t1);	else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))		return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);	else		return ((0xFFFFFFFF - t1) + t2);} static voidacpi_processor_power_activate(struct acpi_processor *pr,			      struct acpi_processor_cx *new){	struct acpi_processor_cx *old; 	if (!pr || !new)		return; 	old = pr->power.state; 	if (old)		old->promotion.count = 0;	new->demotion.count = 0; 	/* Cleanup from old state. */	if (old) {		switch (old->type) {		case ACPI_STATE_C3:			/* Disable bus master reload */			if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)				acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);			break;		}	} 	/* Prepare to use new state. */	switch (new->type) {	case ACPI_STATE_C3:		/* Enable bus master reload */		if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);		break;	} 	pr->power.state = new; 	return;} static void acpi_safe_halt(void){	current_thread_info()->status &= ~TS_POLLING;	/*	 * TS_POLLING-cleared state must be visible before we	 * test NEED_RESCHED:	 */	smp_mb();	if (!need_resched())		safe_halt();	current_thread_info()->status |= TS_POLLING;} static atomic_t c3_cpu_count; /* Common C-state entry for C2, C3, .. */static void acpi_cstate_enter(struct acpi_processor_cx *cstate){	if (cstate->space_id == ACPI_CSTATE_FFH) {		/* Call into architectural FFH based C-state */		acpi_processor_ffh_cstate_enter(cstate);	} else {		int unused;		/* IO port based C-state */		inb(cstate->address);		/* Dummy wait op - must do something useless after P_LVL2 read		   because chipsets cannot guarantee that STPCLK# signal		   gets asserted in time to freeze execution properly. */		unused = inl(acpi_gbl_FADT.xpm_timer_block.address);	}} #ifdef ARCH_APICTIMER_STOPS_ON_C3 /* * Some BIOS implementations switch to C3 in the published C2 state. * This seems to be a common problem on AMD boxen, but other vendors * are affected too. We pick the most conservative approach: we assume * that the local APIC stops in both C2 and C3. */static void acpi_timer_check_state(int state, struct acpi_processor *pr,				   struct acpi_processor_cx *cx){	struct acpi_processor_power *pwr = &pr->power;	u8 type = local_apic_timer_c2_ok ? ACPI_STATE_C3 : ACPI_STATE_C2; 	/*	 * Check, if one of the previous states already marked the lapic	 * unstable	 */	if (pwr->timer_broadcast_on_state < state)		return; 	if (cx->type >= type)		pr->power.timer_broadcast_on_state = state;} static void acpi_propagate_timer_broadcast(struct acpi_processor *pr){#ifdef CONFIG_GENERIC_CLOCKEVENTS	unsigned long reason; 	reason = pr->power.timer_broadcast_on_state < INT_MAX ?		CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; 	clockevents_notify(reason, &pr->id);#else	cpumask_t mask = cpumask_of_cpu(pr->id); 	if (pr->power.timer_broadcast_on_state < INT_MAX)		on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);	else		on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);#endif} /* Power(C) State timer broadcast control */static void acpi_state_timer_broadcast(struct acpi_processor *pr,				       struct acpi_processor_cx *cx,				       int broadcast){#ifdef CONFIG_GENERIC_CLOCKEVENTS 	int state = cx - pr->power.states; 	if (state >= pr->power.timer_broadcast_on_state) {		unsigned long reason; 		reason = broadcast ?  CLOCK_EVT_NOTIFY_BROADCAST_ENTER :			CLOCK_EVT_NOTIFY_BROADCAST_EXIT;		clockevents_notify(reason, &pr->id);	}#endif} #else static void acpi_timer_check_state(int state, struct acpi_processor *pr,				   struct acpi_processor_cx *cstate) { }static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { }static void acpi_state_timer_broadcast(struct acpi_processor *pr,				       struct acpi_processor_cx *cx,				       int broadcast){} #endif static void acpi_processor_idle(void){	struct acpi_processor *pr = NULL;	struct acpi_processor_cx *cx = NULL;	struct acpi_processor_cx *next_state = NULL;	int sleep_ticks = 0;	u32 t1, t2 = 0; 	pr = processors[smp_processor_id()];	if (!pr)		return; 	/*	 * Interrupts must be disabled during bus mastering calculations and	 * for C2/C3 transitions.	 */	local_irq_disable(); 	/*	 * Check whether we truly need to go idle, or should	 * reschedule:	 */	if (unlikely(need_resched())) {		local_irq_enable();		return;	} 	cx = pr->power.state;	if (!cx) {		if (pm_idle_save)			pm_idle_save();		else			acpi_safe_halt();		return;	} 	/*	 * Check BM Activity	 * -----------------	 * Check for bus mastering activity (if required), record, and check	 * for demotion.	 */	if (pr->flags.bm_check) {		u32 bm_status = 0;		unsigned long diff = jiffies - pr->power.bm_check_timestamp; 		if (diff > 31)			diff = 31; 		pr->power.bm_activity <<= diff; 		acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);		if (bm_status) {			pr->power.bm_activity |= 0x1;			acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);		}		/*		 * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect		 * the true state of bus mastering activity; forcing us to		 * manually check the BMIDEA bit of each IDE channel.		 */		else if (errata.piix4.bmisx) {			if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)			    || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))				pr->power.bm_activity |= 0x1;		} 		pr->power.bm_check_timestamp = jiffies; 		/*		 * If bus mastering is or was active this jiffy, demote		 * to avoid a faulty transition.  Note that the processor		 * won't enter a low-power state during this call (to this		 * function) but should upon the next.		 *		 * TBD: A better policy might be to fallback to the demotion		 *      state (use it for this quantum only) istead of		 *      demoting -- and rely on duration as our sole demotion		 *      qualification.  This may, however, introduce DMA		 *      issues (e.g. floppy DMA transfer overrun/underrun).		 */		if ((pr->power.bm_activity & 0x1) &&		    cx->demotion.threshold.bm) {			local_irq_enable();			next_state = cx->demotion.state;			goto end;		}	} #ifdef CONFIG_HOTPLUG_CPU	/*	 * Check for P_LVL2_UP flag before entering C2 and above on	 * an SMP system. We do it here instead of doing it at _CST/P_LVL	 * detection phase, to work cleanly with logical CPU hotplug.	 */	if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && 	    !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))		cx = &pr->power.states[ACPI_STATE_C1];#endif 	/*	 * Sleep:	 * ------	 * Invoke the current Cx state to put the processor to sleep.	 */	if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {		current_thread_info()->status &= ~TS_POLLING;		/*		 * TS_POLLING-cleared state must be visible before we		 * test NEED_RESCHED:		 */		smp_mb();		if (need_resched()) {			current_thread_info()->status |= TS_POLLING;			local_irq_enable();			return;		}	} 	switch (cx->type) { 	case ACPI_STATE_C1:		/*		 * Invoke C1.		 * Use the appropriate idle routine, the one that would		 * be used without acpi C-states.		 */		if (pm_idle_save)			pm_idle_save();		else			acpi_safe_halt(); 		/*		 * TBD: Can't get time duration while in C1, as resumes		 *      go to an ISR rather than here.  Need to instrument		 *      base interrupt handler.		 */		sleep_ticks = 0xFFFFFFFF;		break; 	case ACPI_STATE_C2:		/* Get start time (ticks) */		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);		/* Invoke C2 */		acpi_state_timer_broadcast(pr, cx, 1);		acpi_cstate_enter(cx);		/* Get end time (ticks) */		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); #ifdef CONFIG_GENERIC_TIME		/* TSC halts in C2, so notify users */		mark_tsc_unstable();#endif		/* Re-enable interrupts */		local_irq_enable();		current_thread_info()->status |= TS_POLLING;		/* Compute time (ticks) that we were actually asleep */		sleep_ticks =		    ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;		acpi_state_timer_broadcast(pr, cx, 0);		break; 	case ACPI_STATE_C3: 		if (pr->flags.bm_check) {			if (atomic_inc_return(&c3_cpu_count) ==

Lines 1–500 of 1317.