aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2014-06-14 20:41:35 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-07 06:52:02 -0400
commitf92fca0060fc4dc9227342d0072d75df98c1e5a5 (patch)
tree134942fc36a326f40fab33133c839bb145078d05
parent66b42b78bc1e816f92b662e8888c89195e4199e1 (diff)
ACPI / EC: Add asynchronous command byte write support
Move the first command byte write into advance_transaction() so that all EC register accesses that can affect the command processing state machine can happen in this asynchronous state machine advancement function. The advance_transaction() function then can be a complete implementation of an asyncrhonous transaction for a single command so that: 1. The first command byte can be written in the interrupt context; 2. The command completion waiter can also be used to wait the first command byte's timeout; 3. In BURST mode, the follow-up command bytes can be written in the interrupt context directly, so that it doesn't need to return to the task context. Returning to the task context reduces the throughput of the BURST mode and in the worst cases where the system workload is very high, this leads to the hardware driven automatic BURST mode exit. In order not to increase memory consumption, convert 'done' into 'flags' to contain multiple indications: 1. ACPI_EC_COMMAND_COMPLETE: converting from original 'done' condition, indicating the completion of the command transaction. 2. ACPI_EC_COMMAND_POLL: indicating the availability of writing the first command byte. A new command can utilize this flag to compete for the right of accessing the underlying hardware. There is a follow-up bug fix that has utilized this new flag. The 2 flags are important because it also reflects a key concept of IO programs' design used in the system softwares. Normally an IO program running in the kernel should first be implemented in the asynchronous way. And the 2 flags are the most common way to implement its synchronous operations on top of the asynchronous operations: 1. POLL: This flag can be used to block until the asynchronous operations can happen. 2. COMPLETE: This flag can be used to block until the asynchronous operations have completed. By constructing code cleanly in this way, many difficult problems can be solved smoothly. Link: https://bugzilla.kernel.org/show_bug.cgi?id=70891 Link: https://bugzilla.kernel.org/show_bug.cgi?id=63931 Link: https://bugzilla.kernel.org/show_bug.cgi?id=59911 Reported-and-tested-by: Gareth Williams <gareth@garethwilliams.me.uk> Reported-and-tested-by: Hans de Goede <jwrdegoede@fedoraproject.org> Reported-by: Barton Xu <tank.xuhan@gmail.com> Tested-by: Steffen Weber <steffen.weber@gmail.com> Tested-by: Arthur Chen <axchen@nvidia.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Cc: All applicable <stable@vger.kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/ec.c83
1 files changed, 48 insertions, 35 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 762b4cc9d7b1..f09386e9745f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -78,6 +78,9 @@ enum {
78 EC_FLAGS_BLOCKED, /* Transactions are blocked */ 78 EC_FLAGS_BLOCKED, /* Transactions are blocked */
79}; 79};
80 80
81#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
82#define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */
83
81/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */ 84/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
82static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; 85static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
83module_param(ec_delay, uint, 0644); 86module_param(ec_delay, uint, 0644);
@@ -109,7 +112,7 @@ struct transaction {
109 u8 ri; 112 u8 ri;
110 u8 wlen; 113 u8 wlen;
111 u8 rlen; 114 u8 rlen;
112 bool done; 115 u8 flags;
113}; 116};
114 117
115struct acpi_ec *boot_ec, *first_ec; 118struct acpi_ec *boot_ec, *first_ec;
@@ -150,63 +153,68 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
150 outb(data, ec->data_addr); 153 outb(data, ec->data_addr);
151} 154}
152 155
153static int ec_transaction_done(struct acpi_ec *ec) 156static int ec_transaction_completed(struct acpi_ec *ec)
154{ 157{
155 unsigned long flags; 158 unsigned long flags;
156 int ret = 0; 159 int ret = 0;
157 spin_lock_irqsave(&ec->lock, flags); 160 spin_lock_irqsave(&ec->lock, flags);
158 if (!ec->curr || ec->curr->done) 161 if (!ec->curr || (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
159 ret = 1; 162 ret = 1;
160 spin_unlock_irqrestore(&ec->lock, flags); 163 spin_unlock_irqrestore(&ec->lock, flags);
161 return ret; 164 return ret;
162} 165}
163 166
164static void start_transaction(struct acpi_ec *ec)
165{
166 ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
167 ec->curr->done = false;
168 acpi_ec_write_cmd(ec, ec->curr->command);
169}
170
171static void advance_transaction(struct acpi_ec *ec) 167static void advance_transaction(struct acpi_ec *ec)
172{ 168{
173 unsigned long flags;
174 struct transaction *t; 169 struct transaction *t;
175 u8 status; 170 u8 status;
176 171
177 spin_lock_irqsave(&ec->lock, flags);
178 pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); 172 pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK");
179 status = acpi_ec_read_status(ec); 173 status = acpi_ec_read_status(ec);
180 t = ec->curr; 174 t = ec->curr;
181 if (!t) 175 if (!t)
182 goto unlock; 176 goto err;
183 if (t->wlen > t->wi) { 177 if (t->flags & ACPI_EC_COMMAND_POLL) {
184 if ((status & ACPI_EC_FLAG_IBF) == 0) 178 if (t->wlen > t->wi) {
185 acpi_ec_write_data(ec, 179 if ((status & ACPI_EC_FLAG_IBF) == 0)
186 t->wdata[t->wi++]); 180 acpi_ec_write_data(ec, t->wdata[t->wi++]);
187 else 181 else
188 goto err; 182 goto err;
189 } else if (t->rlen > t->ri) { 183 } else if (t->rlen > t->ri) {
190 if ((status & ACPI_EC_FLAG_OBF) == 1) { 184 if ((status & ACPI_EC_FLAG_OBF) == 1) {
191 t->rdata[t->ri++] = acpi_ec_read_data(ec); 185 t->rdata[t->ri++] = acpi_ec_read_data(ec);
192 if (t->rlen == t->ri) 186 if (t->rlen == t->ri)
193 t->done = true; 187 t->flags |= ACPI_EC_COMMAND_COMPLETE;
188 } else
189 goto err;
190 } else if (t->wlen == t->wi &&
191 (status & ACPI_EC_FLAG_IBF) == 0)
192 t->flags |= ACPI_EC_COMMAND_COMPLETE;
193 return;
194 } else {
195 if ((status & ACPI_EC_FLAG_IBF) == 0) {
196 acpi_ec_write_cmd(ec, t->command);
197 t->flags |= ACPI_EC_COMMAND_POLL;
194 } else 198 } else
195 goto err; 199 goto err;
196 } else if (t->wlen == t->wi && 200 return;
197 (status & ACPI_EC_FLAG_IBF) == 0) 201 }
198 t->done = true;
199 goto unlock;
200err: 202err:
201 /* 203 /*
202 * If SCI bit is set, then don't think it's a false IRQ 204 * If SCI bit is set, then don't think it's a false IRQ
203 * otherwise will take a not handled IRQ as a false one. 205 * otherwise will take a not handled IRQ as a false one.
204 */ 206 */
205 if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI)) 207 if (!(status & ACPI_EC_FLAG_SCI)) {
206 ++t->irq_count; 208 if (in_interrupt() && t)
209 ++t->irq_count;
210 }
211}
207 212
208unlock: 213static void start_transaction(struct acpi_ec *ec)
209 spin_unlock_irqrestore(&ec->lock, flags); 214{
215 ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
216 ec->curr->flags = 0;
217 advance_transaction(ec);
210} 218}
211 219
212static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); 220static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
@@ -231,15 +239,17 @@ static int ec_poll(struct acpi_ec *ec)
231 /* don't sleep with disabled interrupts */ 239 /* don't sleep with disabled interrupts */
232 if (EC_FLAGS_MSI || irqs_disabled()) { 240 if (EC_FLAGS_MSI || irqs_disabled()) {
233 udelay(ACPI_EC_MSI_UDELAY); 241 udelay(ACPI_EC_MSI_UDELAY);
234 if (ec_transaction_done(ec)) 242 if (ec_transaction_completed(ec))
235 return 0; 243 return 0;
236 } else { 244 } else {
237 if (wait_event_timeout(ec->wait, 245 if (wait_event_timeout(ec->wait,
238 ec_transaction_done(ec), 246 ec_transaction_completed(ec),
239 msecs_to_jiffies(1))) 247 msecs_to_jiffies(1)))
240 return 0; 248 return 0;
241 } 249 }
250 spin_lock_irqsave(&ec->lock, flags);
242 advance_transaction(ec); 251 advance_transaction(ec);
252 spin_unlock_irqrestore(&ec->lock, flags);
243 } while (time_before(jiffies, delay)); 253 } while (time_before(jiffies, delay));
244 pr_debug("controller reset, restart transaction\n"); 254 pr_debug("controller reset, restart transaction\n");
245 spin_lock_irqsave(&ec->lock, flags); 255 spin_lock_irqsave(&ec->lock, flags);
@@ -637,10 +647,13 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
637static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, 647static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
638 u32 gpe_number, void *data) 648 u32 gpe_number, void *data)
639{ 649{
650 unsigned long flags;
640 struct acpi_ec *ec = data; 651 struct acpi_ec *ec = data;
641 652
653 spin_lock_irqsave(&ec->lock, flags);
642 advance_transaction(ec); 654 advance_transaction(ec);
643 if (ec_transaction_done(ec) && 655 spin_unlock_irqrestore(&ec->lock, flags);
656 if (ec_transaction_completed(ec) &&
644 (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { 657 (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
645 wake_up(&ec->wait); 658 wake_up(&ec->wait);
646 ec_check_sci(ec, acpi_ec_read_status(ec)); 659 ec_check_sci(ec, acpi_ec_read_status(ec));