4f86d3a8e2
commit e5a16b1f9eec0af7cfa0830304b41c1c0833cf9f Author: Len Brown <len.brown@intel.com> Date: Tue Oct 2 23:44:44 2007 -0400 cpuidle: shrink diff processor_idle.c | 440 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 429 insertions(+), 11 deletions(-) Signed-off-by: Len Brown <len.brown@intel.com> commit dfbb9d5aedfb18848a3e0d6f6e3e4969febb209c Author: Len Brown <len.brown@intel.com> Date: Wed Sep 26 02:17:55 2007 -0400 cpuidle: reduce diff size Reduces the cpuidle processor_idle.c diff vs 2.6.22 from this processor_idle.c | 2006 ++++++++++++++++++++++++++----------------- 1 file changed, 1219 insertions(+), 787 deletions(-) to this: processor_idle.c | 502 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 458 insertions(+), 44 deletions(-) ...for the purpose of making the cpuilde patch less invasive and easier to review. no functional changes. build tested only. Signed-off-by: Len Brown <len.brown@intel.com> commit 889172fc915f5a7fe20f35b133cbd205ce69bf6c Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Sep 13 13:40:05 2007 -0700 cpuidle: Retain old ACPI policy for !CONFIG_CPU_IDLE Retain the old policy in processor_idle, so that when CPU_IDLE is not configured, old C-state policy will still be used. This provides a clean gradual migration path from old ACPI policy to new cpuidle based policy. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 9544a8181edc7ecc33b3bfd69271571f98ed08bc Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Sep 13 13:39:17 2007 -0700 cpuidle: Configure governors by default Quoting Len "Do not give an option to users to shoot themselves in the foot". Remove the configurability of ladder and menu governors as they are needed for default policy of cpuidle. That way users will not be able to have cpuidle without any policy loosing all C-state power savings. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 8975059a2c1e56cfe83d1bcf031bcf4cb39be743 Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:27:07 2007 -0400 CPUIDLE: load ACPI properly when CPUIDLE is disabled Change the registration return codes for when CPUIDLE support is not compiled into the kernel. As a result, the ACPI processor driver will load properly even if CPUIDLE is unavailable. However, it may be possible to cleanup the ACPI processor driver further and eliminate some dead code paths. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit e0322e2b58dd1b12ec669bf84693efe0dc2414a8 Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:26:06 2007 -0400 CPUIDLE: remove cpuidle_get_bm_activity() Remove cpuidle_get_bm_activity() and updates governors accordingly. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 18a6e770d5c82ba26653e53d240caa617e09e9ab Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:25:58 2007 -0400 CPUIDLE: max_cstate fix Currently max_cstate is limited to 0, resulting in no idle processor power management on ACPI platforms. This patch restores the value to the array size. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 1fdc0887286179b40ce24bcdbde663172e205ef0 Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:25:40 2007 -0400 CPUIDLE: handle BM detection inside the ACPI Processor driver Update the ACPI processor driver to detect BM activity and limit state entry depth internally, rather than exposing such requirements to CPUIDLE. As a result, CPUIDLE can drop this ACPI-specific interface and become more platform independent. BM activity is now handled much more aggressively than it was in the original implementation, so some testing coverage may be needed to verify that this doesn't introduce any DMA buffer under-run issues. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 0ef38840db666f48e3cdd2b769da676c57228dd9 Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:25:14 2007 -0400 CPUIDLE: menu governor updates Tweak the menu governor to more effectively handle non-timer break events. Non-timer break events are detected by comparing the actual sleep time to the expected sleep time. In future revisions, it may be more reliable to use the timer data structures directly. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit bb4d74fca63fa96cf3ace644b15ae0f12b7df5a1 Author: Adam Belay <abelay@novell.com> Date: Tue Aug 21 18:24:40 2007 -0400 CPUIDLE: fix 'current_governor' sysfs entry Allow the "current_governor" sysfs entry to properly handle input terminated with '\n'. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit df3c71559bb69b125f1a48971bf0d17f78bbdf47 Author: Len Brown <len.brown@intel.com> Date: Sun Aug 12 02:00:45 2007 -0400 cpuidle: fix IA64 build (again) Signed-off-by: Len Brown <len.brown@intel.com> commit a02064579e3f9530fd31baae16b1fc46b5a7bca8 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Sun Aug 12 01:39:27 2007 -0400 cpuidle: Remove support for runtime changing of max_cstate Remove support for runtime changeability of max_cstate. Drivers can use use latency APIs. max_cstate can still be used as a boot time option and dmi override. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 0912a44b13adf22f5e3f607d263aed23b4910d7e Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Sun Aug 12 01:39:16 2007 -0400 cpuidle: Remove ACPI cstate_limit calls from ipw2100 ipw2100 already has code to use accetable_latency interfaces to limit the C-state. Remove the calls to acpi_set_cstate_limit and acpi_get_cstate_limit as they are redundant. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit c649a76e76be6bff1fd770d0a775798813a3f6e0 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Sun Aug 12 01:35:39 2007 -0400 cpuidle: compile fix for pause and resume functions Fix the compilation failure when cpuidle is not compiled in. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Acked-by: Adam Belay <adam.belay@novell.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 2305a5920fb8ee6ccec1c62ade05aa8351091d71 Author: Adam Belay <abelay@novell.com> Date: Thu Jul 19 00:49:00 2007 -0400 cpuidle: re-write Some portions have been rewritten to make the code cleaner and lighter weight. The following is a list of changes: 1.) the state name is now included in the sysfs interface 2.) detection, hotplug, and available state modifications are handled by CPUIDLE drivers directly 3.) the CPUIDLE idle handler is only ever installed when at least one cpuidle_device is enabled and ready 4.) the menu governor BM code no longer overflows 5.) the sysfs attributes are now printed as unsigned integers, avoiding negative values 6.) a variety of other small cleanups Also, Idle drivers are no longer swappable during runtime through the CPUIDLE sysfs inteface. On i386 and x86_64 most idle handlers (e.g. poll, mwait, halt, etc.) don't benefit from an infrastructure that supports multiple states, so I think using a more general case idle handler selection mechanism would be cleaner. Signed-off-by: Adam Belay <abelay@novell.com> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Acked-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit df25b6b56955714e6e24b574d88d1fd11f0c3ee5 Author: Len Brown <len.brown@intel.com> Date: Tue Jul 24 17:08:21 2007 -0400 cpuidle: fix IA64 buid Signed-off-by: Len Brown <len.brown@intel.com> commit fd6ada4c14488755ff7068860078c437431fbccd Author: Adrian Bunk <bunk@stusta.de> Date: Mon Jul 9 11:33:13 2007 -0700 cpuidle: static make cpuidle_replace_governor() static Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit c1d4a2cebcadf2429c0c72e1d29aa2a9684c32e0 Author: Adrian Bunk <bunk@stusta.de> Date: Tue Jul 3 00:54:40 2007 -0400 cpuidle: static This patch makes the needlessly global struct menu_governor static. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit dbf8780c6e8d572c2c273da97ed1cca7608fd999 Author: Andrew Morton <akpm@linux-foundation.org> Date: Tue Jul 3 00:49:14 2007 -0400 export symbol tick_nohz_get_sleep_length ERROR: "tick_nohz_get_sleep_length" [drivers/cpuidle/governors/menu.ko] undefined! ERROR: "tick_nohz_get_idle_jiffies" [drivers/cpuidle/governors/menu.ko] undefined! And please be sure to get your changes to core kernel suitably reviewed. Cc: Adam Belay <abelay@novell.com> Cc: Venki Pallipadi <venkatesh.pallipadi@intel.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: john stultz <johnstul@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 29f0e248e7017be15f99febf9143a2cef00b2961 Author: Andrew Morton <akpm@linux-foundation.org> Date: Tue Jul 3 00:43:04 2007 -0400 tick.h needs hrtimer.h It uses hrtimers. Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit e40cede7d63a029e92712a3fe02faee60cc38fb4 Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:40:34 2007 -0400 cpuidle: first round of documentation updates Documentation changes based on Pavel's feedback. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 83b42be2efece386976507555c29e7773a0dfcd1 Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:39:25 2007 -0400 cpuidle: add rating to the governors and pick the one with highest rating by default Introduce a governor rating scheme to pick the right governor by default. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit d2a74b8c5e8f22def4709330d4bfc4a29209b71c Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:38:08 2007 -0400 cpuidle: make cpuidle sysfs driver governor switch off by default Make default cpuidle sysfs to show current_governor and current_driver in read-only mode. More elaborate available_governors and available_drivers with writeable current_governor and current_driver interface only appear with "cpuidle_sysfs_switch" boot parameter. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 1f60a0e80bf83cf6b55c8845bbe5596ed8f6307b Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:37:00 2007 -0400 cpuidle: menu governor: change the early break condition Change the C-state early break out algorithm in menu governor. We only look at early breakouts that result in wakeups shorter than idle state's target_residency. If such a breakout is frequent enough, eliminate the particular idle state upto a timeout period. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 45a42095cf64b003b4a69be3ce7f434f97d7af51 Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:35:38 2007 -0400 cpuidle: fix uninitialized variable in sysfs routine Fix the uninitialized usage of ret. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 80dca7cdba3e6ee13eae277660873ab9584eb3be Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:34:16 2007 -0400 cpuidle: reenable /proc/acpi//power interface for the time being Keep /proc/acpi/processor/CPU*/power around for a while as powertop depends on it. It will be marked deprecated and removed in future. powertop can use cpuidle interfaces instead. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 589c37c2646c5e3813a51255a5ee1159cb4c33fc Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Jul 3 00:32:37 2007 -0400 cpuidle: menu governor and hrtimer compile fix Compile fix for menu governor. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 0ba80bd9ab3ed304cb4f19b722e4cc6740588b5e Author: Len Brown <len.brown@intel.com> Date: Thu May 31 22:51:43 2007 -0400 cpuidle: build fix - cpuidle vs ipw2100 module ERROR: "acpi_set_cstate_limit" [drivers/net/wireless/ipw2100.ko] undefined! Signed-off-by: Len Brown <len.brown@intel.com> commit d7d8fa7f96a7f7682be7c6cc0cc53fa7a18c3b58 Author: Adam Belay <abelay@novell.com> Date: Sat Mar 24 03:47:07 2007 -0400 cpuidle: add the 'menu' governor Here is my first take at implementing an idle PM governor that takes full advantage of NO_HZ. I call it the 'menu' governor because it considers the full list of idle states before each entry. I've kept the implementation fairly simple. It attempts to guess the next residency time and then chooses a state that would meet at least the break-even point between power savings and entry cost. To this end, it selects the deepest idle state that satisfies the following constraints: 1. If the idle time elapsed since bus master activity was detected is below a threshold (currently 20 ms), then limit the selection to C2-type or above. 2. Do not choose a state with a break-even residency that exceeds the expected time remaining until the next timer interrupt. 3. Do not choose a state with a break-even residency that exceeds the elapsed time between the last pair of break events, excluding timer interrupts. This governor has an advantage over "ladder" governor because it proactively checks how much time remains until the next timer interrupt using the tick infrastructure. Also, it handles device interrupt activity more intelligently by not including timer interrupts in break event calculations. Finally, it doesn't make policy decisions using the number of state entries, which can have variable residency times (NO_HZ makes these potentially very large), and instead only considers sleep time deltas. The menu governor can be selected during runtime using the cpuidle sysfs interface like so: "echo "menu" > /sys/devices/system/cpu/cpuidle/current_governor" Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Len Brown <len.brown@intel.com> commit a4bec7e65aa3b7488b879d971651cc99a6c410fe Author: Adam Belay <abelay@novell.com> Date: Sat Mar 24 03:47:03 2007 -0400 cpuidle: export time until next timer interrupt using NO_HZ Expose information about the time remaining until the next timer interrupt expires by utilizing the dynticks infrastructure. Also modify the main idle loop to allow dynticks to handle non-interrupt break events (e.g. DMA). Finally, expose sleep ticks information to external code. Thomas Gleixner is responsible for much of the code in this patch. However, I've made some additional changes, so I'm probably responsible if there are any bugs or oversights :) Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 2929d8996fbc77f41a5ff86bb67cdde3ca7d2d72 Author: Adam Belay <abelay@novell.com> Date: Sat Mar 24 03:46:58 2007 -0400 cpuidle: governor API changes This patch prepares cpuidle for the menu governor. It adds an optional stage after idle state entry to give the governor an opportunity to check why the state was exited. Also it makes sure the idle loop returns after each state entry, allowing the appropriate dynticks code to run. Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 3a7fd42f9825c3b03e364ca59baa751bb350775f Author: Venki Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Apr 26 00:03:59 2007 -0700 cpuidle: hang fix Prevent hang on x86-64, when ACPI processor driver is added as a module on a system that does not support C-states. x86-64 expects all idle handlers to enable interrupts before returning from idle handler. This is due to enter_idle(), exit_idle() races. Make cpuidle_idle_call() confirm to this when there is no pm_idle_old. Also, cpuidle look at the return values of attch_driver() and set current_driver to NULL if attach fails on all CPUs. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 4893339a142afbd5b7c01ffadfd53d14746e858e Author: Shaohua Li <shaohua.li@intel.com> Date: Thu Apr 26 10:40:09 2007 +0800 cpuidle: add support for max_cstate limit With CPUIDLE framework, the max_cstate (to limit max cpu c-state) parameter is ingored. Some systems require it to ignore C2/C3 and some drivers like ipw require it too. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 43bbbbe1cb998cbd2df656f55bb3bfe30f30e7d1 Author: Shaohua Li <shaohua.li@intel.com> Date: Thu Apr 26 10:40:13 2007 +0800 cpuidle: add cpuidle_fore_redetect_devices API add cpuidle_force_redetect_devices API, which forces all CPU redetect idle states. Next patch will use it. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit d1edadd608f24836def5ec483d2edccfb37b1d19 Author: Shaohua Li <shaohua.li@intel.com> Date: Thu Apr 26 10:40:01 2007 +0800 cpuidle: fix sysfs related issue Fix the cpuidle sysfs issue. a. make kobject dynamicaly allocated b. fixed sysfs init issue to avoid suspend/resume issue Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 7169a5cc0d67b263978859672e86c13c23a5570d Author: Randy Dunlap <randy.dunlap@oracle.com> Date: Wed Mar 28 22:52:53 2007 -0400 cpuidle: 1-bit field must be unsigned A 1-bit bitfield has no room for a sign bit. drivers/cpuidle/governors/ladder.c:54:16: error: dubious bitfield without explicit `signed' or `unsigned' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 4658620158dc2fbd9e4bcb213c5b6fb5d05ba7d4 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Wed Mar 28 22:52:41 2007 -0400 cpuidle: fix boot hang Patch for cpuidle boot hang reported by Larry Finger here. http://www.ussg.iu.edu/hypermail/linux/kernel/0703.2/2025.html Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Larry Finger <larry.finger@lwfinger.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit c17e168aa6e5fe3851baaae8df2fbc1cf11443a9 Author: Len Brown <len.brown@intel.com> Date: Wed Mar 7 04:37:53 2007 -0500 cpuidle: ladder does not depend on ACPI build fix for CONFIG_ACPI=n In file included from drivers/cpuidle/governors/ladder.c:21: include/acpi/processor.h:88: error: expected specifier-qualifier-list before âacpi_integerâ include/acpi/processor.h:106: error: expected specifier-qualifier-list before âacpi_integerâ include/acpi/processor.h:168: error: expected specifier-qualifier-list before âacpi_handleâ Signed-off-by: Len Brown <len.brown@intel.com> commit 8c91d958246bde68db0c3f0c57b535962ce861cb Author: Adrian Bunk <bunk@stusta.de> Date: Tue Mar 6 02:29:40 2007 -0800 cpuidle: make code static This patch makes the following needlessly global code static: - driver.c: __cpuidle_find_driver() - governor.c: __cpuidle_find_governor() - ladder.c: struct ladder_governor Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Adam Belay <abelay@novell.com> Cc: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 0c39dc3187094c72c33ab65a64d2017b21f372d2 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Wed Mar 7 02:38:22 2007 -0500 cpu_idle: fix build break This patch fixes a build breakage with !CONFIG_HOTPLUG_CPU and CONFIG_CPU_IDLE. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 8112e3b115659b07df340ef170515799c0105f82 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Tue Mar 6 02:29:39 2007 -0800 cpuidle: build fix for !CPU_IDLE Fix the compile issues when CPU_IDLE is not configured. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Adam Belay <abelay@novell.com> Cc: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com> commit 1eb4431e9599cd25e0d9872f3c2c8986821839dd Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Feb 22 13:54:57 2007 -0800 cpuidle take2: Basic documentation for cpuidle Documentation for cpuidle infrastructure Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> commit ef5f15a8b79123a047285ec2e3899108661df779 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Feb 22 13:54:03 2007 -0800 cpuidle take2: Hookup ACPI C-states driver with cpuidle Hookup ACPI C-states onto generic cpuidle infrastructure. drivers/acpi/procesor_idle.c is now a ACPI C-states driver that registers as a driver in cpuidle infrastructure and the policy part is removed from drivers/acpi/processor_idle.c. We use governor in cpuidle instead. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Len Brown <len.brown@intel.com> commit 987196fa82d4db52c407e8c9d5dec884ba602183 Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Date: Thu Feb 22 13:52:57 2007 -0800 cpuidle take2: Core cpuidle infrastructure Announcing 'cpuidle', a new CPU power management infrastructure to manage idle CPUs in a clean and efficient manner. cpuidle separates out the drivers that can provide support for multiple types of idle states and policy governors that decide on what idle state to use at run time. A cpuidle driver can support multiple idle states based on parameters like varying power consumption, wakeup latency, etc (ACPI C-states for example). A cpuidle governor can be usage model specific (laptop, server, laptop on battery etc). Main advantage of the infrastructure being, it allows independent development of drivers and governors and allows for better CPU power management. A huge thanks to Adam Belay and Shaohua Li who were part of this mini-project since its beginning and are greatly responsible for this patchset. This patch: Core cpuidle infrastructure. Introduces a new abstraction layer for cpuidle: * which manages drivers that can support multiple idles states. Drivers can be generic or particular to specific hardware/platform * allows pluging in multiple policy governors that can take idle state policy decision * The core also has a set of sysfs interfaces with which administrato can know about supported drivers and governors and switch them at run time. Signed-off-by: Adam Belay <abelay@novell.com> Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
1233 lines
28 KiB
C
1233 lines
28 KiB
C
/*
|
|
* acpi_osl.c - OS-dependent functions ($Revision: 83 $)
|
|
*
|
|
* Copyright (C) 2000 Andrew Henroid
|
|
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
|
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* 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/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kmod.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/nmi.h>
|
|
#include <linux/acpi.h>
|
|
#include <acpi/acpi.h>
|
|
#include <asm/io.h>
|
|
#include <acpi/acpi_bus.h>
|
|
#include <acpi/processor.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <linux/efi.h>
|
|
|
|
#define _COMPONENT ACPI_OS_SERVICES
|
|
ACPI_MODULE_NAME("osl");
|
|
#define PREFIX "ACPI: "
|
|
struct acpi_os_dpc {
|
|
acpi_osd_exec_callback function;
|
|
void *context;
|
|
struct work_struct work;
|
|
};
|
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
|
#include CONFIG_ACPI_CUSTOM_DSDT_FILE
|
|
#endif
|
|
|
|
#ifdef ENABLE_DEBUGGER
|
|
#include <linux/kdb.h>
|
|
|
|
/* stuff for debugger support */
|
|
int acpi_in_debugger;
|
|
EXPORT_SYMBOL(acpi_in_debugger);
|
|
|
|
extern char line_buf[80];
|
|
#endif /*ENABLE_DEBUGGER */
|
|
|
|
static unsigned int acpi_irq_irq;
|
|
static acpi_osd_handler acpi_irq_handler;
|
|
static void *acpi_irq_context;
|
|
static struct workqueue_struct *kacpid_wq;
|
|
static struct workqueue_struct *kacpi_notify_wq;
|
|
|
|
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
|
|
static char osi_additional_string[OSI_STRING_LENGTH_MAX];
|
|
|
|
static int osi_linux; /* disable _OSI(Linux) by default */
|
|
|
|
#ifdef CONFIG_DMI
|
|
static struct __initdata dmi_system_id acpi_osl_dmi_table[];
|
|
#endif
|
|
|
|
static void __init acpi_request_region (struct acpi_generic_address *addr,
|
|
unsigned int length, char *desc)
|
|
{
|
|
struct resource *res;
|
|
|
|
if (!addr->address || !length)
|
|
return;
|
|
|
|
if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
|
res = request_region(addr->address, length, desc);
|
|
else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
|
res = request_mem_region(addr->address, length, desc);
|
|
}
|
|
|
|
static int __init acpi_reserve_resources(void)
|
|
{
|
|
acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
|
|
"ACPI PM1a_EVT_BLK");
|
|
|
|
acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
|
|
"ACPI PM1b_EVT_BLK");
|
|
|
|
acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
|
|
"ACPI PM1a_CNT_BLK");
|
|
|
|
acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
|
|
"ACPI PM1b_CNT_BLK");
|
|
|
|
if (acpi_gbl_FADT.pm_timer_length == 4)
|
|
acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
|
|
|
|
acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
|
|
"ACPI PM2_CNT_BLK");
|
|
|
|
/* Length of GPE blocks must be a non-negative multiple of 2 */
|
|
|
|
if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
|
|
acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
|
|
acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
|
|
|
|
if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
|
|
acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
|
|
acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
|
|
|
|
return 0;
|
|
}
|
|
device_initcall(acpi_reserve_resources);
|
|
|
|
acpi_status __init acpi_os_initialize(void)
|
|
{
|
|
dmi_check_system(acpi_osl_dmi_table);
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status acpi_os_initialize1(void)
|
|
{
|
|
/*
|
|
* Initialize PCI configuration space access, as we'll need to access
|
|
* it while walking the namespace (bus 0 and root bridges w/ _BBNs).
|
|
*/
|
|
if (!raw_pci_ops) {
|
|
printk(KERN_ERR PREFIX
|
|
"Access to PCI configuration space unavailable\n");
|
|
return AE_NULL_ENTRY;
|
|
}
|
|
kacpid_wq = create_singlethread_workqueue("kacpid");
|
|
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
|
|
BUG_ON(!kacpid_wq);
|
|
BUG_ON(!kacpi_notify_wq);
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status acpi_os_terminate(void)
|
|
{
|
|
if (acpi_irq_handler) {
|
|
acpi_os_remove_interrupt_handler(acpi_irq_irq,
|
|
acpi_irq_handler);
|
|
}
|
|
|
|
destroy_workqueue(kacpid_wq);
|
|
destroy_workqueue(kacpi_notify_wq);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
void acpi_os_printf(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
acpi_os_vprintf(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_printf);
|
|
|
|
void acpi_os_vprintf(const char *fmt, va_list args)
|
|
{
|
|
static char buffer[512];
|
|
|
|
vsprintf(buffer, fmt, args);
|
|
|
|
#ifdef ENABLE_DEBUGGER
|
|
if (acpi_in_debugger) {
|
|
kdb_printf("%s", buffer);
|
|
} else {
|
|
printk("%s", buffer);
|
|
}
|
|
#else
|
|
printk("%s", buffer);
|
|
#endif
|
|
}
|
|
|
|
acpi_physical_address __init acpi_os_get_root_pointer(void)
|
|
{
|
|
if (efi_enabled) {
|
|
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
|
|
return efi.acpi20;
|
|
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
|
|
return efi.acpi;
|
|
else {
|
|
printk(KERN_ERR PREFIX
|
|
"System description tables not found\n");
|
|
return 0;
|
|
}
|
|
} else
|
|
return acpi_find_rsdp();
|
|
}
|
|
|
|
void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
|
|
{
|
|
if (phys > ULONG_MAX) {
|
|
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
|
|
return NULL;
|
|
}
|
|
if (acpi_gbl_permanent_mmap)
|
|
/*
|
|
* ioremap checks to ensure this is in reserved space
|
|
*/
|
|
return ioremap((unsigned long)phys, size);
|
|
else
|
|
return __acpi_map_table((unsigned long)phys, size);
|
|
}
|
|
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
|
|
|
|
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
|
|
{
|
|
if (acpi_gbl_permanent_mmap) {
|
|
iounmap(virt);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
|
|
|
|
#ifdef ACPI_FUTURE_USAGE
|
|
acpi_status
|
|
acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
|
|
{
|
|
if (!phys || !virt)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
*phys = virt_to_phys(virt);
|
|
|
|
return AE_OK;
|
|
}
|
|
#endif
|
|
|
|
#define ACPI_MAX_OVERRIDE_LEN 100
|
|
|
|
static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
|
|
|
|
acpi_status
|
|
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
|
|
acpi_string * new_val)
|
|
{
|
|
if (!init_val || !new_val)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
*new_val = NULL;
|
|
if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
|
|
printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
|
|
acpi_os_name);
|
|
*new_val = acpi_os_name;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_table_override(struct acpi_table_header * existing_table,
|
|
struct acpi_table_header ** new_table)
|
|
{
|
|
if (!existing_table || !new_table)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
|
if (strncmp(existing_table->signature, "DSDT", 4) == 0)
|
|
*new_table = (struct acpi_table_header *)AmlCode;
|
|
else
|
|
*new_table = NULL;
|
|
#else
|
|
*new_table = NULL;
|
|
#endif
|
|
return AE_OK;
|
|
}
|
|
|
|
static irqreturn_t acpi_irq(int irq, void *dev_id)
|
|
{
|
|
return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
|
|
void *context)
|
|
{
|
|
unsigned int irq;
|
|
|
|
/*
|
|
* Ignore the GSI from the core, and use the value in our copy of the
|
|
* FADT. It may not be the same if an interrupt source override exists
|
|
* for the SCI.
|
|
*/
|
|
gsi = acpi_gbl_FADT.sci_interrupt;
|
|
if (acpi_gsi_to_irq(gsi, &irq) < 0) {
|
|
printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
|
|
gsi);
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_irq_handler = handler;
|
|
acpi_irq_context = context;
|
|
if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
|
|
printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
|
|
return AE_NOT_ACQUIRED;
|
|
}
|
|
acpi_irq_irq = irq;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
|
|
{
|
|
if (irq) {
|
|
free_irq(irq, acpi_irq);
|
|
acpi_irq_handler = NULL;
|
|
acpi_irq_irq = 0;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
/*
|
|
* Running in interpreter thread context, safe to sleep
|
|
*/
|
|
|
|
void acpi_os_sleep(acpi_integer ms)
|
|
{
|
|
schedule_timeout_interruptible(msecs_to_jiffies(ms));
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_sleep);
|
|
|
|
void acpi_os_stall(u32 us)
|
|
{
|
|
while (us) {
|
|
u32 delay = 1000;
|
|
|
|
if (delay > us)
|
|
delay = us;
|
|
udelay(delay);
|
|
touch_nmi_watchdog();
|
|
us -= delay;
|
|
}
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_stall);
|
|
|
|
/*
|
|
* Support ACPI 3.0 AML Timer operand
|
|
* Returns 64-bit free-running, monotonically increasing timer
|
|
* with 100ns granularity
|
|
*/
|
|
u64 acpi_os_get_timer(void)
|
|
{
|
|
static u64 t;
|
|
|
|
#ifdef CONFIG_HPET
|
|
/* TBD: use HPET if available */
|
|
#endif
|
|
|
|
#ifdef CONFIG_X86_PM_TIMER
|
|
/* TBD: default to PM timer if HPET was not available */
|
|
#endif
|
|
if (!t)
|
|
printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n");
|
|
|
|
return ++t;
|
|
}
|
|
|
|
acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
|
|
{
|
|
u32 dummy;
|
|
|
|
if (!value)
|
|
value = &dummy;
|
|
|
|
switch (width) {
|
|
case 8:
|
|
*(u8 *) value = inb(port);
|
|
break;
|
|
case 16:
|
|
*(u16 *) value = inw(port);
|
|
break;
|
|
case 32:
|
|
*(u32 *) value = inl(port);
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_read_port);
|
|
|
|
acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
|
|
{
|
|
switch (width) {
|
|
case 8:
|
|
outb(value, port);
|
|
break;
|
|
case 16:
|
|
outw(value, port);
|
|
break;
|
|
case 32:
|
|
outl(value, port);
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_write_port);
|
|
|
|
acpi_status
|
|
acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
|
|
{
|
|
u32 dummy;
|
|
void __iomem *virt_addr;
|
|
|
|
virt_addr = ioremap(phys_addr, width);
|
|
if (!value)
|
|
value = &dummy;
|
|
|
|
switch (width) {
|
|
case 8:
|
|
*(u8 *) value = readb(virt_addr);
|
|
break;
|
|
case 16:
|
|
*(u16 *) value = readw(virt_addr);
|
|
break;
|
|
case 32:
|
|
*(u32 *) value = readl(virt_addr);
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
iounmap(virt_addr);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
|
|
{
|
|
void __iomem *virt_addr;
|
|
|
|
virt_addr = ioremap(phys_addr, width);
|
|
|
|
switch (width) {
|
|
case 8:
|
|
writeb(value, virt_addr);
|
|
break;
|
|
case 16:
|
|
writew(value, virt_addr);
|
|
break;
|
|
case 32:
|
|
writel(value, virt_addr);
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
iounmap(virt_addr);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
|
|
void *value, u32 width)
|
|
{
|
|
int result, size;
|
|
|
|
if (!value)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
switch (width) {
|
|
case 8:
|
|
size = 1;
|
|
break;
|
|
case 16:
|
|
size = 2;
|
|
break;
|
|
case 32:
|
|
size = 4;
|
|
break;
|
|
default:
|
|
return AE_ERROR;
|
|
}
|
|
|
|
BUG_ON(!raw_pci_ops);
|
|
|
|
result = raw_pci_ops->read(pci_id->segment, pci_id->bus,
|
|
PCI_DEVFN(pci_id->device, pci_id->function),
|
|
reg, size, value);
|
|
|
|
return (result ? AE_ERROR : AE_OK);
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_read_pci_configuration);
|
|
|
|
acpi_status
|
|
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
|
|
acpi_integer value, u32 width)
|
|
{
|
|
int result, size;
|
|
|
|
switch (width) {
|
|
case 8:
|
|
size = 1;
|
|
break;
|
|
case 16:
|
|
size = 2;
|
|
break;
|
|
case 32:
|
|
size = 4;
|
|
break;
|
|
default:
|
|
return AE_ERROR;
|
|
}
|
|
|
|
BUG_ON(!raw_pci_ops);
|
|
|
|
result = raw_pci_ops->write(pci_id->segment, pci_id->bus,
|
|
PCI_DEVFN(pci_id->device, pci_id->function),
|
|
reg, size, value);
|
|
|
|
return (result ? AE_ERROR : AE_OK);
|
|
}
|
|
|
|
/* TODO: Change code to take advantage of driver model more */
|
|
static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
|
|
acpi_handle chandle, /* current node */
|
|
struct acpi_pci_id **id,
|
|
int *is_bridge, u8 * bus_number)
|
|
{
|
|
acpi_handle handle;
|
|
struct acpi_pci_id *pci_id = *id;
|
|
acpi_status status;
|
|
unsigned long temp;
|
|
acpi_object_type type;
|
|
u8 tu8;
|
|
|
|
acpi_get_parent(chandle, &handle);
|
|
if (handle != rhandle) {
|
|
acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
|
|
bus_number);
|
|
|
|
status = acpi_get_type(handle, &type);
|
|
if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
|
|
return;
|
|
|
|
status =
|
|
acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
|
|
&temp);
|
|
if (ACPI_SUCCESS(status)) {
|
|
pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
|
|
pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
|
|
|
|
if (*is_bridge)
|
|
pci_id->bus = *bus_number;
|
|
|
|
/* any nicer way to get bus number of bridge ? */
|
|
status =
|
|
acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8,
|
|
8);
|
|
if (ACPI_SUCCESS(status)
|
|
&& ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) {
|
|
status =
|
|
acpi_os_read_pci_configuration(pci_id, 0x18,
|
|
&tu8, 8);
|
|
if (!ACPI_SUCCESS(status)) {
|
|
/* Certainly broken... FIX ME */
|
|
return;
|
|
}
|
|
*is_bridge = 1;
|
|
pci_id->bus = tu8;
|
|
status =
|
|
acpi_os_read_pci_configuration(pci_id, 0x19,
|
|
&tu8, 8);
|
|
if (ACPI_SUCCESS(status)) {
|
|
*bus_number = tu8;
|
|
}
|
|
} else
|
|
*is_bridge = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
|
|
acpi_handle chandle, /* current node */
|
|
struct acpi_pci_id **id)
|
|
{
|
|
int is_bridge = 1;
|
|
u8 bus_number = (*id)->bus;
|
|
|
|
acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
|
|
}
|
|
|
|
static void acpi_os_execute_deferred(struct work_struct *work)
|
|
{
|
|
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
|
if (!dpc) {
|
|
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
|
return;
|
|
}
|
|
|
|
dpc->function(dpc->context);
|
|
kfree(dpc);
|
|
|
|
/* Yield cpu to notify thread */
|
|
cond_resched();
|
|
|
|
return;
|
|
}
|
|
|
|
static void acpi_os_execute_notify(struct work_struct *work)
|
|
{
|
|
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
|
|
|
if (!dpc) {
|
|
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
|
return;
|
|
}
|
|
|
|
dpc->function(dpc->context);
|
|
|
|
kfree(dpc);
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_execute
|
|
*
|
|
* PARAMETERS: Type - Type of the callback
|
|
* Function - Function to be executed
|
|
* Context - Function parameters
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Depending on type, either queues function for deferred execution or
|
|
* immediately executes function on a separate thread.
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status acpi_os_execute(acpi_execute_type type,
|
|
acpi_osd_exec_callback function, void *context)
|
|
{
|
|
acpi_status status = AE_OK;
|
|
struct acpi_os_dpc *dpc;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
|
"Scheduling function [%p(%p)] for deferred execution.\n",
|
|
function, context));
|
|
|
|
if (!function)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
/*
|
|
* Allocate/initialize DPC structure. Note that this memory will be
|
|
* freed by the callee. The kernel handles the work_struct list in a
|
|
* way that allows us to also free its memory inside the callee.
|
|
* Because we may want to schedule several tasks with different
|
|
* parameters we can't use the approach some kernel code uses of
|
|
* having a static work_struct.
|
|
*/
|
|
|
|
dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
|
|
if (!dpc)
|
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
|
|
|
dpc->function = function;
|
|
dpc->context = context;
|
|
|
|
if (type == OSL_NOTIFY_HANDLER) {
|
|
INIT_WORK(&dpc->work, acpi_os_execute_notify);
|
|
if (!queue_work(kacpi_notify_wq, &dpc->work)) {
|
|
status = AE_ERROR;
|
|
kfree(dpc);
|
|
}
|
|
} else {
|
|
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
|
if (!queue_work(kacpid_wq, &dpc->work)) {
|
|
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
|
"Call to queue_work() failed.\n"));
|
|
status = AE_ERROR;
|
|
kfree(dpc);
|
|
}
|
|
}
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_execute);
|
|
|
|
void acpi_os_wait_events_complete(void *context)
|
|
{
|
|
flush_workqueue(kacpid_wq);
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_wait_events_complete);
|
|
|
|
/*
|
|
* Allocate the memory for a spinlock and initialize it.
|
|
*/
|
|
acpi_status acpi_os_create_lock(acpi_spinlock * handle)
|
|
{
|
|
spin_lock_init(*handle);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
/*
|
|
* Deallocate the memory for a spinlock.
|
|
*/
|
|
void acpi_os_delete_lock(acpi_spinlock handle)
|
|
{
|
|
return;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
|
|
{
|
|
struct semaphore *sem = NULL;
|
|
|
|
|
|
sem = acpi_os_allocate(sizeof(struct semaphore));
|
|
if (!sem)
|
|
return AE_NO_MEMORY;
|
|
memset(sem, 0, sizeof(struct semaphore));
|
|
|
|
sema_init(sem, initial_units);
|
|
|
|
*handle = (acpi_handle *) sem;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n",
|
|
*handle, initial_units));
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_create_semaphore);
|
|
|
|
/*
|
|
* TODO: A better way to delete semaphores? Linux doesn't have a
|
|
* 'delete_semaphore()' function -- may result in an invalid
|
|
* pointer dereference for non-synchronized consumers. Should
|
|
* we at least check for blocked threads and signal/cancel them?
|
|
*/
|
|
|
|
acpi_status acpi_os_delete_semaphore(acpi_handle handle)
|
|
{
|
|
struct semaphore *sem = (struct semaphore *)handle;
|
|
|
|
|
|
if (!sem)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
|
|
|
|
kfree(sem);
|
|
sem = NULL;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_delete_semaphore);
|
|
|
|
/*
|
|
* TODO: The kernel doesn't have a 'down_timeout' function -- had to
|
|
* improvise. The process is to sleep for one scheduler quantum
|
|
* until the semaphore becomes available. Downside is that this
|
|
* may result in starvation for timeout-based waits when there's
|
|
* lots of semaphore activity.
|
|
*
|
|
* TODO: Support for units > 1?
|
|
*/
|
|
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
|
|
{
|
|
acpi_status status = AE_OK;
|
|
struct semaphore *sem = (struct semaphore *)handle;
|
|
int ret = 0;
|
|
|
|
|
|
if (!sem || (units < 1))
|
|
return AE_BAD_PARAMETER;
|
|
|
|
if (units > 1)
|
|
return AE_SUPPORT;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
|
|
handle, units, timeout));
|
|
|
|
/*
|
|
* This can be called during resume with interrupts off.
|
|
* Like boot-time, we should be single threaded and will
|
|
* always get the lock if we try -- timeout or not.
|
|
* If this doesn't succeed, then we will oops courtesy of
|
|
* might_sleep() in down().
|
|
*/
|
|
if (!down_trylock(sem))
|
|
return AE_OK;
|
|
|
|
switch (timeout) {
|
|
/*
|
|
* No Wait:
|
|
* --------
|
|
* A zero timeout value indicates that we shouldn't wait - just
|
|
* acquire the semaphore if available otherwise return AE_TIME
|
|
* (a.k.a. 'would block').
|
|
*/
|
|
case 0:
|
|
if (down_trylock(sem))
|
|
status = AE_TIME;
|
|
break;
|
|
|
|
/*
|
|
* Wait Indefinitely:
|
|
* ------------------
|
|
*/
|
|
case ACPI_WAIT_FOREVER:
|
|
down(sem);
|
|
break;
|
|
|
|
/*
|
|
* Wait w/ Timeout:
|
|
* ----------------
|
|
*/
|
|
default:
|
|
// TODO: A better timeout algorithm?
|
|
{
|
|
int i = 0;
|
|
static const int quantum_ms = 1000 / HZ;
|
|
|
|
ret = down_trylock(sem);
|
|
for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) {
|
|
schedule_timeout_interruptible(1);
|
|
ret = down_trylock(sem);
|
|
}
|
|
|
|
if (ret != 0)
|
|
status = AE_TIME;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ACPI_FAILURE(status)) {
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
|
|
"Failed to acquire semaphore[%p|%d|%d], %s",
|
|
handle, units, timeout,
|
|
acpi_format_exception(status)));
|
|
} else {
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
|
|
"Acquired semaphore[%p|%d|%d]", handle,
|
|
units, timeout));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_wait_semaphore);
|
|
|
|
/*
|
|
* TODO: Support for units > 1?
|
|
*/
|
|
acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
|
|
{
|
|
struct semaphore *sem = (struct semaphore *)handle;
|
|
|
|
|
|
if (!sem || (units < 1))
|
|
return AE_BAD_PARAMETER;
|
|
|
|
if (units > 1)
|
|
return AE_SUPPORT;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
|
|
units));
|
|
|
|
up(sem);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_signal_semaphore);
|
|
|
|
#ifdef ACPI_FUTURE_USAGE
|
|
u32 acpi_os_get_line(char *buffer)
|
|
{
|
|
|
|
#ifdef ENABLE_DEBUGGER
|
|
if (acpi_in_debugger) {
|
|
u32 chars;
|
|
|
|
kdb_read(buffer, sizeof(line_buf));
|
|
|
|
/* remove the CR kdb includes */
|
|
chars = strlen(buffer) - 1;
|
|
buffer[chars] = '\0';
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif /* ACPI_FUTURE_USAGE */
|
|
|
|
acpi_status acpi_os_signal(u32 function, void *info)
|
|
{
|
|
switch (function) {
|
|
case ACPI_SIGNAL_FATAL:
|
|
printk(KERN_ERR PREFIX "Fatal opcode executed\n");
|
|
break;
|
|
case ACPI_SIGNAL_BREAKPOINT:
|
|
/*
|
|
* AML Breakpoint
|
|
* ACPI spec. says to treat it as a NOP unless
|
|
* you are debugging. So if/when we integrate
|
|
* AML debugger into the kernel debugger its
|
|
* hook will go here. But until then it is
|
|
* not useful to print anything on breakpoints.
|
|
*/
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
EXPORT_SYMBOL(acpi_os_signal);
|
|
|
|
static int __init acpi_os_name_setup(char *str)
|
|
{
|
|
char *p = acpi_os_name;
|
|
int count = ACPI_MAX_OVERRIDE_LEN - 1;
|
|
|
|
if (!str || !*str)
|
|
return 0;
|
|
|
|
for (; count-- && str && *str; str++) {
|
|
if (isalnum(*str) || *str == ' ' || *str == ':')
|
|
*p++ = *str;
|
|
else if (*str == '\'' || *str == '"')
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
*p = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
__setup("acpi_os_name=", acpi_os_name_setup);
|
|
|
|
static void enable_osi_linux(int enable) {
|
|
|
|
if (osi_linux != enable)
|
|
printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
|
|
enable ? "En": "Dis");
|
|
|
|
osi_linux = enable;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Modify the list of "OS Interfaces" reported to BIOS via _OSI
|
|
*
|
|
* empty string disables _OSI
|
|
* string starting with '!' disables that string
|
|
* otherwise string is added to list, augmenting built-in strings
|
|
*/
|
|
static int __init acpi_osi_setup(char *str)
|
|
{
|
|
if (str == NULL || *str == '\0') {
|
|
printk(KERN_INFO PREFIX "_OSI method disabled\n");
|
|
acpi_gbl_create_osi_method = FALSE;
|
|
} else if (!strcmp("!Linux", str)) {
|
|
enable_osi_linux(0);
|
|
} else if (*str == '!') {
|
|
if (acpi_osi_invalidate(++str) == AE_OK)
|
|
printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
|
|
} else if (!strcmp("Linux", str)) {
|
|
enable_osi_linux(1);
|
|
} else if (*osi_additional_string == '\0') {
|
|
strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
|
|
printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
__setup("acpi_osi=", acpi_osi_setup);
|
|
|
|
/* enable serialization to combat AE_ALREADY_EXISTS errors */
|
|
static int __init acpi_serialize_setup(char *str)
|
|
{
|
|
printk(KERN_INFO PREFIX "serialize enabled\n");
|
|
|
|
acpi_gbl_all_methods_serialized = TRUE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
__setup("acpi_serialize", acpi_serialize_setup);
|
|
|
|
/*
|
|
* Wake and Run-Time GPES are expected to be separate.
|
|
* We disable wake-GPEs at run-time to prevent spurious
|
|
* interrupts.
|
|
*
|
|
* However, if a system exists that shares Wake and
|
|
* Run-time events on the same GPE this flag is available
|
|
* to tell Linux to keep the wake-time GPEs enabled at run-time.
|
|
*/
|
|
static int __init acpi_wake_gpes_always_on_setup(char *str)
|
|
{
|
|
printk(KERN_INFO PREFIX "wake GPEs not disabled\n");
|
|
|
|
acpi_gbl_leave_wake_gpes_disabled = FALSE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
|
|
|
|
/*
|
|
* Acquire a spinlock.
|
|
*
|
|
* handle is a pointer to the spinlock_t.
|
|
*/
|
|
|
|
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
|
|
{
|
|
acpi_cpu_flags flags;
|
|
spin_lock_irqsave(lockp, flags);
|
|
return flags;
|
|
}
|
|
|
|
/*
|
|
* Release a spinlock. See above.
|
|
*/
|
|
|
|
void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
|
|
{
|
|
spin_unlock_irqrestore(lockp, flags);
|
|
}
|
|
|
|
#ifndef ACPI_USE_LOCAL_CACHE
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_create_cache
|
|
*
|
|
* PARAMETERS: name - Ascii name for the cache
|
|
* size - Size of each cached object
|
|
* depth - Maximum depth of the cache (in objects) <ignored>
|
|
* cache - Where the new cache object is returned
|
|
*
|
|
* RETURN: status
|
|
*
|
|
* DESCRIPTION: Create a cache object
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status
|
|
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
|
|
{
|
|
*cache = kmem_cache_create(name, size, 0, 0, NULL);
|
|
if (*cache == NULL)
|
|
return AE_ERROR;
|
|
else
|
|
return AE_OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_purge_cache
|
|
*
|
|
* PARAMETERS: Cache - Handle to cache object
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Free all objects within the requested cache.
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
|
|
{
|
|
kmem_cache_shrink(cache);
|
|
return (AE_OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_delete_cache
|
|
*
|
|
* PARAMETERS: Cache - Handle to cache object
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Free all objects within the requested cache and delete the
|
|
* cache object.
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
|
|
{
|
|
kmem_cache_destroy(cache);
|
|
return (AE_OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_release_object
|
|
*
|
|
* PARAMETERS: Cache - Handle to cache object
|
|
* Object - The object to be released
|
|
*
|
|
* RETURN: None
|
|
*
|
|
* DESCRIPTION: Release an object to the specified cache. If cache is full,
|
|
* the object is deleted.
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
|
|
{
|
|
kmem_cache_free(cache, object);
|
|
return (AE_OK);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_validate_interface
|
|
*
|
|
* PARAMETERS: interface - Requested interface to be validated
|
|
*
|
|
* RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise
|
|
*
|
|
* DESCRIPTION: Match an interface string to the interfaces supported by the
|
|
* host. Strings originate from an AML call to the _OSI method.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
acpi_status
|
|
acpi_os_validate_interface (char *interface)
|
|
{
|
|
if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
|
|
return AE_OK;
|
|
if (!strcmp("Linux", interface)) {
|
|
printk(KERN_WARNING PREFIX
|
|
"System BIOS is requesting _OSI(Linux)\n");
|
|
printk(KERN_WARNING PREFIX
|
|
"If \"acpi_osi=Linux\" works better,\n"
|
|
"Please send dmidecode "
|
|
"to linux-acpi@vger.kernel.org\n");
|
|
if(osi_linux)
|
|
return AE_OK;
|
|
}
|
|
return AE_SUPPORT;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_os_validate_address
|
|
*
|
|
* PARAMETERS: space_id - ACPI space ID
|
|
* address - Physical address
|
|
* length - Address length
|
|
*
|
|
* RETURN: AE_OK if address/length is valid for the space_id. Otherwise,
|
|
* should return AE_AML_ILLEGAL_ADDRESS.
|
|
*
|
|
* DESCRIPTION: Validate a system address via the host OS. Used to validate
|
|
* the addresses accessed by AML operation regions.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
acpi_status
|
|
acpi_os_validate_address (
|
|
u8 space_id,
|
|
acpi_physical_address address,
|
|
acpi_size length)
|
|
{
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
#ifdef CONFIG_DMI
|
|
static int dmi_osi_linux(struct dmi_system_id *d)
|
|
{
|
|
printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
|
|
enable_osi_linux(1);
|
|
return 0;
|
|
}
|
|
|
|
static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
|
|
/*
|
|
* Boxes that need _OSI(Linux)
|
|
*/
|
|
{
|
|
.callback = dmi_osi_linux,
|
|
.ident = "Intel Napa CRB",
|
|
.matches = {
|
|
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
|
|
DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
|
|
},
|
|
},
|
|
{}
|
|
};
|
|
#endif /* CONFIG_DMI */
|
|
|
|
#endif
|