diff options
author | Randall Spangler <rspangler@chromium.org> | 2014-04-04 12:33:03 -0700 |
---|---|---|
committer | Shawn Nematbakhsh <shawnn@chromium.org> | 2014-04-05 22:18:14 +0000 |
commit | c19d5b53c761ab12e59ab3d4f3644d9ba41103c9 (patch) | |
tree | 514561993c52b166a6ca56004daceecde2bed788 | |
parent | e86c3185cc5249044698a846976ce33128051b68 (diff) | |
download | chrome-ec-c19d5b53c761ab12e59ab3d4f3644d9ba41103c9.tar.gz |
Retry 8042 keyboard interrupts if host isn't responding
If the host somehow fails to see an edge on the keyboard IRQ line, it
won't read the 8042 data register. The EC won't ever send another
IRQ, because it only does so after filling the register. So the
keyboard will hang.
Work around this with a retry mechanism. If the AP hasn't responded
after 3 additional keyboard events, generate another IRQ. So a stuck
key will get unstuck if you tap it a few times. That's reasonable,
and matches what people do already if they have a sticky key due to
crud accumulating in the keyboard.
I've tested this when the system is booted to the OS. I don't see any
additional IRQs generated on the EC console ("KB extra IRQ"), so the
host is keeping up with the keyboard input stream.
If I'm in dev or recovery mode and bang on the keyboard right after
powering the system on (when the BIOS isn't yet paying attention to
the keyboard), I can see extra IRQs generated. This shows the retry
mechanism is working. The extra IRQs have no negative effect on the
boot process, and the keyboard works normally when the OS does
eventually boot.
BUG=chrome-os-partner:27222
BRANCH=rambi
TEST=Bang on the keyboard like a monkey. Keyboard should still work.
Change-Id: I6faff3f42f541d5f8d939a8ae7ba1c9867812ae6
Original-Change-Id: Idd41b2d133267f48f959bca0cf062a18ca6551fb
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/193363
Reviewed-by: Shawn Nematbakhsh <shawnn@chromium.org>
Commit-Queue: Shawn Nematbakhsh <shawnn@chromium.org>
Tested-by: Shawn Nematbakhsh <shawnn@chromium.org>
-rw-r--r-- | common/keyboard_8042.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/common/keyboard_8042.c b/common/keyboard_8042.c index 78a20dc479..0d8192b166 100644 --- a/common/keyboard_8042.c +++ b/common/keyboard_8042.c @@ -59,6 +59,9 @@ enum scancode_set_list { #define MAX_SCAN_CODE_LEN 4 +/* Number of bytes host can get behind before we start generating extra IRQs */ +#define KB_TO_HOST_RETRIES 3 + /* * Mutex to control write access to the to-host buffer head. Don't need to * mutex the tail because reads are only done in one place. @@ -891,6 +894,7 @@ static void keyboard_special(uint16_t k) void keyboard_protocol_task(void) { int wait = -1; + int retries = 0; reset_rate_and_delay(); @@ -926,9 +930,28 @@ void keyboard_protocol_task(void) if (queue_is_empty(&to_host)) break; - /* Host interface must have space */ - if (lpc_keyboard_has_char()) + /* Handle data waiting for host */ + if (lpc_keyboard_has_char()) { + /* If interrupts disabled, nothing we can do */ + if (!i8042_irq_enabled) + break; + + /* Give the host a little longer to respond */ + if (++retries < KB_TO_HOST_RETRIES) + break; + + /* + * We keep getting data, but the host keeps + * ignoring us. Fine, we're done waiting. + * Hey, host, are you ever gonna get to this + * data? Send it another interrupt in case it + * somehow missed the first one. + */ + CPRINTF("[%T KB extra IRQ]\n"); + lpc_keyboard_resume_irq(); + retries = 0; break; + } /* Get a char from buffer. */ kblog_put('k', to_host.head); @@ -937,6 +960,7 @@ void keyboard_protocol_task(void) /* Write to host. */ lpc_keyboard_put_char(chr, i8042_irq_enabled); + retries = 0; } } } |