[coreboot-gerrit] New patch to review for coreboot: 38e17f2 boot state: add notion of blocking transitions
Aaron Durbin (adurbin@google.com)
gerrit at coreboot.org
Fri May 3 23:27:04 CEST 2013
Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3191
-gerrit
commit 38e17f27794e25e517a7df798c05b9a8c582b97d
Author: Aaron Durbin <adurbin at chromium.org>
Date: Fri May 3 12:53:22 2013 -0500
boot state: add notion of blocking transitions
There are 3 phases of a state: entry, running, and exit.
During the entry and exit phases callbacks can be run. In order to
prevent states from transitioning the introduction of a completion
deadline is made. As the callbacks are currently called synchronously
by the main thread the result is a nop in comparison to not having
completion deadlines for callbacks.
Change-Id: I188b262873df4469163000c979293c442e21cb31
Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
src/include/bootstate.h | 74 +++++++++++++++++++++++++++++++++++++++++++------
src/lib/hardwaremain.c | 67 ++++++++++++++++++++++++++++++++++++++------
2 files changed, 123 insertions(+), 18 deletions(-)
diff --git a/src/include/bootstate.h b/src/include/bootstate.h
index f732d1e..bfb3481 100644
--- a/src/include/bootstate.h
+++ b/src/include/bootstate.h
@@ -110,11 +110,27 @@ typedef enum {
BS_ON_EXIT
} boot_state_sequence_t;
+/* The boot_state_completion sturcture is used inernally to the state machine
+ * to indicate that a call back needs to complete by the provided sequence
+ * in the boot state machine. */
+struct boot_state_completion {
+ boot_state_t state;
+ boot_state_sequence_t when;
+};
+
+/* The BS_RAMSTAGE_EXIT is a special purpose encoding of a state to indicate
+ * when a callback should be completed. The completion state of
+ * BS_RAMSTAGE_EXIT indicates that a callback needs to be completed prior
+ * to leaving ramstage. i.e. BS_OS_RESUME and BS_PAYLOAD_BOOT. */
+#define BS_RAMSTAGE_EXIT -1
+
struct boot_state_callback {
void *arg;
void (*callback)(void *arg);
- /* For use internal to the boot state machine. */
+ /* Everything below this comment should be considered private and
+ * controlled by the boot state machine. */
struct boot_state_callback *next;
+ struct boot_state_completion deadline;
#if BOOT_STATE_DEBUG
const char *location;
#endif
@@ -130,14 +146,18 @@ struct boot_state_callback {
#define INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_)
#endif
-#define BOOT_STATE_CALLBACK_INIT(func_, arg_) \
- { \
- .arg = arg_, \
- .callback = func_, \
- .next = NULL, \
- BOOT_STATE_CALLBACK_INIT_DEBUG \
+#define BOOT_STATE_CALLBACK_INIT_DEADLINE(func_, arg_, state_, seq_) \
+ { \
+ .arg = arg_, \
+ .callback = func_, \
+ .next = NULL, \
+ .deadline = { state_, seq_ }, \
+ BOOT_STATE_CALLBACK_INIT_DEBUG \
}
+#define BOOT_STATE_CALLBACK_INIT(func_, arg_) \
+ BOOT_STATE_CALLBACK_INIT_DEADLINE(func_, arg_, -2, -2)
+
#define BOOT_STATE_CALLBACK(name_, func_, arg_) \
struct boot_state_callback name_ = BOOT_STATE_CALLBACK_INIT(func_, arg_)
@@ -147,6 +167,32 @@ struct boot_state_callback {
bscb_->callback = func_; \
bscb_->arg = arg_
+/* The boot_state_complete_by_(entry|exit) functions can be called on
+ * a boot state callback prior to being scheduled. The completion deadline
+ * is just like the start state and sequence. The boot state machine will
+ * not proceed past the state until the callback is complete. */
+static inline void
+boot_state_complete_by_entry(struct boot_state_callback *bscb,
+ boot_state_t state)
+{
+ bscb->deadline.state = state;
+ bscb->deadline.when = BS_ON_ENTRY;
+}
+
+static inline void
+boot_state_complete_by_exit(struct boot_state_callback *bscb,
+ boot_state_t state)
+{
+ bscb->deadline.state = state;
+ bscb->deadline.when = BS_ON_EXIT;
+}
+
+static inline void
+boot_state_complete_by_ramstage_exit(struct boot_state_callback *bscb)
+{
+ bscb->deadline.state = BS_RAMSTAGE_EXIT;
+}
+
/* The following 2 functions schedule a callback to be called on entry/exit
* to a given state. Note that thare are no ordering guarantees between the
* individual callbacks on a given state. 0 is returned on success < 0 on
@@ -173,11 +219,21 @@ struct boot_state_init_entry {
#define BOOT_STATE_INIT_ENTRIES(name_) \
static struct boot_state_init_entry name_[] BOOT_STATE_INIT_ATTR
-#define BOOT_STATE_INIT_ENTRY(state_, when_, func_, arg_) \
+#define BOOT_STATE_INIT_ENTRY_DEADLINE(state_, when_, func_, arg_, end_state_, end_when_) \
{ \
.state = state_, \
.when = when_, \
- .bscb = BOOT_STATE_CALLBACK_INIT(func_, arg_), \
+ .bscb = BOOT_STATE_CALLBACK_INIT_DEADLINE(func_, arg_, end_state_, end_when_), \
}
+/* By default the callback needs to run to completion at the same step the
+ * callback is called. */
+#define BOOT_STATE_INIT_ENTRY(state_, when_, func_, arg_) \
+ BOOT_STATE_INIT_ENTRY_DEADLINE(state_, when_, func_, arg_,\
+ state_, when_)
+
+#define BOOT_STATE_INIT_ENTRY_RAMSTAGE_EXIT(state_, when_, func_, arg_) \
+ BOOT_STATE_INIT_ENTRY_DEADLINE(state_, when_, func_, arg_, \
+ BS_RAMSTAGE_EXIT, 0)
+
#endif /* BOOTSTATE_H */
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index 8e5481e..a4d2fc9 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -72,10 +72,12 @@ struct boot_state_times {
struct mono_time samples[MAX_TIME_SAMPLES];
};
+
struct boot_state {
const char *name;
boot_state_t id;
struct boot_state_callback *seq_callbacks[2];
+ int seq_blocked[2];
boot_state_t (*run_state)(void *arg);
void *arg;
int complete : 1;
@@ -90,6 +92,7 @@ struct boot_state {
.name = #state_, \
.id = state_, \
.seq_callbacks = { NULL, NULL }, \
+ .seq_blocked = { 0, 0 }, \
.run_state = run_func_, \
.arg = NULL, \
.complete = 0, \
@@ -296,22 +299,41 @@ static void bs_run_timers(int drain)
static void bs_run_timers(int drain) {}
#endif
+static void bs_call_callback(struct boot_state_callback *bscb)
+{
+ bscb->callback(bscb->arg);
+
+ if (bscb->deadline.state == BS_RAMSTAGE_EXIT) {
+ boot_states[BS_OS_RESUME].seq_blocked[BS_ON_ENTRY]--;
+ boot_states[BS_PAYLOAD_BOOT].seq_blocked[BS_ON_ENTRY]--;
+ return;
+ }
+ boot_states[bscb->deadline.state].seq_blocked[bscb->deadline.when]--;
+}
+
static void bs_call_callbacks(struct boot_state *state,
boot_state_sequence_t seq)
{
- while (state->seq_callbacks[seq] != NULL) {
- struct boot_state_callback *bscb;
+ while (state->seq_blocked[seq] != 0) {
+ if (state->seq_callbacks[seq] != NULL) {
+ struct boot_state_callback *bscb;
- /* Remove the first callback. */
- bscb = state->seq_callbacks[seq];
- state->seq_callbacks[seq] = bscb->next;
- bscb->next = NULL;
+ /* Remove the first callback. */
+ bscb = state->seq_callbacks[seq];
+ state->seq_callbacks[seq] = bscb->next;
+ bscb->next = NULL;
#if BOOT_STATE_DEBUG
- printk(BS_DEBUG_LVL, "BS: callback (%p) @ %s.\n",
- bscb, bscb->location);
+ printk(BS_DEBUG_LVL, "BS: callback (%p) @ %s.\n",
+ bscb, bscb->location);
#endif
- bscb->callback(bscb->arg);
+ bs_call_callback(bscb);
+ continue;
+ }
+
+ /* Run the timers to make forward progress if a timeout callback
+ * is blocking this state transition. */
+ bs_run_timers(0);
}
}
@@ -355,6 +377,31 @@ static void bs_walk_state_machine(boot_state_t current_state_id)
}
}
+static void boot_state_sched_completion(struct boot_state *start_state,
+ struct boot_state_callback *bscb,
+ boot_state_sequence_t seq)
+{
+ if (bscb->deadline.state == BS_RAMSTAGE_EXIT) {
+ boot_states[BS_OS_RESUME].seq_blocked[BS_ON_ENTRY]++;
+ boot_states[BS_PAYLOAD_BOOT].seq_blocked[BS_ON_ENTRY]++;
+ return;
+ }
+
+ /* Handle unitialized completion deadline or a completion deadline
+ * for a state beforeteh current scheduled one. In both cases the
+ * deadline is the start state and sequence. */
+ if (bscb->deadline.state < start_state->id ||
+ (bscb->deadline.state == start_state->id &&
+ bscb->deadline.when < seq)) {
+ bscb->deadline.state = start_state->id;
+ bscb->deadline.when = seq;
+ start_state->seq_blocked[seq]++;
+ return;
+ }
+
+ boot_states[bscb->deadline.state].seq_blocked[bscb->deadline.when]++;
+}
+
static int boot_state_sched_callback(struct boot_state *state,
struct boot_state_callback *bscb,
boot_state_sequence_t seq)
@@ -370,6 +417,8 @@ static int boot_state_sched_callback(struct boot_state *state,
bscb->next = state->seq_callbacks[seq];
state->seq_callbacks[seq] = bscb;
+ boot_state_sched_completion(state, bscb, seq);
+
return 0;
}
More information about the coreboot-gerrit
mailing list