diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2008-09-25 13:00:31 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-09-25 16:23:03 -0400 |
commit | 7c6db4e050601f359081fde418ca6dc4fc2d0011 (patch) | |
tree | e7492d3cb6cfb14b52639a01a656c5c73637871c /drivers/acpi | |
parent | 72d31053f62c4bc464c2783974926969614a8649 (diff) |
ACPI: EC: do transaction from interrupt context
It is easier and faster to do transaction directly from interrupt context
rather than waking control thread.
Also, cleaner GPE storm avoidance is implemented.
References: http://bugzilla.kernel.org/show_bug.cgi?id=9998
http://bugzilla.kernel.org/show_bug.cgi?id=10724
http://bugzilla.kernel.org/show_bug.cgi?id=10919
http://bugzilla.kernel.org/show_bug.cgi?id=11309
http://bugzilla.kernel.org/show_bug.cgi?id=11549
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/ec.c | 309 |
1 files changed, 149 insertions, 160 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 13593f9f2197..7f0d81c0ec99 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ec.c - ACPI Embedded Controller Driver (v2.0) | 2 | * ec.c - ACPI Embedded Controller Driver (v2.1) |
3 | * | 3 | * |
4 | * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> | 4 | * Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de> |
5 | * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com> | 5 | * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com> |
6 | * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> | 6 | * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> |
7 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 7 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
@@ -26,7 +26,7 @@ | |||
26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* Uncomment next line to get verbose print outs*/ | 29 | /* Uncomment next line to get verbose printout */ |
30 | /* #define DEBUG */ | 30 | /* #define DEBUG */ |
31 | 31 | ||
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/seq_file.h> | 38 | #include <linux/seq_file.h> |
39 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
41 | #include <linux/spinlock.h> | ||
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
42 | #include <acpi/acpi_bus.h> | 43 | #include <acpi/acpi_bus.h> |
43 | #include <acpi/acpi_drivers.h> | 44 | #include <acpi/acpi_drivers.h> |
@@ -65,22 +66,21 @@ enum ec_command { | |||
65 | ACPI_EC_COMMAND_QUERY = 0x84, | 66 | ACPI_EC_COMMAND_QUERY = 0x84, |
66 | }; | 67 | }; |
67 | 68 | ||
68 | /* EC events */ | ||
69 | enum ec_event { | ||
70 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | ||
71 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ | ||
72 | }; | ||
73 | |||
74 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ | 69 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
75 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 70 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
76 | #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ | 71 | #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ |
77 | 72 | ||
73 | #define ACPI_EC_STORM_THRESHOLD 20 /* number of false interrupts | ||
74 | per one transaction */ | ||
75 | |||
78 | enum { | 76 | enum { |
79 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ | ||
80 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 77 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
81 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ | 78 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent |
79 | * for status change */ | ||
82 | EC_FLAGS_NO_GPE, /* Don't use GPE mode */ | 80 | EC_FLAGS_NO_GPE, /* Don't use GPE mode */ |
83 | EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ | 81 | EC_FLAGS_GPE_STORM, /* GPE storm detected */ |
82 | EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and | ||
83 | * OpReg are installed */ | ||
84 | }; | 84 | }; |
85 | 85 | ||
86 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ | 86 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
@@ -95,6 +95,14 @@ struct acpi_ec_query_handler { | |||
95 | u8 query_bit; | 95 | u8 query_bit; |
96 | }; | 96 | }; |
97 | 97 | ||
98 | struct transaction_data { | ||
99 | const u8 *wdata; | ||
100 | u8 *rdata; | ||
101 | unsigned short irq_count; | ||
102 | u8 wlen; | ||
103 | u8 rlen; | ||
104 | }; | ||
105 | |||
98 | static struct acpi_ec { | 106 | static struct acpi_ec { |
99 | acpi_handle handle; | 107 | acpi_handle handle; |
100 | unsigned long gpe; | 108 | unsigned long gpe; |
@@ -105,9 +113,8 @@ static struct acpi_ec { | |||
105 | struct mutex lock; | 113 | struct mutex lock; |
106 | wait_queue_head_t wait; | 114 | wait_queue_head_t wait; |
107 | struct list_head list; | 115 | struct list_head list; |
108 | struct delayed_work work; | 116 | struct transaction_data *t; |
109 | atomic_t irq_count; | 117 | spinlock_t t_lock; |
110 | u8 handlers_installed; | ||
111 | } *boot_ec, *first_ec; | 118 | } *boot_ec, *first_ec; |
112 | 119 | ||
113 | /* | 120 | /* |
@@ -150,7 +157,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) | |||
150 | { | 157 | { |
151 | u8 x = inb(ec->data_addr); | 158 | u8 x = inb(ec->data_addr); |
152 | pr_debug(PREFIX "---> data = 0x%2.2x\n", x); | 159 | pr_debug(PREFIX "---> data = 0x%2.2x\n", x); |
153 | return inb(ec->data_addr); | 160 | return x; |
154 | } | 161 | } |
155 | 162 | ||
156 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) | 163 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) |
@@ -165,68 +172,79 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
165 | outb(data, ec->data_addr); | 172 | outb(data, ec->data_addr); |
166 | } | 173 | } |
167 | 174 | ||
168 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) | 175 | static int ec_transaction_done(struct acpi_ec *ec) |
169 | { | 176 | { |
170 | if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) | 177 | unsigned long flags; |
171 | return 0; | 178 | int ret = 0; |
172 | if (event == ACPI_EC_EVENT_OBF_1) { | 179 | spin_lock_irqsave(&ec->t_lock, flags); |
173 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) | 180 | if (!ec->t || (!ec->t->wlen && !ec->t->rlen)) |
174 | return 1; | 181 | ret = 1; |
175 | } else if (event == ACPI_EC_EVENT_IBF_0) { | 182 | spin_unlock_irqrestore(&ec->t_lock, flags); |
176 | if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) | 183 | return ret; |
177 | return 1; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | 184 | } |
182 | 185 | ||
183 | static void ec_schedule_ec_poll(struct acpi_ec *ec) | 186 | static void gpe_transaction(struct acpi_ec *ec, u8 status) |
184 | { | 187 | { |
185 | if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) | 188 | unsigned long flags; |
186 | schedule_delayed_work(&ec->work, | 189 | spin_lock_irqsave(&ec->t_lock, flags); |
187 | msecs_to_jiffies(ACPI_EC_DELAY)); | 190 | if (!ec->t) |
191 | goto unlock; | ||
192 | if (ec->t->wlen > 0) { | ||
193 | if ((status & ACPI_EC_FLAG_IBF) == 0) { | ||
194 | acpi_ec_write_data(ec, *(ec->t->wdata++)); | ||
195 | --ec->t->wlen; | ||
196 | } else | ||
197 | /* false interrupt, state didn't change */ | ||
198 | ++ec->t->irq_count; | ||
199 | |||
200 | } else if (ec->t->rlen > 0) { | ||
201 | if ((status & ACPI_EC_FLAG_OBF) == 1) { | ||
202 | *(ec->t->rdata++) = acpi_ec_read_data(ec); | ||
203 | --ec->t->rlen; | ||
204 | } else | ||
205 | /* false interrupt, state didn't change */ | ||
206 | ++ec->t->irq_count; | ||
207 | } | ||
208 | unlock: | ||
209 | spin_unlock_irqrestore(&ec->t_lock, flags); | ||
188 | } | 210 | } |
189 | 211 | ||
190 | static void ec_switch_to_poll_mode(struct acpi_ec *ec) | 212 | static int acpi_ec_wait(struct acpi_ec *ec) |
191 | { | 213 | { |
214 | if (wait_event_timeout(ec->wait, ec_transaction_done(ec), | ||
215 | msecs_to_jiffies(ACPI_EC_DELAY))) | ||
216 | return 0; | ||
217 | /* missing GPEs, switch back to poll mode */ | ||
218 | if (printk_ratelimit()) | ||
219 | pr_info(PREFIX "missing confirmations, " | ||
220 | "switch off interrupt mode.\n"); | ||
192 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); | 221 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
193 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 222 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
194 | acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 223 | return 1; |
195 | set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | ||
196 | } | 224 | } |
197 | 225 | ||
198 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 226 | static void acpi_ec_gpe_query(void *ec_cxt); |
227 | |||
228 | static int ec_check_sci(struct acpi_ec *ec, u8 state) | ||
199 | { | 229 | { |
200 | atomic_set(&ec->irq_count, 0); | 230 | if (state & ACPI_EC_FLAG_SCI) { |
201 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && | 231 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
202 | likely(!force_poll)) { | 232 | return acpi_os_execute(OSL_EC_BURST_HANDLER, |
203 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | 233 | acpi_ec_gpe_query, ec); |
204 | msecs_to_jiffies(ACPI_EC_DELAY))) | 234 | } |
205 | return 0; | 235 | return 0; |
206 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 236 | } |
207 | if (acpi_ec_check_status(ec, event)) { | 237 | |
208 | /* missing GPEs, switch back to poll mode */ | 238 | static int ec_poll(struct acpi_ec *ec) |
209 | if (printk_ratelimit()) | 239 | { |
210 | pr_info(PREFIX "missing confirmations, " | 240 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
211 | "switch off interrupt mode.\n"); | 241 | msleep(1); |
212 | ec_switch_to_poll_mode(ec); | 242 | while (time_before(jiffies, delay)) { |
213 | ec_schedule_ec_poll(ec); | 243 | gpe_transaction(ec, acpi_ec_read_status(ec)); |
214 | return 0; | 244 | msleep(1); |
215 | } | 245 | if (ec_transaction_done(ec)) |
216 | } else { | ||
217 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | ||
218 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
219 | while (time_before(jiffies, delay)) { | ||
220 | if (acpi_ec_check_status(ec, event)) | ||
221 | return 0; | ||
222 | msleep(1); | ||
223 | } | ||
224 | if (acpi_ec_check_status(ec,event)) | ||
225 | return 0; | 246 | return 0; |
226 | } | 247 | } |
227 | pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", | ||
228 | acpi_ec_read_status(ec), | ||
229 | (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\""); | ||
230 | return -ETIME; | 248 | return -ETIME; |
231 | } | 249 | } |
232 | 250 | ||
@@ -235,45 +253,51 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | |||
235 | u8 * rdata, unsigned rdata_len, | 253 | u8 * rdata, unsigned rdata_len, |
236 | int force_poll) | 254 | int force_poll) |
237 | { | 255 | { |
238 | int result = 0; | 256 | unsigned long tmp; |
239 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 257 | struct transaction_data t = {.wdata = wdata, .rdata = rdata, |
258 | .wlen = wdata_len, .rlen = rdata_len, | ||
259 | .irq_count = 0}; | ||
260 | int ret = 0; | ||
240 | pr_debug(PREFIX "transaction start\n"); | 261 | pr_debug(PREFIX "transaction start\n"); |
241 | acpi_ec_write_cmd(ec, command); | 262 | /* disable GPE during transaction if storm is detected */ |
242 | for (; wdata_len > 0; --wdata_len) { | 263 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
243 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); | 264 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
244 | if (result) { | 265 | acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
245 | pr_err(PREFIX | ||
246 | "write_cmd timeout, command = %d\n", command); | ||
247 | goto end; | ||
248 | } | ||
249 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
250 | acpi_ec_write_data(ec, *(wdata++)); | ||
251 | } | 266 | } |
252 | 267 | /* start transaction */ | |
253 | if (!rdata_len) { | 268 | spin_lock_irqsave(&ec->t_lock, tmp); |
254 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); | 269 | /* following two actions should be kept atomic */ |
255 | if (result) { | 270 | ec->t = &t; |
256 | pr_err(PREFIX | 271 | acpi_ec_write_cmd(ec, command); |
257 | "finish-write timeout, command = %d\n", command); | 272 | if (command == ACPI_EC_COMMAND_QUERY) |
258 | goto end; | ||
259 | } | ||
260 | } else if (command == ACPI_EC_COMMAND_QUERY) | ||
261 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 273 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
262 | 274 | spin_unlock_irqrestore(&ec->t_lock, tmp); | |
263 | for (; rdata_len > 0; --rdata_len) { | 275 | /* if we selected poll mode or failed in GPE-mode do a poll loop */ |
264 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); | 276 | if (force_poll || |
265 | if (result) { | 277 | !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || |
266 | pr_err(PREFIX "read timeout, command = %d\n", command); | 278 | acpi_ec_wait(ec)) |
267 | goto end; | 279 | ret = ec_poll(ec); |
268 | } | ||
269 | /* Don't expect GPE after last read */ | ||
270 | if (rdata_len > 1) | ||
271 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
272 | *(rdata++) = acpi_ec_read_data(ec); | ||
273 | } | ||
274 | end: | ||
275 | pr_debug(PREFIX "transaction end\n"); | 280 | pr_debug(PREFIX "transaction end\n"); |
276 | return result; | 281 | spin_lock_irqsave(&ec->t_lock, tmp); |
282 | ec->t = NULL; | ||
283 | spin_unlock_irqrestore(&ec->t_lock, tmp); | ||
284 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | ||
285 | /* check if we received SCI during transaction */ | ||
286 | ec_check_sci(ec, acpi_ec_read_status(ec)); | ||
287 | /* it is safe to enable GPE outside of transaction */ | ||
288 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | ||
289 | } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && | ||
290 | t.irq_count > ACPI_EC_STORM_THRESHOLD) { | ||
291 | pr_debug(PREFIX "GPE storm detected\n"); | ||
292 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | ||
293 | } | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static int ec_check_ibf0(struct acpi_ec *ec) | ||
298 | { | ||
299 | u8 status = acpi_ec_read_status(ec); | ||
300 | return (status & ACPI_EC_FLAG_IBF) == 0; | ||
277 | } | 301 | } |
278 | 302 | ||
279 | static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | 303 | static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, |
@@ -283,40 +307,34 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
283 | { | 307 | { |
284 | int status; | 308 | int status; |
285 | u32 glk; | 309 | u32 glk; |
286 | |||
287 | if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) | 310 | if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) |
288 | return -EINVAL; | 311 | return -EINVAL; |
289 | |||
290 | if (rdata) | 312 | if (rdata) |
291 | memset(rdata, 0, rdata_len); | 313 | memset(rdata, 0, rdata_len); |
292 | |||
293 | mutex_lock(&ec->lock); | 314 | mutex_lock(&ec->lock); |
294 | if (ec->global_lock) { | 315 | if (ec->global_lock) { |
295 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 316 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
296 | if (ACPI_FAILURE(status)) { | 317 | if (ACPI_FAILURE(status)) { |
297 | mutex_unlock(&ec->lock); | 318 | status = -ENODEV; |
298 | return -ENODEV; | 319 | goto unlock; |
299 | } | 320 | } |
300 | } | 321 | } |
301 | 322 | if (!wait_event_timeout(ec->wait, ec_check_ibf0(ec), | |
302 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); | 323 | msecs_to_jiffies(ACPI_EC_DELAY))) { |
303 | if (status) { | ||
304 | pr_err(PREFIX "input buffer is not empty, " | 324 | pr_err(PREFIX "input buffer is not empty, " |
305 | "aborting transaction\n"); | 325 | "aborting transaction\n"); |
326 | status = -ETIME; | ||
306 | goto end; | 327 | goto end; |
307 | } | 328 | } |
308 | |||
309 | status = acpi_ec_transaction_unlocked(ec, command, | 329 | status = acpi_ec_transaction_unlocked(ec, command, |
310 | wdata, wdata_len, | 330 | wdata, wdata_len, |
311 | rdata, rdata_len, | 331 | rdata, rdata_len, |
312 | force_poll); | 332 | force_poll); |
313 | 333 | end: | |
314 | end: | ||
315 | |||
316 | if (ec->global_lock) | 334 | if (ec->global_lock) |
317 | acpi_release_global_lock(glk); | 335 | acpi_release_global_lock(glk); |
336 | unlock: | ||
318 | mutex_unlock(&ec->lock); | 337 | mutex_unlock(&ec->lock); |
319 | |||
320 | return status; | 338 | return status; |
321 | } | 339 | } |
322 | 340 | ||
@@ -332,7 +350,9 @@ int acpi_ec_burst_enable(struct acpi_ec *ec) | |||
332 | 350 | ||
333 | int acpi_ec_burst_disable(struct acpi_ec *ec) | 351 | int acpi_ec_burst_disable(struct acpi_ec *ec) |
334 | { | 352 | { |
335 | return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); | 353 | return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? |
354 | acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, | ||
355 | NULL, 0, NULL, 0, 0) : 0; | ||
336 | } | 356 | } |
337 | 357 | ||
338 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) | 358 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) |
@@ -513,46 +533,26 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
513 | 533 | ||
514 | static u32 acpi_ec_gpe_handler(void *data) | 534 | static u32 acpi_ec_gpe_handler(void *data) |
515 | { | 535 | { |
516 | acpi_status status = AE_OK; | ||
517 | struct acpi_ec *ec = data; | 536 | struct acpi_ec *ec = data; |
518 | u8 state = acpi_ec_read_status(ec); | 537 | u8 status; |
519 | 538 | ||
520 | pr_debug(PREFIX "~~~> interrupt\n"); | 539 | pr_debug(PREFIX "~~~> interrupt\n"); |
521 | atomic_inc(&ec->irq_count); | 540 | status = acpi_ec_read_status(ec); |
522 | if (atomic_read(&ec->irq_count) > 5) { | 541 | |
523 | pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); | 542 | gpe_transaction(ec, status); |
524 | ec_switch_to_poll_mode(ec); | 543 | if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) |
525 | goto end; | ||
526 | } | ||
527 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
528 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) | ||
529 | wake_up(&ec->wait); | 544 | wake_up(&ec->wait); |
530 | 545 | ||
531 | if (state & ACPI_EC_FLAG_SCI) { | 546 | ec_check_sci(ec, status); |
532 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) | 547 | if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
533 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, | 548 | !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { |
534 | acpi_ec_gpe_query, ec); | ||
535 | } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && | ||
536 | !test_bit(EC_FLAGS_NO_GPE, &ec->flags) && | ||
537 | in_interrupt()) { | ||
538 | /* this is non-query, must be confirmation */ | 549 | /* this is non-query, must be confirmation */ |
539 | if (printk_ratelimit()) | 550 | if (printk_ratelimit()) |
540 | pr_info(PREFIX "non-query interrupt received," | 551 | pr_info(PREFIX "non-query interrupt received," |
541 | " switching to interrupt mode\n"); | 552 | " switching to interrupt mode\n"); |
542 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 553 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
543 | clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | ||
544 | } | 554 | } |
545 | end: | 555 | return ACPI_INTERRUPT_HANDLED; |
546 | ec_schedule_ec_poll(ec); | ||
547 | return ACPI_SUCCESS(status) ? | ||
548 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | ||
549 | } | ||
550 | |||
551 | static void do_ec_poll(struct work_struct *work) | ||
552 | { | ||
553 | struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); | ||
554 | atomic_set(&ec->irq_count, 0); | ||
555 | (void)acpi_ec_gpe_handler(ec); | ||
556 | } | 556 | } |
557 | 557 | ||
558 | /* -------------------------------------------------------------------------- | 558 | /* -------------------------------------------------------------------------- |
@@ -696,8 +696,7 @@ static struct acpi_ec *make_acpi_ec(void) | |||
696 | mutex_init(&ec->lock); | 696 | mutex_init(&ec->lock); |
697 | init_waitqueue_head(&ec->wait); | 697 | init_waitqueue_head(&ec->wait); |
698 | INIT_LIST_HEAD(&ec->list); | 698 | INIT_LIST_HEAD(&ec->list); |
699 | INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); | 699 | spin_lock_init(&ec->t_lock); |
700 | atomic_set(&ec->irq_count, 0); | ||
701 | return ec; | 700 | return ec; |
702 | } | 701 | } |
703 | 702 | ||
@@ -736,22 +735,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
736 | return AE_CTRL_TERMINATE; | 735 | return AE_CTRL_TERMINATE; |
737 | } | 736 | } |
738 | 737 | ||
739 | static void ec_poll_stop(struct acpi_ec *ec) | ||
740 | { | ||
741 | clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | ||
742 | cancel_delayed_work(&ec->work); | ||
743 | } | ||
744 | |||
745 | static void ec_remove_handlers(struct acpi_ec *ec) | 738 | static void ec_remove_handlers(struct acpi_ec *ec) |
746 | { | 739 | { |
747 | ec_poll_stop(ec); | ||
748 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, | 740 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
749 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) | 741 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
750 | pr_err(PREFIX "failed to remove space handler\n"); | 742 | pr_err(PREFIX "failed to remove space handler\n"); |
751 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, | 743 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, |
752 | &acpi_ec_gpe_handler))) | 744 | &acpi_ec_gpe_handler))) |
753 | pr_err(PREFIX "failed to remove gpe handler\n"); | 745 | pr_err(PREFIX "failed to remove gpe handler\n"); |
754 | ec->handlers_installed = 0; | 746 | clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
755 | } | 747 | } |
756 | 748 | ||
757 | static int acpi_ec_add(struct acpi_device *device) | 749 | static int acpi_ec_add(struct acpi_device *device) |
@@ -846,17 +838,15 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) | |||
846 | static int ec_install_handlers(struct acpi_ec *ec) | 838 | static int ec_install_handlers(struct acpi_ec *ec) |
847 | { | 839 | { |
848 | acpi_status status; | 840 | acpi_status status; |
849 | if (ec->handlers_installed) | 841 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
850 | return 0; | 842 | return 0; |
851 | status = acpi_install_gpe_handler(NULL, ec->gpe, | 843 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
852 | ACPI_GPE_EDGE_TRIGGERED, | 844 | ACPI_GPE_EDGE_TRIGGERED, |
853 | &acpi_ec_gpe_handler, ec); | 845 | &acpi_ec_gpe_handler, ec); |
854 | if (ACPI_FAILURE(status)) | 846 | if (ACPI_FAILURE(status)) |
855 | return -ENODEV; | 847 | return -ENODEV; |
856 | |||
857 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); | 848 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
858 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 849 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
859 | |||
860 | status = acpi_install_address_space_handler(ec->handle, | 850 | status = acpi_install_address_space_handler(ec->handle, |
861 | ACPI_ADR_SPACE_EC, | 851 | ACPI_ADR_SPACE_EC, |
862 | &acpi_ec_space_handler, | 852 | &acpi_ec_space_handler, |
@@ -866,7 +856,7 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
866 | return -ENODEV; | 856 | return -ENODEV; |
867 | } | 857 | } |
868 | 858 | ||
869 | ec->handlers_installed = 1; | 859 | set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
870 | return 0; | 860 | return 0; |
871 | } | 861 | } |
872 | 862 | ||
@@ -887,7 +877,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
887 | 877 | ||
888 | /* EC is fully operational, allow queries */ | 878 | /* EC is fully operational, allow queries */ |
889 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 879 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
890 | ec_schedule_ec_poll(ec); | ||
891 | return ret; | 880 | return ret; |
892 | } | 881 | } |
893 | 882 | ||
@@ -906,7 +895,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
906 | 895 | ||
907 | int __init acpi_boot_ec_enable(void) | 896 | int __init acpi_boot_ec_enable(void) |
908 | { | 897 | { |
909 | if (!boot_ec || boot_ec->handlers_installed) | 898 | if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) |
910 | return 0; | 899 | return 0; |
911 | if (!ec_install_handlers(boot_ec)) { | 900 | if (!ec_install_handlers(boot_ec)) { |
912 | first_ec = boot_ec; | 901 | first_ec = boot_ec; |