diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/ec.c | 79 |
1 files changed, 38 insertions, 41 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7b4178393e34..08fbe62a2db4 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -65,7 +65,7 @@ enum ec_command { | |||
65 | /* EC events */ | 65 | /* EC events */ |
66 | enum ec_event { | 66 | enum ec_event { |
67 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | 67 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ |
68 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ | 68 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ |
69 | }; | 69 | }; |
70 | 70 | ||
71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ | 71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
@@ -76,6 +76,11 @@ static enum ec_mode { | |||
76 | EC_POLL, /* Input buffer empty */ | 76 | EC_POLL, /* Input buffer empty */ |
77 | } acpi_ec_mode = EC_INTR; | 77 | } acpi_ec_mode = EC_INTR; |
78 | 78 | ||
79 | enum { | ||
80 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ | ||
81 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | ||
82 | }; | ||
83 | |||
79 | static int acpi_ec_remove(struct acpi_device *device, int type); | 84 | static int acpi_ec_remove(struct acpi_device *device, int type); |
80 | static int acpi_ec_start(struct acpi_device *device); | 85 | static int acpi_ec_start(struct acpi_device *device); |
81 | static int acpi_ec_stop(struct acpi_device *device, int type); | 86 | static int acpi_ec_stop(struct acpi_device *device, int type); |
@@ -116,9 +121,8 @@ static struct acpi_ec { | |||
116 | unsigned long command_addr; | 121 | unsigned long command_addr; |
117 | unsigned long data_addr; | 122 | unsigned long data_addr; |
118 | unsigned long global_lock; | 123 | unsigned long global_lock; |
124 | unsigned long flags; | ||
119 | struct mutex lock; | 125 | struct mutex lock; |
120 | atomic_t query_pending; | ||
121 | atomic_t event_count; | ||
122 | wait_queue_head_t wait; | 126 | wait_queue_head_t wait; |
123 | struct list_head list; | 127 | struct list_head list; |
124 | u8 handlers_installed; | 128 | u8 handlers_installed; |
@@ -148,45 +152,42 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
148 | outb(data, ec->data_addr); | 152 | outb(data, ec->data_addr); |
149 | } | 153 | } |
150 | 154 | ||
151 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event, | 155 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) |
152 | unsigned old_count) | ||
153 | { | 156 | { |
154 | u8 status = acpi_ec_read_status(ec); | 157 | if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) |
155 | if (old_count == atomic_read(&ec->event_count)) | ||
156 | return 0; | 158 | return 0; |
157 | if (event == ACPI_EC_EVENT_OBF_1) { | 159 | if (event == ACPI_EC_EVENT_OBF_1) { |
158 | if (status & ACPI_EC_FLAG_OBF) | 160 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) |
159 | return 1; | 161 | return 1; |
160 | } else if (event == ACPI_EC_EVENT_IBF_0) { | 162 | } else if (event == ACPI_EC_EVENT_IBF_0) { |
161 | if (!(status & ACPI_EC_FLAG_IBF)) | 163 | if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) |
162 | return 1; | 164 | return 1; |
163 | } | 165 | } |
164 | 166 | ||
165 | return 0; | 167 | return 0; |
166 | } | 168 | } |
167 | 169 | ||
168 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, | 170 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
169 | unsigned count, int force_poll) | ||
170 | { | 171 | { |
171 | if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) { | 172 | if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) { |
172 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | 173 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
174 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
173 | while (time_before(jiffies, delay)) { | 175 | while (time_before(jiffies, delay)) { |
174 | if (acpi_ec_check_status(ec, event, 0)) | 176 | if (acpi_ec_check_status(ec, event)) |
175 | return 0; | 177 | return 0; |
176 | } | 178 | } |
177 | } else { | 179 | } else { |
178 | if (wait_event_timeout(ec->wait, | 180 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), |
179 | acpi_ec_check_status(ec, event, count), | 181 | msecs_to_jiffies(ACPI_EC_DELAY))) |
180 | msecs_to_jiffies(ACPI_EC_DELAY)) || | 182 | return 0; |
181 | acpi_ec_check_status(ec, event, 0)) { | 183 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
184 | if (acpi_ec_check_status(ec, event)) { | ||
182 | return 0; | 185 | return 0; |
183 | } else { | ||
184 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | ||
185 | " status = %d, expect_event = %d\n", | ||
186 | acpi_ec_read_status(ec), event); | ||
187 | } | 186 | } |
188 | } | 187 | } |
189 | 188 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | |
189 | " status = %d, expect_event = %d\n", | ||
190 | acpi_ec_read_status(ec), event); | ||
190 | return -ETIME; | 191 | return -ETIME; |
191 | } | 192 | } |
192 | 193 | ||
@@ -196,39 +197,38 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | |||
196 | int force_poll) | 197 | int force_poll) |
197 | { | 198 | { |
198 | int result = 0; | 199 | int result = 0; |
199 | unsigned count = atomic_read(&ec->event_count); | 200 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
200 | acpi_ec_write_cmd(ec, command); | 201 | acpi_ec_write_cmd(ec, command); |
201 | 202 | ||
202 | for (; wdata_len > 0; --wdata_len) { | 203 | for (; wdata_len > 0; --wdata_len) { |
203 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); | 204 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
204 | if (result) { | 205 | if (result) { |
205 | printk(KERN_ERR PREFIX | 206 | printk(KERN_ERR PREFIX |
206 | "write_cmd timeout, command = %d\n", command); | 207 | "write_cmd timeout, command = %d\n", command); |
207 | goto end; | 208 | goto end; |
208 | } | 209 | } |
209 | count = atomic_read(&ec->event_count); | 210 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
210 | acpi_ec_write_data(ec, *(wdata++)); | 211 | acpi_ec_write_data(ec, *(wdata++)); |
211 | } | 212 | } |
212 | 213 | ||
213 | if (!rdata_len) { | 214 | if (!rdata_len) { |
214 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); | 215 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
215 | if (result) { | 216 | if (result) { |
216 | printk(KERN_ERR PREFIX | 217 | printk(KERN_ERR PREFIX |
217 | "finish-write timeout, command = %d\n", command); | 218 | "finish-write timeout, command = %d\n", command); |
218 | goto end; | 219 | goto end; |
219 | } | 220 | } |
220 | } else if (command == ACPI_EC_COMMAND_QUERY) { | 221 | } else if (command == ACPI_EC_COMMAND_QUERY) |
221 | atomic_set(&ec->query_pending, 0); | 222 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
222 | } | ||
223 | 223 | ||
224 | for (; rdata_len > 0; --rdata_len) { | 224 | for (; rdata_len > 0; --rdata_len) { |
225 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll); | 225 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); |
226 | if (result) { | 226 | if (result) { |
227 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", | 227 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", |
228 | command); | 228 | command); |
229 | goto end; | 229 | goto end; |
230 | } | 230 | } |
231 | count = atomic_read(&ec->event_count); | 231 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
232 | *(rdata++) = acpi_ec_read_data(ec); | 232 | *(rdata++) = acpi_ec_read_data(ec); |
233 | } | 233 | } |
234 | end: | 234 | end: |
@@ -261,7 +261,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
261 | /* Make sure GPE is enabled before doing transaction */ | 261 | /* Make sure GPE is enabled before doing transaction */ |
262 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 262 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
263 | 263 | ||
264 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); | 264 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); |
265 | if (status) { | 265 | if (status) { |
266 | printk(KERN_ERR PREFIX | 266 | printk(KERN_ERR PREFIX |
267 | "input buffer is not empty, aborting transaction\n"); | 267 | "input buffer is not empty, aborting transaction\n"); |
@@ -476,20 +476,18 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
476 | static u32 acpi_ec_gpe_handler(void *data) | 476 | static u32 acpi_ec_gpe_handler(void *data) |
477 | { | 477 | { |
478 | acpi_status status = AE_OK; | 478 | acpi_status status = AE_OK; |
479 | u8 value; | ||
480 | struct acpi_ec *ec = data; | 479 | struct acpi_ec *ec = data; |
481 | 480 | ||
482 | atomic_inc(&ec->event_count); | 481 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
483 | 482 | ||
484 | if (acpi_ec_mode == EC_INTR) { | 483 | if (acpi_ec_mode == EC_INTR) { |
485 | wake_up(&ec->wait); | 484 | wake_up(&ec->wait); |
486 | } | 485 | } |
487 | 486 | ||
488 | value = acpi_ec_read_status(ec); | 487 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { |
489 | if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { | 488 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
490 | atomic_set(&ec->query_pending, 1); | 489 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, |
491 | status = | 490 | acpi_ec_gpe_query, ec); |
492 | acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); | ||
493 | } | 491 | } |
494 | 492 | ||
495 | return status == AE_OK ? | 493 | return status == AE_OK ? |
@@ -642,8 +640,7 @@ static struct acpi_ec *make_acpi_ec(void) | |||
642 | if (!ec) | 640 | if (!ec) |
643 | return NULL; | 641 | return NULL; |
644 | 642 | ||
645 | atomic_set(&ec->query_pending, 1); | 643 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; |
646 | atomic_set(&ec->event_count, 1); | ||
647 | mutex_init(&ec->lock); | 644 | mutex_init(&ec->lock); |
648 | init_waitqueue_head(&ec->wait); | 645 | init_waitqueue_head(&ec->wait); |
649 | INIT_LIST_HEAD(&ec->list); | 646 | INIT_LIST_HEAD(&ec->list); |
@@ -833,7 +830,7 @@ static int acpi_ec_start(struct acpi_device *device) | |||
833 | ret = ec_install_handlers(ec); | 830 | ret = ec_install_handlers(ec); |
834 | 831 | ||
835 | /* EC is fully operational, allow queries */ | 832 | /* EC is fully operational, allow queries */ |
836 | atomic_set(&ec->query_pending, 0); | 833 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
837 | return ret; | 834 | return ret; |
838 | } | 835 | } |
839 | 836 | ||