11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * processor_idle - idle state submodule to the ACPI processor driver 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 6c5ab81caSDominik Brodowski * Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de> 71da177e4SLinus Torvalds * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> 81da177e4SLinus Torvalds * - Added processor hotplug support 902df8b93SVenkatesh Pallipadi * Copyright (C) 2005 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 1002df8b93SVenkatesh Pallipadi * - Added support for C3 on SMP 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 151da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 161da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 171da177e4SLinus Torvalds * your option) any later version. 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, but 201da177e4SLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 211da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 221da177e4SLinus Torvalds * General Public License for more details. 231da177e4SLinus Torvalds * 241da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License along 251da177e4SLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 261da177e4SLinus Torvalds * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 291da177e4SLinus Torvalds */ 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #include <linux/kernel.h> 321da177e4SLinus Torvalds #include <linux/module.h> 331da177e4SLinus Torvalds #include <linux/init.h> 341da177e4SLinus Torvalds #include <linux/cpufreq.h> 351da177e4SLinus Torvalds #include <linux/proc_fs.h> 361da177e4SLinus Torvalds #include <linux/seq_file.h> 371da177e4SLinus Torvalds #include <linux/acpi.h> 381da177e4SLinus Torvalds #include <linux/dmi.h> 391da177e4SLinus Torvalds #include <linux/moduleparam.h> 404e57b681STim Schmielau #include <linux/sched.h> /* need_resched() */ 415c87579eSArjan van de Ven #include <linux/latency.h> 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #include <asm/io.h> 441da177e4SLinus Torvalds #include <asm/uaccess.h> 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #include <acpi/acpi_bus.h> 471da177e4SLinus Torvalds #include <acpi/processor.h> 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #define ACPI_PROCESSOR_COMPONENT 0x01000000 501da177e4SLinus Torvalds #define ACPI_PROCESSOR_CLASS "processor" 511da177e4SLinus Torvalds #define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" 521da177e4SLinus Torvalds #define _COMPONENT ACPI_PROCESSOR_COMPONENT 53f52fd66dSLen Brown ACPI_MODULE_NAME("processor_idle"); 541da177e4SLinus Torvalds #define ACPI_PROCESSOR_FILE_POWER "power" 551da177e4SLinus Torvalds #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) 561da177e4SLinus Torvalds #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ 571da177e4SLinus Torvalds #define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */ 58b6835052SAndreas Mohr static void (*pm_idle_save) (void) __read_mostly; 591da177e4SLinus Torvalds module_param(max_cstate, uint, 0644); 601da177e4SLinus Torvalds 61b6835052SAndreas Mohr static unsigned int nocst __read_mostly; 621da177e4SLinus Torvalds module_param(nocst, uint, 0000); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* 651da177e4SLinus Torvalds * bm_history -- bit-mask with a bit per jiffy of bus-master activity 661da177e4SLinus Torvalds * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms 671da177e4SLinus Torvalds * 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms 681da177e4SLinus Torvalds * 100 HZ: 0x0000000F: 4 jiffies = 40ms 691da177e4SLinus Torvalds * reduce history for more aggressive entry into C3 701da177e4SLinus Torvalds */ 71b6835052SAndreas Mohr static unsigned int bm_history __read_mostly = 724be44fcdSLen Brown (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1)); 731da177e4SLinus Torvalds module_param(bm_history, uint, 0644); 741da177e4SLinus Torvalds /* -------------------------------------------------------------------------- 751da177e4SLinus Torvalds Power Management 761da177e4SLinus Torvalds -------------------------------------------------------------------------- */ 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. 801da177e4SLinus Torvalds * For now disable this. Probably a bug somewhere else. 811da177e4SLinus Torvalds * 821da177e4SLinus Torvalds * To skip this limit, boot/load with a large max_cstate limit. 831da177e4SLinus Torvalds */ 84335f16beSDavid Shaohua Li static int set_max_cstate(struct dmi_system_id *id) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds if (max_cstate > ACPI_PROCESSOR_MAX_POWER) 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds 893d35600aSLen Brown printk(KERN_NOTICE PREFIX "%s detected - limiting to C%ld max_cstate." 901da177e4SLinus Torvalds " Override with \"processor.max_cstate=%d\"\n", id->ident, 913d35600aSLen Brown (long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1); 921da177e4SLinus Torvalds 933d35600aSLen Brown max_cstate = (long)id->driver_data; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds return 0; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 987ded5689SAshok Raj /* Actually this shouldn't be __cpuinitdata, would be better to fix the 997ded5689SAshok Raj callers to only run once -AK */ 1007ded5689SAshok Raj static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { 101335f16beSDavid Shaohua Li { set_max_cstate, "IBM ThinkPad R40e", { 102876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 103f831335dSBartlomiej Swiercz DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1}, 104f831335dSBartlomiej Swiercz { set_max_cstate, "IBM ThinkPad R40e", { 105f831335dSBartlomiej Swiercz DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 106876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1}, 107876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 108876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 109876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1}, 110876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 111876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 112876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1}, 113876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 114876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 115876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1}, 116876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 117876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 118876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1}, 119876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 120876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 121876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1}, 122876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 123876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 124876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1}, 125876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 126876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 127876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1}, 128876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 129876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 130876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1}, 131876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 132876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 133876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1}, 134876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 135876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 136876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1}, 137876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 138876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 139876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1}, 140876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 141876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 142876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1}, 143876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 144876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 145876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1}, 146876c184bSThomas Rosner { set_max_cstate, "IBM ThinkPad R40e", { 147876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), 148876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1}, 149335f16beSDavid Shaohua Li { set_max_cstate, "Medion 41700", { 150876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), 151876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1}, 152335f16beSDavid Shaohua Li { set_max_cstate, "Clevo 5600D", { 153876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), 154876c184bSThomas Rosner DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, 155335f16beSDavid Shaohua Li (void *)2}, 1561da177e4SLinus Torvalds {}, 1571da177e4SLinus Torvalds }; 1581da177e4SLinus Torvalds 1594be44fcdSLen Brown static inline u32 ticks_elapsed(u32 t1, u32 t2) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds if (t2 >= t1) 1621da177e4SLinus Torvalds return (t2 - t1); 163cee324b1SAlexey Starikovskiy else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER)) 1641da177e4SLinus Torvalds return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); 1651da177e4SLinus Torvalds else 1661da177e4SLinus Torvalds return ((0xFFFFFFFF - t1) + t2); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds static void 1704be44fcdSLen Brown acpi_processor_power_activate(struct acpi_processor *pr, 1711da177e4SLinus Torvalds struct acpi_processor_cx *new) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct acpi_processor_cx *old; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds if (!pr || !new) 1761da177e4SLinus Torvalds return; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds old = pr->power.state; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds if (old) 1811da177e4SLinus Torvalds old->promotion.count = 0; 1821da177e4SLinus Torvalds new->demotion.count = 0; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds /* Cleanup from old state. */ 1851da177e4SLinus Torvalds if (old) { 1861da177e4SLinus Torvalds switch (old->type) { 1871da177e4SLinus Torvalds case ACPI_STATE_C3: 1881da177e4SLinus Torvalds /* Disable bus master reload */ 18902df8b93SVenkatesh Pallipadi if (new->type != ACPI_STATE_C3 && pr->flags.bm_check) 190d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); 1911da177e4SLinus Torvalds break; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /* Prepare to use new state. */ 1961da177e4SLinus Torvalds switch (new->type) { 1971da177e4SLinus Torvalds case ACPI_STATE_C3: 1981da177e4SLinus Torvalds /* Enable bus master reload */ 19902df8b93SVenkatesh Pallipadi if (old->type != ACPI_STATE_C3 && pr->flags.bm_check) 200d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1); 2011da177e4SLinus Torvalds break; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds pr->power.state = new; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds return; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 20964c7c8f8SNick Piggin static void acpi_safe_halt(void) 21064c7c8f8SNick Piggin { 211495ab9c0SAndi Kleen current_thread_info()->status &= ~TS_POLLING; 2120888f06aSIngo Molnar /* 2130888f06aSIngo Molnar * TS_POLLING-cleared state must be visible before we 2140888f06aSIngo Molnar * test NEED_RESCHED: 2150888f06aSIngo Molnar */ 2160888f06aSIngo Molnar smp_mb(); 21764c7c8f8SNick Piggin if (!need_resched()) 21864c7c8f8SNick Piggin safe_halt(); 219495ab9c0SAndi Kleen current_thread_info()->status |= TS_POLLING; 22064c7c8f8SNick Piggin } 22164c7c8f8SNick Piggin 22202df8b93SVenkatesh Pallipadi static atomic_t c3_cpu_count; 22302df8b93SVenkatesh Pallipadi 224991528d7SVenkatesh Pallipadi /* Common C-state entry for C2, C3, .. */ 225991528d7SVenkatesh Pallipadi static void acpi_cstate_enter(struct acpi_processor_cx *cstate) 226991528d7SVenkatesh Pallipadi { 227991528d7SVenkatesh Pallipadi if (cstate->space_id == ACPI_CSTATE_FFH) { 228991528d7SVenkatesh Pallipadi /* Call into architectural FFH based C-state */ 229991528d7SVenkatesh Pallipadi acpi_processor_ffh_cstate_enter(cstate); 230991528d7SVenkatesh Pallipadi } else { 231991528d7SVenkatesh Pallipadi int unused; 232991528d7SVenkatesh Pallipadi /* IO port based C-state */ 233991528d7SVenkatesh Pallipadi inb(cstate->address); 234991528d7SVenkatesh Pallipadi /* Dummy wait op - must do something useless after P_LVL2 read 235991528d7SVenkatesh Pallipadi because chipsets cannot guarantee that STPCLK# signal 236991528d7SVenkatesh Pallipadi gets asserted in time to freeze execution properly. */ 237cee324b1SAlexey Starikovskiy unused = inl(acpi_gbl_FADT.xpm_timer_block.address); 238991528d7SVenkatesh Pallipadi } 239991528d7SVenkatesh Pallipadi } 240991528d7SVenkatesh Pallipadi 2411da177e4SLinus Torvalds static void acpi_processor_idle(void) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds struct acpi_processor *pr = NULL; 2441da177e4SLinus Torvalds struct acpi_processor_cx *cx = NULL; 2451da177e4SLinus Torvalds struct acpi_processor_cx *next_state = NULL; 2461da177e4SLinus Torvalds int sleep_ticks = 0; 2471da177e4SLinus Torvalds u32 t1, t2 = 0; 2481da177e4SLinus Torvalds 24964c7c8f8SNick Piggin pr = processors[smp_processor_id()]; 2501da177e4SLinus Torvalds if (!pr) 2511da177e4SLinus Torvalds return; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* 2541da177e4SLinus Torvalds * Interrupts must be disabled during bus mastering calculations and 2551da177e4SLinus Torvalds * for C2/C3 transitions. 2561da177e4SLinus Torvalds */ 2571da177e4SLinus Torvalds local_irq_disable(); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds /* 2601da177e4SLinus Torvalds * Check whether we truly need to go idle, or should 2611da177e4SLinus Torvalds * reschedule: 2621da177e4SLinus Torvalds */ 2631da177e4SLinus Torvalds if (unlikely(need_resched())) { 2641da177e4SLinus Torvalds local_irq_enable(); 2651da177e4SLinus Torvalds return; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds cx = pr->power.state; 26964c7c8f8SNick Piggin if (!cx) { 27064c7c8f8SNick Piggin if (pm_idle_save) 27164c7c8f8SNick Piggin pm_idle_save(); 27264c7c8f8SNick Piggin else 27364c7c8f8SNick Piggin acpi_safe_halt(); 27464c7c8f8SNick Piggin return; 27564c7c8f8SNick Piggin } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* 2781da177e4SLinus Torvalds * Check BM Activity 2791da177e4SLinus Torvalds * ----------------- 2801da177e4SLinus Torvalds * Check for bus mastering activity (if required), record, and check 2811da177e4SLinus Torvalds * for demotion. 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds if (pr->flags.bm_check) { 2841da177e4SLinus Torvalds u32 bm_status = 0; 2851da177e4SLinus Torvalds unsigned long diff = jiffies - pr->power.bm_check_timestamp; 2861da177e4SLinus Torvalds 287c5ab81caSDominik Brodowski if (diff > 31) 288c5ab81caSDominik Brodowski diff = 31; 2891da177e4SLinus Torvalds 290c5ab81caSDominik Brodowski pr->power.bm_activity <<= diff; 2911da177e4SLinus Torvalds 292d8c71b6dSBob Moore acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); 2931da177e4SLinus Torvalds if (bm_status) { 294c5ab81caSDominik Brodowski pr->power.bm_activity |= 0x1; 295d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds /* 2981da177e4SLinus Torvalds * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect 2991da177e4SLinus Torvalds * the true state of bus mastering activity; forcing us to 3001da177e4SLinus Torvalds * manually check the BMIDEA bit of each IDE channel. 3011da177e4SLinus Torvalds */ 3021da177e4SLinus Torvalds else if (errata.piix4.bmisx) { 3031da177e4SLinus Torvalds if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01) 3041da177e4SLinus Torvalds || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01)) 305c5ab81caSDominik Brodowski pr->power.bm_activity |= 0x1; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds pr->power.bm_check_timestamp = jiffies; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* 311c4a001b1SDominik Brodowski * If bus mastering is or was active this jiffy, demote 3121da177e4SLinus Torvalds * to avoid a faulty transition. Note that the processor 3131da177e4SLinus Torvalds * won't enter a low-power state during this call (to this 314c4a001b1SDominik Brodowski * function) but should upon the next. 3151da177e4SLinus Torvalds * 3161da177e4SLinus Torvalds * TBD: A better policy might be to fallback to the demotion 3171da177e4SLinus Torvalds * state (use it for this quantum only) istead of 3181da177e4SLinus Torvalds * demoting -- and rely on duration as our sole demotion 3191da177e4SLinus Torvalds * qualification. This may, however, introduce DMA 3201da177e4SLinus Torvalds * issues (e.g. floppy DMA transfer overrun/underrun). 3211da177e4SLinus Torvalds */ 322c4a001b1SDominik Brodowski if ((pr->power.bm_activity & 0x1) && 323c4a001b1SDominik Brodowski cx->demotion.threshold.bm) { 3241da177e4SLinus Torvalds local_irq_enable(); 3251da177e4SLinus Torvalds next_state = cx->demotion.state; 3261da177e4SLinus Torvalds goto end; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 3304c033552SVenkatesh Pallipadi #ifdef CONFIG_HOTPLUG_CPU 3314c033552SVenkatesh Pallipadi /* 3324c033552SVenkatesh Pallipadi * Check for P_LVL2_UP flag before entering C2 and above on 3334c033552SVenkatesh Pallipadi * an SMP system. We do it here instead of doing it at _CST/P_LVL 3344c033552SVenkatesh Pallipadi * detection phase, to work cleanly with logical CPU hotplug. 3354c033552SVenkatesh Pallipadi */ 3364c033552SVenkatesh Pallipadi if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && 337cee324b1SAlexey Starikovskiy !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) 3381e483969SDavid Shaohua Li cx = &pr->power.states[ACPI_STATE_C1]; 3394c033552SVenkatesh Pallipadi #endif 3401e483969SDavid Shaohua Li 3411da177e4SLinus Torvalds /* 3421da177e4SLinus Torvalds * Sleep: 3431da177e4SLinus Torvalds * ------ 3441da177e4SLinus Torvalds * Invoke the current Cx state to put the processor to sleep. 3451da177e4SLinus Torvalds */ 3462a298a35SNick Piggin if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { 347495ab9c0SAndi Kleen current_thread_info()->status &= ~TS_POLLING; 3480888f06aSIngo Molnar /* 3490888f06aSIngo Molnar * TS_POLLING-cleared state must be visible before we 3500888f06aSIngo Molnar * test NEED_RESCHED: 3510888f06aSIngo Molnar */ 3520888f06aSIngo Molnar smp_mb(); 3532a298a35SNick Piggin if (need_resched()) { 354495ab9c0SAndi Kleen current_thread_info()->status |= TS_POLLING; 355af2eb17bSLinus Torvalds local_irq_enable(); 3562a298a35SNick Piggin return; 3572a298a35SNick Piggin } 3582a298a35SNick Piggin } 3592a298a35SNick Piggin 3601da177e4SLinus Torvalds switch (cx->type) { 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds case ACPI_STATE_C1: 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * Invoke C1. 3651da177e4SLinus Torvalds * Use the appropriate idle routine, the one that would 3661da177e4SLinus Torvalds * be used without acpi C-states. 3671da177e4SLinus Torvalds */ 3681da177e4SLinus Torvalds if (pm_idle_save) 3691da177e4SLinus Torvalds pm_idle_save(); 3701da177e4SLinus Torvalds else 37164c7c8f8SNick Piggin acpi_safe_halt(); 37264c7c8f8SNick Piggin 3731da177e4SLinus Torvalds /* 3741da177e4SLinus Torvalds * TBD: Can't get time duration while in C1, as resumes 3751da177e4SLinus Torvalds * go to an ISR rather than here. Need to instrument 3761da177e4SLinus Torvalds * base interrupt handler. 3771da177e4SLinus Torvalds */ 3781da177e4SLinus Torvalds sleep_ticks = 0xFFFFFFFF; 3791da177e4SLinus Torvalds break; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds case ACPI_STATE_C2: 3821da177e4SLinus Torvalds /* Get start time (ticks) */ 383cee324b1SAlexey Starikovskiy t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); 3841da177e4SLinus Torvalds /* Invoke C2 */ 385991528d7SVenkatesh Pallipadi acpi_cstate_enter(cx); 3861da177e4SLinus Torvalds /* Get end time (ticks) */ 387cee324b1SAlexey Starikovskiy t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 388539eb11eSjohn stultz 389539eb11eSjohn stultz #ifdef CONFIG_GENERIC_TIME 390539eb11eSjohn stultz /* TSC halts in C2, so notify users */ 391539eb11eSjohn stultz mark_tsc_unstable(); 392539eb11eSjohn stultz #endif 3931da177e4SLinus Torvalds /* Re-enable interrupts */ 3941da177e4SLinus Torvalds local_irq_enable(); 395495ab9c0SAndi Kleen current_thread_info()->status |= TS_POLLING; 3961da177e4SLinus Torvalds /* Compute time (ticks) that we were actually asleep */ 3974be44fcdSLen Brown sleep_ticks = 3984be44fcdSLen Brown ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; 3991da177e4SLinus Torvalds break; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds case ACPI_STATE_C3: 40202df8b93SVenkatesh Pallipadi 40302df8b93SVenkatesh Pallipadi if (pr->flags.bm_check) { 40402df8b93SVenkatesh Pallipadi if (atomic_inc_return(&c3_cpu_count) == 40502df8b93SVenkatesh Pallipadi num_online_cpus()) { 40602df8b93SVenkatesh Pallipadi /* 40702df8b93SVenkatesh Pallipadi * All CPUs are trying to go to C3 40802df8b93SVenkatesh Pallipadi * Disable bus master arbitration 40902df8b93SVenkatesh Pallipadi */ 410d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); 41102df8b93SVenkatesh Pallipadi } 41202df8b93SVenkatesh Pallipadi } else { 41302df8b93SVenkatesh Pallipadi /* SMP with no shared cache... Invalidate cache */ 41402df8b93SVenkatesh Pallipadi ACPI_FLUSH_CPU_CACHE(); 41502df8b93SVenkatesh Pallipadi } 41602df8b93SVenkatesh Pallipadi 4171da177e4SLinus Torvalds /* Get start time (ticks) */ 418cee324b1SAlexey Starikovskiy t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); 4191da177e4SLinus Torvalds /* Invoke C3 */ 420991528d7SVenkatesh Pallipadi acpi_cstate_enter(cx); 4211da177e4SLinus Torvalds /* Get end time (ticks) */ 422cee324b1SAlexey Starikovskiy t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 42302df8b93SVenkatesh Pallipadi if (pr->flags.bm_check) { 4241da177e4SLinus Torvalds /* Enable bus master arbitration */ 42502df8b93SVenkatesh Pallipadi atomic_dec(&c3_cpu_count); 426d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); 42702df8b93SVenkatesh Pallipadi } 42802df8b93SVenkatesh Pallipadi 429539eb11eSjohn stultz #ifdef CONFIG_GENERIC_TIME 430539eb11eSjohn stultz /* TSC halts in C3, so notify users */ 431539eb11eSjohn stultz mark_tsc_unstable(); 432539eb11eSjohn stultz #endif 4331da177e4SLinus Torvalds /* Re-enable interrupts */ 4341da177e4SLinus Torvalds local_irq_enable(); 435495ab9c0SAndi Kleen current_thread_info()->status |= TS_POLLING; 4361da177e4SLinus Torvalds /* Compute time (ticks) that we were actually asleep */ 4374be44fcdSLen Brown sleep_ticks = 4384be44fcdSLen Brown ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; 4391da177e4SLinus Torvalds break; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds default: 4421da177e4SLinus Torvalds local_irq_enable(); 4431da177e4SLinus Torvalds return; 4441da177e4SLinus Torvalds } 445a3c6598fSDominik Brodowski cx->usage++; 446a3c6598fSDominik Brodowski if ((cx->type != ACPI_STATE_C1) && (sleep_ticks > 0)) 447a3c6598fSDominik Brodowski cx->time += sleep_ticks; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds next_state = pr->power.state; 4501da177e4SLinus Torvalds 4511e483969SDavid Shaohua Li #ifdef CONFIG_HOTPLUG_CPU 4521e483969SDavid Shaohua Li /* Don't do promotion/demotion */ 4531e483969SDavid Shaohua Li if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) && 454cee324b1SAlexey Starikovskiy !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) { 4551e483969SDavid Shaohua Li next_state = cx; 4561e483969SDavid Shaohua Li goto end; 4571e483969SDavid Shaohua Li } 4581e483969SDavid Shaohua Li #endif 4591e483969SDavid Shaohua Li 4601da177e4SLinus Torvalds /* 4611da177e4SLinus Torvalds * Promotion? 4621da177e4SLinus Torvalds * ---------- 4631da177e4SLinus Torvalds * Track the number of longs (time asleep is greater than threshold) 4641da177e4SLinus Torvalds * and promote when the count threshold is reached. Note that bus 4651da177e4SLinus Torvalds * mastering activity may prevent promotions. 4661da177e4SLinus Torvalds * Do not promote above max_cstate. 4671da177e4SLinus Torvalds */ 4681da177e4SLinus Torvalds if (cx->promotion.state && 4691da177e4SLinus Torvalds ((cx->promotion.state - pr->power.states) <= max_cstate)) { 4705c87579eSArjan van de Ven if (sleep_ticks > cx->promotion.threshold.ticks && 4715c87579eSArjan van de Ven cx->promotion.state->latency <= system_latency_constraint()) { 4721da177e4SLinus Torvalds cx->promotion.count++; 4731da177e4SLinus Torvalds cx->demotion.count = 0; 4744be44fcdSLen Brown if (cx->promotion.count >= 4754be44fcdSLen Brown cx->promotion.threshold.count) { 4761da177e4SLinus Torvalds if (pr->flags.bm_check) { 4774be44fcdSLen Brown if (! 4784be44fcdSLen Brown (pr->power.bm_activity & cx-> 4794be44fcdSLen Brown promotion.threshold.bm)) { 4804be44fcdSLen Brown next_state = 4814be44fcdSLen Brown cx->promotion.state; 4821da177e4SLinus Torvalds goto end; 4831da177e4SLinus Torvalds } 4844be44fcdSLen Brown } else { 4851da177e4SLinus Torvalds next_state = cx->promotion.state; 4861da177e4SLinus Torvalds goto end; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds /* 4931da177e4SLinus Torvalds * Demotion? 4941da177e4SLinus Torvalds * --------- 4951da177e4SLinus Torvalds * Track the number of shorts (time asleep is less than time threshold) 4961da177e4SLinus Torvalds * and demote when the usage threshold is reached. 4971da177e4SLinus Torvalds */ 4981da177e4SLinus Torvalds if (cx->demotion.state) { 4991da177e4SLinus Torvalds if (sleep_ticks < cx->demotion.threshold.ticks) { 5001da177e4SLinus Torvalds cx->demotion.count++; 5011da177e4SLinus Torvalds cx->promotion.count = 0; 5021da177e4SLinus Torvalds if (cx->demotion.count >= cx->demotion.threshold.count) { 5031da177e4SLinus Torvalds next_state = cx->demotion.state; 5041da177e4SLinus Torvalds goto end; 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds end: 5101da177e4SLinus Torvalds /* 5111da177e4SLinus Torvalds * Demote if current state exceeds max_cstate 5125c87579eSArjan van de Ven * or if the latency of the current state is unacceptable 5131da177e4SLinus Torvalds */ 5145c87579eSArjan van de Ven if ((pr->power.state - pr->power.states) > max_cstate || 5155c87579eSArjan van de Ven pr->power.state->latency > system_latency_constraint()) { 5161da177e4SLinus Torvalds if (cx->demotion.state) 5171da177e4SLinus Torvalds next_state = cx->demotion.state; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* 5211da177e4SLinus Torvalds * New Cx State? 5221da177e4SLinus Torvalds * ------------- 5231da177e4SLinus Torvalds * If we're going to start using a new Cx state we must clean up 5241da177e4SLinus Torvalds * from the previous and prepare to use the new. 5251da177e4SLinus Torvalds */ 5261da177e4SLinus Torvalds if (next_state != pr->power.state) 5271da177e4SLinus Torvalds acpi_processor_power_activate(pr, next_state); 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5304be44fcdSLen Brown static int acpi_processor_set_power_policy(struct acpi_processor *pr) 5311da177e4SLinus Torvalds { 5321da177e4SLinus Torvalds unsigned int i; 5331da177e4SLinus Torvalds unsigned int state_is_set = 0; 5341da177e4SLinus Torvalds struct acpi_processor_cx *lower = NULL; 5351da177e4SLinus Torvalds struct acpi_processor_cx *higher = NULL; 5361da177e4SLinus Torvalds struct acpi_processor_cx *cx; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds if (!pr) 540d550d98dSPatrick Mochel return -EINVAL; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds /* 5431da177e4SLinus Torvalds * This function sets the default Cx state policy (OS idle handler). 5441da177e4SLinus Torvalds * Our scheme is to promote quickly to C2 but more conservatively 5451da177e4SLinus Torvalds * to C3. We're favoring C2 for its characteristics of low latency 5461da177e4SLinus Torvalds * (quick response), good power savings, and ability to allow bus 5471da177e4SLinus Torvalds * mastering activity. Note that the Cx state policy is completely 5481da177e4SLinus Torvalds * customizable and can be altered dynamically. 5491da177e4SLinus Torvalds */ 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds /* startup state */ 5521da177e4SLinus Torvalds for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { 5531da177e4SLinus Torvalds cx = &pr->power.states[i]; 5541da177e4SLinus Torvalds if (!cx->valid) 5551da177e4SLinus Torvalds continue; 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds if (!state_is_set) 5581da177e4SLinus Torvalds pr->power.state = cx; 5591da177e4SLinus Torvalds state_is_set++; 5601da177e4SLinus Torvalds break; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds if (!state_is_set) 564d550d98dSPatrick Mochel return -ENODEV; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /* demotion */ 5671da177e4SLinus Torvalds for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { 5681da177e4SLinus Torvalds cx = &pr->power.states[i]; 5691da177e4SLinus Torvalds if (!cx->valid) 5701da177e4SLinus Torvalds continue; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds if (lower) { 5731da177e4SLinus Torvalds cx->demotion.state = lower; 5741da177e4SLinus Torvalds cx->demotion.threshold.ticks = cx->latency_ticks; 5751da177e4SLinus Torvalds cx->demotion.threshold.count = 1; 5761da177e4SLinus Torvalds if (cx->type == ACPI_STATE_C3) 5771da177e4SLinus Torvalds cx->demotion.threshold.bm = bm_history; 5781da177e4SLinus Torvalds } 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds lower = cx; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds /* promotion */ 5841da177e4SLinus Torvalds for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) { 5851da177e4SLinus Torvalds cx = &pr->power.states[i]; 5861da177e4SLinus Torvalds if (!cx->valid) 5871da177e4SLinus Torvalds continue; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds if (higher) { 5901da177e4SLinus Torvalds cx->promotion.state = higher; 5911da177e4SLinus Torvalds cx->promotion.threshold.ticks = cx->latency_ticks; 5921da177e4SLinus Torvalds if (cx->type >= ACPI_STATE_C2) 5931da177e4SLinus Torvalds cx->promotion.threshold.count = 4; 5941da177e4SLinus Torvalds else 5951da177e4SLinus Torvalds cx->promotion.threshold.count = 10; 5961da177e4SLinus Torvalds if (higher->type == ACPI_STATE_C3) 5971da177e4SLinus Torvalds cx->promotion.threshold.bm = bm_history; 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds higher = cx; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 603d550d98dSPatrick Mochel return 0; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) 6071da177e4SLinus Torvalds { 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds if (!pr) 610d550d98dSPatrick Mochel return -EINVAL; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (!pr->pblk) 613d550d98dSPatrick Mochel return -ENODEV; 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds /* if info is obtained from pblk/fadt, type equals state */ 6161da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; 6171da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; 6181da177e4SLinus Torvalds 6194c033552SVenkatesh Pallipadi #ifndef CONFIG_HOTPLUG_CPU 6204c033552SVenkatesh Pallipadi /* 6214c033552SVenkatesh Pallipadi * Check for P_LVL2_UP flag before entering C2 and above on 6224c033552SVenkatesh Pallipadi * an SMP system. 6234c033552SVenkatesh Pallipadi */ 624ad71860aSAlexey Starikovskiy if ((num_online_cpus() > 1) && 625cee324b1SAlexey Starikovskiy !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) 626d550d98dSPatrick Mochel return -ENODEV; 6274c033552SVenkatesh Pallipadi #endif 6284c033552SVenkatesh Pallipadi 6291da177e4SLinus Torvalds /* determine C2 and C3 address from pblk */ 6301da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4; 6311da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds /* determine latencies from FADT */ 634cee324b1SAlexey Starikovskiy pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency; 635cee324b1SAlexey Starikovskiy pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6381da177e4SLinus Torvalds "lvl2[0x%08x] lvl3[0x%08x]\n", 6391da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C2].address, 6401da177e4SLinus Torvalds pr->power.states[ACPI_STATE_C3].address)); 6411da177e4SLinus Torvalds 642d550d98dSPatrick Mochel return 0; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 645991528d7SVenkatesh Pallipadi static int acpi_processor_get_power_info_default(struct acpi_processor *pr) 646acf05f4bSVenkatesh Pallipadi { 647991528d7SVenkatesh Pallipadi if (!pr->power.states[ACPI_STATE_C1].valid) { 648cf824788SJanosch Machowinski /* set the first C-State to C1 */ 649991528d7SVenkatesh Pallipadi /* all processors need to support C1 */ 650acf05f4bSVenkatesh Pallipadi pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; 651acf05f4bSVenkatesh Pallipadi pr->power.states[ACPI_STATE_C1].valid = 1; 652991528d7SVenkatesh Pallipadi } 653991528d7SVenkatesh Pallipadi /* the C0 state only exists as a filler in our array */ 654991528d7SVenkatesh Pallipadi pr->power.states[ACPI_STATE_C0].valid = 1; 655d550d98dSPatrick Mochel return 0; 656acf05f4bSVenkatesh Pallipadi } 657acf05f4bSVenkatesh Pallipadi 6581da177e4SLinus Torvalds static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds acpi_status status = 0; 6611da177e4SLinus Torvalds acpi_integer count; 662cf824788SJanosch Machowinski int current_count; 6631da177e4SLinus Torvalds int i; 6641da177e4SLinus Torvalds struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 6651da177e4SLinus Torvalds union acpi_object *cst; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds if (nocst) 669d550d98dSPatrick Mochel return -ENODEV; 6701da177e4SLinus Torvalds 671991528d7SVenkatesh Pallipadi current_count = 0; 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); 6741da177e4SLinus Torvalds if (ACPI_FAILURE(status)) { 6751da177e4SLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n")); 676d550d98dSPatrick Mochel return -ENODEV; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 67950dd0969SJan Engelhardt cst = buffer.pointer; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds /* There must be at least 2 elements */ 6821da177e4SLinus Torvalds if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) { 6836468463aSLen Brown printk(KERN_ERR PREFIX "not enough elements in _CST\n"); 6841da177e4SLinus Torvalds status = -EFAULT; 6851da177e4SLinus Torvalds goto end; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds count = cst->package.elements[0].integer.value; 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* Validate number of power states. */ 6911da177e4SLinus Torvalds if (count < 1 || count != cst->package.count - 1) { 6926468463aSLen Brown printk(KERN_ERR PREFIX "count given by _CST is not valid\n"); 6931da177e4SLinus Torvalds status = -EFAULT; 6941da177e4SLinus Torvalds goto end; 6951da177e4SLinus Torvalds } 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds /* Tell driver that at least _CST is supported. */ 6981da177e4SLinus Torvalds pr->flags.has_cst = 1; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds for (i = 1; i <= count; i++) { 7011da177e4SLinus Torvalds union acpi_object *element; 7021da177e4SLinus Torvalds union acpi_object *obj; 7031da177e4SLinus Torvalds struct acpi_power_register *reg; 7041da177e4SLinus Torvalds struct acpi_processor_cx cx; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds memset(&cx, 0, sizeof(cx)); 7071da177e4SLinus Torvalds 70850dd0969SJan Engelhardt element = &(cst->package.elements[i]); 7091da177e4SLinus Torvalds if (element->type != ACPI_TYPE_PACKAGE) 7101da177e4SLinus Torvalds continue; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds if (element->package.count != 4) 7131da177e4SLinus Torvalds continue; 7141da177e4SLinus Torvalds 71550dd0969SJan Engelhardt obj = &(element->package.elements[0]); 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds if (obj->type != ACPI_TYPE_BUFFER) 7181da177e4SLinus Torvalds continue; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds reg = (struct acpi_power_register *)obj->buffer.pointer; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO && 7231da177e4SLinus Torvalds (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) 7241da177e4SLinus Torvalds continue; 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds /* There should be an easy way to extract an integer... */ 72750dd0969SJan Engelhardt obj = &(element->package.elements[1]); 7281da177e4SLinus Torvalds if (obj->type != ACPI_TYPE_INTEGER) 7291da177e4SLinus Torvalds continue; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds cx.type = obj->integer.value; 732991528d7SVenkatesh Pallipadi /* 733991528d7SVenkatesh Pallipadi * Some buggy BIOSes won't list C1 in _CST - 734991528d7SVenkatesh Pallipadi * Let acpi_processor_get_power_info_default() handle them later 735991528d7SVenkatesh Pallipadi */ 736991528d7SVenkatesh Pallipadi if (i == 1 && cx.type != ACPI_STATE_C1) 737991528d7SVenkatesh Pallipadi current_count++; 7381da177e4SLinus Torvalds 739991528d7SVenkatesh Pallipadi cx.address = reg->address; 740991528d7SVenkatesh Pallipadi cx.index = current_count + 1; 7411da177e4SLinus Torvalds 742991528d7SVenkatesh Pallipadi cx.space_id = ACPI_CSTATE_SYSTEMIO; 743991528d7SVenkatesh Pallipadi if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { 744991528d7SVenkatesh Pallipadi if (acpi_processor_ffh_cstate_probe 745991528d7SVenkatesh Pallipadi (pr->id, &cx, reg) == 0) { 746991528d7SVenkatesh Pallipadi cx.space_id = ACPI_CSTATE_FFH; 747991528d7SVenkatesh Pallipadi } else if (cx.type != ACPI_STATE_C1) { 748991528d7SVenkatesh Pallipadi /* 749991528d7SVenkatesh Pallipadi * C1 is a special case where FIXED_HARDWARE 750991528d7SVenkatesh Pallipadi * can be handled in non-MWAIT way as well. 751991528d7SVenkatesh Pallipadi * In that case, save this _CST entry info. 752991528d7SVenkatesh Pallipadi * That is, we retain space_id of SYSTEM_IO for 753991528d7SVenkatesh Pallipadi * halt based C1. 754991528d7SVenkatesh Pallipadi * Otherwise, ignore this info and continue. 755991528d7SVenkatesh Pallipadi */ 7561da177e4SLinus Torvalds continue; 757991528d7SVenkatesh Pallipadi } 758991528d7SVenkatesh Pallipadi } 7591da177e4SLinus Torvalds 76050dd0969SJan Engelhardt obj = &(element->package.elements[2]); 7611da177e4SLinus Torvalds if (obj->type != ACPI_TYPE_INTEGER) 7621da177e4SLinus Torvalds continue; 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds cx.latency = obj->integer.value; 7651da177e4SLinus Torvalds 76650dd0969SJan Engelhardt obj = &(element->package.elements[3]); 7671da177e4SLinus Torvalds if (obj->type != ACPI_TYPE_INTEGER) 7681da177e4SLinus Torvalds continue; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds cx.power = obj->integer.value; 7711da177e4SLinus Torvalds 772cf824788SJanosch Machowinski current_count++; 773cf824788SJanosch Machowinski memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx)); 774cf824788SJanosch Machowinski 775cf824788SJanosch Machowinski /* 776cf824788SJanosch Machowinski * We support total ACPI_PROCESSOR_MAX_POWER - 1 777cf824788SJanosch Machowinski * (From 1 through ACPI_PROCESSOR_MAX_POWER - 1) 778cf824788SJanosch Machowinski */ 779cf824788SJanosch Machowinski if (current_count >= (ACPI_PROCESSOR_MAX_POWER - 1)) { 780cf824788SJanosch Machowinski printk(KERN_WARNING 781cf824788SJanosch Machowinski "Limiting number of power states to max (%d)\n", 782cf824788SJanosch Machowinski ACPI_PROCESSOR_MAX_POWER); 783cf824788SJanosch Machowinski printk(KERN_WARNING 784cf824788SJanosch Machowinski "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); 785cf824788SJanosch Machowinski break; 786cf824788SJanosch Machowinski } 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7894be44fcdSLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n", 790cf824788SJanosch Machowinski current_count)); 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds /* Validate number of power states discovered */ 793cf824788SJanosch Machowinski if (current_count < 2) 7946d93c648SVenkatesh Pallipadi status = -EFAULT; 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds end: 79702438d87SLen Brown kfree(buffer.pointer); 7981da177e4SLinus Torvalds 799d550d98dSPatrick Mochel return status; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) 8031da177e4SLinus Torvalds { 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds if (!cx->address) 806d550d98dSPatrick Mochel return; 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds /* 8091da177e4SLinus Torvalds * C2 latency must be less than or equal to 100 8101da177e4SLinus Torvalds * microseconds. 8111da177e4SLinus Torvalds */ 8121da177e4SLinus Torvalds else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { 8131da177e4SLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, 8144be44fcdSLen Brown "latency too large [%d]\n", cx->latency)); 815d550d98dSPatrick Mochel return; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds /* 8191da177e4SLinus Torvalds * Otherwise we've met all of our C2 requirements. 8201da177e4SLinus Torvalds * Normalize the C2 latency to expidite policy 8211da177e4SLinus Torvalds */ 8221da177e4SLinus Torvalds cx->valid = 1; 8231da177e4SLinus Torvalds cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); 8241da177e4SLinus Torvalds 825d550d98dSPatrick Mochel return; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds 8284be44fcdSLen Brown static void acpi_processor_power_verify_c3(struct acpi_processor *pr, 8291da177e4SLinus Torvalds struct acpi_processor_cx *cx) 8301da177e4SLinus Torvalds { 83102df8b93SVenkatesh Pallipadi static int bm_check_flag; 83202df8b93SVenkatesh Pallipadi 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds if (!cx->address) 835d550d98dSPatrick Mochel return; 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds /* 8381da177e4SLinus Torvalds * C3 latency must be less than or equal to 1000 8391da177e4SLinus Torvalds * microseconds. 8401da177e4SLinus Torvalds */ 8411da177e4SLinus Torvalds else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { 8421da177e4SLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, 8434be44fcdSLen Brown "latency too large [%d]\n", cx->latency)); 844d550d98dSPatrick Mochel return; 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds /* 8481da177e4SLinus Torvalds * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) 8491da177e4SLinus Torvalds * DMA transfers are used by any ISA device to avoid livelock. 8501da177e4SLinus Torvalds * Note that we could disable Type-F DMA (as recommended by 8511da177e4SLinus Torvalds * the erratum), but this is known to disrupt certain ISA 8521da177e4SLinus Torvalds * devices thus we take the conservative approach. 8531da177e4SLinus Torvalds */ 8541da177e4SLinus Torvalds else if (errata.piix4.fdma) { 8551da177e4SLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, 8561da177e4SLinus Torvalds "C3 not supported on PIIX4 with Type-F DMA\n")); 857d550d98dSPatrick Mochel return; 8581da177e4SLinus Torvalds } 8591da177e4SLinus Torvalds 86002df8b93SVenkatesh Pallipadi /* All the logic here assumes flags.bm_check is same across all CPUs */ 86102df8b93SVenkatesh Pallipadi if (!bm_check_flag) { 86202df8b93SVenkatesh Pallipadi /* Determine whether bm_check is needed based on CPU */ 86302df8b93SVenkatesh Pallipadi acpi_processor_power_init_bm_check(&(pr->flags), pr->id); 86402df8b93SVenkatesh Pallipadi bm_check_flag = pr->flags.bm_check; 86502df8b93SVenkatesh Pallipadi } else { 86602df8b93SVenkatesh Pallipadi pr->flags.bm_check = bm_check_flag; 86702df8b93SVenkatesh Pallipadi } 86802df8b93SVenkatesh Pallipadi 86902df8b93SVenkatesh Pallipadi if (pr->flags.bm_check) { 87002df8b93SVenkatesh Pallipadi /* bus mastering control is necessary */ 87102df8b93SVenkatesh Pallipadi if (!pr->flags.bm_control) { 87202df8b93SVenkatesh Pallipadi ACPI_DEBUG_PRINT((ACPI_DB_INFO, 87302df8b93SVenkatesh Pallipadi "C3 support requires bus mastering control\n")); 874d550d98dSPatrick Mochel return; 87502df8b93SVenkatesh Pallipadi } 87602df8b93SVenkatesh Pallipadi } else { 87702df8b93SVenkatesh Pallipadi /* 87802df8b93SVenkatesh Pallipadi * WBINVD should be set in fadt, for C3 state to be 87902df8b93SVenkatesh Pallipadi * supported on when bm_check is not required. 88002df8b93SVenkatesh Pallipadi */ 881cee324b1SAlexey Starikovskiy if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) { 88202df8b93SVenkatesh Pallipadi ACPI_DEBUG_PRINT((ACPI_DB_INFO, 88302df8b93SVenkatesh Pallipadi "Cache invalidation should work properly" 88402df8b93SVenkatesh Pallipadi " for C3 to be enabled on SMP systems\n")); 885d550d98dSPatrick Mochel return; 88602df8b93SVenkatesh Pallipadi } 887d8c71b6dSBob Moore acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); 88802df8b93SVenkatesh Pallipadi } 88902df8b93SVenkatesh Pallipadi 8901da177e4SLinus Torvalds /* 8911da177e4SLinus Torvalds * Otherwise we've met all of our C3 requirements. 8921da177e4SLinus Torvalds * Normalize the C3 latency to expidite policy. Enable 8931da177e4SLinus Torvalds * checking of bus mastering status (bm_check) so we can 8941da177e4SLinus Torvalds * use this in our C3 policy 8951da177e4SLinus Torvalds */ 8961da177e4SLinus Torvalds cx->valid = 1; 8971da177e4SLinus Torvalds cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); 8981da177e4SLinus Torvalds 899d550d98dSPatrick Mochel return; 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds static int acpi_processor_power_verify(struct acpi_processor *pr) 9031da177e4SLinus Torvalds { 9041da177e4SLinus Torvalds unsigned int i; 9051da177e4SLinus Torvalds unsigned int working = 0; 9066eb0a0fdSVenkatesh Pallipadi 907bd663347SAndi Kleen #ifdef ARCH_APICTIMER_STOPS_ON_C3 9080b5c59a1SAndi Kleen int timer_broadcast = 0; 9090b5c59a1SAndi Kleen cpumask_t mask = cpumask_of_cpu(pr->id); 9106eb0a0fdSVenkatesh Pallipadi on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); 9116eb0a0fdSVenkatesh Pallipadi #endif 9126eb0a0fdSVenkatesh Pallipadi 9131da177e4SLinus Torvalds for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { 9141da177e4SLinus Torvalds struct acpi_processor_cx *cx = &pr->power.states[i]; 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds switch (cx->type) { 9171da177e4SLinus Torvalds case ACPI_STATE_C1: 9181da177e4SLinus Torvalds cx->valid = 1; 9191da177e4SLinus Torvalds break; 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds case ACPI_STATE_C2: 9221da177e4SLinus Torvalds acpi_processor_power_verify_c2(cx); 923bd663347SAndi Kleen #ifdef ARCH_APICTIMER_STOPS_ON_C3 924bd663347SAndi Kleen /* Some AMD systems fake C3 as C2, but still 925bd663347SAndi Kleen have timer troubles */ 926bd663347SAndi Kleen if (cx->valid && 927bd663347SAndi Kleen boot_cpu_data.x86_vendor == X86_VENDOR_AMD) 928bd663347SAndi Kleen timer_broadcast++; 929bd663347SAndi Kleen #endif 9301da177e4SLinus Torvalds break; 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds case ACPI_STATE_C3: 9331da177e4SLinus Torvalds acpi_processor_power_verify_c3(pr, cx); 9346eb0a0fdSVenkatesh Pallipadi #ifdef ARCH_APICTIMER_STOPS_ON_C3 935bd663347SAndi Kleen if (cx->valid) 936bd663347SAndi Kleen timer_broadcast++; 9376eb0a0fdSVenkatesh Pallipadi #endif 9381da177e4SLinus Torvalds break; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds if (cx->valid) 9421da177e4SLinus Torvalds working++; 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds 9450b5c59a1SAndi Kleen #ifdef ARCH_APICTIMER_STOPS_ON_C3 946bd663347SAndi Kleen if (timer_broadcast) 947bd663347SAndi Kleen on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); 9480b5c59a1SAndi Kleen #endif 949bd663347SAndi Kleen 9501da177e4SLinus Torvalds return (working); 9511da177e4SLinus Torvalds } 9521da177e4SLinus Torvalds 9534be44fcdSLen Brown static int acpi_processor_get_power_info(struct acpi_processor *pr) 9541da177e4SLinus Torvalds { 9551da177e4SLinus Torvalds unsigned int i; 9561da177e4SLinus Torvalds int result; 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /* NOTE: the idle thread may not be running while calling 9601da177e4SLinus Torvalds * this function */ 9611da177e4SLinus Torvalds 962991528d7SVenkatesh Pallipadi /* Zero initialize all the C-states info. */ 963991528d7SVenkatesh Pallipadi memset(pr->power.states, 0, sizeof(pr->power.states)); 964991528d7SVenkatesh Pallipadi 9651da177e4SLinus Torvalds result = acpi_processor_get_power_info_cst(pr); 9666d93c648SVenkatesh Pallipadi if (result == -ENODEV) 967c5a114f1SDarrick J. Wong result = acpi_processor_get_power_info_fadt(pr); 9686d93c648SVenkatesh Pallipadi 969991528d7SVenkatesh Pallipadi if (result) 970991528d7SVenkatesh Pallipadi return result; 971991528d7SVenkatesh Pallipadi 972991528d7SVenkatesh Pallipadi acpi_processor_get_power_info_default(pr); 973991528d7SVenkatesh Pallipadi 974cf824788SJanosch Machowinski pr->power.count = acpi_processor_power_verify(pr); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds /* 9771da177e4SLinus Torvalds * Set Default Policy 9781da177e4SLinus Torvalds * ------------------ 9791da177e4SLinus Torvalds * Now that we know which states are supported, set the default 9801da177e4SLinus Torvalds * policy. Note that this policy can be changed dynamically 9811da177e4SLinus Torvalds * (e.g. encourage deeper sleeps to conserve battery life when 9821da177e4SLinus Torvalds * not on AC). 9831da177e4SLinus Torvalds */ 9841da177e4SLinus Torvalds result = acpi_processor_set_power_policy(pr); 9851da177e4SLinus Torvalds if (result) 986d550d98dSPatrick Mochel return result; 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds /* 9891da177e4SLinus Torvalds * if one state of type C2 or C3 is available, mark this 9901da177e4SLinus Torvalds * CPU as being "idle manageable" 9911da177e4SLinus Torvalds */ 9921da177e4SLinus Torvalds for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { 993acf05f4bSVenkatesh Pallipadi if (pr->power.states[i].valid) { 9941da177e4SLinus Torvalds pr->power.count = i; 9952203d6edSLinus Torvalds if (pr->power.states[i].type >= ACPI_STATE_C2) 9961da177e4SLinus Torvalds pr->flags.power = 1; 9971da177e4SLinus Torvalds } 998acf05f4bSVenkatesh Pallipadi } 9991da177e4SLinus Torvalds 1000d550d98dSPatrick Mochel return 0; 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds int acpi_processor_cst_has_changed(struct acpi_processor *pr) 10041da177e4SLinus Torvalds { 10051da177e4SLinus Torvalds int result = 0; 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds if (!pr) 1009d550d98dSPatrick Mochel return -EINVAL; 10101da177e4SLinus Torvalds 101102df8b93SVenkatesh Pallipadi if (nocst) { 1012d550d98dSPatrick Mochel return -ENODEV; 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds if (!pr->flags.power_setup_done) 1016d550d98dSPatrick Mochel return -ENODEV; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds /* Fall back to the default idle loop */ 10191da177e4SLinus Torvalds pm_idle = pm_idle_save; 1020fbd568a3SPaul E. McKenney synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds pr->flags.power = 0; 10231da177e4SLinus Torvalds result = acpi_processor_get_power_info(pr); 10241da177e4SLinus Torvalds if ((pr->flags.power == 1) && (pr->flags.power_setup_done)) 10251da177e4SLinus Torvalds pm_idle = acpi_processor_idle; 10261da177e4SLinus Torvalds 1027d550d98dSPatrick Mochel return result; 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 10301da177e4SLinus Torvalds /* proc interface */ 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) 10331da177e4SLinus Torvalds { 103450dd0969SJan Engelhardt struct acpi_processor *pr = seq->private; 10351da177e4SLinus Torvalds unsigned int i; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds if (!pr) 10391da177e4SLinus Torvalds goto end; 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds seq_printf(seq, "active state: C%zd\n" 10421da177e4SLinus Torvalds "max_cstate: C%d\n" 10435c87579eSArjan van de Ven "bus master activity: %08x\n" 10445c87579eSArjan van de Ven "maximum allowed latency: %d usec\n", 10451da177e4SLinus Torvalds pr->power.state ? pr->power.state - pr->power.states : 0, 10465c87579eSArjan van de Ven max_cstate, (unsigned)pr->power.bm_activity, 10475c87579eSArjan van de Ven system_latency_constraint()); 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds seq_puts(seq, "states:\n"); 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds for (i = 1; i <= pr->power.count; i++) { 10521da177e4SLinus Torvalds seq_printf(seq, " %cC%d: ", 10534be44fcdSLen Brown (&pr->power.states[i] == 10544be44fcdSLen Brown pr->power.state ? '*' : ' '), i); 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds if (!pr->power.states[i].valid) { 10571da177e4SLinus Torvalds seq_puts(seq, "<not supported>\n"); 10581da177e4SLinus Torvalds continue; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds switch (pr->power.states[i].type) { 10621da177e4SLinus Torvalds case ACPI_STATE_C1: 10631da177e4SLinus Torvalds seq_printf(seq, "type[C1] "); 10641da177e4SLinus Torvalds break; 10651da177e4SLinus Torvalds case ACPI_STATE_C2: 10661da177e4SLinus Torvalds seq_printf(seq, "type[C2] "); 10671da177e4SLinus Torvalds break; 10681da177e4SLinus Torvalds case ACPI_STATE_C3: 10691da177e4SLinus Torvalds seq_printf(seq, "type[C3] "); 10701da177e4SLinus Torvalds break; 10711da177e4SLinus Torvalds default: 10721da177e4SLinus Torvalds seq_printf(seq, "type[--] "); 10731da177e4SLinus Torvalds break; 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds if (pr->power.states[i].promotion.state) 10771da177e4SLinus Torvalds seq_printf(seq, "promotion[C%zd] ", 10781da177e4SLinus Torvalds (pr->power.states[i].promotion.state - 10791da177e4SLinus Torvalds pr->power.states)); 10801da177e4SLinus Torvalds else 10811da177e4SLinus Torvalds seq_puts(seq, "promotion[--] "); 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds if (pr->power.states[i].demotion.state) 10841da177e4SLinus Torvalds seq_printf(seq, "demotion[C%zd] ", 10851da177e4SLinus Torvalds (pr->power.states[i].demotion.state - 10861da177e4SLinus Torvalds pr->power.states)); 10871da177e4SLinus Torvalds else 10881da177e4SLinus Torvalds seq_puts(seq, "demotion[--] "); 10891da177e4SLinus Torvalds 1090a3c6598fSDominik Brodowski seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n", 10911da177e4SLinus Torvalds pr->power.states[i].latency, 1092a3c6598fSDominik Brodowski pr->power.states[i].usage, 1093b0b7eaafSAlexey Starikovskiy (unsigned long long)pr->power.states[i].time); 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds end: 1097d550d98dSPatrick Mochel return 0; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) 11011da177e4SLinus Torvalds { 11021da177e4SLinus Torvalds return single_open(file, acpi_processor_power_seq_show, 11031da177e4SLinus Torvalds PDE(inode)->data); 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds 1106d7508032SArjan van de Ven static const struct file_operations acpi_processor_power_fops = { 11071da177e4SLinus Torvalds .open = acpi_processor_power_open_fs, 11081da177e4SLinus Torvalds .read = seq_read, 11091da177e4SLinus Torvalds .llseek = seq_lseek, 11101da177e4SLinus Torvalds .release = single_release, 11111da177e4SLinus Torvalds }; 11121da177e4SLinus Torvalds 11131fec74a9SAndrew Morton #ifdef CONFIG_SMP 11145c87579eSArjan van de Ven static void smp_callback(void *v) 11155c87579eSArjan van de Ven { 11165c87579eSArjan van de Ven /* we already woke the CPU up, nothing more to do */ 11175c87579eSArjan van de Ven } 11185c87579eSArjan van de Ven 11195c87579eSArjan van de Ven /* 11205c87579eSArjan van de Ven * This function gets called when a part of the kernel has a new latency 11215c87579eSArjan van de Ven * requirement. This means we need to get all processors out of their C-state, 11225c87579eSArjan van de Ven * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that 11235c87579eSArjan van de Ven * wakes them all right up. 11245c87579eSArjan van de Ven */ 11255c87579eSArjan van de Ven static int acpi_processor_latency_notify(struct notifier_block *b, 11265c87579eSArjan van de Ven unsigned long l, void *v) 11275c87579eSArjan van de Ven { 11285c87579eSArjan van de Ven smp_call_function(smp_callback, NULL, 0, 1); 11295c87579eSArjan van de Ven return NOTIFY_OK; 11305c87579eSArjan van de Ven } 11315c87579eSArjan van de Ven 11325c87579eSArjan van de Ven static struct notifier_block acpi_processor_latency_notifier = { 11335c87579eSArjan van de Ven .notifier_call = acpi_processor_latency_notify, 11345c87579eSArjan van de Ven }; 11351fec74a9SAndrew Morton #endif 11365c87579eSArjan van de Ven 11377af8b660SPierre Ossman int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, 11384be44fcdSLen Brown struct acpi_device *device) 11391da177e4SLinus Torvalds { 11401da177e4SLinus Torvalds acpi_status status = 0; 1141b6835052SAndreas Mohr static int first_run; 11421da177e4SLinus Torvalds struct proc_dir_entry *entry = NULL; 11431da177e4SLinus Torvalds unsigned int i; 11441da177e4SLinus Torvalds 11451da177e4SLinus Torvalds 11461da177e4SLinus Torvalds if (!first_run) { 11471da177e4SLinus Torvalds dmi_check_system(processor_power_dmi_table); 11481da177e4SLinus Torvalds if (max_cstate < ACPI_C_STATES_MAX) 11494be44fcdSLen Brown printk(KERN_NOTICE 11504be44fcdSLen Brown "ACPI: processor limited to max C-state %d\n", 11514be44fcdSLen Brown max_cstate); 11521da177e4SLinus Torvalds first_run++; 11531fec74a9SAndrew Morton #ifdef CONFIG_SMP 11545c87579eSArjan van de Ven register_latency_notifier(&acpi_processor_latency_notifier); 11551fec74a9SAndrew Morton #endif 11561da177e4SLinus Torvalds } 11571da177e4SLinus Torvalds 115802df8b93SVenkatesh Pallipadi if (!pr) 1159d550d98dSPatrick Mochel return -EINVAL; 116002df8b93SVenkatesh Pallipadi 1161cee324b1SAlexey Starikovskiy if (acpi_gbl_FADT.cst_control && !nocst) { 11624be44fcdSLen Brown status = 1163cee324b1SAlexey Starikovskiy acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8); 11641da177e4SLinus Torvalds if (ACPI_FAILURE(status)) { 1165a6fc6720SThomas Renninger ACPI_EXCEPTION((AE_INFO, status, 1166a6fc6720SThomas Renninger "Notifying BIOS of _CST ability failed")); 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds } 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds acpi_processor_get_power_info(pr); 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds /* 11731da177e4SLinus Torvalds * Install the idle handler if processor power management is supported. 11741da177e4SLinus Torvalds * Note that we use previously set idle handler will be used on 11751da177e4SLinus Torvalds * platforms that only support C1. 11761da177e4SLinus Torvalds */ 11771da177e4SLinus Torvalds if ((pr->flags.power) && (!boot_option_idle_override)) { 11781da177e4SLinus Torvalds printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id); 11791da177e4SLinus Torvalds for (i = 1; i <= pr->power.count; i++) 11801da177e4SLinus Torvalds if (pr->power.states[i].valid) 11814be44fcdSLen Brown printk(" C%d[C%d]", i, 11824be44fcdSLen Brown pr->power.states[i].type); 11831da177e4SLinus Torvalds printk(")\n"); 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds if (pr->id == 0) { 11861da177e4SLinus Torvalds pm_idle_save = pm_idle; 11871da177e4SLinus Torvalds pm_idle = acpi_processor_idle; 11881da177e4SLinus Torvalds } 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds /* 'power' [R] */ 11921da177e4SLinus Torvalds entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, 11931da177e4SLinus Torvalds S_IRUGO, acpi_device_dir(device)); 11941da177e4SLinus Torvalds if (!entry) 1195a6fc6720SThomas Renninger return -EIO; 11961da177e4SLinus Torvalds else { 11971da177e4SLinus Torvalds entry->proc_fops = &acpi_processor_power_fops; 11981da177e4SLinus Torvalds entry->data = acpi_driver_data(device); 11991da177e4SLinus Torvalds entry->owner = THIS_MODULE; 12001da177e4SLinus Torvalds } 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds pr->flags.power_setup_done = 1; 12031da177e4SLinus Torvalds 1204d550d98dSPatrick Mochel return 0; 12051da177e4SLinus Torvalds } 12061da177e4SLinus Torvalds 12074be44fcdSLen Brown int acpi_processor_power_exit(struct acpi_processor *pr, 12084be44fcdSLen Brown struct acpi_device *device) 12091da177e4SLinus Torvalds { 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds pr->flags.power_setup_done = 0; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds if (acpi_device_dir(device)) 12144be44fcdSLen Brown remove_proc_entry(ACPI_PROCESSOR_FILE_POWER, 12154be44fcdSLen Brown acpi_device_dir(device)); 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds /* Unregister the idle handler when processor #0 is removed. */ 12181da177e4SLinus Torvalds if (pr->id == 0) { 12191da177e4SLinus Torvalds pm_idle = pm_idle_save; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds /* 12221da177e4SLinus Torvalds * We are about to unload the current idle thread pm callback 12231da177e4SLinus Torvalds * (pm_idle), Wait for all processors to update cached/local 12241da177e4SLinus Torvalds * copies of pm_idle before proceeding. 12251da177e4SLinus Torvalds */ 12261da177e4SLinus Torvalds cpu_idle_wait(); 12271fec74a9SAndrew Morton #ifdef CONFIG_SMP 12285c87579eSArjan van de Ven unregister_latency_notifier(&acpi_processor_latency_notifier); 12291fec74a9SAndrew Morton #endif 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds 1232d550d98dSPatrick Mochel return 0; 12331da177e4SLinus Torvalds } 1234