summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-04-04 12:33:03 -0700
committerShawn Nematbakhsh <shawnn@chromium.org>2014-04-05 22:18:14 +0000
commitc19d5b53c761ab12e59ab3d4f3644d9ba41103c9 (patch)
tree514561993c52b166a6ca56004daceecde2bed788
parente86c3185cc5249044698a846976ce33128051b68 (diff)
downloadchrome-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.c28
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;
}
}
}