[ltp] [patch 10/11] ibm-acpi: workaround for EC 0x2f initialization bug

Henrique de Moraes Holschuh linux-thinkpad@linux-thinkpad.org
Mon, 09 Oct 2006 09:41:41 -0300


Some ThinkPad ECs fail to initialize EC register 0x2f both in the EC firmware,
and in the ACPI DSDT.  There are no reports of this happening on old ECs, so we
apply the workaround only on new-style ECs.

The workaround flags the status and level as "unknown" on module load/kernel
boot, until we are certain at least one fan control command was issued.

We don't work around this by initializing the EC fan control in auto mode
because the ACPI DSDT might have set it to level 7 due to a thermal condition,
and we don't want to override that.

We should be setting the workaround flag to "status known" upon resume, as
reports say that a sleep cycle always fixes the fan status.  But since we
don't have suspend/resume handlers in ibm-acpi, we don't (for now, anyway).

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
---
 Documentation/ibm-acpi.txt |    7 +++++++
 drivers/acpi/ibm_acpi.c    |   43 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 39 insertions(+), 11 deletions(-)

Index: 2.6.18/drivers/acpi/ibm_acpi.c
===================================================================
--- 2.6.18.orig/drivers/acpi/ibm_acpi.c	2006-10-06 17:26:27.000000000 -0300
+++ 2.6.18/drivers/acpi/ibm_acpi.c	2006-10-06 17:29:35.000000000 -0300
@@ -1717,6 +1717,7 @@
 static enum fan_status_access_mode fan_status_access_mode;
 static enum fan_control_access_mode fan_control_access_mode;
 static enum fan_control_commands fan_control_commands;
+static int fan_control_status_known;
 
 static int fan_init(void)
 {
@@ -1725,6 +1726,7 @@
 	fan_status_access_mode = IBMACPI_FAN_NONE;
 	fan_control_access_mode = IBMACPI_FAN_WR_NONE;
 	fan_control_commands = 0;
+	fan_control_status_known = 1;
 
 	if (gfan_handle) {
 		/* 570, 600e/x, 770e, 770x */
@@ -1734,6 +1736,11 @@
 		 * ThinkPad ECs supports the fan control register */
 		if (likely(acpi_ec_read(fan_status_offset, &status))) {
 			fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
+
+			/* Some new EC firmwares don't initialize
+			 * the fan status */
+			if (ibm_thinkpad_ec_found)
+				fan_control_status_known = 0;
 		} else {
 			printk(IBM_ERR
 				"ThinkPad ACPI EC access misbehaving, "
@@ -1794,18 +1801,26 @@
 		if (unlikely(!acpi_ec_read(fan_status_offset, &status)))
 			return -EIO;
 
-		len += sprintf(p + len, "status:\t\t%s\n"
-				"level:\t\t",
-				(status != 0) ? "enabled" : "disabled" );
-		if (status & IBMACPI_FAN_EC_DISENGAGED)
-			/* Disengaged mode takes precedence */
-			len += sprintf(p + len, "disengaged\n");
-		else if (status & IBMACPI_FAN_EC_AUTO)
-			len += sprintf(p + len, "auto\n");
-		else
-			len += sprintf(p + len, "%d\n", status);
+		if (fan_control_status_known) {
+			len += sprintf(p + len, "status:\t\t%s\n"
+					"level:\t\t",
+					(status != 0) ? "enabled" : "disabled" );
+			if (status & IBMACPI_FAN_EC_DISENGAGED)
+				/* Disengaged mode takes precedence */
+				len += sprintf(p + len, "disengaged\n");
+			else if (status & IBMACPI_FAN_EC_AUTO)
+				len += sprintf(p + len, "auto\n");
+			else
+				len += sprintf(p + len, "%d\n", status);
+		} else {
+			len += sprintf(p + len, "status:\t\tunknown\n"
+					"level:\t\tunknown\n");
+		}
 
-		if (status & IBMACPI_FAN_EC_DISENGAGED)
+		/* No ThinkPad boots on disengaged mode, assume tachometer
+		 * is online if fan control status is unknown */
+		if ((status & IBMACPI_FAN_EC_DISENGAGED) &&
+		    fan_control_status_known)
 			/* tachometer is offline */
 			len += sprintf(p + len, "speed:\t\tunknown\n");
 		else {
@@ -1881,6 +1896,8 @@
 
 		if (!acpi_ec_write(fan_status_offset, level))
 			*rc = -EIO;
+		else
+			fan_control_status_known = 1;
 		break;
 
 	default:
@@ -1904,6 +1921,8 @@
 	case IBMACPI_FAN_WR_TPEC:
 		if (!acpi_ec_write(fan_status_offset, IBMACPI_FAN_EC_AUTO))
 			*rc = -EIO;
+		else
+			fan_control_status_known = 1;
 		break;
 
 	case IBMACPI_FAN_WR_ACPI_SFAN:
@@ -1930,6 +1949,8 @@
 	case IBMACPI_FAN_WR_TPEC:
 		if (!acpi_ec_write(fan_status_offset, 0x00))
 			*rc = -EIO;
+		else
+			fan_control_status_known = 1;
 		break;
 
 	case IBMACPI_FAN_WR_ACPI_SFAN:
Index: 2.6.18/Documentation/ibm-acpi.txt
===================================================================
--- 2.6.18.orig/Documentation/ibm-acpi.txt	2006-10-06 17:30:17.000000000 -0300
+++ 2.6.18/Documentation/ibm-acpi.txt	2006-10-06 17:40:26.000000000 -0300
@@ -671,6 +671,13 @@
 certain conditions are met.  It will override any fan programming done
 through ibm-acpi.
 
+Some ThinkPads have a bug where it is impossible to trust the validity
+of the operating fan level until it is set at least once.  For this
+reason, the fan status and level may show up as "unknown" when
+ibm-acpi is started (either by the kernel boot, or by being loaded as
+a module).  They will remain in "unknown" state until ibm-acpi is used
+to either program a new fan level, enable it, or disable it.
+
 
 Multiple Commands, Module Parameters
 ------------------------------------

--
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh