Lines 1-7
Link Here
|
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> |
Lines 26-32
Link Here
|
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> |
Lines 38-43
Link Here
|
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> |
Lines 65-86
enum ec_command {
Link Here
|
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 for status change */ |
82 |
EC_FLAGS_NO_GPE, /* Don't use GPE mode */ |
79 |
EC_FLAGS_NO_GPE, /* Don't use GPE mode */ |
83 |
EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ |
80 |
EC_FLAGS_GPE_STORM /* GPE storm detected */ |
84 |
}; |
81 |
}; |
85 |
|
82 |
|
86 |
/* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
83 |
/* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
Lines 95-100
struct acpi_ec_query_handler {
Link Here
|
95 |
u8 query_bit; |
92 |
u8 query_bit; |
96 |
}; |
93 |
}; |
97 |
|
94 |
|
|
|
95 |
struct transaction_data { |
96 |
const u8 *wdata; |
97 |
u8 *rdata; |
98 |
u8 wlen; |
99 |
u8 rlen; |
100 |
}; |
101 |
|
98 |
static struct acpi_ec { |
102 |
static struct acpi_ec { |
99 |
acpi_handle handle; |
103 |
acpi_handle handle; |
100 |
unsigned long gpe; |
104 |
unsigned long gpe; |
Lines 105-111
static struct acpi_ec {
Link Here
|
105 |
struct mutex lock; |
109 |
struct mutex lock; |
106 |
wait_queue_head_t wait; |
110 |
wait_queue_head_t wait; |
107 |
struct list_head list; |
111 |
struct list_head list; |
108 |
struct delayed_work work; |
112 |
struct transaction_data *t; |
|
|
113 |
spinlock_t spinlock; |
109 |
atomic_t irq_count; |
114 |
atomic_t irq_count; |
110 |
u8 handlers_installed; |
115 |
u8 handlers_installed; |
111 |
} *boot_ec, *first_ec; |
116 |
} *boot_ec, *first_ec; |
Lines 150-156
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
Link Here
|
150 |
{ |
155 |
{ |
151 |
u8 x = inb(ec->data_addr); |
156 |
u8 x = inb(ec->data_addr); |
152 |
pr_debug(PREFIX "---> data = 0x%2.2x\n", x); |
157 |
pr_debug(PREFIX "---> data = 0x%2.2x\n", x); |
153 |
return inb(ec->data_addr); |
158 |
return x; |
154 |
} |
159 |
} |
155 |
|
160 |
|
156 |
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) |
161 |
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) |
Lines 165-232
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
Link Here
|
165 |
outb(data, ec->data_addr); |
170 |
outb(data, ec->data_addr); |
166 |
} |
171 |
} |
167 |
|
172 |
|
168 |
static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) |
173 |
static inline struct transaction_data *ec_get_transaction(struct acpi_ec *ec) |
169 |
{ |
174 |
{ |
170 |
if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) |
175 |
unsigned long flags; |
171 |
return 0; |
176 |
struct transaction_data *t; |
172 |
if (event == ACPI_EC_EVENT_OBF_1) { |
177 |
spin_lock_irqsave(&ec->spinlock, flags); |
173 |
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) |
178 |
t = ec->t; |
174 |
return 1; |
179 |
spin_unlock_irqrestore(&ec->spinlock, flags); |
175 |
} else if (event == ACPI_EC_EVENT_IBF_0) { |
180 |
return t; |
176 |
if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) |
181 |
} |
177 |
return 1; |
|
|
178 |
} |
179 |
|
182 |
|
|
|
183 |
static int ec_transaction_done(struct acpi_ec *ec) |
184 |
{ |
185 |
struct transaction_data *t = ec_get_transaction(ec); |
186 |
if (!t || (!t->wlen && !t->rlen)) |
187 |
return 1; |
180 |
return 0; |
188 |
return 0; |
181 |
} |
189 |
} |
182 |
|
190 |
|
183 |
static void ec_schedule_ec_poll(struct acpi_ec *ec) |
191 |
static void gpe_transaction(struct acpi_ec *ec, u8 status) |
184 |
{ |
192 |
{ |
185 |
if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) |
193 |
struct transaction_data *t = ec_get_transaction(ec); |
186 |
schedule_delayed_work(&ec->work, |
194 |
if (!t) |
187 |
msecs_to_jiffies(ACPI_EC_DELAY)); |
195 |
return; |
|
|
196 |
if (t->wlen > 0) { |
197 |
if ((status & ACPI_EC_FLAG_IBF) == 0) { |
198 |
acpi_ec_write_data(ec, *(t->wdata++)); |
199 |
--t->wlen; |
200 |
} else |
201 |
/* false interrupt, state didn't change */ |
202 |
atomic_inc(&ec->irq_count); |
203 |
|
204 |
} else if (t->rlen > 0) { |
205 |
if ((status & ACPI_EC_FLAG_OBF) == 1) { |
206 |
*(t->rdata++) = acpi_ec_read_data(ec); |
207 |
--t->rlen; |
208 |
} else |
209 |
/* false interrupt, state didn't change */ |
210 |
atomic_inc(&ec->irq_count); |
211 |
} |
188 |
} |
212 |
} |
189 |
|
213 |
|
190 |
static void ec_switch_to_poll_mode(struct acpi_ec *ec) |
214 |
static int acpi_ec_wait(struct acpi_ec *ec) |
191 |
{ |
215 |
{ |
|
|
216 |
if (wait_event_timeout(ec->wait, ec_transaction_done(ec), |
217 |
msecs_to_jiffies(ACPI_EC_DELAY))) |
218 |
return 0; |
219 |
/* missing GPEs, switch back to poll mode */ |
220 |
if (printk_ratelimit()) |
221 |
pr_info(PREFIX "missing confirmations, " |
222 |
"switch off interrupt mode.\n"); |
192 |
set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
223 |
set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
193 |
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
224 |
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
194 |
acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
225 |
return 1; |
195 |
set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); |
|
|
196 |
} |
226 |
} |
197 |
|
227 |
|
198 |
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
228 |
static void acpi_ec_gpe_query(void *ec_cxt); |
|
|
229 |
|
230 |
static int ec_check_sci(struct acpi_ec *ec, u8 state) |
199 |
{ |
231 |
{ |
200 |
atomic_set(&ec->irq_count, 0); |
232 |
if (state & ACPI_EC_FLAG_SCI) { |
201 |
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && |
233 |
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
202 |
likely(!force_poll)) { |
234 |
return acpi_os_execute(OSL_EC_BURST_HANDLER, |
203 |
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), |
235 |
acpi_ec_gpe_query, ec); |
204 |
msecs_to_jiffies(ACPI_EC_DELAY))) |
236 |
} |
205 |
return 0; |
237 |
return 0; |
206 |
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
238 |
} |
207 |
if (acpi_ec_check_status(ec, event)) { |
239 |
|
208 |
/* missing GPEs, switch back to poll mode */ |
240 |
static int ec_poll(struct acpi_ec *ec) |
209 |
if (printk_ratelimit()) |
241 |
{ |
210 |
pr_info(PREFIX "missing confirmations, " |
242 |
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
211 |
"switch off interrupt mode.\n"); |
243 |
while (time_before(jiffies, delay)) { |
212 |
ec_switch_to_poll_mode(ec); |
244 |
gpe_transaction(ec, acpi_ec_read_status(ec)); |
213 |
ec_schedule_ec_poll(ec); |
245 |
/* do a shortest sleep */ |
214 |
return 0; |
246 |
msleep(1); |
215 |
} |
247 |
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; |
248 |
return 0; |
226 |
} |
249 |
} |
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; |
250 |
return -ETIME; |
231 |
} |
251 |
} |
232 |
|
252 |
|
Lines 235-279
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
Link Here
|
235 |
u8 * rdata, unsigned rdata_len, |
255 |
u8 * rdata, unsigned rdata_len, |
236 |
int force_poll) |
256 |
int force_poll) |
237 |
{ |
257 |
{ |
238 |
int result = 0; |
258 |
unsigned long tmp; |
239 |
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
259 |
struct transaction_data t = {.wdata = wdata, .rdata = rdata, |
|
|
260 |
.wlen = wdata_len, .rlen = rdata_len}; |
261 |
int ret = 0; |
240 |
pr_debug(PREFIX "transaction start\n"); |
262 |
pr_debug(PREFIX "transaction start\n"); |
|
|
263 |
/* disable GPE during transaction if storm is detected */ |
264 |
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
265 |
set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
266 |
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
267 |
acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
268 |
} |
269 |
atomic_set(&ec->irq_count, 0); |
270 |
/* start transaction */ |
271 |
spin_lock_irqsave(&ec->spinlock, tmp); |
272 |
/* following two actions should be kept atomic */ |
273 |
ec->t = &t; |
241 |
acpi_ec_write_cmd(ec, command); |
274 |
acpi_ec_write_cmd(ec, command); |
242 |
for (; wdata_len > 0; --wdata_len) { |
275 |
spin_unlock_irqrestore(&ec->spinlock, tmp); |
243 |
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
276 |
/* if we selected poll mode or failed in GPE-mode do a poll loop */ |
244 |
if (result) { |
277 |
if (force_poll || |
245 |
pr_err(PREFIX |
278 |
!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || |
246 |
"write_cmd timeout, command = %d\n", command); |
279 |
acpi_ec_wait(ec)) |
247 |
goto end; |
280 |
ret = ec_poll(ec); |
248 |
} |
281 |
end: |
249 |
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
282 |
pr_debug(PREFIX "transaction end\n"); |
250 |
acpi_ec_write_data(ec, *(wdata++)); |
283 |
/* no need to guard against the interrupt handler */ |
|
|
284 |
ec->t = NULL; |
285 |
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
286 |
/* check if we received SCI during transaction */ |
287 |
ec_check_sci(ec, acpi_ec_read_status(ec)); |
288 |
/* it is safe to enable GPE outside of transaction */ |
289 |
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
290 |
} else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
291 |
atomic_read(&ec->irq_count) > ACPI_EC_STORM_THRESHOLD) { |
292 |
pr_debug(PREFIX "GPE storm detected\n"); |
293 |
set_bit(EC_FLAGS_GPE_STORM, &ec->flags); |
251 |
} |
294 |
} |
|
|
295 |
return ret; |
296 |
} |
252 |
|
297 |
|
253 |
if (!rdata_len) { |
298 |
static int ec_check_ibf0(struct acpi_ec *ec) |
254 |
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
299 |
{ |
255 |
if (result) { |
300 |
u8 status = acpi_ec_read_status(ec); |
256 |
pr_err(PREFIX |
301 |
return (status & ACPI_EC_FLAG_IBF) == 0; |
257 |
"finish-write timeout, command = %d\n", command); |
|
|
258 |
goto end; |
259 |
} |
260 |
} else if (command == ACPI_EC_COMMAND_QUERY) |
261 |
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
262 |
|
263 |
for (; rdata_len > 0; --rdata_len) { |
264 |
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); |
265 |
if (result) { |
266 |
pr_err(PREFIX "read timeout, command = %d\n", command); |
267 |
goto end; |
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"); |
276 |
return result; |
277 |
} |
302 |
} |
278 |
|
303 |
|
279 |
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, |
304 |
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, |
Lines 283-322
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
Link Here
|
283 |
{ |
308 |
{ |
284 |
int status; |
309 |
int status; |
285 |
u32 glk; |
310 |
u32 glk; |
286 |
|
|
|
287 |
if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) |
311 |
if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) |
288 |
return -EINVAL; |
312 |
return -EINVAL; |
289 |
|
|
|
290 |
if (rdata) |
313 |
if (rdata) |
291 |
memset(rdata, 0, rdata_len); |
314 |
memset(rdata, 0, rdata_len); |
292 |
|
|
|
293 |
mutex_lock(&ec->lock); |
315 |
mutex_lock(&ec->lock); |
294 |
if (ec->global_lock) { |
316 |
if (ec->global_lock) { |
295 |
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
317 |
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
296 |
if (ACPI_FAILURE(status)) { |
318 |
if (ACPI_FAILURE(status)) { |
297 |
mutex_unlock(&ec->lock); |
319 |
status = -ENODEV; |
298 |
return -ENODEV; |
320 |
goto unlock; |
299 |
} |
321 |
} |
300 |
} |
322 |
} |
301 |
|
323 |
if (!wait_event_timeout(ec->wait, ec_check_ibf0(ec), |
302 |
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); |
324 |
msecs_to_jiffies(ACPI_EC_DELAY))) { |
303 |
if (status) { |
|
|
304 |
pr_err(PREFIX "input buffer is not empty, " |
325 |
pr_err(PREFIX "input buffer is not empty, " |
305 |
"aborting transaction\n"); |
326 |
"aborting transaction\n"); |
|
|
327 |
status = -ETIME; |
306 |
goto end; |
328 |
goto end; |
307 |
} |
329 |
} |
308 |
|
|
|
309 |
status = acpi_ec_transaction_unlocked(ec, command, |
330 |
status = acpi_ec_transaction_unlocked(ec, command, |
310 |
wdata, wdata_len, |
331 |
wdata, wdata_len, |
311 |
rdata, rdata_len, |
332 |
rdata, rdata_len, |
312 |
force_poll); |
333 |
force_poll); |
313 |
|
334 |
end: |
314 |
end: |
|
|
315 |
|
316 |
if (ec->global_lock) |
335 |
if (ec->global_lock) |
317 |
acpi_release_global_lock(glk); |
336 |
acpi_release_global_lock(glk); |
|
|
337 |
unlock: |
318 |
mutex_unlock(&ec->lock); |
338 |
mutex_unlock(&ec->lock); |
319 |
|
|
|
320 |
return status; |
339 |
return status; |
321 |
} |
340 |
} |
322 |
|
341 |
|
Lines 332-338
int acpi_ec_burst_enable(struct acpi_ec *ec)
Link Here
|
332 |
|
351 |
|
333 |
int acpi_ec_burst_disable(struct acpi_ec *ec) |
352 |
int acpi_ec_burst_disable(struct acpi_ec *ec) |
334 |
{ |
353 |
{ |
335 |
return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); |
354 |
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST)? |
|
|
355 |
acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, |
356 |
NULL, 0, NULL, 0, 0) : 0; |
336 |
} |
357 |
} |
337 |
|
358 |
|
338 |
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) |
359 |
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) |
Lines 437-442
static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
Link Here
|
437 |
*/ |
458 |
*/ |
438 |
|
459 |
|
439 |
result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); |
460 |
result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); |
|
|
461 |
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
440 |
if (result) |
462 |
if (result) |
441 |
return result; |
463 |
return result; |
442 |
|
464 |
|
Lines 515-538
static u32 acpi_ec_gpe_handler(void *data)
Link Here
|
515 |
{ |
537 |
{ |
516 |
acpi_status status = AE_OK; |
538 |
acpi_status status = AE_OK; |
517 |
struct acpi_ec *ec = data; |
539 |
struct acpi_ec *ec = data; |
518 |
u8 state = acpi_ec_read_status(ec); |
540 |
u8 state; |
519 |
|
541 |
|
520 |
pr_debug(PREFIX "~~~> interrupt\n"); |
542 |
pr_debug(PREFIX "~~~> interrupt\n"); |
521 |
atomic_inc(&ec->irq_count); |
543 |
state = acpi_ec_read_status(ec); |
522 |
if (atomic_read(&ec->irq_count) > 5) { |
544 |
|
523 |
pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); |
545 |
gpe_transaction(ec, state); |
524 |
ec_switch_to_poll_mode(ec); |
546 |
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); |
547 |
wake_up(&ec->wait); |
530 |
|
548 |
|
531 |
if (state & ACPI_EC_FLAG_SCI) { |
549 |
status = ec_check_sci(ec, state); |
532 |
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
550 |
if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
533 |
status = acpi_os_execute(OSL_EC_BURST_HANDLER, |
|
|
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) && |
551 |
!test_bit(EC_FLAGS_NO_GPE, &ec->flags) && |
537 |
in_interrupt()) { |
552 |
in_interrupt()) { |
538 |
/* this is non-query, must be confirmation */ |
553 |
/* this is non-query, must be confirmation */ |
Lines 540-560
static u32 acpi_ec_gpe_handler(void *data)
Link Here
|
540 |
pr_info(PREFIX "non-query interrupt received," |
555 |
pr_info(PREFIX "non-query interrupt received," |
541 |
" switching to interrupt mode\n"); |
556 |
" switching to interrupt mode\n"); |
542 |
set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
557 |
set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
543 |
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); |
|
|
544 |
} |
558 |
} |
545 |
end: |
|
|
546 |
ec_schedule_ec_poll(ec); |
547 |
return ACPI_SUCCESS(status) ? |
559 |
return ACPI_SUCCESS(status) ? |
548 |
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
560 |
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
549 |
} |
561 |
} |
550 |
|
562 |
|
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 |
} |
557 |
|
558 |
/* -------------------------------------------------------------------------- |
563 |
/* -------------------------------------------------------------------------- |
559 |
Address Space Management |
564 |
Address Space Management |
560 |
-------------------------------------------------------------------------- */ |
565 |
-------------------------------------------------------------------------- */ |
Lines 696-703
static struct acpi_ec *make_acpi_ec(void)
Link Here
|
696 |
mutex_init(&ec->lock); |
701 |
mutex_init(&ec->lock); |
697 |
init_waitqueue_head(&ec->wait); |
702 |
init_waitqueue_head(&ec->wait); |
698 |
INIT_LIST_HEAD(&ec->list); |
703 |
INIT_LIST_HEAD(&ec->list); |
699 |
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); |
|
|
700 |
atomic_set(&ec->irq_count, 0); |
704 |
atomic_set(&ec->irq_count, 0); |
|
|
705 |
spin_lock_init(&ec->spinlock); |
701 |
return ec; |
706 |
return ec; |
702 |
} |
707 |
} |
703 |
|
708 |
|
Lines 736-750
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
Link Here
|
736 |
return AE_CTRL_TERMINATE; |
741 |
return AE_CTRL_TERMINATE; |
737 |
} |
742 |
} |
738 |
|
743 |
|
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) |
744 |
static void ec_remove_handlers(struct acpi_ec *ec) |
746 |
{ |
745 |
{ |
747 |
ec_poll_stop(ec); |
|
|
748 |
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
746 |
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
749 |
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
747 |
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
750 |
pr_err(PREFIX "failed to remove space handler\n"); |
748 |
pr_err(PREFIX "failed to remove space handler\n"); |
Lines 849-862
static int ec_install_handlers(struct acpi_ec *ec)
Link Here
|
849 |
if (ec->handlers_installed) |
847 |
if (ec->handlers_installed) |
850 |
return 0; |
848 |
return 0; |
851 |
status = acpi_install_gpe_handler(NULL, ec->gpe, |
849 |
status = acpi_install_gpe_handler(NULL, ec->gpe, |
852 |
ACPI_GPE_EDGE_TRIGGERED, |
850 |
ACPI_GPE_EDGE_TRIGGERED, |
853 |
&acpi_ec_gpe_handler, ec); |
851 |
&acpi_ec_gpe_handler, ec); |
854 |
if (ACPI_FAILURE(status)) |
852 |
if (ACPI_FAILURE(status)) |
855 |
return -ENODEV; |
853 |
return -ENODEV; |
856 |
|
|
|
857 |
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
854 |
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
858 |
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
855 |
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
859 |
|
|
|
860 |
status = acpi_install_address_space_handler(ec->handle, |
856 |
status = acpi_install_address_space_handler(ec->handle, |
861 |
ACPI_ADR_SPACE_EC, |
857 |
ACPI_ADR_SPACE_EC, |
862 |
&acpi_ec_space_handler, |
858 |
&acpi_ec_space_handler, |
Lines 887-893
static int acpi_ec_start(struct acpi_device *device)
Link Here
|
887 |
|
883 |
|
888 |
/* EC is fully operational, allow queries */ |
884 |
/* EC is fully operational, allow queries */ |
889 |
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
885 |
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
890 |
ec_schedule_ec_poll(ec); |
|
|
891 |
return ret; |
886 |
return ret; |
892 |
} |
887 |
} |
893 |
|
888 |
|