1215 lines · 30.6 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/module.h>#include <linux/acpi.h>#include <linux/dmi.h>#include <linux/sched.h>       /* need_resched() */#include <linux/clockchips.h>#include <linux/cpuidle.h>#include <linux/syscore_ops.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 <acpi/acpi_bus.h>#include <acpi/processor.h> #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS            "processor"#define _COMPONENT              ACPI_PROCESSOR_COMPONENTACPI_MODULE_NAME("processor_idle"); static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;module_param(max_cstate, uint, 0000);static unsigned int nocst __read_mostly;module_param(nocst, uint, 0000);static int bm_check_disable __read_mostly;module_param(bm_check_disable, uint, 0000); static unsigned int latency_factor __read_mostly = 2;module_param(latency_factor, uint, 0644); static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); static DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX],								acpi_cstate); static int disabled_by_idle_boot_param(void){	return boot_option_idle_override == IDLE_POLL ||		boot_option_idle_override == IDLE_HALT;} /* * 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(const 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;} static struct dmi_system_id processor_power_dmi_table[] = {	{ 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},	{ set_max_cstate, "Pavilion zv5000", {	  DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),	  DMI_MATCH(DMI_PRODUCT_NAME,"Pavilion zv5000 (DS502A#ABA)")},	 (void *)1},	{ set_max_cstate, "Asus L8400B", {	  DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),	  DMI_MATCH(DMI_PRODUCT_NAME,"L8400B series Notebook PC")},	 (void *)1},	{},};  /* * Callers should disable interrupts before the call and enable * interrupts after return. */static void acpi_safe_halt(void){	if (!tif_need_resched()) {		safe_halt();		local_irq_disable();	}} #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 lapic_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; 	if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))		return; 	if (amd_e400_c1e_detected)		type = ACPI_STATE_C1; 	/*	 * 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 __lapic_timer_propagate_broadcast(void *arg){	struct acpi_processor *pr = (struct acpi_processor *) arg;	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);} static void lapic_timer_propagate_broadcast(struct acpi_processor *pr){	smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast,				 (void *)pr, 1);} /* Power(C) State timer broadcast control */static void lapic_timer_state_broadcast(struct acpi_processor *pr,				       struct acpi_processor_cx *cx,				       int broadcast){	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);	}} #else static void lapic_timer_check_state(int state, struct acpi_processor *pr,				   struct acpi_processor_cx *cstate) { }static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { }static void lapic_timer_state_broadcast(struct acpi_processor *pr,				       struct acpi_processor_cx *cx,				       int broadcast){} #endif #ifdef CONFIG_PM_SLEEPstatic u32 saved_bm_rld; static int acpi_processor_suspend(void){	acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);	return 0;} static void acpi_processor_resume(void){	u32 resumed_bm_rld; 	acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);	if (resumed_bm_rld == saved_bm_rld)		return; 	acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);} static struct syscore_ops acpi_processor_syscore_ops = {	.suspend = acpi_processor_suspend,	.resume = acpi_processor_resume,}; void acpi_processor_syscore_init(void){	register_syscore_ops(&acpi_processor_syscore_ops);} void acpi_processor_syscore_exit(void){	unregister_syscore_ops(&acpi_processor_syscore_ops);}#endif /* CONFIG_PM_SLEEP */ #if defined(CONFIG_X86)static void tsc_check_state(int state){	switch (boot_cpu_data.x86_vendor) {	case X86_VENDOR_AMD:	case X86_VENDOR_INTEL:		/*		 * AMD Fam10h TSC will tick in all		 * C/P/S0/S1 states when this bit is set.		 */		if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))			return; 		/*FALL THROUGH*/	default:		/* TSC could halt in idle, so notify users */		if (state > ACPI_STATE_C1)			mark_tsc_unstable("TSC halts in idle");	}}#elsestatic void tsc_check_state(int state) { return; }#endif static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr){ 	if (!pr->pblk)		return -ENODEV; 	/* if info is obtained from pblk/fadt, type equals state */	pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;	pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; #ifndef CONFIG_HOTPLUG_CPU	/*	 * Check for P_LVL2_UP flag before entering C2 and above on	 * an SMP system.	 */	if ((num_online_cpus() > 1) &&	    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))		return -ENODEV;#endif 	/* determine C2 and C3 address from pblk */	pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4;	pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5; 	/* determine latencies from FADT */	pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.c2_latency;	pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.c3_latency; 	/*	 * FADT specified C2 latency must be less than or equal to	 * 100 microseconds.	 */	if (acpi_gbl_FADT.c2_latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {		ACPI_DEBUG_PRINT((ACPI_DB_INFO,			"C2 latency too large [%d]\n", acpi_gbl_FADT.c2_latency));		/* invalidate C2 */		pr->power.states[ACPI_STATE_C2].address = 0;	} 	/*	 * FADT supplied C3 latency must be less than or equal to	 * 1000 microseconds.	 */	if (acpi_gbl_FADT.c3_latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {		ACPI_DEBUG_PRINT((ACPI_DB_INFO,			"C3 latency too large [%d]\n", acpi_gbl_FADT.c3_latency));		/* invalidate C3 */		pr->power.states[ACPI_STATE_C3].address = 0;	} 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,			  "lvl2[0x%08x] lvl3[0x%08x]\n",			  pr->power.states[ACPI_STATE_C2].address,			  pr->power.states[ACPI_STATE_C3].address)); 	return 0;} static int acpi_processor_get_power_info_default(struct acpi_processor *pr){	if (!pr->power.states[ACPI_STATE_C1].valid) {		/* set the first C-State to C1 */		/* all processors need to support C1 */		pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;		pr->power.states[ACPI_STATE_C1].valid = 1;		pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;	}	/* the C0 state only exists as a filler in our array */	pr->power.states[ACPI_STATE_C0].valid = 1;	return 0;} static int acpi_processor_get_power_info_cst(struct acpi_processor *pr){	acpi_status status = 0;	u64 count;	int current_count;	int i;	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };	union acpi_object *cst;  	if (nocst)		return -ENODEV; 	current_count = 0; 	status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);	if (ACPI_FAILURE(status)) {		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n"));		return -ENODEV;	} 	cst = buffer.pointer; 	/* There must be at least 2 elements */	if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {		printk(KERN_ERR PREFIX "not enough elements in _CST\n");		status = -EFAULT;		goto end;	} 	count = cst->package.elements[0].integer.value; 	/* Validate number of power states. */	if (count < 1 || count != cst->package.count - 1) {		printk(KERN_ERR PREFIX "count given by _CST is not valid\n");		status = -EFAULT;		goto end;	} 	/* Tell driver that at least _CST is supported. */	pr->flags.has_cst = 1; 	for (i = 1; i <= count; i++) {		union acpi_object *element;		union acpi_object *obj;		struct acpi_power_register *reg;		struct acpi_processor_cx cx; 		memset(&cx, 0, sizeof(cx)); 		element = &(cst->package.elements[i]);		if (element->type != ACPI_TYPE_PACKAGE)			continue; 		if (element->package.count != 4)			continue; 		obj = &(element->package.elements[0]); 		if (obj->type != ACPI_TYPE_BUFFER)			continue; 		reg = (struct acpi_power_register *)obj->buffer.pointer; 		if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&		    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))			continue; 		/* There should be an easy way to extract an integer... */		obj = &(element->package.elements[1]);		if (obj->type != ACPI_TYPE_INTEGER)			continue; 		cx.type = obj->integer.value;		/*		 * Some buggy BIOSes won't list C1 in _CST -		 * Let acpi_processor_get_power_info_default() handle them later		 */		if (i == 1 && cx.type != ACPI_STATE_C1)			current_count++; 		cx.address = reg->address;		cx.index = current_count + 1; 		cx.entry_method = ACPI_CSTATE_SYSTEMIO;		if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {			if (acpi_processor_ffh_cstate_probe					(pr->id, &cx, reg) == 0) {				cx.entry_method = ACPI_CSTATE_FFH;			} else if (cx.type == ACPI_STATE_C1) {				/*				 * C1 is a special case where FIXED_HARDWARE				 * can be handled in non-MWAIT way as well.				 * In that case, save this _CST entry info.				 * Otherwise, ignore this info and continue.				 */				cx.entry_method = ACPI_CSTATE_HALT;				snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");			} else {				continue;			}			if (cx.type == ACPI_STATE_C1 &&			    (boot_option_idle_override == IDLE_NOMWAIT)) {				/*				 * In most cases the C1 space_id obtained from				 * _CST object is FIXED_HARDWARE access mode.				 * But when the option of idle=halt is added,				 * the entry_method type should be changed from				 * CSTATE_FFH to CSTATE_HALT.				 * When the option of idle=nomwait is added,				 * the C1 entry_method type should be				 * CSTATE_HALT.				 */				cx.entry_method = ACPI_CSTATE_HALT;				snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");			}		} else {			snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",				 cx.address);		} 		if (cx.type == ACPI_STATE_C1) {			cx.valid = 1;		} 		obj = &(element->package.elements[2]);		if (obj->type != ACPI_TYPE_INTEGER)			continue; 		cx.latency = obj->integer.value; 		obj = &(element->package.elements[3]);		if (obj->type != ACPI_TYPE_INTEGER)			continue; 		current_count++;		memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx)); 		/*		 * We support total ACPI_PROCESSOR_MAX_POWER - 1		 * (From 1 through ACPI_PROCESSOR_MAX_POWER - 1)		 */		if (current_count >= (ACPI_PROCESSOR_MAX_POWER - 1)) {			printk(KERN_WARNING			       "Limiting number of power states to max (%d)\n",			       ACPI_PROCESSOR_MAX_POWER);			printk(KERN_WARNING			       "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");			break;		}	} 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n",			  current_count)); 	/* Validate number of power states discovered */	if (current_count < 2)		status = -EFAULT;       end:	kfree(buffer.pointer); 	return status;}

Lines 1–500 of 1215.