aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2012-07-27 14:12:46 -0400
committerGuenter Roeck <linux@roeck-us.net>2012-07-27 17:00:12 -0400
commit829917cd7246204d6c5f066c40b66d2b62d0930d (patch)
treeeb63dc0146157820aa1ad674e3a50001b7ed2d2a /drivers/hwmon
parent5953e2761be088f66fd930dfbf6b36a5a41d82a3 (diff)
hwmon: (applesmc) Decode and act on read/write status codes
The behavior of the SMC has changed several times over the years, causing read failures in the driver. It seems the problem can be explained by a shift in SMC speed combined with improper action on status codes. We should first wait for the SMC to settle, which was the most frequent response on the old slow machines. Then, if the SMC is busy, we need to try again later by resending the command. This was the most likely response until 2012. Now, with a shorter wait time, we are again most likely to poll while the SMC is settling, and as a result we see high failure rates on many old and new models. With the distinction between busy and failure, we can also wait longer before retrying, without sacrificing speed. This seems to bring failures down to virtually zero on all models. Tested on: MBA1,1 MBA3,1 MBA5,1 MBA5,2 MBP9,2 Tested-by: Adam Somerville <adamsomerville@gmail.com> Tested-by: Hubert Eichner <hubert.georg.eichner@gmail.com> Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/applesmc.c70
1 files changed, 46 insertions, 24 deletions
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 4d937a18fadb..282708860517 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -55,9 +55,9 @@
55 55
56/* wait up to 32 ms for a status change. */ 56/* wait up to 32 ms for a status change. */
57#define APPLESMC_MIN_WAIT 0x0010 57#define APPLESMC_MIN_WAIT 0x0010
58#define APPLESMC_RETRY_WAIT 0x0100
58#define APPLESMC_MAX_WAIT 0x8000 59#define APPLESMC_MAX_WAIT 0x8000
59 60
60#define APPLESMC_STATUS_MASK 0x0f
61#define APPLESMC_READ_CMD 0x10 61#define APPLESMC_READ_CMD 0x10
62#define APPLESMC_WRITE_CMD 0x11 62#define APPLESMC_WRITE_CMD 0x11
63#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 63#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
@@ -162,51 +162,68 @@ static unsigned int key_at_index;
162static struct workqueue_struct *applesmc_led_wq; 162static struct workqueue_struct *applesmc_led_wq;
163 163
164/* 164/*
165 * __wait_status - Wait up to 32ms for the status port to get a certain value 165 * wait_read - Wait for a byte to appear on SMC port. Callers must
166 * (masked with 0x0f), returning zero if the value is obtained. Callers must
167 * hold applesmc_lock. 166 * hold applesmc_lock.
168 */ 167 */
169static int __wait_status(u8 val) 168static int wait_read(void)
170{ 169{
170 u8 status;
171 int us; 171 int us;
172
173 val = val & APPLESMC_STATUS_MASK;
174
175 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { 172 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
176 udelay(us); 173 udelay(us);
177 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) 174 status = inb(APPLESMC_CMD_PORT);
175 /* read: wait for smc to settle */
176 if (status & 0x01)
178 return 0; 177 return 0;
179 } 178 }
180 179
180 pr_warn("wait_read() fail: 0x%02x\n", status);
181 return -EIO; 181 return -EIO;
182} 182}
183 183
184/* 184/*
185 * special treatment of command port - on newer macbooks, it seems necessary 185 * send_byte - Write to SMC port, retrying when necessary. Callers
186 * to resend the command byte before polling the status again. Callers must 186 * must hold applesmc_lock.
187 * hold applesmc_lock.
188 */ 187 */
189static int send_command(u8 cmd) 188static int send_byte(u8 cmd, u16 port)
190{ 189{
190 u8 status;
191 int us; 191 int us;
192
193 outb(cmd, port);
192 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { 194 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
193 outb(cmd, APPLESMC_CMD_PORT);
194 udelay(us); 195 udelay(us);
195 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) 196 status = inb(APPLESMC_CMD_PORT);
197 /* write: wait for smc to settle */
198 if (status & 0x02)
199 continue;
200 /* ready: cmd accepted, return */
201 if (status & 0x04)
196 return 0; 202 return 0;
203 /* timeout: give up */
204 if (us << 1 == APPLESMC_MAX_WAIT)
205 break;
206 /* busy: long wait and resend */
207 udelay(APPLESMC_RETRY_WAIT);
208 outb(cmd, port);
197 } 209 }
210
211 pr_warn("send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status);
198 return -EIO; 212 return -EIO;
199} 213}
200 214
215static int send_command(u8 cmd)
216{
217 return send_byte(cmd, APPLESMC_CMD_PORT);
218}
219
201static int send_argument(const char *key) 220static int send_argument(const char *key)
202{ 221{
203 int i; 222 int i;
204 223
205 for (i = 0; i < 4; i++) { 224 for (i = 0; i < 4; i++)
206 outb(key[i], APPLESMC_DATA_PORT); 225 if (send_byte(key[i], APPLESMC_DATA_PORT))
207 if (__wait_status(0x04))
208 return -EIO; 226 return -EIO;
209 }
210 return 0; 227 return 0;
211} 228}
212 229
@@ -219,11 +236,14 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
219 return -EIO; 236 return -EIO;
220 } 237 }
221 238
222 outb(len, APPLESMC_DATA_PORT); 239 if (send_byte(len, APPLESMC_DATA_PORT)) {
240 pr_warn("%.4s: read len fail\n", key);
241 return -EIO;
242 }
223 243
224 for (i = 0; i < len; i++) { 244 for (i = 0; i < len; i++) {
225 if (__wait_status(0x05)) { 245 if (wait_read()) {
226 pr_warn("%.4s: read data fail\n", key); 246 pr_warn("%.4s: read data[%d] fail\n", key, i);
227 return -EIO; 247 return -EIO;
228 } 248 }
229 buffer[i] = inb(APPLESMC_DATA_PORT); 249 buffer[i] = inb(APPLESMC_DATA_PORT);
@@ -241,14 +261,16 @@ static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
241 return -EIO; 261 return -EIO;
242 } 262 }
243 263
244 outb(len, APPLESMC_DATA_PORT); 264 if (send_byte(len, APPLESMC_DATA_PORT)) {
265 pr_warn("%.4s: write len fail\n", key);
266 return -EIO;
267 }
245 268
246 for (i = 0; i < len; i++) { 269 for (i = 0; i < len; i++) {
247 if (__wait_status(0x04)) { 270 if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
248 pr_warn("%s: write data fail\n", key); 271 pr_warn("%s: write data fail\n", key);
249 return -EIO; 272 return -EIO;
250 } 273 }
251 outb(buffer[i], APPLESMC_DATA_PORT);
252 } 274 }
253 275
254 return 0; 276 return 0;