summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2018-11-29 15:29:46 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-12-06 14:40:45 +0000
commite037caa88266fcec071600952df8d67402e19eeb (patch)
treecc0276d6bbdb4af8ad5c9678df31966ba60059be /chip
parent0bb40e2bdd726fcacdfbf8119a55ca0888bb2750 (diff)
downloadchrome-ec-e037caa88266fcec071600952df8d67402e19eeb.tar.gz
wov: Detect I2S overrun/underrun bursts
This CL adds logic to detect when bursts of I2S overrun/underruns are ocurring. If this condiditon is ocurring then the ISR may consume all of the EC processing power resulint in watchdog events. BRANCH=none BUG=b:116766596 TEST=On Cheza, had BCLK on EC set 2x higher than AP. Without this CL, would consistently trigger watchdog reset. With CL, underrun storm is detected based on console print and watchdog reset no longer occurs. Change-Id: Ia398d5b36525a63d3341bf42fd3f6d12d93d41e0 Signed-off-by: Scott Collyer <scollyer@google.com> Reviewed-on: https://chromium-review.googlesource.com/1356180 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Wai-Hong Tam <waihong@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/1365636 Reviewed-by: Jett Rink <jettrink@chromium.org> Commit-Queue: Jett Rink <jettrink@chromium.org> Tested-by: Jett Rink <jettrink@chromium.org> Trybot-Ready: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r--chip/npcx/wov.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/chip/npcx/wov.c b/chip/npcx/wov.c
index 57302fd01b..94cd8251d2 100644
--- a/chip/npcx/wov.c
+++ b/chip/npcx/wov.c
@@ -173,6 +173,14 @@ static wov_call_back_t callback_fun;
const uint32_t voice_buffer[VOICE_BUF_SIZE] = {0};
+#define WOV_RATE_ERROR_THRESH_MSEC 10
+#define WOV_RATE_ERROR_THRESH 5
+
+static int irq_underrun_count;
+static int irq_overrun_count;
+static uint32_t wov_i2s_underrun_tstamp;
+static uint32_t wov_i2s_overrun_tstamp;
+
#define WOV_CALLBACK(event) \
{ \
if (callback_fun != NULL) \
@@ -536,6 +544,36 @@ static enum ec_error_list wov_set_mic_source_l(void)
return EC_SUCCESS;
}
+static void wov_over_under_deferred(void)
+{
+ CPRINTS("wov: Under/Over run error: under = %d, over = %d",
+ irq_underrun_count, irq_overrun_count);
+}
+DECLARE_DEFERRED(wov_over_under_deferred);
+
+static void wov_under_over_error_handler(int *count, uint32_t *last_time)
+{
+ uint32_t time_delta_msec;
+ uint32_t current_time = get_time().le.lo;
+
+ if (!(*count)) {
+ *last_time = current_time;
+ (*count)++;
+ } else {
+ time_delta_msec = (current_time - *last_time) / MSEC;
+ *last_time = current_time;
+ if (time_delta_msec < WOV_RATE_ERROR_THRESH_MSEC)
+ (*count)++;
+ else
+ *count = 0;
+
+ if (*count >= WOV_RATE_ERROR_THRESH) {
+ wov_stop_i2s_capture();
+ hook_call_deferred(&wov_over_under_deferred_data, 0);
+ }
+ }
+}
+
/**
* WoV interrupt handler.
*
@@ -586,12 +624,16 @@ void wov_interrupt_handler(void)
/* I2S FIFO is overrun. Reset the I2S FIFO and inform the FW. */
if (WOV_IS_I2S_FIFO_OVERRUN(wov_status)) {
WOV_CALLBACK(WOV_EVENT_ERROR_I2S_FIFO_OVERRUN);
+ wov_under_over_error_handler(&irq_overrun_count,
+ &wov_i2s_overrun_tstamp);
wov_i2s_fifo_reset();
}
/* I2S FIFO is underrun. Reset the I2S FIFO and inform the FW. */
if (WOV_IS_I2S_FIFO_UNDERRUN(wov_status)) {
WOV_CALLBACK(WOV_EVENT_ERROR_I2S_FIFO_UNDERRUN);
+ wov_under_over_error_handler(&irq_underrun_count,
+ &wov_i2s_underrun_tstamp);
wov_i2s_fifo_reset();
}
@@ -1166,6 +1208,10 @@ void wov_i2s_fifo_reset(void)
*/
void wov_start_i2s_capture(void)
{
+ /* Clear counters used to track for underrun/overrun errors */
+ irq_underrun_count = 0;
+ irq_overrun_count = 0;
+
/* Clear the I2S status bits in WoV status register. */
SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, 0x18);