All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/3] Initialisation Sequence Framework
@ 2012-04-22 15:23 Graeme Russ
  2012-04-22 15:23 ` [U-Boot] [PATCH 1/3] init_func: Add fundamental framework Graeme Russ
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Graeme Russ @ 2012-04-22 15:23 UTC (permalink / raw)
  To: u-boot

Well here it is (finally) - My Initialisation Sequence Framework

This series is limited to x86 and is controlled by CONFIG_INIT_FUNC so
no other arch should be effected. I don't have any cross compilers, so I
would appreciate if others could confirm the zero impact assertion

Asbestos suit on

Fire away ;)

Regards,

Graeme

Graeme Russ (3):
  init_func: Add fundamental framework
  init_func: Add x86 support
  init_func: Use for eNET board

 Makefile                         |   34 +-
 arch/x86/cpu/cpu.c               |    3 +
 arch/x86/cpu/sc520/sc520_sdram.c |    3 +
 arch/x86/cpu/sc520/sc520_timer.c |    2 +
 arch/x86/cpu/u-boot.lds          |   23 +
 arch/x86/lib/board.c             |   10 +-
 arch/x86/lib/init_helpers.c      |   14 +
 arch/x86/lib/init_wrappers.c     |   11 +-
 arch/x86/lib/pcat_interrupts.c   |    2 +
 arch/x86/lib/relocate.c          |    4 +
 board/eNET/eNET.c                |    5 +
 common/Makefile                  |    2 +
 common/console.c                 |    3 +
 common/env_dataflash.c           |    1 +
 common/env_eeprom.c              |    1 +
 common/env_fat.c                 |    1 +
 common/env_flash.c               |    2 +
 common/env_mgdisk.c              |    1 +
 common/env_mmc.c                 |    1 +
 common/env_nand.c                |    1 +
 common/env_nowhere.c             |    1 +
 common/env_nvram.c               |    1 +
 common/env_onenand.c             |    1 +
 common/env_sf.c                  |    1 +
 common/serial.c                  |    2 +
 common/stdio.c                   |    2 +
 config.mk                        |    2 +
 doc/README.INIT_FUNC             |   65 ++
 include/configs/eNET.h           |    1 +
 include/init_func.h              |   37 +
 tools/Makefile                   |    6 +
 tools/mkinitseq.c                | 1512 ++++++++++++++++++++++++++++++++++++++
 32 files changed, 1746 insertions(+), 9 deletions(-)
 create mode 100644 doc/README.INIT_FUNC
 create mode 100644 include/init_func.h
 create mode 100644 tools/mkinitseq.c

-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-04-22 15:23 [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Graeme Russ
@ 2012-04-22 15:23 ` Graeme Russ
  2012-05-03  0:08   ` Marek Vasut
  2012-04-22 15:23 ` [U-Boot] [PATCH 2/3] init_func: Add x86 support Graeme Russ
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Graeme Russ @ 2012-04-22 15:23 UTC (permalink / raw)
  To: u-boot


Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
 Makefile             |   34 ++-
 common/Makefile      |    2 +
 config.mk            |    2 +
 doc/README.INIT_FUNC |   65 +++
 include/init_func.h  |   37 ++
 tools/Makefile       |    6 +
 tools/mkinitseq.c    | 1512 ++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 1657 insertions(+), 1 deletions(-)
 create mode 100644 doc/README.INIT_FUNC
 create mode 100644 include/init_func.h
 create mode 100644 tools/mkinitseq.c

diff --git a/Makefile b/Makefile
index cdd4294..62d9f81 100644
--- a/Makefile
+++ b/Makefile
@@ -467,8 +467,40 @@ GEN_UBOOT = \
 			-Map u-boot.map -o u-boot
 endif
 
+ifeq ($(CONFIG_INIT_FUNC),y)
+INIT_SEQ = $(obj)init_seq.o
+
+GEN_UBOOT_INIT = \
+		UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
+		sed  -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
+		cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $$UNDEF_SYM $(__OBJS) \
+			--start-group $(__LIBS) --end-group \
+			-Map u-boot-init.map -o u-boot-init
+
+$(obj)u-boot-init.lds: $(LDSCRIPT)
+		$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -DMAKE_INIT_LDS -P - <$^ >$@
+
+$(obj)u-boot-init:	depend \
+		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(obj)u-boot-init.lds
+		$(GEN_UBOOT_INIT)
+
+$(obj)u-boot-init.bin:	$(obj)u-boot-init
+		$(OBJCOPY) -j .initfuncs -O binary $< $@
+
+$(obj)init_seq.c:	depend \
+		$(obj)u-boot-init.bin
+		$(obj)tools/mkinitseq $(obj)u-boot-init.bin $(obj)common/init_seq.c
+
+$(obj)init_seq.o:	depend \
+		$(obj)init_seq.c
+		$(MAKE) BUILD_INIT_SEQ=y -C common all
+else
+INIT_SEQ =
+endif
+
 $(obj)u-boot:	depend \
