diff options
-rw-r--r-- | src/device/device.c | 75 | ||||
-rw-r--r-- | src/include/device/device.h | 5 | ||||
-rw-r--r-- | src/lib/hardwaremain.c | 3 |
3 files changed, 83 insertions, 0 deletions
diff --git a/src/device/device.c b/src/device/device.c index 3837928743..a2a64b2cae 100644 --- a/src/device/device.c +++ b/src/device/device.c @@ -72,6 +72,26 @@ void dev_initialize_chips(void) } } +/** + * Finalize all chips of statically known devices. + * + * This is the last call before calling the payload. This is a good place + * to lock registers or other final cleanup. + */ +void dev_finalize_chips(void) +{ + struct device *dev; + + for (dev = all_devices; dev; dev = dev->next) { + /* Initialize chip if we haven't yet. */ + if (dev->chip_ops && dev->chip_ops->final && + !dev->chip_ops->finalized) { + dev->chip_ops->final(dev->chip_info); + dev->chip_ops->finalized = 1; + } + } +} + DECLARE_SPIN_LOCK(dev_lock) #if CONFIG_GFXUMA @@ -1167,3 +1187,58 @@ void dev_initialize(void) printk(BIOS_INFO, "Devices initialized\n"); show_all_devs(BIOS_SPEW, "After init."); } + +/** + * Finalize a specific device. + * + * The parent should be finalized first to avoid having an ordering problem. + * This is done by calling the parent's final() method before its childrens' + * final() methods. + * + * @param dev The device to be initialized. + */ +static void final_dev(struct device *dev) +{ + if (!dev->enabled) + return; + + if (dev->ops && dev->ops->final) { + printk(BIOS_DEBUG, "%s final\n", dev_path(dev)); + dev->ops->final(dev); + } +} + +static void final_link(struct bus *link) +{ + struct device *dev; + struct bus *c_link; + + for (dev = link->children; dev; dev = dev->sibling) + final_dev(dev); + + for (dev = link->children; dev; dev = dev->sibling) { + for (c_link = dev->link_list; c_link; c_link = c_link->next) + final_link(c_link); + } +} +/** + * Finalize all devices in the global device tree. + * + * Starting at the root device, call the device's final() method to do + * device-specific cleanup, then call each child's final() method. + */ +void dev_finalize(void) +{ + struct bus *link; + + printk(BIOS_INFO, "Finalize devices...\n"); + + /* First call the mainboard finalize. */ + final_dev(&dev_root); + + /* Now finalize everything. */ + for (link = dev_root.link_list; link; link = link->next) + final_link(link); + + printk(BIOS_INFO, "Devices finalized\n"); +} diff --git a/src/include/device/device.h b/src/include/device/device.h index c0e6e0f6c6..fec0497508 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -22,7 +22,9 @@ struct pnp_mode_ops; struct chip_operations { void (*enable_dev)(struct device *dev); void (*init)(void *chip_info); + void (*final)(void *chip_info); unsigned int initialized : 1; + unsigned int finalized : 1; const char *name; }; @@ -35,6 +37,7 @@ struct device_operations { void (*set_resources)(device_t dev); void (*enable_resources)(device_t dev); void (*init)(device_t dev); + void (*final)(device_t dev); unsigned int (*scan_bus)(device_t bus, unsigned int max); void (*enable)(device_t dev); void (*disable)(device_t dev); @@ -140,6 +143,8 @@ void dev_configure(void); void dev_enable(void); void dev_initialize(void); void dev_optimize(void); +void dev_finalize(void); +void dev_finalize_chips(void); /* Generic device helper functions */ int reset_bus(struct bus *bus); diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c index a5993c41dc..501591f114 100644 --- a/src/lib/hardwaremain.c +++ b/src/lib/hardwaremain.c @@ -175,6 +175,7 @@ static boot_state_t bs_dev_init(void *arg) static boot_state_t bs_post_device(void *arg) { + dev_finalize(); timestamp_add_now(TS_DEVICE_DONE); timestamp_reinit(); @@ -217,6 +218,8 @@ static boot_state_t bs_write_tables(void *arg) */ write_tables(); + dev_finalize_chips(); + return BS_PAYLOAD_LOAD; } |