summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-04-04 12:33:03 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-04-05 00:01:29 +0000
commitfe84900c6faa281067212ba6c2c4f564f5d0fe34 (patch)
tree12d51899366925df4da798c66f0317be6270f5d4
parentdfb7ac632baa0b32a2b4422aeb89a7dd14536278 (diff)
downloadchrome-ec-fe84900c6faa281067212ba6c2c4f564f5d0fe34.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: Idd41b2d133267f48f959bca0cf062a18ca6551fb Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/193272 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Benson Leung <bleung@chromium.org> Reviewed-by: Yung-chieh Lo <yjlou@chromium.org>
-rw-r--r--common/keyboard_8042.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/common/keyboard_8042.c b/common/keyboard_8042.c
index 321abfecb9..5460991c22 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.
@@ -899,6 +902,7 @@ static void keyboard_special(uint16_t k)
void keyboard_protocol_task(void)
{
int wait = -1;
+ int retries = 0;
reset_rate_and_delay();
@@ -934,9 +938,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);
@@ -945,6 +968,7 @@ void keyboard_protocol_task(void)
/* Write to host. */
lpc_keyboard_put_char(chr, i8042_irq_enabled);
+ retries = 0;
}
}
}