-		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
+		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) \
+		$(INIT_SEQ) $(obj)u-boot.lds
 		$(GEN_UBOOT)
 ifeq ($(CONFIG_KALLSYMS),y)
 		smap=`$(call SYSTEM_MAP,u-boot) | \
diff --git a/common/Makefile b/common/Makefile
index d9f10f3..02a4485 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -195,6 +195,8 @@ COBJS-y += dlmalloc.o
 COBJS-y += memsize.o
 COBJS-y += stdio.o
 
+# initialisation sequence (second build stage)
+COBJS-$(BUILD_INIT_SEQ) += init_seq.o
 
 COBJS	:= $(sort $(COBJS-y))
 XCOBJS	:= $(sort $(XCOBJS-y))
diff --git a/config.mk b/config.mk
index fa33e62..2124b84 100644
--- a/config.mk
+++ b/config.mk
@@ -257,6 +257,8 @@ ifneq ($(CONFIG_SYS_TEXT_BASE),)
 LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
 endif
 
+LDFLAGS_u-boot-init += -T $(obj)u-boot-init.lds $(LDFLAGS_FINAL)
+
 LDFLAGS_u-boot-spl += -T $(obj)u-boot-spl.lds $(LDFLAGS_FINAL)
 ifneq ($(CONFIG_SPL_TEXT_BASE),)
 LDFLAGS_u-boot-spl += -Ttext $(CONFIG_SPL_TEXT_BASE)
diff --git a/doc/README.INIT_FUNC b/doc/README.INIT_FUNC
new file mode 100644
index 0000000..f9a0b18
--- /dev/null
+++ b/doc/README.INIT_FUNC
@@ -0,0 +1,65 @@
+The INIT_FUNC macro allows initialisation functions (i.e. functions which are
+executed before the main loop) to be easily added to the init sequence
+
+
+Specifying an Initialisation Function and is Dependencies
+---------------------------------------------------------
+The format of the INIT_FUNC macro is:
+
+INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
+
+fn is the name of the init function to call. This function must have the
+following prototype:
+
+int foo(void);
+
+Each init function must return 0 to indicate success - any other return value
+indicates failure and the init sequence will stop
+
+grp is the name of the group that the init function belongs to. grp may be
+the same as fn for any individual init function, but between init functions,
+fn and grp must be unique.
+
+The purpose of groups is to allow functions to be grouped together so other
+functions can specify the group as a whole as a dependency rather than having
+to list every function in the group in the dependency list
+
+man_reqs is a space seperated list of functions or groups that MUST exist and
+MUST run BEFORE fn
+
+pre_reqs is a space seperated list of functions or groups that MAY exist and
+(if they do) MUST run BEFORE fn
+
+pst_reqs is a space seperated list of functions or groups that MAY exist and
+(if they do) MUST run AFTER fn
+
+Skipping or Replacing a Function or Group
+-----------------------------------------
+Occassionally, a board may provide a completely seperate implementation for
+an initialisation function that is provided in the common arch, SoC or
+common code.
+
+SKIP_INIT(fn_or_group)
+
+After the initialisation function dependencies are calculated, all functions
+and groups listed in any SKIP_INITs are removed - This may result in
+dependent functions being removed - It is up to the board code developer
+to ensure suitable replacements are in place
+
+REPLACE_INIT(old_fn_or_group, new_fn_or_group)
+
+Like SKIP_INIT but replaces on function with another (or one group with
+another)
+
+Example: In the SoC code yoy may have
+
+INIT_FUNC(init_cpu_f, RESET, , , );
+
+In the board code, you may want a slightly tweaked version, so you might
+have:
+
+int my_new_init_cpu_f(void)
+{
+	...
+}
+REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
diff --git a/include/init_func.h b/include/init_func.h
new file mode 100644
index 0000000..e4366b8
--- /dev/null
+++ b/include/init_func.h
@@ -0,0 +1,37 @@
+#ifndef __INIT_FUNC_H__
+#define __INIT_FUNC_H__
+
+/*
+ * The requirements for any new initalization function is simple: it is
+ * a function with no parameters which returns an integer return code,
+ * where 0 means "continue" and != 0 means "fatal error, hang the system"
+ */
+typedef int (init_fnc_t) (void);
+
+extern init_fnc_t *init_sequence_f[];
+extern init_fnc_t *init_sequence_f_r[];
+extern init_fnc_t *init_sequence_r[];
+
+#ifdef CONFIG_INIT_FUNC
+#include <linux/compiler.h>
+
+#define INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs) \
+	static const char __init_func_ ## fn[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"(f:" #fn ":" #grp ":" #man_reqs " | " #pre_reqs " | " #pst_reqs ")\n";
+
+#define SKIP_INIT(fn_or_group) \
+	static const char __skip_init_ ## fn_or_group[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"(s:" #fn_or_group ")\n";
+
+#define REPLACE_INIT(old_fn_or_group, new_fn_or_group) \
+	static const char __replace_init_ ## old_fn_or_group[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"(r:" #old_fn_or_group ":" #new_fn_or_group ")\n";
+#else
+#define INIT_FUNC(fn, group, man_reqs, pre_reqs, post_reqs)
+#define SKIP_INIT(fn_or_group)
+#define REPLACE_INIT(old_fn_or_group, new_fn_or_group)
+#endif
+#endif /* !__INIT_FUNC_H__ */
diff --git a/tools/Makefile b/tools/Makefile
index 8993fdd..e6ba6ef 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -68,6 +68,7 @@ BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
 BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
 BIN_FILES-y += mkenvimage$(SFX)
 BIN_FILES-y += mkimage$(SFX)
+BIN_FILES-$(CONFIG_INIT_FUNC) += mkinitseq$(SFX)
 BIN_FILES-$(CONFIG_SMDK5250) += mksmdk5250spl$(SFX)
 BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
 BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
@@ -95,6 +96,7 @@ NOPED_OBJ_FILES-y += imximage.o
 NOPED_OBJ_FILES-y += omapimage.o
 NOPED_OBJ_FILES-y += mkenvimage.o
 NOPED_OBJ_FILES-y += mkimage.o
+NOPED_OBJ_FILES-$(CONFIG_INIT_FUNC) += mkinitseq.o
 OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
 OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
 OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
@@ -215,6 +217,10 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
 
+$(obj)mkinitseq$(SFX):	$(obj)mkinitseq.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
 $(obj)mk$(BOARD)spl$(SFX):	$(obj)mkexynosspl.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
new file mode 100644
index 0000000..b150de4
--- /dev/null
+++ b/tools/mkinitseq.c
@@ -0,0 +1,1512 @@
+/*
+ * (C) Copyright 2012
+ * Graeme Russ <graeme.russ@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <version.h>
+
+struct func_def {
+	struct list_head list;
+	char *name;
+};
+
+struct init_def {
+	struct list_head list;
+
+	char *function;
+	char *group;
+
+	int cyclic_checked;
+
+	struct list_head mandatory_deps;
+	struct list_head pre_deps;
+	struct list_head post_deps;
+};
+
+struct skip_def {
+	struct list_head list;
+	char *name;
+};
+
+struct replace_def {
+	struct list_head list;
+	char *old_name;
+	char *new_name;
+};
+
+
+struct init_group {
+	struct list_head list;
+
+	char *name;
+
+	struct list_head functions;
+};
+
+struct list_head init_defs;
+struct list_head skip_defs;
+struct list_head replace_defs;
+
+struct list_head mandatory_functions;
+struct list_head init_groups;
+
+struct list_head init_sequence;
+
+/* These are the initialisation sequence placeholders */
+static const char default_init_reset[] = "f:RESET:RESET: |  | SDRAM";
+static const char default_init_sdram[] = "f:SDRAM:SDRAM: RESET |  | RELOC";
+static const char default_init_reloc[] = "f:RELOC:RELOC: SDRAM |  | ";
+
+static void free_function_list(struct list_head *function_list)
+{
+	struct func_def *tmp;
+
+	while (!list_empty(function_list)) {
+
+		tmp = list_first_entry(function_list, struct func_def, list);
+
+		free(tmp->name);
+		list_del(&tmp->list);
+	}
+}
+
+static int function_exists(const char *function)
+{
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	list_for_each(init_def_pos , &init_defs) {
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (!strcmp(init_def->function, function))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int check_for_empty_groups(void)
+{
+	int err = 0;
+	struct list_head *group_pos;
+	struct init_group *init_group;
+
+	/* Look for an existing group */
+	list_for_each(group_pos, &init_groups)
+	{
+		init_group = list_entry(group_pos, struct init_group, list);
+
+		if (list_empty(&init_group->functions)) {
+			fprintf(stderr,
+				"Empty init group '%s'\n",
+				init_group->name);
+			err = 1;
+		}
+	}
+
+	return err;
+}
+
+static struct init_def *pop_first_independent_function(void)
+{
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (list_empty(&init_def->pre_deps)) {
+			list_del(init_def_pos);
+			return init_def;
+		}
+	}
+
+	return NULL;
+}
+
+static int find_or_create_group(const char *group,
+				struct init_group **init_group)
+{
+	struct list_head *group_pos;
+
+	/* Look for an existing group */
+	list_for_each(group_pos, &init_groups)
+	{
+		*init_group = list_entry(group_pos, struct init_group, list);
+
+		if (!strcmp((*init_group)->name, group))
+			return 0;
+	}
+
+	/* No existing group found - Create a new group */
+	*init_group = malloc(sizeof(struct init_group));
+
+	if (!(*init_group))
+		return -ENOMEM;
+
+	(*init_group)->name = strdup(group);
+
+	if (!(*init_group)->name) {
+		free(*init_group);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&(*init_group)->functions);
+	list_add(&(*init_group)->list, &init_groups);
+
+	return 0;
+}
+
+static int add_function_to_group(const char *function,
+				 const char *group)
+{
+	int err;
+	struct init_group *init_group;
+	struct func_def *func_def;
+
+	if (!strcmp(group, ""))
+		return 0;
+
+	err = find_or_create_group(group, &init_group);
+	if (err)
+		return err;
+
+	/* Add the function to the group */
+	func_def = malloc(sizeof(struct func_def));
+
+	if (!func_def)
+		return -ENOMEM;
+
+	func_def->name = strdup(function);
+
+	if (!func_def->name) {
+		free(func_def);
+		return -ENOMEM;
+	}
+
+	list_add(&func_def->list, &init_group->functions);
+
+	return 0;
+}
+
+static void delete_group(const char *group)
+{
+	struct list_head *init_group_pos;
+	struct list_head *q;
+	struct init_group *init_group;
+
+
+	list_for_each_safe(init_group_pos, q, &init_groups) {
+		init_group = list_entry(init_group_pos,
+					struct init_group,
+					list);
+
+		if (!strcmp(init_group->name, group)) {
+			free(init_group->name);
+			free_function_list(&init_group->functions);
+
+			list_del(init_group_pos);
+
+			free(init_group);
+		}
+	}
+
+}
+
+static void delete_dep_from_init_defs(const char *dep)
+{
+	struct list_head *init_def_pos;
+	struct list_head *func_def_pos;
+	struct init_def *init_def;
+	struct func_def *func_def;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos,
+				      struct init_def,
+				      list);
+
+		list_for_each(func_def_pos , &init_def->pre_deps)
+		{
+			func_def = list_entry(func_def_pos,
+					      struct func_def,
+					      list);
+
+			if (!strcmp(func_def->name, dep)) {
+				free(func_def->name);
+				list_del(func_def_pos);
+				free(func_def);
+				break;
+			}
+		}
+
+	}
+}
+
+
+static int add_mandatory_function(const char *name)
+{
+	struct list_head *position;
+	struct func_def *func_def;
+
+	list_for_each(position, &mandatory_functions)
+	{
+		func_def = list_entry(position, struct func_def, list);
+
+		if (!strcmp(func_def->name, name))
+			return 0;
+	}
+
+	func_def = malloc(sizeof(struct func_def));
+
+	if (!func_def)
+		return -ENOMEM;
+
+	func_def->name = strdup(name);
+
+	if (!func_def->name) {
+		free(func_def);
+		return -ENOMEM;
+	}
+
+	list_add(&func_def->list, &mandatory_functions);
+
+	return 0;
+}
+
+static int process_dep_list(struct list_head *dep_list,
+			    char *deps,
+			    int mandatory)
+{
+	int err = 0;
+	struct func_def *func_def;
+	char *save_ptr;
+
+	char *dep_function;
+
+	dep_function = strtok_r(deps, " \t", &save_ptr);
+
+	while (dep_function) {
+		func_def = malloc(sizeof(struct func_def));
+
+		if (!func_def)
+			return -ENOMEM;
+
+		func_def->name = strdup(dep_function);
+
+		if (!func_def->name) {
+			free(func_def);
+			return -ENOMEM;
+		}
+
+		list_add(&func_def->list, dep_list);
+
+		if (mandatory)
+			if (add_mandatory_function(dep_function))
+				err = 1;
+
+		dep_function = strtok_r(NULL, " ", &save_ptr);
+	};
+
+	return err;
+}
+
+static int process_init_info(struct init_def *init_def,
+			     char *deps)
+{
+	char *mandatory_deps;
+	char *pre_deps;
+	char *post_deps;
+	char *save_ptr;
+
+	INIT_LIST_HEAD(&init_def->mandatory_deps);
+	INIT_LIST_HEAD(&init_def->pre_deps);
+	INIT_LIST_HEAD(&init_def->post_deps);
+
+	mandatory_deps = strtok_r(deps, "|", &save_ptr);
+	pre_deps = strtok_r(NULL, "|", &save_ptr);
+	post_deps = strtok_r(NULL, "|", &save_ptr);
+
+	process_dep_list(&init_def->mandatory_deps, mandatory_deps, 1);
+	process_dep_list(&init_def->pre_deps, pre_deps, 0);
+	process_dep_list(&init_def->post_deps, post_deps, 0);
+
+	return 0;
+}
+
+static int check_for_duplicates(const char *function,
+				const char *group)
+{
+	struct list_head *position;
+	struct init_def *init_def;
+
+	list_for_each(position , &init_defs)
+	{
+		init_def = list_entry(position, struct init_def, list);
+
+		if (!strcmp(function, init_def->function)) {
+			fprintf(stderr,
+				"Duplicate function name '%s'\n",
+				function);
+
+			return -EEXIST;
+		}
+
+		if (!strcmp(function, init_def->group)) {
+			fprintf(stderr,
+				"Function '%s' matches an existing group\n",
+				function);
+
+			return -EEXIST;
+		}
+
+		if (!strcmp(group, init_def->function)) {
+			fprintf(stderr,
+				"Group '%s' matches an existing function\n",
+				function);
+
+			return -EEXIST;
+		}
+	}
+
+	return 0;
+}
+
+static int add_to_init_list(const char *function,
+			    const char *group,
+			    char *deps)
+{
+	int err;
+	struct init_def *init_def;
+
+	/* Check that the function is not already included */
+	err = check_for_duplicates(function, group);
+
+	if (err)
+		return err;
+
+	/* Create a list node for the new init function */
+	init_def = malloc(sizeof(struct init_def));
+
+	if (!init_def)
+		return -ENOMEM;
+
+	init_def->function = strdup(function);
+	init_def->group = strdup(group);
+	init_def->cyclic_checked = 0;
+
+	if ((!init_def->function) ||
+	    (!init_def->group)) {
+		free(init_def->function);
+		free(init_def->group);
+		free(init_def);
+		return -ENOMEM;
+	}
+
+	/* Add the new function to the init function list */
+	list_add(&init_def->list, &init_defs);
+
+	/* Process the new functions dependencies */
+	err = process_init_info(init_def, deps);
+
+	if (err)
+		return err;
+
+	return add_function_to_group(function, group);
+}
+
+static int add_to_skip_list(const char *function_name)
+{
+	struct list_head *skip_pos;
+	struct list_head *replace_pos;
+
+	struct skip_def *skip_def = NULL;
+	struct replace_def *rdef;
+
+	/* Duplicate skip definitions are OK, but we only need the fist one */
+	list_for_each(skip_pos, &skip_defs)
+	{
+		skip_def = list_entry(skip_pos, struct skip_def, list);
+
+		if (!strcmp(function_name, skip_def->name))
+			return 0;
+	}
+
+	/* Skip definitions matching a replace definition are not OK */
+	list_for_each(replace_pos, &replace_defs)
+	{
+		rdef = list_entry(replace_pos,
+				  struct replace_def,
+				  list);
+
+		if (!strcmp(skip_def->name, rdef->old_name) ||
+		    !strcmp(skip_def->name, rdef->new_name)) {
+			fprintf(stderr,
+				"Skip '%s' is in a replace definition\n",
+				skip_def->name);
+			return -EEXIST;
+		}
+	}
+
+	skip_def = malloc(sizeof(struct skip_def));
+
+	if (!skip_def)
+		return -ENOMEM;
+
+	skip_def->name = strdup(function_name);
+
+	if (!skip_def->name) {
+		free(skip_def);
+		return -ENOMEM;
+	}
+
+	list_add(&skip_def->list, &skip_defs);
+
+	return 0;
+}
+
+static int add_to_replace_list(const char *old_name, const char *new_name)
+{
+	struct list_head *skip_pos;
+	struct list_head *replace_pos;
+
+	struct skip_def *skip_def;
+	struct replace_def *rdef;
+
+	/* Duplicate replace definitions are not OK */
+	list_for_each(replace_pos , &replace_defs)
+	{
+		rdef = list_entry(replace_pos,
+				  struct replace_def,
+				  list);
+
+		if (!strcmp(old_name, rdef->old_name) ||
+		    !strcmp(old_name, rdef->new_name)) {
+			fprintf(stderr,
+				"Multiple replace defs for function '%s'\n",
+				old_name);
+
+			return -EEXIST;
+		}
+
+		if (!strcmp(new_name, rdef->old_name) ||
+		    !strcmp(new_name, rdef->new_name)) {
+			fprintf(stderr,
+				"Multiple replace defs for function '%s'\n",
+				new_name);
+
+			return -EEXIST;
+		}
+	}
+
+	/* Replace definitions matching a skip definition are not OK */
+	list_for_each(skip_pos, &skip_defs)
+	{
+		skip_def = list_entry(skip_pos, struct skip_def, list);
+
+		if (!strcmp(skip_def->name, old_name)) {
+			fprintf(stderr,
+				"Replace '%s' is in a skip definition\n",
+				old_name);
+			return -EEXIST;
+		}
+
+		if (!strcmp(skip_def->name, new_name)) {
+			fprintf(stderr,
+				"Replace '%s' is in a skip definition\n",
+				new_name);
+			return -EEXIST;
+		}
+	}
+
+	rdef = malloc(sizeof(struct replace_def));
+
+	if (!rdef)
+		return -ENOMEM;
+
+	rdef->old_name = strdup(old_name);
+	rdef->new_name = strdup(new_name);
+
+	if ((!rdef->old_name) || (!rdef->new_name)) {
+		free(rdef->old_name);
+		free(rdef->new_name);
+		free(rdef);
+		return -ENOMEM;
+	}
+
+	list_add(&rdef->list, &replace_defs);
+
+	return 0;
+}
+
+static int process_initcall_string(const char *string)
+{
+	char *save_ptr;
+	char *def_type;
+	char *function;
+	char *group;
+	char *old_name;
+	char *new_name;
+	char *deps;
+	int err;
+
+	char *local_string = strdup(string);
+
+	if (!local_string)
+		return -ENOMEM;
+
+	def_type = strtok_r(local_string, ":", &save_ptr);
+
+	switch (def_type[0]) {
+	case 'f':
+		/* An init function definition - Get the function name */
+		function = strtok_r(NULL, ":", &save_ptr);
+		group = strtok_r(NULL, ":", &save_ptr);
+		deps = strtok_r(NULL, ":", &save_ptr);
+
+		err = add_to_init_list(function, group, deps);
+		break;
+
+	case 's':
+		function = strtok_r(NULL, ":", &save_ptr);
+
+		err = add_to_skip_list(function);
+		break;
+
+	case 'r':
+		old_name = strtok_r(NULL, ":", &save_ptr);
+		new_name = strtok_r(NULL, ":", &save_ptr);
+
+		err = add_to_replace_list(old_name, new_name);
+		break;
+
+	default:
+		fprintf(stderr, "Unknown Init Type: %s", def_type);
+		err = -ENOENT;
+		break;
+	}
+
+	free(local_string);
+	return err;
+}
+
+static int process_marker_strings(void)
+{
+	int err = 0;
+
+	err = process_initcall_string(default_init_reset);
+	if (err)
+		return err;
+
+	err = process_initcall_string(default_init_sdram);
+	if (err)
+		return err;
+
+	err = process_initcall_string(default_init_reloc);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int build_function_list(char *buffer)
+{
+	int err = 0;
+
+	char *save_ptr;
+
+	char *init_call_string;
+
+	err = process_marker_strings();
+	if (err)
+		return err;
+
+	init_call_string = strtok_r(buffer, "()", &save_ptr);
+
+	while (init_call_string) {
+		if (process_initcall_string(init_call_string))
+			err = 1;
+
+		/* Skip the garbage between init definitions */
+		init_call_string = strtok_r(NULL, "(", &save_ptr);
+
+		/* Get the next init definition */
+		init_call_string = strtok_r(NULL, ")", &save_ptr);
+	};
+
+	return err;
+}
+
+static int open_file(const char *file, char **buffer, int *buf_size)
+{
+	struct stat sbuf;
+	int file_ptr;
+
+	char *ptr;
+
+	file_ptr = open(file, O_RDONLY|O_BINARY);
+
+	if (file_ptr < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
+		return errno;
+	}
+
+	if (fstat(file_ptr, &sbuf) < 0) {
+		fprintf(stderr, "Can't stat %s: %s\n", file, strerror(errno));
+		return errno;
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, file_ptr, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s: %s\n", file, strerror(errno));
+		return errno;
+	}
+
+	*buffer = malloc(sbuf.st_size + 1);
+
+	if (!*buffer)
+		return -ENOMEM;
+
+	*buf_size = sbuf.st_size;
+	memcpy(*buffer, ptr, sbuf.st_size);
+	(*buffer)[sbuf.st_size] = 0x00;
+
+	munmap((void *)ptr, sbuf.st_size);
+	close(file_ptr);
+
+	return 0;
+}
+
+static int check_mandatory_list(void)
+{
+	int err = 0;
+	struct list_head *position;
+	struct list_head *q;
+	struct list_head *sub_position;
+	struct init_def *init_def;
+	struct func_def *func_def;
+
+
+	/* Remove functions that exist from the mandatory functions list */
+	list_for_each_safe(position, q, &mandatory_functions) {
+		func_def = list_entry(position, struct func_def, list);
+
+		list_for_each(sub_position , &init_defs) {
+			init_def = list_entry(sub_position,
+					      struct init_def,
+					      list);
+
+			if (!strcmp(func_def->name, init_def->function) ||
+			    !strcmp(func_def->name, init_def->group)) {
+				free(func_def->name);
+
+				list_del(position);
+				free(func_def);
+			}
+		}
+
+	}
+
+	list_for_each(position , &mandatory_functions) {
+		func_def = list_entry(position, struct func_def, list);
+
+		fprintf(stderr,
+			"Missing mandatory function: %s\n",
+			func_def->name);
+		err = 1;
+	}
+
+	return err;
+}
+
+static int process_skip_list(void)
+{
+	int err = 0;
+	int group_skip = 0;
+
+	/*
+	 * The same function cannot appear in both the skip list and the
+	 * replace list (either as the new or old function name)
+	 */
+	struct list_head *skip_pos;
+	struct skip_def *skip_def;
+
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	struct list_head *q;
+
+	list_for_each(skip_pos, &skip_defs)
+	{
+		skip_def = list_entry(skip_pos, struct skip_def, list);
+
+		/* Remove the named skip from init entries */
+		list_for_each_safe(init_def_pos, q, &init_defs) {
+			init_def = list_entry(init_def_pos,
+					      struct init_def,
+					      list);
+			/*
+			 * We already know that function and group names
+			 * are unique across both namespaces so we can
+			 * delete any init definitions whose function or
+			 * group name matches the skip name
+			 */
+			if (!strcmp(init_def->group, skip_def->name))
+				group_skip = 1;
+
+			if (!strcmp(init_def->function, skip_def->name) ||
+			    group_skip) {
+				free(init_def->function);
+				free(init_def->group);
+
+				free_function_list(&init_def->mandatory_deps);
+				free_function_list(&init_def->post_deps);
+				free_function_list(&init_def->pre_deps);
+
+				list_del(init_def_pos);
+
+				free(init_def);
+			}
+		}
+
+		if (group_skip)
+			/* Remove the named skip group */
+			delete_group(skip_def->name);
+	}
+
+	return err;
+}
+
+static int process_replace_list(void)
+{
+	int err = 0;
+
+	struct list_head *init_def_pos;
+	struct list_head *replace_pos;
+
+	struct init_def *init_def;
+	struct replace_def *rdef;
+
+	struct init_group *dummy;
+
+	int group_replace;
+	int function_replace;
+
+	list_for_each(replace_pos, &replace_defs)
+	{
+		rdef = list_entry(replace_pos, struct replace_def, list);
+
+		group_replace = 0;
+		function_replace = 0;
+
+		list_for_each(init_def_pos , &init_defs)
+		{
+			init_def = list_entry(init_def_pos,
+					      struct init_def,
+					      list);
+
+			if (!strcmp(init_def->function,
+				    rdef->old_name)) {
+				/* Function replacements are easy */
+				function_replace = 1;
+
+				free(init_def->function);
+				init_def->function = strdup(rdef->new_name);
+
+				if (!init_def->function)
+					return -ENOMEM;
+
+			} else if (!strcmp(init_def->group,
+				    rdef->old_name)) {
+				/* Hmm, a group replacement */
+				group_replace = 1;
+
+				free(init_def->group);
+				init_def->group = strdup(rdef->new_name);
+
+				if (!init_def->group)
+					return -ENOMEM;
+			}
+		}
+
+		if (group_replace) {
+			/* Delete 'old name' group */
+			delete_group(rdef->old_name);
+
+			/*
+			 * Create a 'new group' (if it does not already
+			 * exist. It will be tested later and if it is
+			 * empty, an error will be reported
+			 */
+			err = find_or_create_group(rdef->new_name, &dummy);
+			if (!err)
+				return err;
+		}
+
+		if (!group_replace && !function_replace) {
+			fprintf(stderr,
+				"Replace function %s not in init list\n",
+				rdef->old_name);
+			err = ENOENT;
+		}
+	}
+
+	return err;
+}
+
+static int add_dep(const char *function, const char *dep)
+{
+	int found = 0;
+
+	struct list_head *init_def_pos;
+	struct list_head *pre_dep_pos;
+
+	struct init_def *init_def;
+	struct func_def *func_def;
+	struct func_def *pre_dep_id;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (!strcmp(init_def->function, function)) {
+
+			list_for_each(pre_dep_pos, &init_def->pre_deps) {
+				pre_dep_id = list_entry(pre_dep_pos,
+							struct func_def,
+							list);
+				if (!strcmp(pre_dep_id->name, dep)) {
+					found = 1;
+					break;
+				}
+
+			}
+
+			if (!found) {
+				func_def = malloc(sizeof(struct func_def));
+
+				if (!func_def)
+					return -ENOMEM;
+
+				func_def->name = strdup(dep);
+
+				if (!func_def->name) {
+					free(func_def);
+					return -ENOMEM;
+				}
+
+				list_add(&func_def->list, &init_def->pre_deps);
+			}
+
+			return 0;
+		}
+	}
+
+	fprintf(stderr, "Function '%s' not found\n", function);
+	return -ENOENT;
+}
+
+
+static int insert_into_dep_list(struct list_head *dep_list,
+				struct init_group *init_group)
+{
+	struct list_head *position;
+	struct func_def *func_def;
+	struct func_def *new_func_def;
+
+	list_for_each(position, &init_group->functions)
+	{
+		func_def = list_entry(position, struct func_def, list);
+
+		new_func_def = malloc(sizeof(struct func_def));
+
+		if (!new_func_def)
+			return -ENOMEM;
+
+		new_func_def->name = strdup(func_def->name);
+
+		if (!new_func_def->name) {
+			free(new_func_def);
+			return -ENOMEM;
+		}
+
+		list_add(&new_func_def->list, dep_list);
+	}
+
+	return 0;
+}
+
+static int expand_dep_list(struct list_head *dep_list)
+{
+	int err = 0;
+
+	struct list_head *position;
+	struct func_def *func_def;
+	struct list_head *q;
+
+	struct list_head *step_pos;
+	struct init_group *init_group;
+
+
+	list_for_each_safe(position, q, dep_list) {
+		func_def = list_entry(position, struct func_def, list);
+
+		/* Is this a 'step' rather than a 'function' */
+		list_for_each(step_pos, &init_groups)
+		{
+			init_group = list_entry(step_pos,
+						struct init_group,
+						list);
+
+			if (!strcmp(init_group->name, func_def->name)) {
+				/*
+				 * Replace this init id (which is a 'step'
+				 * with the list of step functions
+				 */
+				free(func_def->name);
+
+				list_del(position);
+				free(func_def);
+
+				err = insert_into_dep_list(dep_list,
+							   init_group);
+
+				if (err)
+					return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int expand_dep_lists(void)
+{
+	int err = 0;
+
+	struct list_head *position;
+	struct init_def *init_def;
+
+	list_for_each(position , &init_defs)
+	{
+		init_def = list_entry(position, struct init_def, list);
+
+		err = expand_dep_list(&init_def->mandatory_deps);
+
+		if (err)
+			return err;
+
+		err = expand_dep_list(&init_def->pre_deps);
+
+		if (err)
+			return err;
+
+		err = expand_dep_list(&init_def->post_deps);
+
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+
+static void remove_unused_deps(struct list_head *list,
+			       const char *function,
+			       const char *dep_type)
+{
+	struct list_head *dep_pos;
+	struct func_def *func_def;
+	struct list_head *q;
+
+	list_for_each_safe(dep_pos, q, list)
+	{
+		func_def = list_entry(dep_pos,
+				     struct func_def,
+				     list);
+
+		if (!function_exists(func_def->name)) {
+			fprintf(stderr,
+				"Removing unmet %s dep '%s' from '%s'\n",
+				dep_type,
+				func_def->name,
+				function);
+			free(func_def->name);
+			list_del(dep_pos);
+			free(func_def);
+		}
+	}
+
+}
+
+static int strip_unmet_deps(void)
+{
+	/*
+	 * Any entry in the pre-dep and post-dep lists that do not have a
+	 * matching entry in the init_defs list can be removed
+	 */
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		remove_unused_deps(&init_def->pre_deps,
+				   init_def->function,
+				   "pre");
+		remove_unused_deps(&init_def->post_deps,
+				   init_def->function,
+				   "post");
+	}
+
+	return 0;
+}
+
+static int cleanup_dep_lists(void)
+{
+	int err = 0;
+	int found;
+
+	struct list_head *init_def_pos;
+	struct list_head *dep_pos;
+	struct list_head *pre_dep_pos;
+
+	struct list_head *q;
+
+	struct init_def *init_def;
+	struct func_def *func_def;
+	struct func_def *pre_dep_id;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		/* Convert post-deps into pre-deps */
+		list_for_each_safe(dep_pos, q, &init_def->post_deps)
+		{
+			func_def = list_entry(dep_pos,
+					      struct func_def,
+					      list);
+
+			err = add_dep(func_def->name, init_def->function);
+			if (err)
+				return err;
+
+			list_del(dep_pos);
+
+			free(func_def->name);
+			free(func_def);
+		}
+
+		/* Move mandatory deps into pre-deps list */
+		list_for_each_safe(dep_pos, q, &init_def->mandatory_deps)
+		{
+			func_def = list_entry(dep_pos,
+					      struct func_def,
+					      list);
+
+			list_del(dep_pos);
+
+			found = 0;
+
+			list_for_each(pre_dep_pos, &init_def->pre_deps)
+			{
+				pre_dep_id = list_entry(pre_dep_pos,
+							struct func_def,
+							list);
+
+				if (!strcmp(func_def->name, pre_dep_id->name)) {
+					found = 1;
+					break;
+				}
+
+			}
+
+			if (!found) {
+				list_add(&func_def->list,
+					 &init_def->pre_deps);
+			} else {
+				free(func_def->name);
+				free(func_def);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int check_unique_root_function(void)
+{
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	int root_functions = 0;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (list_empty(&init_def->pre_deps))
+			root_functions++;
+	}
+
+	if (root_functions != 1)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+static void dump_dep_stack(struct list_head *dep_stack, const char *function)
+{
+	struct list_head *func_def_pos;
+	struct func_def *func_def;
+
+	list_for_each(func_def_pos , dep_stack) {
+		func_def = list_entry(func_def_pos, struct func_def, list);
+
+		fprintf(stderr, "  %s\n", func_def->name);
+
+		if (!strcmp(func_def->name, function))
+			return;
+	}
+}
+
+static struct init_def *find_init_def_by_function(const char *function)
+{
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (!strcmp(init_def->function, function))
+			return init_def;
+	}
+
+	fprintf(stderr, "Cannot find %s\n", function);
+
+	return NULL;
+}
+
+static int check_init_def_cyclic(struct init_def *init_def,
+				 struct list_head *dep_stack)
+{
+	int err = 0;
+
+	struct list_head *func_def_pos;
+	struct func_def *func_def;
+
+	struct list_head *dep_init_func_pos;
+	struct func_def *dep_init_func;
+	struct init_def *dep_init_def;
+
+	if (init_def->cyclic_checked)
+		return 0;
+
+	/* Check if this function already in the dependency stack */
+	list_for_each(func_def_pos , dep_stack) {
+		func_def = list_entry(func_def_pos, struct func_def, list);
+
+		if (!strcmp(init_def->function, func_def->name)) {
+			fprintf(stderr,
+				"Function '%s' has cyclic dependency\n",
+				init_def->function);
+
+			/* Dump the dependency stack */
+			dump_dep_stack(dep_stack, init_def->function);
+
+			init_def->cyclic_checked = 1;
+			return -EEXIST;
+		}
+	}
+
+	/* Add this function to the check stack */
+	func_def = malloc(sizeof(struct func_def));
+
+	if (!func_def)
+		return -ENOMEM;
+
+	func_def->name = strdup(init_def->function);
+
+	if (!func_def->name) {
+		free(func_def);
+		return -ENOMEM;
+	}
+
+	list_add(&func_def->list, dep_stack);
+
+	/* Now check the all the dependencies of this function */
+	list_for_each(dep_init_func_pos , &init_def->pre_deps)
+	{
+		dep_init_func = list_entry(dep_init_func_pos,
+					   struct func_def,
+					   list);
+
+		dep_init_def = find_init_def_by_function(dep_init_func->name);
+
+		if (!dep_init_def)
+			return 1;
+
+		if (check_init_def_cyclic(dep_init_def, dep_stack))
+			err = 1;
+	}
+
+	init_def->cyclic_checked = 1;
+
+	return err;
+}
+
+static void clear_dep_stack(struct list_head *dep_stack)
+{
+	struct list_head *func_def_pos;
+	struct list_head *q;
+	struct func_def *func_def;
+
+	list_for_each_safe(func_def_pos, q, dep_stack) {
+		func_def = list_entry(func_def_pos,
+				      struct func_def,
+				      list);
+
+		list_del(func_def_pos);
+		free(func_def->name);
+		free(func_def);
+	}
+}
+
+static int check_for_cyclic_deps(void)
+{
+	int err = 0;
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	struct list_head dep_stack;
+
+
+	INIT_LIST_HEAD(&dep_stack);
+
+	list_for_each(init_def_pos , &init_defs)
+	{
+		clear_dep_stack(&dep_stack);
+
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (!init_def->cyclic_checked)
+			if (check_init_def_cyclic(init_def, &dep_stack))
+				err = 1;
+	}
+
+	clear_dep_stack(&dep_stack);
+
+	return err;
+}
+
+int generate_init_sequence(void)
+{
+	struct init_def *init_def;
+
+	while (!list_empty(&init_defs)) {
+		init_def = pop_first_independent_function();
+
+		if (!init_def) {
+			fprintf(stderr, "Cyclic deps\n");
+			return 0;
+		}
+
+		list_add_tail(&init_def->list, &init_sequence);
+
+		delete_dep_from_init_defs(init_def->function);
+	}
+
+	return 0;
+}
+
+int generate_c_file(const char *file)
+{
+	struct list_head *init_def_pos;
+	struct init_def *init_def;
+
+	FILE *file_ptr = fopen(file, "w");
+
+	if (!file_ptr) {
+		fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
+		return errno;
+	}
+
+	fputs("/*\n", file_ptr);
+	fputs(" * DO NOT MODIFY.\n", file_ptr);
+	fputs(" *\n", file_ptr);
+	fputs(" * This file was generated by mkinitseq\n", file_ptr);
+	fputs(" *\n", file_ptr);
+	fputs(" */\n", file_ptr);
+	fputs("\n", file_ptr);
+	fputs("#include <init_func.h>\n", file_ptr);
+	fputs("#include <linux/stddef.h>\n", file_ptr);
+	fputs("\n", file_ptr);
+
+	list_for_each(init_def_pos , &init_sequence)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (strcmp(init_def->function, "RESET") &
+		    strcmp(init_def->function, "SDRAM") &
+		    strcmp(init_def->function, "RELOC")) {
+			fprintf(file_ptr, "int %s(void);\n",
+				init_def->function);
+		}
+	}
+
+	list_for_each(init_def_pos , &init_sequence)
+	{
+		init_def = list_entry(init_def_pos, struct init_def, list);
+
+		if (!strcmp(init_def->function, "RESET")) {
+			fputs("init_fnc_t *init_sequence_f[] = {\n",
+			      file_ptr);
+		} else if (!strcmp(init_def->function, "SDRAM")) {
+			fputs("\n", file_ptr);
+			fputs("\t\tNULL,\n", file_ptr);
+			fputs("\t};\n", file_ptr);
+
+			fputs("\n", file_ptr);
+			fputs("init_fnc_t *init_sequence_f_r[] = {\n",
+			      file_ptr);
+		} else if (!strcmp(init_def->function, "RELOC")) {
+			fputs("\n", file_ptr);
+			fputs("\t\tNULL,\n", file_ptr);
+			fputs("\t};\n", file_ptr);
+
+			fputs("\n", file_ptr);
+			fputs("init_fnc_t *init_sequence_r[] = {\n",
+			      file_ptr);
+		} else {
+			fprintf(file_ptr, "\t\t%s,\n", init_def->function);
+		}
+	}
+
+	fputs("\n", file_ptr);
+	fputs("\t\tNULL,\n", file_ptr);
+	fputs("\t};\n", file_ptr);
+
+	fclose(file_ptr);
+
+	return 0;
+}
+
+void init_lists(void)
+{
+	INIT_LIST_HEAD(&init_defs);
+	INIT_LIST_HEAD(&skip_defs);
+	INIT_LIST_HEAD(&replace_defs);
+
+	INIT_LIST_HEAD(&mandatory_functions);
+	INIT_LIST_HEAD(&init_groups);
+
+	INIT_LIST_HEAD(&init_sequence);
+}
+
+int main(int argc, const char **argv)
+{
+	int err;
+	int buf_size = 0;
+	char *local_buffer = NULL;
+	char *x;
+
+	printf("Generating init sequence from %s\n", argv[1]);
+
+	/* Read the init function definitions into a local buffer */
+	err = open_file(argv[1], &local_buffer, &buf_size);
+
+	if (err || !local_buffer)
+		exit(EXIT_FAILURE);
+
+	/*
+	 * Convert all the NULLs (except the last one) to non-NULL so
+	 * the buffer can be processed using standard string functions
+	 */
+	for (x = local_buffer; x != &local_buffer[buf_size]; x++) {
+		if (*x == 0x00)
+			*x = 0x01;
+	}
+
+	init_lists();
+
+	if (build_function_list(local_buffer))
+		exit(EXIT_FAILURE);
+
+	if (check_mandatory_list())
+		exit(EXIT_FAILURE);
+
+	if (process_skip_list())
+		exit(EXIT_FAILURE);
+
+	if (process_replace_list())
+		exit(EXIT_FAILURE);
+
+	if (check_for_empty_groups())
+		exit(EXIT_FAILURE);
+
+	if (expand_dep_lists())
+		exit(EXIT_FAILURE);
+
+	if (strip_unmet_deps())
+		exit(EXIT_FAILURE);
+
+	if (cleanup_dep_lists())
+		exit(EXIT_FAILURE);
+
+	if (check_unique_root_function())
+		exit(EXIT_FAILURE);
+
+	if (check_for_cyclic_deps())
+		exit(EXIT_FAILURE);
+
+	if (generate_init_sequence())
+		exit(EXIT_FAILURE);
+
+	if (generate_c_file(argv[2]))
+		exit(EXIT_FAILURE);
+
+	free(local_buffer);
+	exit(EXIT_SUCCESS);
+}
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 2/3] init_func: Add x86 support
  2012-04-22 15:23 [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Graeme Russ
  2012-04-22 15:23 ` [U-Boot] [PATCH 1/3] init_func: Add fundamental framework Graeme Russ
