Yh Lu needed to add a mainboard-specific initialization code for the Tyan s2880 board, and needed it called at a special place in hardwaremain(). In V1, we would use defines and other such trickery to get this capability. We're trying to avoid that in V2.
This problem turns out to be a perfect use for the static device initialization support.
First, we apply patches that are tyan-only or are bug fixes to these files:
src/include/device/pci_ids.h src/mainboard/tyan/s2880/auto.c src/mainboard/tyan/s2880/Config src/mainboard/tyan/s2880/debug.c src/mainboard/tyan/s2880/failover.c src/mainboard/tyan/s2880/static_devices.c src/mainboard/tyan/s2880/tyan-fallback.config src/mainboard/tyan/s2880/tyan-normal.config src/mainboard/tyan/s2880/VERSION src/mainboard/tyan/VERSION src/northbridge/amd/amdk8/coherent_ht.c src/northbridge/amd/amdk8/raminit.c src/southbridge/amd/amd8111/Config src/southbridge/amd/amd8111/Config.lb src/southbridge/amd/amd8131/amd8131_bridge.c targets/tyan/s2880/Config.lb
Now, we need to ensure that YhLu's "special code" is called for his mainboard.
As it happens, the mainboard is also a "chip" in the new scheme. The config tool builds a tree based on this structure, from src/include/device/chip.h:
struct chip { struct chip_control *control; /* for this device */ char *path; /* can be 0, in which case the default is taken */ char *configuration; /* can be 0. */ int irq; struct chip *next, *children; /* there is one of these for each INSTANCE of a chip */ void *chip_info; /* the dreaded "void *" */ };
The tree for the s2880 looks like this:
===== #include <device/chip.h> struct chip static_root, static_dev1, static_dev2, static_dev3, static_dev4, sta tic_dev5, static_dev6, static_dev7, static_dev8, static_dev9, static_dev10; #include "/home/rminnich/src/bios/freebios2/src/mainboard/tyan/s2880/chip.h"
struct chip static_root = { /* mainboard /home/rminnich/src/bios/freebios2/src/mainboard/tyan/s2880 */ .children = &static_dev9, }; struct chip static_dev9 = { /* cpu /home/rminnich/src/bios/freebios2/src/cpu/k8 */ .next = &static_dev8, };
. . .
======
(the rest is removed for clearness)
Note that there are even "chips" for CPUs: it is possible to handle CPU fixup in this system.
Each entry in the above structures defines a static device.
Please recall that static devices consist of a generic structure and then special-purpose (device specific) structures.
The generic structure is this: /* there is one of these for each TYPE of chip */ struct chip_control { void (*enable)(struct chip *, enum chip_pass); char *path; /* the default path. Can be overridden * by commands in config */ // This is the print name for debugging char *name; };
Device-specific classes are defined by the attributes of the device, and hence vary for each device. In the V1 days, we tried to have one generic structure, but that did not even work for the limited case of superio's, so for V2 we are making the structure unique to each device.
We have to define one device structure for the Tyan s2880. The structure has to be defined in an include file that is in the directory that contains the code for the device. So, for the tyan s2880 mainboard, we need to have a definition file in src/mainboard/tyan/s2880. We'll call it src/mainboard/tyan/s2880/chip.h.
In this case, it is rather simple:
struct mainboard_tyan_s2880_config { int fixup_scsi; };
This is the only thing we're controlling at present. Note that the name of the struct is a 'flattened' version of the device name.
We need to tell the config tool where to find the file containing the structure, and how to initialize the struct in the file. Add these lines to src/tyan/s2880/Config.lb. They will define the name of the file to use, and the code to initialize the static device.
config chip.h register "fixup_scsi" = "1"
We need to create the structure that defines the generic structure for the mainboard, so linuxbios can hook into it. So add these lines to the end of src/mainboard/tyan/s2880/mainboard.c:
struct chip_control mainboard_tyan_s2880_control = { enable: enable, name: "Tyan s2880 mainboard " };
Then add the enable function (BEFORE the struct chip_control declaration). Note that it is declared 'static', and has only one entry in the switch.
static void enable(struct chip *chip, enum chip_pass pass) {
struct mainboard_tyan_s2880_config *conf = (struct mainboard_tyan_s2880_config *)chip->chip_info;
switch (pass) { default: break; case CONF_PASS_PRE_BOOT: if (conf->fixup_scsi) onboard_scsi_fixup(); printk_debug("mainboard fixup pass %d done\r\n", pass); break; }
}
That's pretty much it. total changes are 170 lines. The static device tree (which is generated by the config tool, you don't have to write this code) now looks like this:
========== #include <device/chip.h> struct chip static_root, static_dev1, static_dev2, static_dev3, static_dev4, sta tic_dev5, static_dev6, static_dev7, static_dev8, static_dev9, static_dev10; #include "/home/rminnich/src/bios/freebios2/src/mainboard/tyan/s2880/chip.h" extern struct chip_control mainboard_tyan_s2880_control; struct mainboard_tyan_s2880_config mainboard_tyan_s2880_config_0 = { .fixup_scsi = 1, };
struct chip static_root = { /* mainboard /home/rminnich/src/bios/freebios2/src/mainboard/tyan/s2880 */ .children = &static_dev9, .control= &mainboard_tyan_s2880_control, .chip_info = (void *) &mainboard_tyan_s2880_config_0, }; struct chip static_dev9 = { /* cpu /home/rminnich/src/bios/freebios2/src/cpu/k8 */ .next = &static_dev8, }; =====
Note that the mainboard now has several new entries, and there is a new struct for controlling the mainboard, along with an initializer. The enable function for the mainboard will be called at several places in hardwaremain with a different pass #, and since there is only one case defined, only one action is taken.
So to add this capability for this mainbard, we had to: - define a file containing the device-specific structure which we called chip.h, and placed in src/mainboard/tyan/s2880 - add two lines to src/mainboard/tyan/s2880/Config.lb, which define the file we need (chip.h) and the initialization of the structure. - add the "base class" structure to src/mainboard/tyan/s2880/mainboard.c, along with the enable function.
I've built this mainboard and hexdump of the romimage looks pretty good. Yh Lu, can you please verify this? The config.lb is in targets/tyan/s2880/Config.lb. I can send the context diffs if that will help.
Note that this technique will work for anything that the config tool considers a 'device': mainboard, cpu, north and south bridge, superio, etc.
Thanks
ron