diff options
author | Henrik Rydberg <rydberg@euromail.se> | 2008-10-18 23:27:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 11:52:35 -0400 |
commit | 8c9398d1e9766e3659e277acb2e8ca1c17684139 (patch) | |
tree | 160520c76c2dfbe89398b6c53aa8813e212abed3 | |
parent | 07e8dbd3ebbdedc71335049dd4b0d542cb038d7d (diff) |
hwmon: applesmc: lighter wait mechanism, drastic improvement
The read fail ratio is sensitive to the delay between the first byte
written and the first byte read; apparently the sensors cannot be rushed.
Increasing the minimum wait time, without changing the total wait time,
improves the fail ratio from a 8% chance that any of the sensors fails in
one read, down to 0.4%, on a Macbook Air. On a Macbook Pro 3,1, the
effect is even more apparent. By reducing the number of status polls, the
ratio is further improved to below 0.1%. Finally, increasing the total
wait time brings the fail ratio down to virtually zero.
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Tested-by: Bob McElrath <bob@mcelrath.org>
Cc: Nicolas Boichat <nicolas@boichat.ch>
Cc: "Mark M. Hoffman" <mhoffman@lightlink.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/hwmon/applesmc.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 59266ce60cc2..bc011da79e14 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c | |||
@@ -49,6 +49,9 @@ | |||
49 | 49 | ||
50 | #define APPLESMC_MAX_DATA_LENGTH 32 | 50 | #define APPLESMC_MAX_DATA_LENGTH 32 |
51 | 51 | ||
52 | #define APPLESMC_MIN_WAIT 0x0040 | ||
53 | #define APPLESMC_MAX_WAIT 0x8000 | ||
54 | |||
52 | #define APPLESMC_STATUS_MASK 0x0f | 55 | #define APPLESMC_STATUS_MASK 0x0f |
53 | #define APPLESMC_READ_CMD 0x10 | 56 | #define APPLESMC_READ_CMD 0x10 |
54 | #define APPLESMC_WRITE_CMD 0x11 | 57 | #define APPLESMC_WRITE_CMD 0x11 |
@@ -172,25 +175,25 @@ static unsigned int key_at_index; | |||
172 | static struct workqueue_struct *applesmc_led_wq; | 175 | static struct workqueue_struct *applesmc_led_wq; |
173 | 176 | ||
174 | /* | 177 | /* |
175 | * __wait_status - Wait up to 10ms for the status port to get a certain value | 178 | * __wait_status - Wait up to 32ms for the status port to get a certain value |
176 | * (masked with 0x0f), returning zero if the value is obtained. Callers must | 179 | * (masked with 0x0f), returning zero if the value is obtained. Callers must |
177 | * hold applesmc_lock. | 180 | * hold applesmc_lock. |
178 | */ | 181 | */ |
179 | static int __wait_status(u8 val) | 182 | static int __wait_status(u8 val) |
180 | { | 183 | { |
181 | unsigned int i; | 184 | int us; |
182 | 185 | ||
183 | val = val & APPLESMC_STATUS_MASK; | 186 | val = val & APPLESMC_STATUS_MASK; |
184 | 187 | ||
185 | for (i = 0; i < 1000; i++) { | 188 | for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { |
189 | udelay(us); | ||
186 | if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { | 190 | if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { |
187 | if (debug) | 191 | if (debug) |
188 | printk(KERN_DEBUG | 192 | printk(KERN_DEBUG |
189 | "Waited %d us for status %x\n", | 193 | "Waited %d us for status %x\n", |
190 | i*10, val); | 194 | 2 * us - APPLESMC_MIN_WAIT, val); |
191 | return 0; | 195 | return 0; |
192 | } | 196 | } |
193 | udelay(10); | ||
194 | } | 197 | } |
195 | 198 | ||
196 | printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n", | 199 | printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n", |
@@ -206,13 +209,12 @@ static int __wait_status(u8 val) | |||
206 | */ | 209 | */ |
207 | static int send_command(u8 cmd) | 210 | static int send_command(u8 cmd) |
208 | { | 211 | { |
209 | int i; | 212 | int us; |
210 | for (i = 0; i < 1000; i++) { | 213 | for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { |
211 | outb(cmd, APPLESMC_CMD_PORT); | 214 | outb(cmd, APPLESMC_CMD_PORT); |
212 | udelay(5); | 215 | udelay(us); |
213 | if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) | 216 | if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) |
214 | return 0; | 217 | return 0; |
215 | udelay(5); | ||
216 | } | 218 | } |
217 | printk(KERN_WARNING "applesmc: command failed: %x -> %x\n", | 219 | printk(KERN_WARNING "applesmc: command failed: %x -> %x\n", |
218 | cmd, inb(APPLESMC_CMD_PORT)); | 220 | cmd, inb(APPLESMC_CMD_PORT)); |