@ 2012-04-22 15:23 ` Graeme Russ
  2012-04-22 15:23 ` [U-Boot] [PATCH 3/3] init_func: Use for eNET board Graeme Russ
  2012-05-02 23:50 ` [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Marek Vasut
  3 siblings, 0 replies; 10+ messages in thread
From: Graeme Russ @ 2012-04-22 15:23 UTC (permalink / raw)
  To: u-boot


Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
 arch/x86/cpu/u-boot.lds |   23 +++++++++++++++++++++++
 arch/x86/lib/board.c    |   10 +++-------
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds
index fe28030..b88fd57 100644
--- a/arch/x86/cpu/u-boot.lds
+++ b/arch/x86/cpu/u-boot.lds
@@ -28,6 +28,27 @@ ENTRY(_start)
 
 SECTIONS
 {
+#ifdef MAKE_INIT_LDS
+	.initfuncs : { KEEP(*(.initfuncs*)) }
+
+	/DISCARD/ : { *(.text*) }
+	/DISCARD/ : { *(.debug*) }
+	/DISCARD/ : { *(.u_boot_cmd*) }
+	/DISCARD/ : { *(.rodata*) }
+	/DISCARD/ : { *(.data*) }
+	/DISCARD/ : { *(.dynsym*) }
+	/DISCARD/ : { *(.hash*) }
+	/DISCARD/ : { *(.bss*) }
+	/DISCARD/ : { *(.bss) }
+	/DISCARD/ : { *(.rel.dyn*) }
+	/DISCARD/ : { *(.rel.dyn) }
+	/DISCARD/ : { *(.dynstr*) }
+	/DISCARD/ : { *(.dynamic*) }
+	/DISCARD/ : { *(.plt*) }
+	/DISCARD/ : { *(.interp*) }
+	/DISCARD/ : { *(.gnu*) }
+	/DISCARD/ : { *(.comment*) }
+#else
 	. = CONFIG_SYS_TEXT_BASE;	/* Location of bootcode in flash */
 	__text_start = .;
 	.text  : { *(.text*); }
@@ -72,6 +93,7 @@ SECTIONS
 	/DISCARD/ : { *(.plt*) }
 	/DISCARD/ : { *(.interp*) }
 	/DISCARD/ : { *(.gnu*) }
+	/DISCARD/ : { *(.initfuncs*) }
 
 	/* 16bit realmode trampoline code */
 	.realmode REALMODE_BASE : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) }
@@ -94,4 +116,5 @@ SECTIONS
 
 	. = RESET_VEC_LOC;
 	.resetvec : AT (CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE + RESET_VEC_LOC)) { KEEP(*(.resetvec)); }
+#endif
 }
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c
index 5f0b62c..5789581 100644
--- a/arch/x86/lib/board.c
+++ b/arch/x86/lib/board.c
@@ -32,6 +32,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <watchdog.h>
 #include <stdio_dev.h>
 #include <asm/u-boot-x86.h>
@@ -77,13 +78,7 @@
  *      - All remaining initialisation
  */
 
-/*
- * The requirements for any new initalization function is simple: it is
- * a function with no parameters which returns an integer return code,
- * where 0 means "continue" and != 0 means "fatal error, hang the system"
- */
-typedef int (init_fnc_t) (void);
-
+#ifndef CONFIG_INIT_FUNC
 /*
  * init_sequence_f is the list of init functions which are run when U-Boot
  * is executing from Flash with a limited 'C' environment. The following
@@ -206,6 +201,7 @@ init_fnc_t *init_sequence_r[] = {
 #endif
 	NULL,
 };
+#endif
 
 static void do_init_loop(init_fnc_t **init_fnc_ptr)
 {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 3/3] init_func: Use for eNET board
  2012-04-22 15:23 [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Graeme Russ
  2012-04-22 15:23 ` [U-Boot] [PATCH 1/3] init_func: Add fundamental framework Graeme Russ
  2012-04-22 15:23 ` [U-Boot] [PATCH 2/3] init_func: Add x86 support Graeme Russ
@ 2012-04-22 15:23 ` Graeme Russ
  2012-05-02 23:50 ` [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Marek Vasut
  3 siblings, 0 replies; 10+ messages in thread
From: Graeme Russ @ 2012-04-22 15:23 UTC (permalink / raw)
  To: u-boot


Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
 arch/x86/cpu/cpu.c               |    3 +++
 arch/x86/cpu/sc520/sc520_sdram.c |    3 +++
 arch/x86/cpu/sc520/sc520_timer.c |    2 ++
 arch/x86/lib/init_helpers.c      |   14 ++++++++++++++
 arch/x86/lib/init_wrappers.c     |   11 ++++++++++-
 arch/x86/lib/pcat_interrupts.c   |    2 ++
 arch/x86/lib/relocate.c          |    4 ++++
 board/eNET/eNET.c                |    5 +++++
 common/console.c                 |    3 +++
 common/env_dataflash.c           |    1 +
 common/env_eeprom.c              |    1 +
 common/env_fat.c                 |    1 +
 common/env_flash.c               |    2 ++
 common/env_mgdisk.c              |    1 +
 common/env_mmc.c                 |    1 +
 common/env_nand.c                |    1 +
 common/env_nowhere.c             |    1 +
 common/env_nvram.c               |    1 +
 common/env_onenand.c             |    1 +
 common/env_sf.c                  |    1 +
 common/serial.c                  |    2 ++
 common/stdio.c                   |    2 ++
 include/configs/eNET.h           |    1 +
 23 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index e9bb0d7..263df28 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -33,6 +33,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <command.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
@@ -137,6 +138,7 @@ int x86_cpu_init_f(void)
 	return 0;
 }
 int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f")));
+INIT_FUNC(cpu_init_f, cpu_f, RESET, , SDRAM);
 
 int x86_cpu_init_r(void)
 {
@@ -145,6 +147,7 @@ int x86_cpu_init_r(void)
 	return 0;
 }
 int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r")));
+INIT_FUNC(cpu_init_r, cpu_r, mem_malloc_init_r, , );
 
 void x86_enable_caches(void)
 {
diff --git a/arch/x86/cpu/sc520/sc520_sdram.c b/arch/x86/cpu/sc520/sc520_sdram.c
index 9dc1334..7033e18 100644
--- a/arch/x86/cpu/sc520/sc520_sdram.c
+++ b/arch/x86/cpu/sc520/sc520_sdram.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <asm/io.h>
 #include <asm/processor-flags.h>
 #include <asm/arch/sc520.h>
@@ -51,6 +52,7 @@ int dram_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(dram_init_f, dram_f, console_init_f, , SDRAM);
 
 static inline void sc520_dummy_write(void)
 {
@@ -477,3 +479,4 @@ int dram_init(void)
 
 	return 0;
 }
+INIT_FUNC(dram_init, dram_r, , board_early_init_r, );
diff --git a/arch/x86/cpu/sc520/sc520_timer.c b/arch/x86/cpu/sc520/sc520_timer.c
index 41f121f..7b25c08 100644
--- a/arch/x86/cpu/sc520/sc520_timer.c
+++ b/arch/x86/cpu/sc520/sc520_timer.c
@@ -25,6 +25,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <asm/io.h>
 #include <asm/interrupt.h>
 #include <asm/arch/sc520.h>
@@ -69,6 +70,7 @@ int timer_init(void)
 
 	return 0;
 }
+INIT_FUNC(timer_init, timer, interrupt_init, , );
 
 /* Allow boards to override udelay implementation */
 void __udelay(unsigned long usec)
diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c
index 9f4dee0..aa88048 100644
--- a/arch/x86/lib/init_helpers.c
+++ b/arch/x86/lib/init_helpers.c
@@ -21,6 +21,7 @@
  * MA 02111-1307 USA
  */
 #include <common.h>
+#include <init_func.h>
 #include <command.h>
 #include <stdio_dev.h>
 #include <version.h>
@@ -50,6 +51,7 @@ int display_banner(void)
 
 	return 0;
 }
+INIT_FUNC(display_banner, banner, timer_init, , );
 
 int display_dram_config(void)
 {
@@ -64,12 +66,14 @@ int display_dram_config(void)
 
 	return 0;
 }
+INIT_FUNC(display_dram_config, display_dram, display_banner, , );
 
 int init_baudrate_f(void)
 {
 	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
 	return 0;
 }
+INIT_FUNC(init_baudrate_f, display_dram, env_init, , );
 
 int calculate_relocation_address(void)
 {
@@ -106,6 +110,7 @@ int calculate_relocation_address(void)
 
 	return 0;
 }
+INIT_FUNC(calculate_relocation_address, calc_reloc, dram_init_f, , );
 
 int copy_gd_to_ram_f_r(void)
 {
@@ -131,12 +136,14 @@ int copy_gd_to_ram_f_r(void)
 
 	return 0;
 }
+INIT_FUNC(copy_gd_to_ram_f_r, copy_gd, SDRAM, , RELOC);
 
 int init_cache_f_r(void)
 {
 	/* Initialise the CPU cache(s) */
 	return init_cache();
 }
+INIT_FUNC(init_cache_f_r, cache_f_r, copy_gd_to_ram_f_r, , RELOC);
 
 int set_reloc_flag_r(void)
 {
@@ -144,6 +151,7 @@ int set_reloc_flag_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_reloc_flag_r, reloc_flag, RELOC, , );
 
 int mem_malloc_init_r(void)
 {
@@ -152,6 +160,7 @@ int mem_malloc_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(mem_malloc_init_r, malloc, init_bd_struct_r, , );
 
 bd_t bd_data;
 
@@ -162,6 +171,7 @@ int init_bd_struct_r(void)
 
 	return 0;
 }
+INIT_FUNC(init_bd_struct_r, bd_struct, set_reloc_flag_r, , );
 
 #ifndef CONFIG_SYS_NO_FLASH
 int flash_init_r(void)
@@ -177,6 +187,7 @@ int flash_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(flash_init_r, flash_r, RELOC, serial_initialize_r display_dram_config, );
 #endif
 
 int init_ip_address_r(void)
@@ -186,6 +197,7 @@ int init_ip_address_r(void)
 
 	return 0;
 }
+INIT_FUNC(init_ip_address_r, ip_address, env_relocate_r, , pci_init_r stdio_init);
 
 #ifdef CONFIG_STATUS_LED
 int status_led_set_r(void)
@@ -207,6 +219,7 @@ int set_bootfile_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_bootfile_r, set_bootfile, set_load_addr_r, , );
 
 int set_load_addr_r(void)
 {
@@ -215,3 +228,4 @@ int set_load_addr_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_load_addr_r, set_load_addr, enable_interrupts_r, , );
diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c
index 71449fe..87ca713 100644
--- a/arch/x86/lib/init_wrappers.c
+++ b/arch/x86/lib/init_wrappers.c
@@ -21,6 +21,7 @@
  * MA 02111-1307 USA
  */
 #include <common.h>
+#include <init_func.h>
 #include <serial.h>
 #include <kgdb.h>
 #include <scsi.h>
@@ -35,6 +36,7 @@ int serial_initialize_r(void)
 
 	return 0;
 }
+INIT_FUNC(serial_initialize_r, serial_multi, RELOC, display_dram_config, );
 
 int env_relocate_r(void)
 {
@@ -43,7 +45,7 @@ int env_relocate_r(void)
 
 	return 0;
 }
-
+INIT_FUNC(env_relocate_r, env_reloc, RELOC env_init, display_dram_config serial_initialize_r flash_init_r, );
 
 int pci_init_r(void)
 {
@@ -52,6 +54,7 @@ int pci_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(pci_init_r, pci, cpu_r, init_ip_address_r env_relocate_r, stdio_init);
 
 int jumptable_init_r(void)
 {
@@ -59,6 +62,7 @@ int jumptable_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(jumptable_init_r, jumptable, stdio_init, , );
 
 int pcmcia_init_r(void)
 {
@@ -83,6 +87,7 @@ int enable_interrupts_r(void)
 
 	return 0;
 }
+INIT_FUNC(enable_interrupts_r, enable_interrupts, , kgdb_init_r pci_init_r misc_init_r console_init_r, );
 
 int eth_initialize_r(void)
 {
@@ -91,7 +96,9 @@ int eth_initialize_r(void)
 
 	return 0;
 }
+INIT_FUNC(eth_initialize_r, eth, pci, bb_miiphy_init_r doc_init_r scsi_init_r ide_init_r set_bootfile_r set_load_addr_r, );
 
+#ifdef CONFIG_RESET_PHY_R
 int reset_phy_r(void)
 {
 #ifdef DEBUG
@@ -101,6 +108,8 @@ int reset_phy_r(void)
 
 	return 0;
 }
+INIT_FUNC(reset_phy_r, phy_reset, eth, eth_initialize_r, );
+#endif
 
 int ide_init_r(void)
 {
diff --git a/arch/x86/lib/pcat_interrupts.c b/arch/x86/lib/pcat_interrupts.c
index 5dac498..a403b7b 100644
--- a/arch/x86/lib/pcat_interrupts.c
+++ b/arch/x86/lib/pcat_interrupts.c
@@ -31,6 +31,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <asm/io.h>
 #include <asm/i8259.h>
 #include <asm/ibmpc.h>
@@ -82,6 +83,7 @@ int interrupt_init(void)
 
 	return 0;
 }
+INIT_FUNC(interrupt_init, pcat_interrupt, , dram_init, );
 
 void mask_irq(int irq)
 {
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c
index 200baab..69b0fd6 100644
--- a/arch/x86/lib/relocate.c
+++ b/arch/x86/lib/relocate.c
@@ -32,6 +32,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <malloc.h>
 #include <asm/u-boot-x86.h>
 #include <asm/relocate.h>
@@ -45,6 +46,7 @@ int copy_uboot_to_ram(void)
 
 	return 0;
 }
+INIT_FUNC(copy_uboot_to_ram, copy_to_ram, SDRAM, init_cache_f_r, RELOC);
 
 int clear_bss(void)
 {
@@ -55,6 +57,7 @@ int clear_bss(void)
 
 	return 0;
 }
+INIT_FUNC(clear_bss, clear_bss, SDRAM, copy_uboot_to_ram, RELOC);
 
 int do_elf_reloc_fixups(void)
 {
@@ -89,3 +92,4 @@ int do_elf_reloc_fixups(void)
 
 	return 0;
 }
+INIT_FUNC(do_elf_reloc_fixups, elf_reloc, clear_bss, , RELOC);
diff --git a/board/eNET/eNET.c b/board/eNET/eNET.c
index 2f26470..19bbbe4 100644
--- a/board/eNET/eNET.c
+++ b/board/eNET/eNET.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <asm/io.h>
 #include <asm/arch/sc520.h>
 #include <net.h>
@@ -106,6 +107,7 @@ int board_early_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(board_early_init_f, board_early_f, cpu_init_f, , SDRAM);
 
 static void enet_setup_pars(void)
 {
@@ -161,6 +163,7 @@ int board_early_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(board_early_init_r, board_early_r, cpu_init_r, , pci);
 
 void show_boot_progress(int val)
 {
@@ -186,6 +189,8 @@ int last_stage_init(void)
 
 	return 0;
 }
+INIT_FUNC(last_stage_init, last_stage, , eth_initialize_r reset_phy_r, );
+
 
 ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info)
 {
diff --git a/common/console.c b/common/console.c
index 1177f7d..01e6450 100644
--- a/common/console.c
+++ b/common/console.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <stdarg.h>
 #include <malloc.h>
 #include <stdio_dev.h>
@@ -588,6 +589,7 @@ int console_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(console_init_f, console_f, serial_init, , SDRAM);
 
 void stdio_print_current_devices(void)
 {
@@ -775,5 +777,6 @@ int console_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(console_init_r, console_r, stdio_init, jumptable_init_r, );
 
 #endif /* CONFIG_SYS_CONSOLE_IS_IN_ENV */
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..423e0ad 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -114,3 +114,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..75b4e11 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -289,3 +289,4 @@ int env_init(void)
 	return 0;
 }
 #endif
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_fat.c b/common/env_fat.c
index bad92aa..d218094 100644
--- a/common/env_fat.c
+++ b/common/env_fat.c
@@ -53,6 +53,7 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
 
 #ifdef CONFIG_CMD_SAVEENV
 int saveenv(void)
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..5714b5b 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -27,6 +27,7 @@
 /* #define DEBUG */
 
 #include <common.h>
+#include <init_func.h>
 #include <command.h>
 #include <environment.h>
 #include <linux/stddef.h>
@@ -117,6 +118,7 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
 
 #ifdef CMD_SAVEENV
 int saveenv(void)
diff --git a/common/env_mgdisk.c b/common/env_mgdisk.c
index d00e141..e5ffaad 100644
--- a/common/env_mgdisk.c
+++ b/common/env_mgdisk.c
@@ -74,3 +74,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_mmc.c b/common/env_mmc.c
index 0c58ae1..dc8a21a 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -62,6 +62,7 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
 
 static int init_mmc_for_env(struct mmc *mmc)
 {
diff --git a/common/env_nand.c b/common/env_nand.c
index e8daec9..10e84f0 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -134,6 +134,7 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
 
 #ifdef CMD_SAVEENV
 /*
diff --git a/common/env_nowhere.c b/common/env_nowhere.c
index 18fcf2c..04d35e5 100644
--- a/common/env_nowhere.c
+++ b/common/env_nowhere.c
@@ -49,3 +49,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..0487de0 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -134,3 +134,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_onenand.c b/common/env_onenand.c
index 652665a..ec98de5 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -135,3 +135,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..84fd3b2 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -349,3 +349,4 @@ int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, cpu_init_f, board_early_init_f, SDRAM);
diff --git a/common/serial.c b/common/serial.c
index 75cc1bb..920c5d3 100644
--- a/common/serial.c
+++ b/common/serial.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <init_func.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <post.h>
@@ -190,6 +191,7 @@ int serial_init(void)
 {
 	return get_current()->init();
 }
+INIT_FUNC(serial_init, serial_f, init_baudrate_f, , SDRAM);
 
 void serial_setbrg(void)
 {
diff --git a/common/stdio.c b/common/stdio.c
index 1bf9ba0..6472259 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -22,6 +22,7 @@
  */
 
 #include <config.h>
+#include <init_func.h>
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
@@ -242,3 +243,4 @@ int stdio_init (void)
 
 	return (0);
 }
+INIT_FUNC(stdio_init, stdio, env_relocate_r, , );
diff --git a/include/configs/eNET.h b/include/configs/eNET.h
index d5c9cad..57cecff 100644
--- a/include/configs/eNET.h
+++ b/include/configs/eNET.h
@@ -29,6 +29,7 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_INIT_FUNC
 /*
  * High Level Configuration Options
  * (easy to change)
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 0/3] Initialisation Sequence Framework
  2012-04-22 15:23 [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Graeme Russ
                   ` (2 preceding siblings ...)
  2012-04-22 15:23 ` [U-Boot] [PATCH 3/3] init_func: Use for eNET board Graeme Russ
@ 2012-05-02 23:50 ` Marek Vasut
  3 siblings, 0 replies; 10+ messages in thread
