| From 25f2bd7f5add608c1d1405938f39c96927b275ca Mon Sep 17 00:00:00 2001 |
| From: Henrik Rydberg <rydberg@euromail.se> |
| Date: Wed, 2 Oct 2013 19:15:03 +0200 |
| Subject: hwmon: (applesmc) Always read until end of data |
| |
| From: Henrik Rydberg <rydberg@euromail.se> |
| |
| commit 25f2bd7f5add608c1d1405938f39c96927b275ca upstream. |
| |
| The crash reported and investigated in commit 5f4513 turned out to be |
| caused by a change to the read interface on newer (2012) SMCs. |
| |
| Tests by Chris show that simply reading the data valid line is enough |
| for the problem to go away. Additional tests show that the newer SMCs |
| no longer wait for the number of requested bytes, but start sending |
| data right away. Apparently the number of bytes to read is no longer |
| specified as before, but instead found out by reading until end of |
| data. Failure to read until end of data confuses the state machine, |
| which eventually causes the crash. |
| |
| As a remedy, assuming bit0 is the read valid line, make sure there is |
| nothing more to read before leaving the read function. |
| |
| Tested to resolve the original problem, and runtested on MBA3,1, |
| MBP4,1, MBP8,2, MBP10,1, MBP10,2. The patch seems to have no effect on |
| machines before 2012. |
| |
| Tested-by: Chris Murphy <chris@cmurf.com> |
| Signed-off-by: Henrik Rydberg <rydberg@euromail.se> |
| Signed-off-by: Guenter Roeck <linux@roeck-us.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/hwmon/applesmc.c | 13 +++++++++++++ |
| 1 file changed, 13 insertions(+) |
| |
| --- a/drivers/hwmon/applesmc.c |
| +++ b/drivers/hwmon/applesmc.c |
| @@ -230,6 +230,7 @@ static int send_argument(const char *key |
| |
| static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len) |
| { |
| + u8 status, data = 0; |
| int i; |
| |
| if (send_command(cmd) || send_argument(key)) { |
| @@ -237,6 +238,7 @@ static int read_smc(u8 cmd, const char * |
| return -EIO; |
| } |
| |
| + /* This has no effect on newer (2012) SMCs */ |
| if (send_byte(len, APPLESMC_DATA_PORT)) { |
| pr_warn("%.4s: read len fail\n", key); |
| return -EIO; |
| @@ -250,6 +252,17 @@ static int read_smc(u8 cmd, const char * |
| buffer[i] = inb(APPLESMC_DATA_PORT); |
| } |
| |
| + /* Read the data port until bit0 is cleared */ |
| + for (i = 0; i < 16; i++) { |
| + udelay(APPLESMC_MIN_WAIT); |
| + status = inb(APPLESMC_CMD_PORT); |
| + if (!(status & 0x01)) |
| + break; |
| + data = inb(APPLESMC_DATA_PORT); |
| + } |
| + if (i) |
| + pr_warn("flushed %d bytes, last value is: %d\n", i, data); |
| + |
| return 0; |
| } |
| |