diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/ec.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 06b78e5e33a1..390f8f8666da 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -75,7 +75,8 @@ enum { | |||
75 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ | 75 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ |
76 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 76 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
77 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ | 77 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ |
78 | EC_FLAGS_ONLY_IBF_GPE, /* Expect GPE only for IBF = 0 event */ | 78 | EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */ |
79 | EC_FLAGS_ADDRESS, /* Address is being written */ | ||
79 | }; | 80 | }; |
80 | 81 | ||
81 | static int acpi_ec_remove(struct acpi_device *device, int type); | 82 | static int acpi_ec_remove(struct acpi_device *device, int type); |
@@ -166,38 +167,45 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) | |||
166 | 167 | ||
167 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 168 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
168 | { | 169 | { |
170 | int ret = 0; | ||
171 | if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && | ||
172 | test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) | ||
173 | force_poll = 1; | ||
169 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && | 174 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && |
170 | likely(!force_poll)) { | 175 | likely(!force_poll)) { |
171 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | 176 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), |
172 | msecs_to_jiffies(ACPI_EC_DELAY))) | 177 | msecs_to_jiffies(ACPI_EC_DELAY))) |
173 | return 0; | 178 | goto end; |
174 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 179 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
175 | if (acpi_ec_check_status(ec, event)) { | 180 | if (acpi_ec_check_status(ec, event)) { |
176 | if (event == ACPI_EC_EVENT_OBF_1) { | 181 | if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { |
177 | /* miss OBF = 1 GPE, don't expect it anymore */ | 182 | /* miss address GPE, don't expect it anymore */ |
178 | printk(KERN_INFO PREFIX "missing OBF_1 confirmation," | 183 | printk(KERN_INFO PREFIX "missing address confirmation," |
179 | "switching to degraded mode.\n"); | 184 | "don't expect it any longer.\n"); |
180 | set_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags); | 185 | set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags); |
181 | } else { | 186 | } else { |
182 | /* missing GPEs, switch back to poll mode */ | 187 | /* missing GPEs, switch back to poll mode */ |
183 | printk(KERN_INFO PREFIX "missing IBF_1 confirmations," | 188 | printk(KERN_INFO PREFIX "missing confirmations," |
184 | "switch off interrupt mode.\n"); | 189 | "switch off interrupt mode.\n"); |
185 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 190 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
186 | } | 191 | } |
187 | return 0; | 192 | goto end; |
188 | } | 193 | } |
189 | } else { | 194 | } else { |
190 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | 195 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
191 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 196 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
192 | while (time_before(jiffies, delay)) { | 197 | while (time_before(jiffies, delay)) { |
193 | if (acpi_ec_check_status(ec, event)) | 198 | if (acpi_ec_check_status(ec, event)) |
194 | return 0; | 199 | goto end; |
195 | } | 200 | } |
196 | } | 201 | } |
197 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | 202 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," |
198 | " status = %d, expect_event = %d\n", | 203 | " status = %d, expect_event = %d\n", |
199 | acpi_ec_read_status(ec), event); | 204 | acpi_ec_read_status(ec), event); |
200 | return -ETIME; | 205 | ret = -ETIME; |
206 | end: | ||
207 | clear_bit(EC_FLAGS_ADDRESS, &ec->flags); | ||
208 | return ret; | ||
201 | } | 209 | } |
202 | 210 | ||
203 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | 211 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, |
@@ -216,6 +224,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | |||
216 | "write_cmd timeout, command = %d\n", command); | 224 | "write_cmd timeout, command = %d\n", command); |
217 | goto end; | 225 | goto end; |
218 | } | 226 | } |
227 | /* mark the address byte written to EC */ | ||
228 | if (rdata_len + wdata_len > 1) | ||
229 | set_bit(EC_FLAGS_ADDRESS, &ec->flags); | ||
219 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 230 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
220 | acpi_ec_write_data(ec, *(wdata++)); | 231 | acpi_ec_write_data(ec, *(wdata++)); |
221 | } | 232 | } |
@@ -231,8 +242,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | |||
231 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 242 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
232 | 243 | ||
233 | for (; rdata_len > 0; --rdata_len) { | 244 | for (; rdata_len > 0; --rdata_len) { |
234 | if (test_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags)) | ||
235 | force_poll = 1; | ||
236 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); | 245 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); |
237 | if (result) { | 246 | if (result) { |
238 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", | 247 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", |