From: Marek Vasut @ 2012-05-02 23:50 UTC (permalink / raw)
  To: u-boot

Dear Graeme Russ,

> Well here it is (finally) - My Initialisation Sequence Framework
> 
> This series is limited to x86 and is controlled by CONFIG_INIT_FUNC so
> no other arch should be effected. I don't have any cross compilers, so I
> would appreciate if others could confirm the zero impact assertion
> 
> Asbestos suit on

Oh this is gonna be the flamewar of the year now :-E~

Gasoline ready, asbestos pants - check, flamethrower on ... let's go!

                                         )  (  (    (
                                         (  )  () @@  )  (( (
                                     (      (  )( @@  (  )) ) (
                                   (    (  ( ()( /---\   (()( (
     _______                            )  ) )(@ !O O! )@@  ( ) ) )
    <   ____)                      ) (  ( )( ()@ \ o / (@@@@@ ( ()( )
 /--|  |(  o|                     (  )  ) ((@@(@@ !o! @@@@(@@@@@)() (
|   >   \___|                      ) ( @)@@)@ /---\-/---\ )@@@@@()( )
|  /---------+                    (@@@@)@@@( // /-----\ \\ @@@)@@@@@(  .
| |    \ =========______/|@@@@@@@@@@@@@(@@@ // @ /---\ @ \\ @(@@@(@@@ .  .
|  \   \\=========------\|@@@@@@@@@@@@@@@@@ O @@@ /-\ @@@ O @@(@@)@@ @   .
|   \   \----+--\-)))           @@@@@@@@@@ !! @@@@ % @@@@ !! @@)@@@ .. .
|   |\______|_)))/             .    @@@@@@ !! @@ /---\ @@ !! @@(@@@ @ . .
 \__==========           *        .    @@ /MM  /\O   O/\  MM\ @@@@@@@. .
    |   |-\   \          (       .      @ !!!  !! \-/ !!  !!! @@@@@ .
    |   |  \   \          )      .     .  @@@@ !!     !!  .(. @.  .. .
    |   |   \   \        (    /   .(  . \)). ( |O  )( O! @@@@ . )      .
    |   |   /   /         ) (      )).  ((  .) !! ((( !! @@ (. ((. .   .
    |   |  /   /   ()  ))   ))   .( ( ( ) ). ( !!  )( !! ) ((   ))  ..
    |   |_<   /   ( ) ( (  ) )   (( )  )).) ((/ |  (  | \(  )) ((. ).
____<_____\\__\__(___)_))_((_(____))__(_(___.oooO_____Oooo.(_(_)_)((_


Artist:  P.r.i.m.a.l
Borrowed from: http://www.ascii-art.de/ascii/def/flamethrower.txt
Copyright ? 1997-2004 Andreas Freise

> Fire away ;)
> 
> Regards,
> 
> Graeme
> 
> Graeme Russ (3):
>   init_func: Add fundamental framework
>   init_func: Add x86 support
>   init_func: Use for eNET board
> 
>  Makefile                         |   34 +-
>  arch/x86/cpu/cpu.c               |    3 +
>  arch/x86/cpu/sc520/sc520_sdram.c |    3 +
>  arch/x86/cpu/sc520/sc520_timer.c |    2 +
>  arch/x86/cpu/u-boot.lds          |   23 +
>  arch/x86/lib/board.c             |   10 +-
>  arch/x86/lib/init_helpers.c      |   14 +
>  arch/x86/lib/init_wrappers.c     |   11 +-
>  arch/x86/lib/pcat_interrupts.c   |    2 +
>  arch/x86/lib/relocate.c          |    4 +
>  board/eNET/eNET.c                |    5 +
>  common/Makefile                  |    2 +
>  common/console.c                 |    3 +
>  common/env_dataflash.c           |    1 +
>  common/env_eeprom.c              |    1 +
>  common/env_fat.c                 |    1 +
>  common/env_flash.c               |    2 +
>  common/env_mgdisk.c              |    1 +
>  common/env_mmc.c                 |    1 +
>  common/env_nand.c                |    1 +
>  common/env_nowhere.c             |    1 +
>  common/env_nvram.c               |    1 +
>  common/env_onenand.c             |    1 +
>  common/env_sf.c                  |    1 +
>  common/serial.c                  |    2 +
>  common/stdio.c                   |    2 +
>  config.mk                        |    2 +
>  doc/README.INIT_FUNC             |   65 ++
>  include/configs/eNET.h           |    1 +
>  include/init_func.h              |   37 +
>  tools/Makefile                   |    6 +
>  tools/mkinitseq.c                | 1512
> ++++++++++++++++++++++++++++++++++++++ 32 files changed, 1746
> insertions(+), 9 deletions(-)
>  create mode 100644 doc/README.INIT_FUNC
>  create mode 100644 include/init_func.h
>  create mode 100644 tools/mkinitseq.c

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-04-22 15:23 ` [U-Boot] [PATCH 1/3] init_func: Add fundamental framework Graeme Russ
@ 2012-05-03  0:08   ` Marek Vasut
  2012-05-03  3:06     ` Graeme Russ
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Vasut @ 2012-05-03  0:08 UTC (permalink / raw)
  To: u-boot

Dear Graeme Russ,

> Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
> ---
>  Makefile             |   34 ++-
>  common/Makefile      |    2 +
>  config.mk            |    2 +
>  doc/README.INIT_FUNC |   65 +++
>  include/init_func.h  |   37 ++
>  tools/Makefile       |    6 +
>  tools/mkinitseq.c    | 1512
> ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1657
> insertions(+), 1 deletions(-)
>  create mode 100644 doc/README.INIT_FUNC
>  create mode 100644 include/init_func.h
>  create mode 100644 tools/mkinitseq.c
> 

[...]

> --- /dev/null
> +++ b/doc/README.INIT_FUNC
> @@ -0,0 +1,65 @@
> +The INIT_FUNC macro allows initialisation functions (i.e. functions which
> are +executed before the main loop) to be easily added to the init
> sequence +
> +
> +Specifying an Initialisation Function and is Dependencies
> +---------------------------------------------------------
> +The format of the INIT_FUNC macro is:
> +
> +INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
> +
> +fn is the name of the init function to call. This function must have the
> +following prototype:
> +
> +int foo(void);

What if I want to pass some data to such a func ? Clearly, I can think of this 
being doable, but extra hard.

> +
> +Each init function must return 0 to indicate success - any other return
> value +indicates failure and the init sequence will stop
> +
> +grp is the name of the group that the init function belongs to. grp may be
> +the same as fn for any individual init function, but between init
> functions, +fn and grp must be unique.
> +
> +The purpose of groups is to allow functions to be grouped together so
> other +functions can specify the group as a whole as a dependency rather
> than having +to list every function in the group in the dependency list
> +
> +man_reqs is a space seperated list of functions or groups that MUST exist
> and +MUST run BEFORE fn
> +
> +pre_reqs is a space seperated list of functions or groups that MAY exist
> and +(if they do) MUST run BEFORE fn
> +
> +pst_reqs is a space seperated list of functions or groups that MAY exist
> and +(if they do) MUST run AFTER fn

What's the point? Can't you create a kind of proxy object that the pst_reqs will 
have as a pre_req ?

Maybe you should create this:

INIT_FUNC(fn, grp, prereqs, postreqs) and for each function from prereqs and 
postreqs, specify per-function attributes via the GCC __attribute__(()) 
directive, like if the function must run before something or may run before 
something etc?
> +
> +Skipping or Replacing a Function or Group
> +-----------------------------------------
> +Occassionally, a board may provide a completely seperate implementation
> for +an initialisation function that is provided in the common arch, SoC
> or +common code.
> +
> +SKIP_INIT(fn_or_group)
> +
> +After the initialisation function dependencies are calculated, all
> functions +and groups listed in any SKIP_INITs are removed - This may
> result in +dependent functions being removed - It is up to the board code
> developer +to ensure suitable replacements are in place
> +
> +REPLACE_INIT(old_fn_or_group, new_fn_or_group)
> +
> +Like SKIP_INIT but replaces on function with another (or one group with
> +another)
> +
> +Example: In the SoC code yoy may have

Yoy :)

> +
> +INIT_FUNC(init_cpu_f, RESET, , , );
> +
> +In the board code, you may want a slightly tweaked version, so you might
> +have:
> +
> +int my_new_init_cpu_f(void)
> +{
> +	...
> +}
> +REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
> diff --git a/include/init_func.h b/include/init_func.h
> new file mode 100644
> index 0000000..e4366b8
> --- /dev/null
> +++ b/include/init_func.h
> @@ -0,0 +1,37 @@
> +#ifndef __INIT_FUNC_H__
> +#define __INIT_FUNC_H__
> +
> +/*
> + * The requirements for any new initalization function is simple: it is
> + * a function with no parameters which returns an integer return code,
> + * where 0 means "continue" and != 0 means "fatal error, hang the system"
> + */
> +typedef int (init_fnc_t) (void);
> +
> +extern init_fnc_t *init_sequence_f[];
> +extern init_fnc_t *init_sequence_f_r[];
> +extern init_fnc_t *init_sequence_r[];
> +
> +#ifdef CONFIG_INIT_FUNC
> +#include <linux/compiler.h>
> +
> +#define INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs) \
> +	static const char __init_func_ ## fn[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"(f:" #fn ":" #grp ":" #man_reqs " | " #pre_reqs " | " #pst_reqs ")\n";
> +
> +#define SKIP_INIT(fn_or_group) \
> +	static const char __skip_init_ ## fn_or_group[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"(s:" #fn_or_group ")\n";
> +
> +#define REPLACE_INIT(old_fn_or_group, new_fn_or_group) \
> +	static const char __replace_init_ ## old_fn_or_group[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"(r:" #old_fn_or_group ":" #new_fn_or_group ")\n";
> +#else
> +#define INIT_FUNC(fn, group, man_reqs, pre_reqs, post_reqs)
> +#define SKIP_INIT(fn_or_group)
> +#define REPLACE_INIT(old_fn_or_group, new_fn_or_group)
> +#endif
> +#endif /* !__INIT_FUNC_H__ */
> diff --git a/tools/Makefile b/tools/Makefile
> index 8993fdd..e6ba6ef 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -68,6 +68,7 @@ BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
>  BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
>  BIN_FILES-y += mkenvimage$(SFX)
>  BIN_FILES-y += mkimage$(SFX)
> +BIN_FILES-$(CONFIG_INIT_FUNC) += mkinitseq$(SFX)
>  BIN_FILES-$(CONFIG_SMDK5250) += mksmdk5250spl$(SFX)
>  BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
>  BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
> @@ -95,6 +96,7 @@ NOPED_OBJ_FILES-y += imximage.o
>  NOPED_OBJ_FILES-y += omapimage.o
>  NOPED_OBJ_FILES-y += mkenvimage.o
>  NOPED_OBJ_FILES-y += mkimage.o
> +NOPED_OBJ_FILES-$(CONFIG_INIT_FUNC) += mkinitseq.o
>  OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
>  OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
>  OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
> @@ -215,6 +217,10 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \
>  	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
>  	$(HOSTSTRIP) $@
> 
> +$(obj)mkinitseq$(SFX):	$(obj)mkinitseq.o
> +	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
> +	$(HOSTSTRIP) $@
> +
>  $(obj)mk$(BOARD)spl$(SFX):	$(obj)mkexynosspl.o
>  	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
>  	$(HOSTSTRIP) $@
> diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
> new file mode 100644
> index 0000000..b150de4
> --- /dev/null
> +++ b/tools/mkinitseq.c
> @@ -0,0 +1,1512 @@

Ok, this is the worst part. I think this could be reimplemented in shell ;-)

> +/*
> + * (C) Copyright 2012
> + * Graeme Russ <graeme.russ@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +/**
> + * container_of - cast a member of a structure out to the containing
> structure + * @ptr:	the pointer to the member.
> + * @type:	the type of the container struct this is embedded in.
> + * @member:	the name of the member within the struct.
> + *
> + */
> +#define container_of(ptr, type, member) ({			\
> +	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> +	(type *)( (char *)__mptr - offsetof(type,member) );})

Don't we already have this defined in uboot ?

[...]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-05-03  0:08   ` Marek Vasut
@ 2012-05-03  3:06     ` Graeme Russ
  2012-05-03  3:18       ` Marek Vasut
  0 siblings, 1 reply; 10+ messages in thread
From: Graeme Russ @ 2012-05-03  3:06 UTC (permalink / raw)
  To: u-boot

Hi Marek,

Thanks for taking a look


>> +The INIT_FUNC macro allows initialisation functions (i.e. functions which
>> are +executed before the main loop) to be easily added to the init
>> sequence +
>> +
>> +Specifying an Initialisation Function and is Dependencies
>> +---------------------------------------------------------
>> +The format of the INIT_FUNC macro is:
>> +
>> +INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
>> +
>> +fn is the name of the init function to call. This function must have the
>> +following prototype:
>> +
>> +int foo(void);
>
> What if I want to pass some data to such a func ? Clearly, I can think of this
> being doable, but extra hard.

The idea is that no changes are being made to the existing init methodology.

>> +
>> +Each init function must return 0 to indicate success - any other return
>> value +indicates failure and the init sequence will stop
>> +
>> +grp is the name of the group that the init function belongs to. grp may be
>> +the same as fn for any individual init function, but between init
>> functions, +fn and grp must be unique.
>> +
>> +The purpose of groups is to allow functions to be grouped together so
>> other +functions can specify the group as a whole as a dependency rather
>> than having +to list every function in the group in the dependency list
>> +
>> +man_reqs is a space seperated list of functions or groups that MUST exist
>> and +MUST run BEFORE fn
>> +
>> +pre_reqs is a space seperated list of functions or groups that MAY exist
>> and +(if they do) MUST run BEFORE fn
>> +
>> +pst_reqs is a space seperated list of functions or groups that MAY exist
>> and +(if they do) MUST run AFTER fn
>
> What's the point? Can't you create a kind of proxy object that the pst_reqs will
> have as a pre_req ?
>
> Maybe you should create this:
>
> INIT_FUNC(fn, grp, prereqs, postreqs) and for each function from prereqs and
> postreqs, specify per-function attributes via the GCC __attribute__(())
> directive, like if the function must run before something or may run before
> something etc?

Eep, I would like to see that implemented - I'm sure it would be
'interesting'

The way INIT_FUNC and friends work is to simply build a list of static
strings (which we just happen to shove in a seperate section so they can
be filtered in/out based on the link stage)

>> +
>> +Skipping or Replacing a Function or Group
>> +-----------------------------------------
>> +Occassionally, a board may provide a completely seperate implementation
>> for +an initialisation function that is provided in the common arch, SoC
>> or +common code.
>> +
>> +SKIP_INIT(fn_or_group)
>> +
>> +After the initialisation function dependencies are calculated, all
>> functions +and groups listed in any SKIP_INITs are removed - This may
>> result in +dependent functions being removed - It is up to the board code
>> developer +to ensure suitable replacements are in place
>> +
>> +REPLACE_INIT(old_fn_or_group, new_fn_or_group)
>> +
>> +Like SKIP_INIT but replaces on function with another (or one group with
>> +another)
>> +
>> +Example: In the SoC code yoy may have
>
> Yoy :)

Yes. The ultimate goal is to remove a heap of '#ifdef mess' and delegate
the selection of initialiasation functions to where is is most appropriate.
CPU init in ARCH code with board specific init in board code with the
ARCH code 100% unaware of what the board is doing. This will also make it
a lot easier for vendors to implement multi-arch solutions :)

>> +
>> +INIT_FUNC(init_cpu_f, RESET, , , );
>> +
>> +In the board code, you may want a slightly tweaked version, so you might
>> +have:
>> +
>> +int my_new_init_cpu_f(void)
>> +{
>> + ? ? ...
>> +}
>> +REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);

[snip]

>> diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
>> new file mode 100644
>> index 0000000..b150de4
>> --- /dev/null
>> +++ b/tools/mkinitseq.c
>> @@ -0,0 +1,1512 @@
>
> Ok, this is the worst part. I think this could be reimplemented in shell ;-)

Be my guest :) - Have a really good look at what is happening behind the
scenes - Lots of list processing and checking. In particular, the processing
of the REPLACE and SKIP macros would be particularly nasty.

I have no problem with this being done in shell code. BUT if I have to do
so in order for it to be accepted, then I'll bin this patch series right
now. I'm more than happy to integrate somebody elses shell-based tool into
the series. Sorry to be so blunt, but I do not have the time or energy to
re-implement this myself.

My argument is that this is a black-box tool like gcc/ld. Once we prove it
to do what it does correctly, we can 'leave it alone'(tm) and test cases
are fairly trivial. You can even mock-up the input file in vi :)

And is a shell based implementation going to be any easier to understand,
modify, debug, etc?

>> +/*
>> + * (C) Copyright 2012
>> + * Graeme Russ <graeme.russ@gmail.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
>> + * MA 02111-1307 USA
>> + */
>> +
>> +/**
>> + * container_of - cast a member of a structure out to the containing
>> structure + * @ptr: ? the pointer to the member.
>> + * @type: ? ?the type of the container struct this is embedded in.
>> + * @member: ?the name of the member within the struct.
>> + *
>> + */
>> +#define container_of(ptr, type, member) ({ ? ? ? ? ? ? ? ? ? \
>> + ? ? const typeof( ((type *)0)->member ) *__mptr = (ptr); ? ?\
>> + ? ? (type *)( (char *)__mptr - offsetof(type,member) );})
>
> Don't we already have this defined in uboot ?

mkinitseq is host-code so it only brings in host headers (not U-Boot
headers) - If you don't have Linux kernel headers installed, you can't
get this macro. Actually, even though I do have them, I had a hard time
getting this macro in, so I gave up - Any hints?

As an aside, I wonder if the kernel headers are required for the list
macros?

Regards,

Graeme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-05-03  3:06     ` Graeme Russ
@ 2012-05-03  3:18       ` Marek Vasut
  2012-05-03  4:12         ` Graeme Russ
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Vasut @ 2012-05-03  3:18 UTC (permalink / raw)
  To: u-boot

Dear Graeme Russ,

> Hi Marek,
> 
> Thanks for taking a look
> 
> >> +The INIT_FUNC macro allows initialisation functions (i.e. functions
> >> which are +executed before the main loop) to be easily added to the
> >> init sequence +
> >> +
> >> +Specifying an Initialisation Function and is Dependencies
> >> +---------------------------------------------------------
> >> +The format of the INIT_FUNC macro is:
> >> +
> >> +INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
> >> +
> >> +fn is the name of the init function to call. This function must have
> >> the +following prototype:
> >> +
> >> +int foo(void);
> > 
> > What if I want to pass some data to such a func ? Clearly, I can think of
> > this being doable, but extra hard.
> 
> The idea is that no changes are being made to the existing init
> methodology.

Well ... what if I want to pass eg. pdata?

> 
> >> +
> >> +Each init function must return 0 to indicate success - any other return
> >> value +indicates failure and the init sequence will stop
> >> +
> >> +grp is the name of the group that the init function belongs to. grp may
> >> be +the same as fn for any individual init function, but between init
> >> functions, +fn and grp must be unique.
> >> +
> >> +The purpose of groups is to allow functions to be grouped together so
> >> other +functions can specify the group as a whole as a dependency rather
> >> than having +to list every function in the group in the dependency list
> >> +
> >> +man_reqs is a space seperated list of functions or groups that MUST
> >> exist and +MUST run BEFORE fn
> >> +
> >> +pre_reqs is a space seperated list of functions or groups that MAY
> >> exist and +(if they do) MUST run BEFORE fn
> >> +
> >> +pst_reqs is a space seperated list of functions or groups that MAY
> >> exist and +(if they do) MUST run AFTER fn
> > 
> > What's the point? Can't you create a kind of proxy object that the
> > pst_reqs will have as a pre_req ?
> > 
> > Maybe you should create this:
> > 
> > INIT_FUNC(fn, grp, prereqs, postreqs) and for each function from prereqs
> > and postreqs, specify per-function attributes via the GCC
> > __attribute__(()) directive, like if the function must run before
> > something or may run before something etc?
> 
> Eep, I would like to see that implemented - I'm sure it would be
> 'interesting'

Pervy and sadistic at least :-)

> The way INIT_FUNC and friends work is to simply build a list of static
> strings (which we just happen to shove in a seperate section so they can
> be filtered in/out based on the link stage)

Yes, I got the understanding of it. I was more bothered by the man_reqs and 
pre_reqs, what if we soon need functions that are executed under another weird 
condition? And if you look at it the other way -- if you need function that's 
executed conditionally, why not wrap the condition into the pre_req (or some 
proxy object, whatever).

> 
> >> +
> >> +Skipping or Replacing a Function or Group
> >> +-----------------------------------------
> >> +Occassionally, a board may provide a completely seperate implementation
> >> for +an initialisation function that is provided in the common arch, SoC
> >> or +common code.
> >> +
> >> +SKIP_INIT(fn_or_group)
> >> +
> >> +After the initialisation function dependencies are calculated, all
> >> functions +and groups listed in any SKIP_INITs are removed - This may
> >> result in +dependent functions being removed - It is up to the board
> >> code developer +to ensure suitable replacements are in place
> >> +
> >> +REPLACE_INIT(old_fn_or_group, new_fn_or_group)
> >> +
> >> +Like SKIP_INIT but replaces on function with another (or one group with
> >> +another)
> >> +
> >> +Example: In the SoC code yoy may have
> > 
> > Yoy :)
> 
> Yes. The ultimate goal is to remove a heap of '#ifdef mess' and delegate
> the selection of initialiasation functions to where is is most appropriate.
> CPU init in ARCH code with board specific init in board code with the
> ARCH code 100% unaware of what the board is doing. This will also make it
> a lot easier for vendors to implement multi-arch solutions :)

Correct, alongside kbuild and driver model, we'll make an awesome bootloader. 
But fix that s/yoy/you/ please ;-)

> >> +
> >> +INIT_FUNC(init_cpu_f, RESET, , , );
> >> +
> >> +In the board code, you may want a slightly tweaked version, so you
> >> might +have:
> >> +
> >> +int my_new_init_cpu_f(void)
> >> +{
> >> +     ...
> >> +}
> >> +REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
> 
> [snip]
> 
> >> diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
> >> new file mode 100644
> >> index 0000000..b150de4
> >> --- /dev/null
> >> +++ b/tools/mkinitseq.c
> >> @@ -0,0 +1,1512 @@
> > 
> > Ok, this is the worst part. I think this could be reimplemented in shell
> > ;-)
> 
> Be my guest :) - Have a really good look at what is happening behind the
> scenes - Lots of list processing and checking. In particular, the
> processing of the REPLACE and SKIP macros would be particularly nasty.

That's what sed can do for you, can't it ?

> I have no problem with this being done in shell code. BUT if I have to do
> so in order for it to be accepted, then I'll bin this patch series right
> now. I'm more than happy to integrate somebody elses shell-based tool into
> the series. Sorry to be so blunt, but I do not have the time or energy to
> re-implement this myself.

Ooh, I smell flame-fuel :-) I'd certainly prefer to see this in shell, since I 
believe the substitutions and reordering of text might be easier there.

> My argument is that this is a black-box tool like gcc/ld. Once we prove it
> to do what it does correctly, we can 'leave it alone'(tm) and test cases
> are fairly trivial. You can even mock-up the input file in vi :)

Ewwwwww ... like gcc/ld ... or maybe like Windows (TM)(C)(R)(?) :-D

> And is a shell based implementation going to be any easier to understand,
> modify, debug, etc?

I wonder :-)

> >> +/*
> >> + * (C) Copyright 2012
> >> + * Graeme Russ <graeme.russ@gmail.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or
> >> + * modify it under the terms of the GNU General Public License as
> >> + * published by the Free Software Foundation; either version 2 of
> >> + * the License, or (at your option) any later version.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program; if not, write to the Free Software
> >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> >> + * MA 02111-1307 USA
> >> + */
> >> +
> >> +/**
> >> + * container_of - cast a member of a structure out to the containing
> >> structure + * @ptr:   the pointer to the member.
> >> + * @type:    the type of the container struct this is embedded in.
> >> + * @member:  the name of the member within the struct.
> >> + *
> >> + */
> >> +#define container_of(ptr, type, member) ({                   \
> >> +     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
> >> +     (type *)( (char *)__mptr - offsetof(type,member) );})
> > 
> > Don't we already have this defined in uboot ?
> 
> mkinitseq is host-code so it only brings in host headers (not U-Boot
> headers) - If you don't have Linux kernel headers installed, you can't
> get this macro. Actually, even though I do have them, I had a hard time
> getting this macro in, so I gave up - Any hints?

Reimplement this thing in shell :-)

> 
> As an aside, I wonder if the kernel headers are required for the list
> macros?

Nope.
> 
> Regards,
> 
> Graeme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-05-03  3:18       ` Marek Vasut
@ 2012-05-03  4:12         ` Graeme Russ
  2012-05-03 14:38           ` Marek Vasut
  0 siblings, 1 reply; 10+ messages in thread
From: Graeme Russ @ 2012-05-03  4:12 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On Thu, May 3, 2012 at 1:18 PM, Marek Vasut <marex@denx.de> wrote:
> Dear Graeme Russ,
>
>> Hi Marek,
>>
>> Thanks for taking a look
>>
>> >> +The INIT_FUNC macro allows initialisation functions (i.e. functions
>> >> which are +executed before the main loop) to be easily added to the
>> >> init sequence +
>> >> +
>> >> +Specifying an Initialisation Function and is Dependencies
>> >> +---------------------------------------------------------
>> >> +The format of the INIT_FUNC macro is:
>> >> +
>> >> +INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
>> >> +
>> >> +fn is the name of the init function to call. This function must have
>> >> the +following prototype:
>> >> +
>> >> +int foo(void);
>> >
>> > What if I want to pass some data to such a func ? Clearly, I can think of
>> > this being doable, but extra hard.
>>
>> The idea is that no changes are being made to the existing init
>> methodology.
>
> Well ... what if I want to pass eg. pdata?

Do what we do now - Global Data is the only way to pass data between
initialisation functions. Sure, this _might_ change in the future (but I
doubt it) but we can deal with that later

>> >> +
>> >> +Each init function must return 0 to indicate success - any other return
>> >> value +indicates failure and the init sequence will stop
>> >> +
>> >> +grp is the name of the group that the init function belongs to. grp may
>> >> be +the same as fn for any individual init function, but between init
>> >> functions, +fn and grp must be unique.
>> >> +
>> >> +The purpose of groups is to allow functions to be grouped together so
>> >> other +functions can specify the group as a whole as a dependency rather
>> >> than having +to list every function in the group in the dependency list
>> >> +
>> >> +man_reqs is a space seperated list of functions or groups that MUST
>> >> exist and +MUST run BEFORE fn
>> >> +
>> >> +pre_reqs is a space seperated list of functions or groups that MAY
>> >> exist and +(if they do) MUST run BEFORE fn
>> >> +
>> >> +pst_reqs is a space seperated list of functions or groups that MAY
>> >> exist and +(if they do) MUST run AFTER fn
>> >
>> > What's the point? Can't you create a kind of proxy object that the
>> > pst_reqs will have as a pre_req ?
>> >
>> > Maybe you should create this:
>> >
>> > INIT_FUNC(fn, grp, prereqs, postreqs) and for each function from prereqs
>> > and postreqs, specify per-function attributes via the GCC
>> > __attribute__(()) directive, like if the function must run before
>> > something or may run before something etc?
>>
>> Eep, I would like to see that implemented - I'm sure it would be
>> 'interesting'
>
> Pervy and sadistic at least :-)
>
>> The way INIT_FUNC and friends work is to simply build a list of static
>> strings (which we just happen to shove in a seperate section so they can
>> be filtered in/out based on the link stage)
>
> Yes, I got the understanding of it. I was more bothered by the man_reqs and
> pre_reqs, what if we soon need functions that are executed under another weird
> condition? And if you look at it the other way -- if you need function that's
> executed conditionally, why not wrap the condition into the pre_req (or some
> proxy object, whatever).

It's not about being executed conditionally - It's about 'I need to be
initialised after 'X', but if 'X' does not exist, I can still initialise'

Network is one example - If you have a PCI network adapter, it must be
intialised after PCI. But if the adapter is not PCI, you still want to be
able to initialise it

Timer is another - Hopefully the timer infrastructure will soon be an arch
independent API. But each arch (and potentially down to the board level)
may have a role to play in getting the timer infrastucture running (FPGA,
PLL, PIT intialiastion). So potentially, the common driver code would be
intialised with:

INIT_FUNC(timer_api, timer, arch_timer, board_timer, );

So the arch_timer function MUST exist and it MUST run before timer_api. The
board specific timer initialisation is optional. If the board has timer
related code, it MUST run before timer_api but timer_api can still run if
board_timer does not exist (i.e. all the timer init done at the arch level)

Now depending on the arch and board, board_timer may be either:

INIT_FUNC(board_timer, timer, arch_timer, , timer_api);

i.e. arch -> board -> api

or

INIT_FUNC(board_timer, timer, , , arch_timer timer_api);

i.e. board -> arch -> api

NOTE: In both of the above example, including timer_api as a post-req
is redundant. The timer_api INIT_FUNC definition already mandated the
order. This is not a problem and including or excluding it makes no
difference to the output. Of course, including timer_api in the above
examples means we could have done:

INIT_FUNC(timer_api, timer, arch_timer, , );

But adding the redundant references makes it clearer when you are looking
at that bit of code. The 'black-box' tool will warn you if you created a
circular reference and will print out what the init sequence is that
created the circular reference.

Now, here is where the fun begins :) - Lets say you need timer support
early, but you can't get the low level infrastructure for hi-res timers
running until later...

board/vendor_me/common/timer.c
INIT_FUNC(me_timer_init, me_late_timer, me_pit_init, , );
INIT_FUNC(me_pit_init, me_late_timer, , fpga_init pll_init, me_timer_init);

(again, me_late_timer in the second INIT_FUNC is redundant)

board/vendor_me/board_a/timer.c
INIT_FUNC(fpga_init, me_late_timer, , , me_pit_init);

board/vendor_me/board_b/timer.c
INIT_FUNC(pll_init, me_late_timer, , , me_pit_init);

(again, me_pit_init in these INIT_FUNCs is redundant)

board/vendor_me/board_c/timer.c
/*
 * This board has the PIT hard-wired to a crystal oscillator so there
 * is now board_level init function - So we can actually initialise
 * the PIT earlier :)
 */
int me_pit_early_init(void)
{
        return me_pit_init();
}
INIT_FUNC(me_pit_early_init, timer, arch_timer, , );

/*
 * Don't need any late timer init - This will skip both me_timer_init and
 * me_pit_init as they have been defined in the me_late_timer group
 */
INIT_SKIP(me_late_timer);

The idea is that me_late_timer() will perform some tweak to the timer API
to redirect it to the hi-res clock source. The hi-res clock source is
driven by a PIT common to all the boards manufacture by this vendor. But
the PIT has a different raw clock source depending on a particular board
Board A has an FPGA, board B has a PLL and board C uses a hard-wired
crystal oscillator

>> >> +
>> >> +Skipping or Replacing a Function or Group
>> >> +-----------------------------------------
>> >> +Occassionally, a board may provide a completely seperate implementation
>> >> for +an initialisation function that is provided in the common arch, SoC
>> >> or +common code.
>> >> +
>> >> +SKIP_INIT(fn_or_group)
>> >> +
>> >> +After the initialisation function dependencies are calculated, all
>> >> functions +and groups listed in any SKIP_INITs are removed - This may
>> >> result in +dependent functions being removed - It is up to the board
>> >> code developer +to ensure suitable replacements are in place
>> >> +
>> >> +REPLACE_INIT(old_fn_or_group, new_fn_or_group)
>> >> +
>> >> +Like SKIP_INIT but replaces on function with another (or one group with
>> >> +another)
>> >> +
>> >> +Example: In the SoC code yoy may have
>> >
>> > Yoy :)
>>
>> Yes. The ultimate goal is to remove a heap of '#ifdef mess' and delegate
>> the selection of initialiasation functions to where is is most appropriate.
>> CPU init in ARCH code with board specific init in board code with the
>> ARCH code 100% unaware of what the board is doing. This will also make it
>> a lot easier for vendors to implement multi-arch solutions :)
>
> Correct, alongside kbuild and driver model, we'll make an awesome bootloader.
> But fix that s/yoy/you/ please ;-)

