diff options
author | Len Brown <len.brown@intel.com> | 2008-10-22 23:27:59 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-10-22 23:27:59 -0400 |
commit | 0fbb3726f246aadd1bebc01114100b6e69afa5b9 (patch) | |
tree | 87e0ca2d5904df9e12e8b7b1d2b303b17758c70a | |
parent | 47bf31adc541bef0c20de15e800e0011f1ae70c7 (diff) | |
parent | c0ff17720ec5f42205b3d2ca03a18da0a8272976 (diff) |
Merge branch 'ec' into test
-rw-r--r-- | drivers/acpi/bus.c | 6 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 374 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 4 | ||||
-rw-r--r-- | include/acpi/acpi_drivers.h | 1 |
4 files changed, 198 insertions, 187 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e6311f432edf..b11400e2f856 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -793,6 +793,12 @@ static int __init acpi_bus_init(void) | |||
793 | goto error1; | 793 | goto error1; |
794 | } | 794 | } |
795 | 795 | ||
796 | /* | ||
797 | * Maybe EC region is required at bus_scan/acpi_get_devices. So it | ||
798 | * is necessary to enable it as early as possible. | ||
799 | */ | ||
800 | acpi_boot_ec_enable(); | ||
801 | |||
796 | printk(KERN_INFO PREFIX "Interpreter enabled\n"); | 802 | printk(KERN_INFO PREFIX "Interpreter enabled\n"); |
797 | 803 | ||
798 | /* Initialize sleep structures */ | 804 | /* Initialize sleep structures */ |
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 4c004286b3d9..4178d17aa0ed 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,15 @@ struct acpi_ec_query_handler { | |||
95 | u8 query_bit; | 95 | u8 query_bit; |
96 | }; | 96 | }; |
97 | 97 | ||
98 | struct transaction { | ||
99 | const u8 *wdata; | ||
100 | u8 *rdata; | ||
101 | unsigned short irq_count; | ||
102 | u8 command; | ||
103 | u8 wlen; | ||
104 | u8 rlen; | ||
105 | }; | ||
106 | |||
98 | static struct acpi_ec { | 107 | static struct acpi_ec { |
99 | acpi_handle handle; | 108 | acpi_handle handle; |
100 | unsigned long gpe; | 109 | unsigned long gpe; |
@@ -105,9 +114,8 @@ static struct acpi_ec { | |||
105 | struct mutex lock; | 114 | struct mutex lock; |
106 | wait_queue_head_t wait; | 115 | wait_queue_head_t wait; |
107 | struct list_head list; | 116 | struct list_head list; |
108 | struct delayed_work work; | 117 | struct transaction *curr; |
109 | atomic_t irq_count; | 118 | spinlock_t curr_lock; |
110 | u8 handlers_installed; | ||
111 | } *boot_ec, *first_ec; | 119 | } *boot_ec, *first_ec; |
112 | 120 | ||
113 | /* | 121 | /* |
@@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) | |||
150 | { | 158 | { |
151 | u8 x = inb(ec->data_addr); | 159 | u8 x = inb(ec->data_addr); |
152 | pr_debug(PREFIX "---> data = 0x%2.2x\n", x); | 160 | pr_debug(PREFIX "---> data = 0x%2.2x\n", x); |
153 | return inb(ec->data_addr); | 161 | return x; |
154 | } | 162 | } |
155 | 163 | ||
156 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) | 164 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) |
@@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
165 | outb(data, ec->data_addr); | 173 | outb(data, ec->data_addr); |
166 | } | 174 | } |
167 | 175 | ||
168 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) | 176 | static int ec_transaction_done(struct acpi_ec *ec) |
169 | { | 177 | { |
170 | if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) | 178 | unsigned long flags; |
171 | return 0; | 179 | int ret = 0; |
172 | if (event == ACPI_EC_EVENT_OBF_1) { | 180 | spin_lock_irqsave(&ec->curr_lock, flags); |
173 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) | 181 | if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen)) |
174 | return 1; | 182 | ret = 1; |
175 | } else if (event == ACPI_EC_EVENT_IBF_0) { | 183 | spin_unlock_irqrestore(&ec->curr_lock, flags); |
176 | if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) | 184 | return ret; |
177 | return 1; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | 185 | } |
182 | 186 | ||
183 | static void ec_schedule_ec_poll(struct acpi_ec *ec) | 187 | static void gpe_transaction(struct acpi_ec *ec, u8 status) |
184 | { | 188 | { |
185 | if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) | 189 | unsigned long flags; |
186 | schedule_delayed_work(&ec->work, | 190 | spin_lock_irqsave(&ec->curr_lock, flags); |
187 | msecs_to_jiffies(ACPI_EC_DELAY)); | 191 | if (!ec->curr) |
192 | goto unlock; | ||
193 | if (ec->curr->wlen > 0) { | ||
194 | if ((status & ACPI_EC_FLAG_IBF) == 0) { | ||
195 | acpi_ec_write_data(ec, *(ec->curr->wdata++)); | ||
196 | --ec->curr->wlen; | ||
197 | } else | ||
198 | /* false interrupt, state didn't change */ | ||
199 | ++ec->curr->irq_count; | ||
200 | |||
201 | } else if (ec->curr->rlen > 0) { | ||
202 | if ((status & ACPI_EC_FLAG_OBF) == 1) { | ||
203 | *(ec->curr->rdata++) = acpi_ec_read_data(ec); | ||
204 | --ec->curr->rlen; | ||
205 | } else | ||
206 | /* false interrupt, state didn't change */ | ||
207 | ++ec->curr->irq_count; | ||
208 | } | ||
209 | unlock: | ||
210 | spin_unlock_irqrestore(&ec->curr_lock, flags); | ||
188 | } | 211 | } |
189 | 212 | ||
190 | static void ec_switch_to_poll_mode(struct acpi_ec *ec) | 213 | static int acpi_ec_wait(struct acpi_ec *ec) |
191 | { | 214 | { |
215 | if (wait_event_timeout(ec->wait, ec_transaction_done(ec), | ||
216 | msecs_to_jiffies(ACPI_EC_DELAY))) | ||
217 | return 0; | ||
218 | /* missing GPEs, switch back to poll mode */ | ||
219 | if (printk_ratelimit()) | ||
220 | pr_info(PREFIX "missing confirmations, " | ||
221 | "switch off interrupt mode.\n"); | ||
192 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); | 222 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
193 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 223 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
194 | acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 224 | return 1; |
195 | set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | ||
196 | } | 225 | } |
197 | 226 | ||
198 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 227 | static void acpi_ec_gpe_query(void *ec_cxt); |
228 | |||
229 | static int ec_check_sci(struct acpi_ec *ec, u8 state) | ||
199 | { | 230 | { |
200 | atomic_set(&ec->irq_count, 0); | 231 | if (state & ACPI_EC_FLAG_SCI) { |
201 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && | 232 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
202 | likely(!force_poll)) { | 233 | return acpi_os_execute(OSL_EC_BURST_HANDLER, |
203 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | 234 | acpi_ec_gpe_query, ec); |
204 | msecs_to_jiffies(ACPI_EC_DELAY))) | 235 | } |
205 | return 0; | 236 | return 0; |
206 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 237 | } |
207 | if (acpi_ec_check_status(ec, event)) { | 238 | |
208 | /* missing GPEs, switch back to poll mode */ | 239 | static int ec_poll(struct acpi_ec *ec) |
209 | if (printk_ratelimit()) | 240 | { |
210 | pr_info(PREFIX "missing confirmations, " | 241 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
211 | "switch off interrupt mode.\n"); | 242 | msleep(1); |
212 | ec_switch_to_poll_mode(ec); | 243 | while (time_before(jiffies, delay)) { |
213 | ec_schedule_ec_poll(ec); | 244 | gpe_transaction(ec, acpi_ec_read_status(ec)); |
214 | return 0; | 245 | msleep(1); |
215 | } | 246 | 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; | 247 | return 0; |
226 | } | 248 | } |
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; | 249 | return -ETIME; |
231 | } | 250 | } |
232 | 251 | ||
233 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | 252 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, |
234 | const u8 * wdata, unsigned wdata_len, | 253 | struct transaction *t, |
235 | 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 | int ret = 0; |
240 | pr_debug(PREFIX "transaction start\n"); | 258 | pr_debug(PREFIX "transaction start\n"); |
241 | acpi_ec_write_cmd(ec, command); | 259 | /* disable GPE during transaction if storm is detected */ |
242 | for (; wdata_len > 0; --wdata_len) { | 260 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
243 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); | 261 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
244 | if (result) { | 262 | 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 | } | 263 | } |
252 | 264 | /* start transaction */ | |
253 | if (!rdata_len) { | 265 | spin_lock_irqsave(&ec->curr_lock, tmp); |
254 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); | 266 | /* following two actions should be kept atomic */ |
255 | if (result) { | 267 | t->irq_count = 0; |
256 | pr_err(PREFIX | 268 | ec->curr = t; |
257 | "finish-write timeout, command = %d\n", command); | 269 | acpi_ec_write_cmd(ec, ec->curr->command); |
258 | goto end; | 270 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) |
259 | } | ||
260 | } else if (command == ACPI_EC_COMMAND_QUERY) | ||
261 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 271 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
262 | 272 | spin_unlock_irqrestore(&ec->curr_lock, tmp); | |
263 | for (; rdata_len > 0; --rdata_len) { | 273 | /* 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); | 274 | if (force_poll || |
265 | if (result) { | 275 | !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || |
266 | pr_err(PREFIX "read timeout, command = %d\n", command); | 276 | acpi_ec_wait(ec)) |
267 | goto end; | 277 | 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"); | 278 | pr_debug(PREFIX "transaction end\n"); |
276 | return result; | 279 | spin_lock_irqsave(&ec->curr_lock, tmp); |
280 | ec->curr = NULL; | ||
281 | spin_unlock_irqrestore(&ec->curr_lock, tmp); | ||
282 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | ||
283 | /* check if we received SCI during transaction */ | ||
284 | ec_check_sci(ec, acpi_ec_read_status(ec)); | ||
285 | /* it is safe to enable GPE outside of transaction */ | ||
286 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | ||
287 | } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && | ||
288 | t->irq_count > ACPI_EC_STORM_THRESHOLD) { | ||
289 | pr_debug(PREFIX "GPE storm detected\n"); | ||
290 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | ||
291 | } | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int ec_check_ibf0(struct acpi_ec *ec) | ||
296 | { | ||
297 | u8 status = acpi_ec_read_status(ec); | ||
298 | return (status & ACPI_EC_FLAG_IBF) == 0; | ||
277 | } | 299 | } |
278 | 300 | ||
279 | static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | 301 | static int ec_wait_ibf0(struct acpi_ec *ec) |
280 | const u8 * wdata, unsigned wdata_len, | 302 | { |
281 | u8 * rdata, unsigned rdata_len, | 303 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
304 | /* interrupt wait manually if GPE mode is not active */ | ||
305 | unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ? | ||
306 | msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1); | ||
307 | while (time_before(jiffies, delay)) | ||
308 | if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout)) | ||
309 | return 0; | ||
310 | return -ETIME; | ||
311 | } | ||
312 | |||
313 | static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t, | ||
282 | int force_poll) | 314 | int force_poll) |
283 | { | 315 | { |
284 | int status; | 316 | int status; |
285 | u32 glk; | 317 | u32 glk; |
286 | 318 | if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) | |
287 | if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) | ||
288 | return -EINVAL; | 319 | return -EINVAL; |
289 | 320 | if (t->rdata) | |
290 | if (rdata) | 321 | memset(t->rdata, 0, t->rlen); |
291 | memset(rdata, 0, rdata_len); | ||
292 | |||
293 | mutex_lock(&ec->lock); | 322 | mutex_lock(&ec->lock); |
294 | if (ec->global_lock) { | 323 | if (ec->global_lock) { |
295 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 324 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
296 | if (ACPI_FAILURE(status)) { | 325 | if (ACPI_FAILURE(status)) { |
297 | mutex_unlock(&ec->lock); | 326 | status = -ENODEV; |
298 | return -ENODEV; | 327 | goto unlock; |
299 | } | 328 | } |
300 | } | 329 | } |
301 | 330 | if (ec_wait_ibf0(ec)) { | |
302 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); | ||
303 | if (status) { | ||
304 | pr_err(PREFIX "input buffer is not empty, " | 331 | pr_err(PREFIX "input buffer is not empty, " |
305 | "aborting transaction\n"); | 332 | "aborting transaction\n"); |
333 | status = -ETIME; | ||
306 | goto end; | 334 | goto end; |
307 | } | 335 | } |
308 | 336 | status = acpi_ec_transaction_unlocked(ec, t, force_poll); | |
309 | status = acpi_ec_transaction_unlocked(ec, command, | 337 | end: |
310 | wdata, wdata_len, | ||
311 | rdata, rdata_len, | ||
312 | force_poll); | ||
313 | |||
314 | end: | ||
315 | |||
316 | if (ec->global_lock) | 338 | if (ec->global_lock) |
317 | acpi_release_global_lock(glk); | 339 | acpi_release_global_lock(glk); |
340 | unlock: | ||
318 | mutex_unlock(&ec->lock); | 341 | mutex_unlock(&ec->lock); |
319 | |||
320 | return status; | 342 | return status; |
321 | } | 343 | } |
322 | 344 | ||
@@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
327 | int acpi_ec_burst_enable(struct acpi_ec *ec) | 349 | int acpi_ec_burst_enable(struct acpi_ec *ec) |
328 | { | 350 | { |
329 | u8 d; | 351 | u8 d; |
330 | return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0); | 352 | struct transaction t = {.command = ACPI_EC_BURST_ENABLE, |
353 | .wdata = NULL, .rdata = &d, | ||
354 | .wlen = 0, .rlen = 1}; | ||
355 | |||
356 | return acpi_ec_transaction(ec, &t, 0); | ||
331 | } | 357 | } |
332 | 358 | ||
333 | int acpi_ec_burst_disable(struct acpi_ec *ec) | 359 | int acpi_ec_burst_disable(struct acpi_ec *ec) |
334 | { | 360 | { |
335 | return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); | 361 | struct transaction t = {.command = ACPI_EC_BURST_DISABLE, |
362 | .wdata = NULL, .rdata = NULL, | ||
363 | .wlen = 0, .rlen = 0}; | ||
364 | |||
365 | return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? | ||
366 | acpi_ec_transaction(ec, &t, 0) : 0; | ||
336 | } | 367 | } |
337 | 368 | ||
338 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) | 369 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) |
339 | { | 370 | { |
340 | int result; | 371 | int result; |
341 | u8 d; | 372 | u8 d; |
373 | struct transaction t = {.command = ACPI_EC_COMMAND_READ, | ||
374 | .wdata = &address, .rdata = &d, | ||
375 | .wlen = 1, .rlen = 1}; | ||
342 | 376 | ||
343 | result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, | 377 | result = acpi_ec_transaction(ec, &t, 0); |
344 | &address, 1, &d, 1, 0); | ||
345 | *data = d; | 378 | *data = d; |
346 | return result; | 379 | return result; |
347 | } | 380 | } |
@@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) | |||
349 | static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) | 382 | static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) |
350 | { | 383 | { |
351 | u8 wdata[2] = { address, data }; | 384 | u8 wdata[2] = { address, data }; |
352 | return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, | 385 | struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, |
353 | wdata, 2, NULL, 0, 0); | 386 | .wdata = wdata, .rdata = NULL, |
387 | .wlen = 2, .rlen = 0}; | ||
388 | |||
389 | return acpi_ec_transaction(ec, &t, 0); | ||
354 | } | 390 | } |
355 | 391 | ||
356 | /* | 392 | /* |
@@ -412,12 +448,13 @@ int ec_transaction(u8 command, | |||
412 | u8 * rdata, unsigned rdata_len, | 448 | u8 * rdata, unsigned rdata_len, |
413 | int force_poll) | 449 | int force_poll) |
414 | { | 450 | { |
451 | struct transaction t = {.command = command, | ||
452 | .wdata = wdata, .rdata = rdata, | ||
453 | .wlen = wdata_len, .rlen = rdata_len}; | ||
415 | if (!first_ec) | 454 | if (!first_ec) |
416 | return -ENODEV; | 455 | return -ENODEV; |
417 | 456 | ||
418 | return acpi_ec_transaction(first_ec, command, wdata, | 457 | return acpi_ec_transaction(first_ec, &t, force_poll); |
419 | wdata_len, rdata, rdata_len, | ||
420 | force_poll); | ||
421 | } | 458 | } |
422 | 459 | ||
423 | EXPORT_SYMBOL(ec_transaction); | 460 | EXPORT_SYMBOL(ec_transaction); |
@@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) | |||
426 | { | 463 | { |
427 | int result; | 464 | int result; |
428 | u8 d; | 465 | u8 d; |
429 | 466 | struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, | |
467 | .wdata = NULL, .rdata = &d, | ||
468 | .wlen = 0, .rlen = 1}; | ||
430 | if (!ec || !data) | 469 | if (!ec || !data) |
431 | return -EINVAL; | 470 | return -EINVAL; |
432 | 471 | ||
@@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) | |||
436 | * bit to be cleared (and thus clearing the interrupt source). | 475 | * bit to be cleared (and thus clearing the interrupt source). |
437 | */ | 476 | */ |
438 | 477 | ||
439 | result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); | 478 | result = acpi_ec_transaction(ec, &t, 0); |
440 | if (result) | 479 | if (result) |
441 | return result; | 480 | return result; |
442 | 481 | ||
@@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
513 | 552 | ||
514 | static u32 acpi_ec_gpe_handler(void *data) | 553 | static u32 acpi_ec_gpe_handler(void *data) |
515 | { | 554 | { |
516 | acpi_status status = AE_OK; | ||
517 | struct acpi_ec *ec = data; | 555 | struct acpi_ec *ec = data; |
518 | u8 state = acpi_ec_read_status(ec); | 556 | u8 status; |
519 | 557 | ||
520 | pr_debug(PREFIX "~~~> interrupt\n"); | 558 | pr_debug(PREFIX "~~~> interrupt\n"); |
521 | atomic_inc(&ec->irq_count); | 559 | status = acpi_ec_read_status(ec); |
522 | if (atomic_read(&ec->irq_count) > 5) { | 560 | |
523 | pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); | 561 | gpe_transaction(ec, status); |
524 | ec_switch_to_poll_mode(ec); | 562 | 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); | 563 | wake_up(&ec->wait); |
530 | 564 | ||
531 | if (state & ACPI_EC_FLAG_SCI) { | 565 | ec_check_sci(ec, status); |
532 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) | 566 | if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
533 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, | 567 | !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 */ | 568 | /* this is non-query, must be confirmation */ |
539 | if (printk_ratelimit()) | 569 | if (printk_ratelimit()) |
540 | pr_info(PREFIX "non-query interrupt received," | 570 | pr_info(PREFIX "non-query interrupt received," |
541 | " switching to interrupt mode\n"); | 571 | " switching to interrupt mode\n"); |
542 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 572 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
543 | clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | ||
544 | } | 573 | } |
545 | end: | 574 | 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 | } | 575 | } |
557 | 576 | ||
558 | /* -------------------------------------------------------------------------- | 577 | /* -------------------------------------------------------------------------- |
@@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void) | |||
696 | mutex_init(&ec->lock); | 715 | mutex_init(&ec->lock); |
697 | init_waitqueue_head(&ec->wait); | 716 | init_waitqueue_head(&ec->wait); |
698 | INIT_LIST_HEAD(&ec->list); | 717 | INIT_LIST_HEAD(&ec->list); |
699 | INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); | 718 | spin_lock_init(&ec->curr_lock); |
700 | atomic_set(&ec->irq_count, 0); | ||
701 | return ec; | 719 | return ec; |
702 | } | 720 | } |
703 | 721 | ||
@@ -736,22 +754,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
736 | return AE_CTRL_TERMINATE; | 754 | return AE_CTRL_TERMINATE; |
737 | } | 755 | } |
738 | 756 | ||
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) | 757 | static void ec_remove_handlers(struct acpi_ec *ec) |
746 | { | 758 | { |
747 | ec_poll_stop(ec); | ||
748 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, | 759 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
749 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) | 760 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
750 | pr_err(PREFIX "failed to remove space handler\n"); | 761 | pr_err(PREFIX "failed to remove space handler\n"); |
751 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, | 762 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, |
752 | &acpi_ec_gpe_handler))) | 763 | &acpi_ec_gpe_handler))) |
753 | pr_err(PREFIX "failed to remove gpe handler\n"); | 764 | pr_err(PREFIX "failed to remove gpe handler\n"); |
754 | ec->handlers_installed = 0; | 765 | clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
755 | } | 766 | } |
756 | 767 | ||
757 | static int acpi_ec_add(struct acpi_device *device) | 768 | static int acpi_ec_add(struct acpi_device *device) |
@@ -846,17 +857,15 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) | |||
846 | static int ec_install_handlers(struct acpi_ec *ec) | 857 | static int ec_install_handlers(struct acpi_ec *ec) |
847 | { | 858 | { |
848 | acpi_status status; | 859 | acpi_status status; |
849 | if (ec->handlers_installed) | 860 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
850 | return 0; | 861 | return 0; |
851 | status = acpi_install_gpe_handler(NULL, ec->gpe, | 862 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
852 | ACPI_GPE_EDGE_TRIGGERED, | 863 | ACPI_GPE_EDGE_TRIGGERED, |
853 | &acpi_ec_gpe_handler, ec); | 864 | &acpi_ec_gpe_handler, ec); |
854 | if (ACPI_FAILURE(status)) | 865 | if (ACPI_FAILURE(status)) |
855 | return -ENODEV; | 866 | return -ENODEV; |
856 | |||
857 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); | 867 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
858 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 868 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
859 | |||
860 | status = acpi_install_address_space_handler(ec->handle, | 869 | status = acpi_install_address_space_handler(ec->handle, |
861 | ACPI_ADR_SPACE_EC, | 870 | ACPI_ADR_SPACE_EC, |
862 | &acpi_ec_space_handler, | 871 | &acpi_ec_space_handler, |
@@ -877,7 +886,7 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
877 | } | 886 | } |
878 | } | 887 | } |
879 | 888 | ||
880 | ec->handlers_installed = 1; | 889 | set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
881 | return 0; | 890 | return 0; |
882 | } | 891 | } |
883 | 892 | ||
@@ -898,7 +907,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
898 | 907 | ||
899 | /* EC is fully operational, allow queries */ | 908 | /* EC is fully operational, allow queries */ |
900 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 909 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
901 | ec_schedule_ec_poll(ec); | ||
902 | return ret; | 910 | return ret; |
903 | } | 911 | } |
904 | 912 | ||
@@ -917,7 +925,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
917 | 925 | ||
918 | int __init acpi_boot_ec_enable(void) | 926 | int __init acpi_boot_ec_enable(void) |
919 | { | 927 | { |
920 | if (!boot_ec || boot_ec->handlers_installed) | 928 | if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) |
921 | return 0; | 929 | return 0; |
922 | if (!ec_install_handlers(boot_ec)) { | 930 | if (!ec_install_handlers(boot_ec)) { |
923 | first_ec = boot_ec; | 931 | first_ec = boot_ec; |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3196749398ea..eae6c801536d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1565,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) | |||
1565 | return result; | 1565 | return result; |
1566 | } | 1566 | } |
1567 | 1567 | ||
1568 | int __init acpi_boot_ec_enable(void); | ||
1569 | 1568 | ||
1570 | static int __init acpi_scan_init(void) | 1569 | static int __init acpi_scan_init(void) |
1571 | { | 1570 | { |
@@ -1599,9 +1598,6 @@ static int __init acpi_scan_init(void) | |||
1599 | */ | 1598 | */ |
1600 | result = acpi_bus_scan_fixed(acpi_root); | 1599 | result = acpi_bus_scan_fixed(acpi_root); |
1601 | 1600 | ||
1602 | /* EC region might be needed at bus_scan, so enable it now */ | ||
1603 | acpi_boot_ec_enable(); | ||
1604 | |||
1605 | if (!result) | 1601 | if (!result) |
1606 | result = acpi_bus_scan(acpi_root, &ops); | 1602 | result = acpi_bus_scan(acpi_root, &ops); |
1607 | 1603 | ||
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index a35c9597d5b1..cf04c6011c2a 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h | |||
@@ -101,6 +101,7 @@ extern int acpi_power_nocheck; | |||
101 | -------------------------------------------------------------------------- */ | 101 | -------------------------------------------------------------------------- */ |
102 | #ifdef CONFIG_ACPI_EC | 102 | #ifdef CONFIG_ACPI_EC |
103 | int acpi_ec_ecdt_probe(void); | 103 | int acpi_ec_ecdt_probe(void); |
104 | int acpi_boot_ec_enable(void); | ||
104 | #endif | 105 | #endif |
105 | 106 | ||
106 | /* -------------------------------------------------------------------------- | 107 | /* -------------------------------------------------------------------------- |