[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