Ah, I see now... Will do

>> >> +
>> >> +INIT_FUNC(init_cpu_f, RESET, , , );
>> >> +
>> >> +In the board code, you may want a slightly tweaked version, so you
>> >> might +have:
>> >> +
>> >> +int my_new_init_cpu_f(void)
>> >> +{
>> >> + ? ? ...
>> >> +}
>> >> +REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
>>
>> [snip]
>>
>> >> diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
>> >> new file mode 100644
>> >> index 0000000..b150de4
>> >> --- /dev/null
>> >> +++ b/tools/mkinitseq.c
>> >> @@ -0,0 +1,1512 @@
>> >
>> > Ok, this is the worst part. I think this could be reimplemented in shell
>> > ;-)
>>
>> Be my guest :) - Have a really good look at what is happening behind the
>> scenes - Lots of list processing and checking. In particular, the
>> processing of the REPLACE and SKIP macros would be particularly nasty.
>
> That's what sed can do for you, can't it ?

So below - If you can show me (i.e. write the whole thing in shell) I might
include it

>> I have no problem with this being done in shell code. BUT if I have to do
>> so in order for it to be accepted, then I'll bin this patch series right
>> now. I'm more than happy to integrate somebody elses shell-based tool into
>> the series. Sorry to be so blunt, but I do not have the time or energy to
>> re-implement this myself.
>
> Ooh, I smell flame-fuel :-) I'd certainly prefer to see this in shell, since I
> believe the substitutions and reordering of text might be easier there.

