Add patch accepted for 2.6.28-rc7
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / releases / upstream / 2.6.28-rc7 / 0001-ACPI-thinkpad-acpi-fix-fan-sleep-resume-path.patch
blob43f1b1d4cda6c9ae781062361cc86239615626fa
1 From 0081b162023690877e0096ef17a82ba1969befa8 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Sun, 9 Nov 2008 10:54:02 -0200
4 Subject: [PATCH 1/1] ACPI: thinkpad-acpi: fix fan sleep/resume path
6 This fixes a regression from v2.6.27, caused by commit
7 5814f737e1cd2cfa2893badd62189acae3e1e1fd, "ACPI: thinkpad-acpi:
8 attempt to preserve fan state on resume".
10 It is possible for fan_suspend() to fail to properly initialize
11 fan_control_desired_level as required by fan_resume(), resulting on
12 the fan always being set to level 7 on resume if the user didn't
13 touch the fan controller.
15 In order to get fan sleep/resume handling to work right:
17 1. Fix the fan_suspend handling of the T43 firmware quirk. If it is
18 still undefined, we didn't touch the fan yet and that means we have no
19 business doing it on resume.
21 2. Store the fan level on its own variable to avoid any possible
22 issues with hijacking fan_control_desired_level (which isn't supposed
23 to have anything other than 0-7 in it, anyway).
25 3. Change the fan_resume code to me more straightforward to understand
26 (although we DO optimize the boolean logic there, otherwise it looks
27 disgusting).
29 4. Add comments to help understand what the code is supposed to be
30 doing.
32 5. Change fan_set_level to be less strict about how auto and
33 full-speed modes are requested.
35 http://bugzilla.kernel.org/show_bug.cgi?id=11982
37 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
38 Reported-by: Tino Keitel <tino.keitel@tikei.de>
39 Signed-off-by: Len Brown <len.brown@intel.com>
40 ---
41 drivers/misc/thinkpad_acpi.c | 57 +++++++++++++++++++++++++++++++++---------
42 1 files changed, 45 insertions(+), 12 deletions(-)
44 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
45 index 7a4a26b..899766e 100644
46 --- a/drivers/misc/thinkpad_acpi.c
47 +++ b/drivers/misc/thinkpad_acpi.c
48 @@ -5318,6 +5318,7 @@ static enum fan_control_commands fan_control_commands;
50 static u8 fan_control_initial_status;
51 static u8 fan_control_desired_level;
52 +static u8 fan_control_resume_level;
53 static int fan_watchdog_maxinterval;
55 static struct mutex fan_mutex;
56 @@ -5440,8 +5441,8 @@ static int fan_set_level(int level)
58 case TPACPI_FAN_WR_ACPI_FANS:
59 case TPACPI_FAN_WR_TPEC:
60 - if ((level != TP_EC_FAN_AUTO) &&
61 - (level != TP_EC_FAN_FULLSPEED) &&
62 + if (!(level & TP_EC_FAN_AUTO) &&
63 + !(level & TP_EC_FAN_FULLSPEED) &&
64 ((level < 0) || (level > 7)))
65 return -EINVAL;
67 @@ -6005,38 +6006,67 @@ static void fan_exit(void)
69 static void fan_suspend(pm_message_t state)
71 + int rc;
73 if (!fan_control_allowed)
74 return;
76 /* Store fan status in cache */
77 - fan_get_status_safe(NULL);
78 + fan_control_resume_level = 0;
79 + rc = fan_get_status_safe(&fan_control_resume_level);
80 + if (rc < 0)
81 + printk(TPACPI_NOTICE
82 + "failed to read fan level for later "
83 + "restore during resume: %d\n", rc);
85 + /* if it is undefined, don't attempt to restore it.
86 + * KEEP THIS LAST */
87 if (tp_features.fan_ctrl_status_undef)
88 - fan_control_desired_level = TP_EC_FAN_AUTO;
89 + fan_control_resume_level = 0;
92 static void fan_resume(void)
94 - u8 saved_fan_level;
95 u8 current_level = 7;
96 bool do_set = false;
97 + int rc;
99 /* DSDT *always* updates status on resume */
100 tp_features.fan_ctrl_status_undef = 0;
102 - saved_fan_level = fan_control_desired_level;
103 if (!fan_control_allowed ||
104 + !fan_control_resume_level ||
105 (fan_get_status_safe(&current_level) < 0))
106 return;
108 switch (fan_control_access_mode) {
109 case TPACPI_FAN_WR_ACPI_SFAN:
110 - do_set = (saved_fan_level > current_level);
111 + /* never decrease fan level */
112 + do_set = (fan_control_resume_level > current_level);
113 break;
114 case TPACPI_FAN_WR_ACPI_FANS:
115 case TPACPI_FAN_WR_TPEC:
116 - do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) ||
117 - (saved_fan_level == 7 &&
118 - !(current_level & TP_EC_FAN_FULLSPEED)));
119 + /* never decrease fan level, scale is:
120 + * TP_EC_FAN_FULLSPEED > 7 >= TP_EC_FAN_AUTO
122 + * We expect the firmware to set either 7 or AUTO, but we
123 + * handle FULLSPEED out of paranoia.
125 + * So, we can safely only restore FULLSPEED or 7, anything
126 + * else could slow the fan. Restoring AUTO is useless, at
127 + * best that's exactly what the DSDT already set (it is the
128 + * slower it uses).
130 + * Always keep in mind that the DSDT *will* have set the
131 + * fans to what the vendor supposes is the best level. We
132 + * muck with it only to speed the fan up.
133 + */
134 + if (fan_control_resume_level != 7 &&
135 + !(fan_control_resume_level & TP_EC_FAN_FULLSPEED))
136 + return;
137 + else
138 + do_set = !(current_level & TP_EC_FAN_FULLSPEED) &&
139 + (current_level != fan_control_resume_level);
140 break;
141 default:
142 return;
143 @@ -6044,8 +6074,11 @@ static void fan_resume(void)
144 if (do_set) {
145 printk(TPACPI_NOTICE
146 "restoring fan level to 0x%02x\n",
147 - saved_fan_level);
148 - fan_set_level_safe(saved_fan_level);
149 + fan_control_resume_level);
150 + rc = fan_set_level_safe(fan_control_resume_level);
151 + if (rc < 0)
152 + printk(TPACPI_NOTICE
153 + "failed to restore fan level: %d\n", rc);
158 1.5.6.5