Ronald G. Minnich (rminnich@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1194
-gerrit
commit ea2ef07eb98af9596cedf598b902303919c2d084 Author: Ronald G. Minnich rminnich@chromium.org Date: Mon Jul 2 10:05:57 2012 -0700
Make the device tree available in the rom stage
We've needed a way to use the device tree in romstage for about ten years, and the need has gotten more urgent as the RAM setup takes longer and longer, and requires information only available in the device tree. Further, RAM setup needs a lot more configuration performed than used to be the case, and we've gotten by with hardcodes until now. Finally, for a better "user experience", it is good to have the platform activate, e.g., backlights, so the user knows that the machine is alive. This last problem was the precipitating event for this change.
We thought about two ways to do this change. The way we decided to try was to #ifdef __PRE_RAM__ and #ifndef __PRE_RAM__ a few things: 1. initializers for ops struct member 2. global declarations 3. Definition of which section to place device tree data in.
The sconfig tool can define a SECTION attribute as a struct tag so that device structs can be placed in the readonly area of romstage.
The sconfig tool will now declare structs as follows: struct bus SECTION dev_root_links[]; There are 46 instances on one test board but this is all generated by sconfig. Translation: almost nobody ever looks at this file so I doubt it matters that it's not pretty.
A device struct now looks like this: static struct device SECTION _dev14 = { .ops = 0, .bus = &_dev7_links[0], .path = {.type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x16,3)}}}, .enabled = 0, .on_mainboard = 1, .subsystem_vendor = 0x1ae0, .subsystem_device = 0xc000, .link_list = NULL, .sibling = &_dev15, .chip_ops = &southbridge_intel_bd82x6x_ops, .chip_info = &southbridge_intel_bd82x6x_info_10, .next=&_dev15 };
The result allows us to compile ram- and rom-stage device tree from one file. The sconfig tool is modified so that: 1. References to ops struct members are not generated for PRE_RAM 2. We try to tag global structs and put them into .text 3. Due to a bug in gld, we have to create an accessor function for last_dev. No idea why.
This is tested on a device at Google, and works fine. It allows us to use the config structs in romstage and remove ugly hard-codes.
It will not affect boards that don't use the device tree in romstage.
Right now, one must use the romcc_io.h pci functions OR the device tree oriented pci functions, due to the all-too-clever overloading of the device_t name. We plan to remove this limitation in a future patch, so that both the lowest level non-device tree functions can be used as well as device tree functions. IIRC that's what we did in v3 as well.
This includes a minor tweak to the lint test to make it work correctly and another minor tweak to PCI Makefile that seems to have gotten lost in the 'type 2 must die' upgrade without which it will not compile.
Change-Id: I01589fb57a070128abbcc236951ad58cf044af19 Signed-off-by: Ronald G. Minnich rminnich@gmail.com --- Makefile.inc | 5 ++ src/arch/x86/lib/Makefile.inc | 3 +- src/devices/Makefile.inc | 3 + src/devices/device.c | 2 - src/devices/device_util.c | 66 ++++++++++++++++++++++++++ src/include/device/device.h | 4 ++ util/lint/lint-stable-002-build-dir-handling | 10 ++-- util/sconfig/main.c | 66 +++++++++++++++++++------- 8 files changed, 134 insertions(+), 25 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc index 176ff67..6c96a58 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -228,6 +228,7 @@ $(obj)/mainboard/$(MAINBOARDDIR)/static.c: $(src)/mainboard/$(MAINBOARDDIR)/devi $(objutil)/sconfig/sconfig $(MAINBOARDDIR) $(obj)/mainboard/$(MAINBOARDDIR)
ramstage-y+=$(obj)/mainboard/$(MAINBOARDDIR)/static.c +romstage-y+=$(obj)/mainboard/$(MAINBOARDDIR)/static.c
$(objutil)/%.o: $(objutil)/%.c @printf " HOSTCC $(subst $(objutil)/,,$(@))\n" @@ -237,6 +238,10 @@ $(obj)/%.ramstage.o $(abspath $(obj))/%.ramstage.o: $(obj)/%.c $(obj)/config.h $ @printf " CC $(subst $(obj)/,,$(@))\n" $(CC) -MMD $(CFLAGS) -c -o $@ $<
+$(obj)/%.romstage.o $(abspath $(obj))/%.romstage.o: $(obj)/%.c $(obj)/config.h $(OPTION_TABLE_H) + @printf " CC $(subst $(obj)/,,$(@))\n" + $(CC) -MMD -D__PRE_RAM__ $(CFLAGS) -c -o $@ $< + ####################################################################### # Clean up rules clean-abuild: diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc index 2186072..78f8a23 100644 --- a/src/arch/x86/lib/Makefile.inc +++ b/src/arch/x86/lib/Makefile.inc @@ -1,7 +1,6 @@ ramstage-y += c_start.S ramstage-y += cpu.c ramstage-y += pci_ops_conf1.c -ramstage-$(CONFIG_PCI_CONF2) += pci_ops_conf2.c ramstage-$(CONFIG_MMCONF_SUPPORT) += pci_ops_mmconf.c ramstage-y += exception.c ramstage-$(CONFIG_IOAPIC) += ioapic.c @@ -13,6 +12,8 @@ romstage-y += romstage_console.c romstage-y += cbfs_and_run.c romstage-y += memset.c romstage-y += memcpy.c +romstage-$(CONFIG_MMCONF_SUPPORT) += pci_ops_mmconf.c +romstage-y += pci_ops_conf1.c
smm-y += memset.c smm-y += memcpy.c diff --git a/src/devices/Makefile.inc b/src/devices/Makefile.inc index 9ffc0bb..79c59ab 100644 --- a/src/devices/Makefile.inc +++ b/src/devices/Makefile.inc @@ -11,6 +11,9 @@ ramstage-y += pnp_device.c ramstage-y += pci_ops.c ramstage-y += smbus_ops.c
+romstage-y+= device_util.c +romstage-y+= pci_ops.c + subdirs-y += oprom
ifeq ($(CONFIG_PCI_ROM_RUN),y) diff --git a/src/devices/device.c b/src/devices/device.c index fafa599..08fdbb0 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -45,8 +45,6 @@ #include <arch/ebda.h> #endif
-/** Linked list of ALL devices */ -struct device *all_devices = &dev_root; /** Pointer to the last device */ extern struct device *last_dev; /** Linked list of free resources */ diff --git a/src/devices/device_util.c b/src/devices/device_util.c index 7c1cde9..c4ddea4 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -29,6 +29,12 @@ #include <device/resource.h> #include <string.h>
+/** Linked list of ALL devices */ +#ifdef __PRE_RAM__ +struct device __attribute__((__section__(".text"))) *all_devices = &dev_root; +#else +struct device *all_devices = &dev_root; + /** * See if a device structure exists for path. * @@ -48,6 +54,23 @@ device_t find_dev_path(struct bus *parent, struct device_path *path) }
/** + * See if a device structure already exists and if not allocate it. + * + * @param parent The bus to find the device on. + * @param path The relative path from the bus to the appropriate device. + * @return Pointer to a device structure for the device on bus at path. + */ +device_t alloc_find_dev(struct bus *parent, struct device_path *path) +{ + device_t child; + child = find_dev_path(parent, path); + if (!child) + child = alloc_dev(parent, path); + return child; +} + +#endif +/** * Given a PCI bus and a devfn number, find the device structure. * * @param bus The bus number. @@ -158,6 +181,47 @@ struct device *dev_find_class(unsigned int class, struct device *from) return from; }
+#ifdef __PRE_RAM__ +const char *dev_path(device_t dev) +{ + if (!dev) { + return "<null>"; + } else { + switch(dev->path.type) { + case DEVICE_PATH_ROOT: + return "Root Device"; + break; + case DEVICE_PATH_PCI: + return "PCI: "; + break; + case DEVICE_PATH_PNP: + return "PNP: "; + break; + case DEVICE_PATH_I2C: + return "I2C: "; + break; + case DEVICE_PATH_APIC: + return "APIC: "; + break; + case DEVICE_PATH_PCI_DOMAIN: + return "PCI_DOMAIN: "; + break; + case DEVICE_PATH_APIC_CLUSTER: + return "APIC_CLUSTER: "; + break; + case DEVICE_PATH_CPU: + return "CPU: "; + break; + case DEVICE_PATH_CPU_BUS: + return "CPU_BUS: "; + break; + default: + return "Unknown"; + break; + } + } +} +#else /* * Warning: This function uses a static buffer. Don't call it more than once * from the same print statement! @@ -856,3 +920,5 @@ int dev_count_cpu(void)
return count; } +#endif + diff --git a/src/include/device/device.h b/src/include/device/device.h index f36710a..4b1b6ef 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -103,12 +103,16 @@ struct device { /** * This is the root of the device tree. The device tree is defined in the * static.c file and is generated by the config tool at compile time. + * In the romstage one must use accessor functions as we do not have + * globals. */ extern struct device dev_root; +#ifndef __PRE_RAM__ extern struct device *all_devices; /* list of all devices */
extern struct resource *free_resources; extern struct bus *free_links; +#endif
/* Generic device interface functions */ device_t alloc_dev(struct bus *parent, struct device_path *path); diff --git a/util/lint/lint-stable-002-build-dir-handling b/util/lint/lint-stable-002-build-dir-handling index c4247b5..60548f1 100755 --- a/util/lint/lint-stable-002-build-dir-handling +++ b/util/lint/lint-stable-002-build-dir-handling @@ -33,7 +33,7 @@ fi
# $1: object directory run_printall() { -$MAKE CONFIG_USE_BLOBS=n CONFIG_CCACHE=n CONFIG_SCANBUILD_ENABLE=n NOMKDIR=1 DOTCONFIG=$TMPCONFIG obj=$1 printall |sed -e "s,^ *,," -e "s,^ramstage-objs:=,," -e "s,mainboard/[^/]*/[^/]*/,.../," |tr " " "\n"|grep "/static.*.[co]" |sort |tr '\012\015' ' ' |sed -e "s, *, ,g" -e "s, *$,," +$MAKE CONFIG_USE_BLOBS=n CONFIG_CCACHE=n CONFIG_SCANBUILD_ENABLE=n NOMKDIR=1 DOTCONFIG=$TMPCONFIG obj=$1 printall |sed -e "s,^ *,," -e "s,^r.mstage-objs:=,," -e "s,mainboard/[^/]*/[^/]*/,.../,g" |tr " " "\n"|grep "/static.*.[co]" |sort |tr '\012\015' ' ' |sed -e "s, *, ,g" -e "s, *$,," }
# find GNU make @@ -54,10 +54,10 @@ $MAKE DOTCONFIG=$TMPCONFIG allyesconfig >/dev/null # look up parent directory PARENTDIR=`dirname $PWD`
-compare_output "`run_printall build`" "build/.../static.c build/.../static.ramstage.o" -compare_output "`run_printall ../obj`" "$PARENTDIR/obj/.../static.c $PARENTDIR/obj/.../static.ramstage.o" -compare_output "`run_printall /tmp`" "/tmp/.../static.c /tmp/.../static.ramstage.o" -compare_output "`run_printall /../tmp`" "/tmp/.../static.c /tmp/.../static.ramstage.o" +compare_output "`run_printall build`" "build/.../static.c build/.../static.c build/.../static.ramstage.o build/.../static.romstage.o" +compare_output "`run_printall ../obj`" "$PARENTDIR/obj/.../static.c $PARENTDIR/obj/.../static.c $PARENTDIR/obj/.../static.ramstage.o $PARENTDIR/obj/.../static.romstage.o" +compare_output "`run_printall /tmp`" "/tmp/.../static.c /tmp/.../static.c /tmp/.../static.ramstage.o /tmp/.../static.romstage.o" +compare_output "`run_printall /../tmp`" "/tmp/.../static.c /tmp/.../static.c /tmp/.../static.ramstage.o /tmp/.../static.romstage.o"
rm -f $TMPCONFIG
diff --git a/util/sconfig/main.c b/util/sconfig/main.c index ca8c3c5..51949f1 100644 --- a/util/sconfig/main.c +++ b/util/sconfig/main.c @@ -361,14 +361,18 @@ void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin, int ir }
static void pass0(FILE *fil, struct device *ptr) { - if (ptr->type == device && ptr->id == 0) - fprintf(fil, "struct bus %s_links[];\n", ptr->name); + if (ptr->type == device && ptr->id == 0){ + fprintf(fil, "struct bus SECTION %s_links[];\n", ptr->name); + } if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used)) { fprintf(fil, "static struct device %s;\n", ptr->name); - if (ptr->rescnt > 0) - fprintf(fil, "struct resource %s_res[];\n", ptr->name); - if (ptr->children || ptr->multidev) - fprintf(fil, "struct bus %s_links[];\n", ptr->name); + if (ptr->rescnt > 0){ + fprintf(fil, "struct resource SECTION %s_res[];\n", ptr->name); + } + if (ptr->children || ptr->multidev){ + fprintf(fil, "struct bus SECTION %s_links[];\n", + ptr->name); + } } }
@@ -376,11 +380,14 @@ static void pass1(FILE *fil, struct device *ptr) { int pin; if (!ptr->used && (ptr->type == device)) { - if (ptr->id != 0) + if (ptr->id) fprintf(fil, "static "); - fprintf(fil, "struct device %s = {\n", ptr->name); + fprintf(fil, "struct device SECTION %s = {\n", ptr->name); + fprintf(fil, "#ifndef __PRE_RAM__\n"); fprintf(fil, "\t.ops = %s,\n", (ptr->ops)?(ptr->ops):"0"); - fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name, ptr->bus->link); + fprintf(fil, "#endif\n"); + fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name, + ptr->bus->link); fprintf(fil, "\t.path = {"); fprintf(fil, ptr->path, ptr->path_a, ptr->path_b); fprintf(fil, "},\n"); @@ -411,7 +418,9 @@ static void pass1(FILE *fil, struct device *ptr) if (ptr->sibling) fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name); if (ptr->chip->chiph_exists) { + fprintf(fil, "#ifndef __PRE_RAM__\n"); fprintf(fil, "\t.chip_ops = &%s_ops,\n", ptr->chip->name_underscore); + fprintf(fil, "#endif\n"); fprintf(fil, "\t.chip_info = &%s_info_%d,\n", ptr->chip->name_underscore, ptr->chip->id); } if (ptr->nextdev) @@ -420,7 +429,8 @@ static void pass1(FILE *fil, struct device *ptr) } if (ptr->rescnt > 0) { int i=1; - fprintf(fil, "struct resource %s_res[] = {\n", ptr->name); + fprintf(fil, "struct resource SECTION %s_res[] = {\n", + ptr->name); struct resource *r = ptr->res; while (r) { fprintf(fil, "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_"); @@ -437,7 +447,7 @@ static void pass1(FILE *fil, struct device *ptr) fprintf(fil, "\t };\n"); } if (!ptr->used && ptr->type == device && (ptr->children || ptr->multidev)) { - fprintf(fil, "struct bus %s_links[] = {\n", ptr->name); + fprintf(fil, "struct bus SECTION %s_links[] = {\n", ptr->name); if (ptr->multidev) { struct device *d = ptr; while (d) { @@ -469,8 +479,9 @@ static void pass1(FILE *fil, struct device *ptr) } if ((ptr->type == chip) && (ptr->chiph_exists)) { if (ptr->reg) { - fprintf(fil, "struct %s_config %s_info_%d\t= {\n", - ptr->name_underscore, ptr->name_underscore, ptr->id); + fprintf(fil, "struct %s_config SECTION %s_info_%d\t= {\n", + ptr->name_underscore, ptr->name_underscore, + ptr->id); struct reg *r = ptr->reg; while (r) { fprintf(fil, "\t.%s = %s,\n", r->key, r->value); @@ -478,7 +489,7 @@ static void pass1(FILE *fil, struct device *ptr) } fprintf(fil, "};\n\n"); } else { - fprintf(fil, "struct %s_config %s_info_%d;\n", + fprintf(fil, "struct %s_config SECTION %s_info_%d;\n", ptr->name_underscore, ptr->name_underscore, ptr->id); } } @@ -606,12 +617,33 @@ int main(int argc, char** argv) { h = h->next; fprintf(autogen, "#include "%s/chip.h"\n", h->name); } - + fprintf(autogen, + "#ifdef __PRE_RAM__\n" + "#define SECTION " + "__attribute__((__section__(".text")))\n" + "#else\n" + "#define SECTION\n" + "#endif\n"); walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL); fprintf(autogen, "\n/* pass 0 */\n"); walk_device_tree(autogen, &root, pass0, NULL); - fprintf(autogen, "\n/* pass 1 */\nstruct mainboard_config mainboard_info_0;\n" - "struct device *last_dev = &%s;\n", lastdev->name); + + /* the section attribute fails (another gld bug?) + * for last_dev. So we have to do the accessor function. + */ + fprintf(autogen,"\n/* pass 1 */\n" + "static struct " + "mainboard_config SECTION mainboard_info_0;\n" + "#ifndef __PRE_RAM__\n" + "struct device *last_dev = &%s;\n" + "#endif\n", + lastdev->name); + /* generate accessor function for PRE_RAM */ + fprintf(autogen,"#ifdef __PRE_RAM__\n"); + fprintf(autogen,"struct device *get_last_dev(void);\n"); + fprintf(autogen,"struct device *get_last_dev(void)\n" + "{\nreturn &%s;\n}\n", lastdev->name); + fprintf(autogen,"#endif\n"); walk_device_tree(autogen, &root, pass1, NULL);
} else if (scan_mode == BOOTBLOCK_MODE) {