See above - be my guest ;)

>> My argument is that this is a black-box tool like gcc/ld. Once we prove it
>> to do what it does correctly, we can 'leave it alone'(tm) and test cases
>> are fairly trivial. You can even mock-up the input file in vi :)
>
> Ewwwwww ... like gcc/ld ... or maybe like Windows (TM)(C)(R)(?) :-D

No, like FLOSS gcc/ld :P

>> And is a shell based implementation going to be any easier to understand,
>> modify, debug, etc?
>
> I wonder :-)

Well, if someone manages to do it in shell, we will see - Take a look at
main() - I have been very carefull to layout the way the tool operates in
a very linear way but ther lists are global, so sharing data between the
shell stages will be a pain (pipes?)

>> >> +/*
>> >> + * (C) Copyright 2012
>> >> + * Graeme Russ <graeme.russ@gmail.com>
>> >> + *
>> >> + * This program is free software; you can redistribute it and/or
>> >> + * modify it under the terms of the GNU General Public License as
>> >> + * published by the Free Software Foundation; either version 2 of
>> >> + * the License, or (at your option) any later version.
>> >> + *
>> >> + * This program is distributed in the hope that it will be useful,
>> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
>> >> + * GNU General Public License for more details.
>> >> + *
>> >> + * You should have received a copy of the GNU General Public License
>> >> + * along with this program; if not, write to the Free Software
>> >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
>> >> + * MA 02111-1307 USA
>> >> + */
>> >> +
>> >> +/**
>> >> + * container_of - cast a member of a structure out to the containing
>> >> structure + * @ptr: ? the pointer to the member.
>> >> + * @type: ? ?the type of the container struct this is embedded in.
>> >> + * @member: ?the name of the member within the struct.
>> >> + *
>> >> + */
>> >> +#define container_of(ptr, type, member) ({ ? ? ? ? ? ? ? ? ? \
>> >> + ? ? const typeof( ((type *)0)->member ) *__mptr = (ptr); ? ?\
>> >> + ? ? (type *)( (char *)__mptr - offsetof(type,member) );})
>> >
>> > Don't we already have this defined in uboot ?
>>
>> mkinitseq is host-code so it only brings in host headers (not U-Boot
>> headers) - If you don't have Linux kernel headers installed, you can't
>> get this macro. Actually, even though I do have them, I had a hard time
>> getting this macro in, so I gave up - Any hints?
>
> Reimplement this thing in shell :-)

