summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-04-03 13:11:05 -0700
committerChromeBot <chrome-bot@google.com>2013-04-04 16:32:27 -0700
commita3dcfd54ef29ac7cbd988ce94e96bcc6ba924ac6 (patch)
tree89787caadeae884edc7b7fe75810aba39c181f73
parentaf4d0fb2976f5d5e9104366f4c525010cfc7489b (diff)
downloadchrome-ec-a3dcfd54ef29ac7cbd988ce94e96bcc6ba924ac6.tar.gz
Improve deferred function calls
1) Check vs. number of allowable deferred function calls is made at link time. 2) Added a check for whether hook_call_deferred() has been made after the start of calculating the time when the hook task should wake. If it has, go back and recalculate the wake time. This works around a race condition. BUG=chrome-os-partner:18473 BRANCH=none TEST=add a bunch of deferrable functions and recompile; generates a link error Change-Id: Ie833e2a699c47b6702957ed67bf7d3925f2df099 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/47266 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/lm4/config.h3
-rw-r--r--chip/stm32/config.h3
-rw-r--r--common/hooks.c36
-rw-r--r--core/cortex-m/ec.lds.S8
-rw-r--r--core/cortex-m/link_defs.h5
5 files changed, 33 insertions, 22 deletions
diff --git a/chip/lm4/config.h b/chip/lm4/config.h
index b82c74eae7..46a0b125cf 100644
--- a/chip/lm4/config.h
+++ b/chip/lm4/config.h
@@ -18,6 +18,9 @@
/* Interval between HOOK_TICK notifications */
#define HOOK_TICK_INTERVAL (250 * MSEC)
+/* Maximum number of deferrable functions */
+#define DEFERRABLE_MAX_COUNT 8
+
/****************************************************************************/
/* Memory mapping */
diff --git a/chip/stm32/config.h b/chip/stm32/config.h
index 7a2d286e82..989cafa087 100644
--- a/chip/stm32/config.h
+++ b/chip/stm32/config.h
@@ -31,6 +31,9 @@
/* Interval between HOOK_TICK notifications */
#define HOOK_TICK_INTERVAL (500 * MSEC)
+/* Maximum number of deferrable functions */
+#define DEFERRABLE_MAX_COUNT 8
+
/* support programming on-chip flash */
#define CONFIG_FLASH
diff --git a/common/hooks.c b/common/hooks.c
index 6ccfaf56e5..3597a77ea8 100644
--- a/common/hooks.c
+++ b/common/hooks.c
@@ -20,10 +20,7 @@
#define CPRINTF(format, args...)
#endif
-/* Maximum number of deferrable functions */
-#ifndef DEFERRABLE_MAX_COUNT
-#define DEFERRABLE_MAX_COUNT 8
-#endif
+#define DEFERRED_FUNCS_COUNT (__deferred_funcs_end - __deferred_funcs)
struct hook_ptrs {
const struct hook_data *start;
@@ -51,7 +48,7 @@ static const struct hook_ptrs hook_list[] = {
/* Times for deferrable functions */
static uint64_t defer_until[DEFERRABLE_MAX_COUNT];
-static int defer_count;
+static int defer_new_call;
void hook_notify(enum hook_type type)
{
@@ -86,9 +83,6 @@ void hook_notify(enum hook_type type)
void hook_init(void)
{
- defer_count = __deferred_funcs_end - __deferred_funcs;
- ASSERT(defer_count <= DEFERRABLE_MAX_COUNT);
-
hook_notify(HOOK_INIT);
}
@@ -105,20 +99,21 @@ int hook_call_deferred(void (*routine)(void), int us)
if (p >= __deferred_funcs_end)
return EC_ERROR_INVAL; /* Routine not registered */
- /* Convert to index */
i = p - __deferred_funcs;
- if (i >= DEFERRABLE_MAX_COUNT)
- return EC_ERROR_UNKNOWN; /* No space to hold time */
if (us == -1) {
/* Cancel */
defer_until[i] = 0;
} else {
+ /* Set alarm */
+ defer_until[i] = get_time().val + us;
/*
- * Set alarm, and wake task so it can re-sleep for the
- * proper time.
+ * Flag that hook_call_deferred() has been called. If the hook
+ * task is already active, this will allow it to go through the
+ * loop one more time before sleeping.
*/
- defer_until[i] = get_time().val + us;
+ defer_new_call = 1;
+ /* Wake task so it can re-sleep for the proper time */
task_wake(TASK_ID_HOOKS);
}
@@ -137,7 +132,7 @@ void hook_task(void)
int i;
/* Handle deferred routines */
- for (i = 0; i < defer_count; i++) {
+ for (i = 0; i < DEFERRED_FUNCS_COUNT; i++) {
if (defer_until[i] && defer_until[i] < t) {
CPRINTF("[%T hook call deferred 0x%p]\n",
__deferred_funcs[i].routine);
@@ -166,7 +161,8 @@ void hook_task(void)
next = last_tick + HOOK_TICK_INTERVAL - t;
/* Wake earlier if needed by a deferred routine */
- for (i = 0; i < defer_count && next > 0; i++) {
+ defer_new_call = 0;
+ for (i = 0; i < DEFERRED_FUNCS_COUNT && next > 0; i++) {
if (!defer_until[i])
continue;
@@ -176,8 +172,12 @@ void hook_task(void)
next = defer_until[i] - t;
}
- /* Sleep until the next event */
- if (next > 0)
+ /*
+ * If nothing is immediately pending, and hook_call_deferred()
+ * hasn't been called since we started calculating next, sleep
+ * until the next event.
+ */
+ if (next > 0 && !defer_new_call)
task_wait_event(next);
}
}
diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S
index cb0f38f35a..339ee4f435 100644
--- a/core/cortex-m/ec.lds.S
+++ b/core/cortex-m/ec.lds.S
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -122,6 +122,12 @@ SECTIONS
} > FLASH
#endif
__ro_end = . ;
+
+ __deferred_funcs_count =
+ (__deferred_funcs_end - __deferred_funcs) / 4;
+ ASSERT(__deferred_funcs_count <= DEFERRABLE_MAX_COUNT,
+ "Increase DEFERRABLE_MAX_COUNT")
+
.bss : {
/* Stacks must be 64-bit aligned */
. = ALIGN(8);
diff --git a/core/cortex-m/link_defs.h b/core/cortex-m/link_defs.h
index dbf2757b21..f78a7c46c4 100644
--- a/core/cortex-m/link_defs.h
+++ b/core/cortex-m/link_defs.h
@@ -44,9 +44,8 @@ extern const struct hook_data __hooks_second[];
extern const struct hook_data __hooks_second_end[];
/* Deferrable functions */
-static const struct deferred_data __deferred_funcs[];
-static const struct deferred_data __deferred_funcs_end[];
-
+extern const struct deferred_data __deferred_funcs[];
+extern const struct deferred_data __deferred_funcs_end[];
/* Host commands */
extern const struct host_command __hcmds[];