# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/11/05 17:39:51-05:00 len.brown@intel.com 
#   [ACPI] Allow limiting idle C-States.
#   
#   Useful to workaround C3 ipw2100 packet loss
#   and resonating noises heard on some laptops.
#   
#   For static processor driver, boot cmdline:
#   processor.acpi_cstate_limit=2
#   
#   For processor module, /etc/modprobe.conf:
#   options processor acpi_cstate_limit=2
#   
#   For manual processor module load:
#   # modprobe processor acpi_cstate_limit=2
#   
#   From kernel or kernel module:
#   #include <linux/acpi.h>
#   acpi_set_cstate_limit(2);
#   
#   Inspired by patches from Jos Delbar and Andi Kleen
#   Signed-off-by: Len Brown <len.brown@intel.com>
# 
# include/linux/acpi.h
#   2004/11/05 17:39:45-05:00 len.brown@intel.com +26 -0
#   define API to set and get acpi_cstate_limit
# 
# drivers/acpi/processor.c
#   2004/11/05 17:39:45-05:00 len.brown@intel.com +10 -1
#   set and obey acpi_cstate_limit
# 
# drivers/acpi/osl.c
#   2004/11/05 17:39:45-05:00 len.brown@intel.com +9 -0
#   define acpi_cstate_limit
# 
diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c	2004-11-05 17:40:07 -05:00
+++ b/drivers/acpi/osl.c	2004-11-05 17:40:07 -05:00
@@ -1078,3 +1078,12 @@
 
 __setup("acpi_leave_gpes_disabled", acpi_leave_gpes_disabled_setup);
 
+/*
+ * acpi_cstate_limit is defined in the base kernel so modules can
+ * change it w/o depending on the state of the processor module.
+ */
+unsigned int acpi_cstate_limit = ACPI_C_STATES_MAX;
+
+
+EXPORT_SYMBOL(acpi_cstate_limit);
+
diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c
--- a/drivers/acpi/processor.c	2004-11-05 17:40:07 -05:00
+++ b/drivers/acpi/processor.c	2004-11-05 17:40:07 -05:00
@@ -459,8 +459,9 @@
 	 * Track the number of longs (time asleep is greater than threshold)
 	 * and promote when the count threshold is reached.  Note that bus
 	 * mastering activity may prevent promotions.
+	 * Do not promote above acpi_cstate_limit.
 	 */
-	if (cx->promotion.state) {
+	if (cx->promotion.state && (cx->promotion.state <= acpi_cstate_limit)) {
 		if (sleep_ticks > cx->promotion.threshold.ticks) {
 			cx->promotion.count++;
  			cx->demotion.count = 0;
@@ -498,6 +499,13 @@
 
 end:
 	/*
+	 * Demote if current state exceeds acpi_cstate_limit
+	 */
+	if (pr->power.state > acpi_cstate_limit) {
+		next_state = acpi_cstate_limit;
+	}
+
+	/*
 	 * New Cx State?
 	 * -------------
 	 * If we're going to start using a new Cx state we must clean up
@@ -2441,5 +2449,6 @@
 
 module_init(acpi_processor_init);
 module_exit(acpi_processor_exit);
+module_param_named(acpi_cstate_limit, acpi_cstate_limit, uint, 0);
 
 EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h
--- a/include/linux/acpi.h	2004-11-05 17:40:07 -05:00
+++ b/include/linux/acpi.h	2004-11-05 17:40:07 -05:00
@@ -471,4 +471,30 @@
 
 #endif /*!CONFIG_ACPI_INTERPRETER*/
 
+#define	ACPI_CSTATE_LIMIT_DEFINED	/* for driver builds */
+#ifdef	CONFIG_ACPI
+
+/*
+ * Set highest legal C-state
+ * 0: C0 okay, but not C1
+ * 1: C1 okay, but not C2
+ * 2: C2 okay, but not C3 etc.
+ */
+
+extern unsigned int acpi_cstate_limit;
+
+static inline unsigned int acpi_get_cstate_limit(void)
+{
+	return acpi_cstate_limit;
+}
+static inline void acpi_set_cstate_limit(unsigned int new_limit)
+{
+	acpi_cstate_limit = new_limit;
+	return;
+}
+#else
+static inline unsigned int acpi_get_cstate_limit(void) { return 0; }
+static inline void acpi_set_cstate_limit(unsigned int new_limit) { return; }
+#endif
+
 #endif /*_LINUX_ACPI_H*/