You already know my answer to this ;)

>> As an aside, I wonder if the kernel headers are required for the list
>> macros?
>
> Nope.

Good :)

Regards,

Graeme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [PATCH 1/3] init_func: Add fundamental framework
  2012-05-03  4:12         ` Graeme Russ
@ 2012-05-03 14:38           ` Marek Vasut
  0 siblings, 0 replies; 10+ messages in thread
From: Marek Vasut @ 2012-05-03 14:38 UTC (permalink / raw)
  To: u-boot

Dear Graeme Russ,

> Hi Marek,
> 
> On Thu, May 3, 2012 at 1:18 PM, Marek Vasut <marex@denx.de> wrote:
> > Dear Graeme Russ,
> > 
> >> Hi Marek,
> >> 
> >> Thanks for taking a look
> >> 
> >> >> +The INIT_FUNC macro allows initialisation functions (i.e. functions
> >> >> which are +executed before the main loop) to be easily added to the
> >> >> init sequence +
> >> >> +
> >> >> +Specifying an Initialisation Function and is Dependencies
> >> >> +---------------------------------------------------------
> >> >> +The format of the INIT_FUNC macro is:
> >> >> +
> >> >> +INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
> >> >> +
> >> >> +fn is the name of the init function to call. This function must have
> >> >> the +following prototype:
> >> >> +
> >> >> +int foo(void);
> >> > 
> >> > What if I want to pass some data to such a func ? Clearly, I can think
> >> > of this being doable, but extra hard.
> >> 
> >> The idea is that no changes are being made to the existing init
> >> methodology.
> > 
> > Well ... what if I want to pass eg. pdata?
> 
> Do what we do now - Global Data is the only way to pass data between
> initialisation functions. Sure, this _might_ change in the future (but I
> doubt it) but we can deal with that later

