diff options
Diffstat (limited to 'drivers/acpi/ec.c')
| -rw-r--r-- | drivers/acpi/ec.c | 400 |
1 files changed, 211 insertions, 189 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 13593f9f219..ef42316f89f 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 | ||
| @@ -718,6 +736,7 @@ static acpi_status | |||
| 718 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | 736 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) |
| 719 | { | 737 | { |
| 720 | acpi_status status; | 738 | acpi_status status; |
| 739 | unsigned long long tmp; | ||
| 721 | 740 | ||
| 722 | struct acpi_ec *ec = context; | 741 | struct acpi_ec *ec = context; |
| 723 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | 742 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
| @@ -727,31 +746,26 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
| 727 | 746 | ||
| 728 | /* Get GPE bit assignment (EC events). */ | 747 | /* Get GPE bit assignment (EC events). */ |
| 729 | /* TODO: Add support for _GPE returning a package */ | 748 | /* TODO: Add support for _GPE returning a package */ |
| 730 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); | 749 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); |
| 731 | if (ACPI_FAILURE(status)) | 750 | if (ACPI_FAILURE(status)) |
| 732 | return status; | 751 | return status; |
| 752 | ec->gpe = tmp; | ||
| 733 | /* Use the global lock for all EC transactions? */ | 753 | /* Use the global lock for all EC transactions? */ |
| 734 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | 754 | acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); |
| 755 | ec->global_lock = tmp; | ||
| 735 | ec->handle = handle; | 756 | ec->handle = handle; |
| 736 | return AE_CTRL_TERMINATE; | 757 | return AE_CTRL_TERMINATE; |
| 737 | } | 758 | } |
| 738 | 759 | ||
| 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) | 760 | static void ec_remove_handlers(struct acpi_ec *ec) |
| 746 | { | 761 | { |
| 747 | ec_poll_stop(ec); | ||
| 748 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, | 762 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
| 749 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) | 763 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
| 750 | pr_err(PREFIX "failed to remove space handler\n"); | 764 | pr_err(PREFIX "failed to remove space handler\n"); |
| 751 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, | 765 | if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, |
| 752 | &acpi_ec_gpe_handler))) | 766 | &acpi_ec_gpe_handler))) |
| 753 | pr_err(PREFIX "failed to remove gpe handler\n"); | 767 | pr_err(PREFIX "failed to remove gpe handler\n"); |
| 754 | ec->handlers_installed = 0; | 768 | clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
| 755 | } | 769 | } |
| 756 | 770 | ||
| 757 | static int acpi_ec_add(struct acpi_device *device) | 771 | static int acpi_ec_add(struct acpi_device *device) |
| @@ -788,7 +802,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
| 788 | 802 | ||
| 789 | if (!first_ec) | 803 | if (!first_ec) |
| 790 | first_ec = ec; | 804 | first_ec = ec; |
| 791 | acpi_driver_data(device) = ec; | 805 | device->driver_data = ec; |
| 792 | acpi_ec_add_fs(device); | 806 | acpi_ec_add_fs(device); |
| 793 | pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", | 807 | pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", |
| 794 | ec->gpe, ec->command_addr, ec->data_addr); | 808 | ec->gpe, ec->command_addr, ec->data_addr); |
| @@ -813,7 +827,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) | |||
| 813 | } | 827 | } |
| 814 | mutex_unlock(&ec->lock); | 828 | mutex_unlock(&ec->lock); |
| 815 | acpi_ec_remove_fs(device); | 829 | acpi_ec_remove_fs(device); |
| 816 | acpi_driver_data(device) = NULL; | 830 | device->driver_data = NULL; |
| 817 | if (ec == first_ec) | 831 | if (ec == first_ec) |
| 818 | first_ec = NULL; | 832 | first_ec = NULL; |
| 819 | kfree(ec); | 833 | kfree(ec); |
| @@ -846,27 +860,36 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) | |||
| 846 | static int ec_install_handlers(struct acpi_ec *ec) | 860 | static int ec_install_handlers(struct acpi_ec *ec) |
| 847 | { | 861 | { |
| 848 | acpi_status status; | 862 | acpi_status status; |
| 849 | if (ec->handlers_installed) | 863 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
| 850 | return 0; | 864 | return 0; |
| 851 | status = acpi_install_gpe_handler(NULL, ec->gpe, | 865 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
| 852 | ACPI_GPE_EDGE_TRIGGERED, | 866 | ACPI_GPE_EDGE_TRIGGERED, |
| 853 | &acpi_ec_gpe_handler, ec); | 867 | &acpi_ec_gpe_handler, ec); |
| 854 | if (ACPI_FAILURE(status)) | 868 | if (ACPI_FAILURE(status)) |
| 855 | return -ENODEV; | 869 | return -ENODEV; |
| 856 | |||
| 857 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); | 870 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
| 858 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 871 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
| 859 | |||
| 860 | status = acpi_install_address_space_handler(ec->handle, | 872 | status = acpi_install_address_space_handler(ec->handle, |
| 861 | ACPI_ADR_SPACE_EC, | 873 | ACPI_ADR_SPACE_EC, |
| 862 | &acpi_ec_space_handler, | 874 | &acpi_ec_space_handler, |
| 863 | NULL, ec); | 875 | NULL, ec); |
| 864 | if (ACPI_FAILURE(status)) { | 876 | if (ACPI_FAILURE(status)) { |
| 865 | acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); | 877 | if (status == AE_NOT_FOUND) { |
| 866 | return -ENODEV; | 878 | /* |
| 879 | * Maybe OS fails in evaluating the _REG object. | ||
| 880 | * The AE_NOT_FOUND error will be ignored and OS | ||
| 881 | * continue to initialize EC. | ||
| 882 | */ | ||
| 883 | printk(KERN_ERR "Fail in evaluating the _REG object" | ||
| 884 | " of EC device. Broken bios is suspected.\n"); | ||
| 885 | } else { | ||
| 886 | acpi_remove_gpe_handler(NULL, ec->gpe, | ||
| 887 | &acpi_ec_gpe_handler); | ||
| 888 | return -ENODEV; | ||
| 889 | } | ||
| 867 | } | 890 | } |
| 868 | 891 | ||
| 869 | ec->handlers_installed = 1; | 892 | set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); |
| 870 | return 0; | 893 | return 0; |
| 871 | } | 894 | } |
| 872 | 895 | ||
| @@ -887,7 +910,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
| 887 | 910 | ||
| 888 | /* EC is fully operational, allow queries */ | 911 | /* EC is fully operational, allow queries */ |
| 889 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 912 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
| 890 | ec_schedule_ec_poll(ec); | ||
| 891 | return ret; | 913 | return ret; |
| 892 | } | 914 | } |
| 893 | 915 | ||
| @@ -906,7 +928,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
| 906 | 928 | ||
| 907 | int __init acpi_boot_ec_enable(void) | 929 | int __init acpi_boot_ec_enable(void) |
| 908 | { | 930 | { |
| 909 | if (!boot_ec || boot_ec->handlers_installed) | 931 | if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) |
| 910 | return 0; | 932 | return 0; |
| 911 | if (!ec_install_handlers(boot_ec)) { | 933 | if (!ec_install_handlers(boot_ec)) { |
| 912 | first_ec = boot_ec; | 934 | first_ec = boot_ec; |