Global data won't die, but they should shrink as much as possible ... so I don't 
like the idea of using global data that way.

> 
> >> >> +
> >> >> +Each init function must return 0 to indicate success - any other
> >> >> return value +indicates failure and the init sequence will stop
> >> >> +
> >> >> +grp is the name of the group that the init function belongs to. grp
> >> >> may be +the same as fn for any individual init function, but between
> >> >> init functions, +fn and grp must be unique.
> >> >> +
> >> >> +The purpose of groups is to allow functions to be grouped together
> >> >> so other +functions can specify the group as a whole as a dependency
> >> >> rather than having +to list every function in the group in the
> >> >> dependency list +
> >> >> +man_reqs is a space seperated list of functions or groups that MUST
> >> >> exist and +MUST run BEFORE fn
> >> >> +
> >> >> +pre_reqs is a space seperated list of functions or groups that MAY
> >> >> exist and +(if they do) MUST run BEFORE fn
> >> >> +
> >> >> +pst_reqs is a space seperated list of functions or groups that MAY
> >> >> exist and +(if they do) MUST run AFTER fn
> >> > 
> >> > What's the point? Can't you create a kind of proxy object that the
> >> > pst_reqs will have as a pre_req ?
> >> > 
> >> > Maybe you should create this:
> >> > 
> >> > INIT_FUNC(fn, grp, prereqs, postreqs) and for each function from
> >> > prereqs and postreqs, specify per-function attributes via the GCC
> >> > __attribute__(()) directive, like if the function must run before
> >> > something or may run before something etc?
> >> 
> >> Eep, I would like to see that implemented - I'm sure it would be
> >> 'interesting'
> > 
> > Pervy and sadistic at least :-)
> > 
> >> The way INIT_FUNC and friends work is to simply build a list of static
> >> strings (which we just happen to shove in a seperate section so they can
> >> be filtered in/out based on the link stage)
> > 
> > Yes, I got the understanding of it. I was more bothered by the man_reqs
> > and pre_reqs, what if we soon need functions that are executed under
> > another weird condition? And if you look at it the other way -- if you
> > need function that's executed conditionally, why not wrap the condition
> > into the pre_req (or some proxy object, whatever).
> 
> It's not about being executed conditionally - It's about 'I need to be
> initialised after 'X', but if 'X' does not exist, I can still initialise'
> 
> Network is one example - If you have a PCI network adapter, it must be
> intialised after PCI. But if the adapter is not PCI, you still want to be
> able to initialise it

So why don't we make function, that can depend on "OR-group" and/or "AND-group" 
then? Won't that be more logical? I mean, group where you must execute as much 
as possible, to be OR-group and group where you must execute everything to be 
AND-group.

> 
> Timer is another - Hopefully the timer infrastructure will soon be an arch
> independent API. But each arch (and potentially down to the board level)
> may have a role to play in getting the timer infrastucture running (FPGA,
> PLL, PIT intialiastion). So potentially, the common driver code would be
> intialised with:

Well, I hope to create unified timer api with the DM biz.

> INIT_FUNC(timer_api, timer, arch_timer, board_timer, );
> 
> So the arch_timer function MUST exist and it MUST run before timer_api. The
> board specific timer initialisation is optional. If the board has timer
> related code, it MUST run before timer_api but timer_api can still run if
> board_timer does not exist (i.e. all the timer init done at the arch level)

Ok, I see. OR-groups won't fit in here?

> Now depending on the arch and board, board_timer may be either:
> 
> INIT_FUNC(board_timer, timer, arch_timer, , timer_api);
> 
> i.e. arch -> board -> api
> 
> or
> 
> INIT_FUNC(board_timer, timer, , , arch_timer timer_api);
> 
> i.e. board -> arch -> api
> 
> NOTE: In both of the above example, including timer_api as a post-req
> is redundant. The timer_api INIT_FUNC definition already mandated the
> order. This is not a problem and including or excluding it makes no
> difference to the output. Of course, including timer_api in the above
> examples means we could have done:
> 
> INIT_FUNC(timer_api, timer, arch_timer, , );
> 
> But adding the redundant references makes it clearer when you are looking
> at that bit of code. The 'black-box' tool will warn you if you created a
> circular reference and will print out what the init sequence is that
> created the circular reference.

Neat.

> Now, here is where the fun begins :) - Lets say you need timer support
> early, but you can't get the low level infrastructure for hi-res timers
> running until later...
> 
> board/vendor_me/common/timer.c
> INIT_FUNC(me_timer_init, me_late_timer, me_pit_init, , );
> INIT_FUNC(me_pit_init, me_late_timer, , fpga_init pll_init, me_timer_init);
> 
> (again, me_late_timer in the second INIT_FUNC is redundant)
> 
> board/vendor_me/board_a/timer.c
> INIT_FUNC(fpga_init, me_late_timer, , , me_pit_init);
> 
> board/vendor_me/board_b/timer.c
> INIT_FUNC(pll_init, me_late_timer, , , me_pit_init);
> 
> (again, me_pit_init in these INIT_FUNCs is redundant)
> 
> board/vendor_me/board_c/timer.c
> /*
>  * This board has the PIT hard-wired to a crystal oscillator so there
>  * is now board_level init function - So we can actually initialise
>  * the PIT earlier :)
>  */
> int me_pit_early_init(void)
> {
>         return me_pit_init();
> }
> INIT_FUNC(me_pit_early_init, timer, arch_timer, , );
> 
> /*
>  * Don't need any late timer init - This will skip both me_timer_init and
>  * me_pit_init as they have been defined in the me_late_timer group
>  */
> INIT_SKIP(me_late_timer);
> 
> The idea is that me_late_timer() will perform some tweak to the timer API
> to redirect it to the hi-res clock source. The hi-res clock source is
> driven by a PIT common to all the boards manufacture by this vendor. But
> the PIT has a different raw clock source depending on a particular board
> Board A has an FPGA, board B has a PLL and board C uses a hard-wired
> crystal oscillator

I see.

> >> >> +
> >> >> +Skipping or Replacing a Function or Group
> >> >> +-----------------------------------------
> >> >> +Occassionally, a board may provide a completely seperate
> >> >> implementation for +an initialisation function that is provided in
> >> >> the common arch, SoC or +common code.
> >> >> +
> >> >> +SKIP_INIT(fn_or_group)
> >> >> +
> >> >> +After the initialisation function dependencies are calculated, all
> >> >> functions +and groups listed in any SKIP_INITs are removed - This may
> >> >> result in +dependent functions being removed - It is up to the board
> >> >> code developer +to ensure suitable replacements are in place
> >> >> +
> >> >> +REPLACE_INIT(old_fn_or_group, new_fn_or_group)
> >> >> +
> >> >> +Like SKIP_INIT but replaces on function with another (or one group
> >> >> with +another)
> >> >> +
> >> >> +Example: In the SoC code yoy may have
> >> > 
> >> > Yoy :)
> >> 
> >> Yes. The ultimate goal is to remove a heap of '#ifdef mess' and delegate
> >> the selection of initialiasation functions to where is is most
> >> appropriate. CPU init in ARCH code with board specific init in board
> >> code with the ARCH code 100% unaware of what the board is doing. This
> >> will also make it a lot easier for vendors to implement multi-arch
> >> solutions :)
> > 
> > Correct, alongside kbuild and driver model, we'll make an awesome
> > bootloader. But fix that s/yoy/you/ please ;-)
> 
> Ah, I see now... Will do
> 
> >> >> +
> >> >> +INIT_FUNC(init_cpu_f, RESET, , , );
> >> >> +
> >> >> +In the board code, you may want a slightly tweaked version, so you
> >> >> might +have:
> >> >> +
> >> >> +int my_new_init_cpu_f(void)
> >> >> +{
> >> >> +     ...
> >> >> +}
> >> >> +REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
> >> 
> >> [snip]
> >> 
> >> >> diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
> >> >> new file mode 100644
> >> >> index 0000000..b150de4
> >> >> --- /dev/null
> >> >> +++ b/tools/mkinitseq.c
> >> >> @@ -0,0 +1,1512 @@
> >> > 
> >> > Ok, this is the worst part. I think this could be reimplemented in
> >> > shell ;-)
> >> 
> >> Be my guest :) - Have a really good look at what is happening behind the
> >> scenes - Lots of list processing and checking. In particular, the
> >> processing of the REPLACE and SKIP macros would be particularly nasty.
> > 
> > That's what sed can do for you, can't it ?
> 
> So below - If you can show me (i.e. write the whole thing in shell) I might
> include it

I'll think about it ;-)

> >> I have no problem with this being done in shell code. BUT if I have to
> >> do so in order for it to be accepted, then I'll bin this patch series
> >> right now. I'm more than happy to integrate somebody elses shell-based
> >> tool into the series. Sorry to be so blunt, but I do not have the time
> >> or energy to re-implement this myself.
> > 
> > Ooh, I smell flame-fuel :-) I'd certainly prefer to see this in shell,
> > since I believe the substitutions and reordering of text might be easier
> > there.
> 
> See above - be my guest ;)
> 
> >> My argument is that this is a black-box tool like gcc/ld. Once we prove
> >> it to do what it does correctly, we can 'leave it alone'(tm) and test
> >> cases are fairly trivial. You can even mock-up the input file in vi :)
> > 
> > Ewwwwww ... like gcc/ld ... or maybe like Windows (TM)(C)(R)(?) :-D
> 
> No, like FLOSS gcc/ld :P

:-)

> >> And is a shell based implementation going to be any easier to
> >> understand, modify, debug, etc?
> > 
> > I wonder :-)
> 
> Well, if someone manages to do it in shell, we will see - Take a look at
> main() - I have been very carefull to layout the way the tool operates in
> a very linear way but ther lists are global, so sharing data between the
> shell stages will be a pain (pipes?)

Bash can do locals ;-)

> >> >> +/*
> >> >> + * (C) Copyright 2012
> >> >> + * Graeme Russ <graeme.russ@gmail.com>
> >> >> + *
> >> >> + * This program is free software; you can redistribute it and/or
> >> >> + * modify it under the terms of the GNU General Public License as
> >> >> + * published by the Free Software Foundation; either version 2 of
> >> >> + * the License, or (at your option) any later version.
> >> >> + *
> >> >> + * This program is distributed in the hope that it will be useful,
> >> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> >> + * GNU General Public License for more details.
> >> >> + *
> >> >> + * You should have received a copy of the GNU General Public License
> >> >> + * along with this program; if not, write to the Free Software
> >> >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> >> >> + * MA 02111-1307 USA
> >> >> + */
> >> >> +
> >> >> +/**
> >> >> + * container_of - cast a member of a structure out to the containing
> >> >> structure + * @ptr:   the pointer to the member.
> >> >> + * @type:    the type of the container struct this is embedded in.
> >> >> + * @member:  the name of the member within the struct.
> >> >> + *
> >> >> + */
> >> >> +#define container_of(ptr, type, member) ({                   \
> >> >> +     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
> >> >> +     (type *)( (char *)__mptr - offsetof(type,member) );})
> >> > 
> >> > Don't we already have this defined in uboot ?
> >> 
> >> mkinitseq is host-code so it only brings in host headers (not U-Boot
> >> headers) - If you don't have Linux kernel headers installed, you can't
> >> get this macro. Actually, even though I do have them, I had a hard time
> >> getting this macro in, so I gave up - Any hints?
> > 
> > Reimplement this thing in shell :-)
> 
> You already know my answer to this ;)
> 
> >> As an aside, I wonder if the kernel headers are required for the list
> >> macros?
> > 
> > Nope.
> 
> Good :)
> 
> Regards,
> 
> Graeme

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-05-03 14:38 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-22 15:23 [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Graeme Russ
2012-04-22 15:23 ` [U-Boot] [PATCH 1/3] init_func: Add fundamental framework Graeme Russ
2012-05-03  0:08   ` Marek Vasut
2012-05-03  3:06     ` Graeme Russ
2012-05-03  3:18       ` Marek Vasut
2012-05-03  4:12         ` Graeme Russ
2012-05-03 14:38           ` Marek Vasut
2012-04-22 15:23 ` [U-Boot] [PATCH 2/3] init_func: Add x86 support Graeme Russ
2012-04-22 15:23 ` [U-Boot] [PATCH 3/3] init_func: Use for eNET board Graeme Russ
2012-05-02 23:50 ` [U-Boot] [PATCH 0/3] Initialisation Sequence Framework Marek Vasut

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.