diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-02-21 01:17:10 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-03-19 12:21:18 +0100 |
commit | 0b5a776c1e9cc6dec8d5fa6d2f97eb8f19d3d325 (patch) | |
tree | 55e998b87b5b4e1cc9b34ffffc02d7ea851239f6 | |
parent | 36ae69a2dcb443bd3d55086f2f620e0057c9d6a6 (diff) | |
download | barebox-0b5a776c1e9cc6dec8d5fa6d2f97eb8f19d3d325.tar.gz barebox-0b5a776c1e9cc6dec8d5fa6d2f97eb8f19d3d325.tar.xz |
Shutdown U-Boot before starting an OS
Some devices, especially the ones doing DMA should be disabled before
giving control to an OS. We take the simple approach here: Just shutdown
the devices in the reverse order they were activated.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | arch/arm/cpu/cpu.c | 2 | ||||
-rw-r--r-- | common/startup.c | 10 | ||||
-rw-r--r-- | include/common.h | 1 | ||||
-rw-r--r-- | include/driver.h | 8 | ||||
-rw-r--r-- | lib/driver.c | 14 |
5 files changed, 34 insertions, 1 deletions
diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c index 84958579eb..c16c79a671 100644 --- a/arch/arm/cpu/cpu.c +++ b/arch/arm/cpu/cpu.c @@ -141,6 +141,8 @@ int cleanup_before_linux (void) { int i; + shutdown_uboot(); + /* flush I/D-cache */ i = 0; asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); diff --git a/common/startup.c b/common/startup.c index 3a37eed293..7179f81203 100644 --- a/common/startup.c +++ b/common/startup.c @@ -156,3 +156,13 @@ void hang (void) puts ("### ERROR ### Please RESET the board ###\n"); for (;;); } + +/* Everything needed to cleanly shutdown U-Boot. + * Should be called before starting an OS to get + * the devices into a clean state + */ +void shutdown_uboot(void) +{ + devices_shutdown(); +} + diff --git a/include/common.h b/include/common.h index a224f9a87e..a580e115c0 100644 --- a/include/common.h +++ b/include/common.h @@ -131,6 +131,7 @@ int parse_area_spec(const char *str, ulong *start, ulong *size); unsigned long strtoul_suffix(const char *str, char **endp, int base); void start_uboot(void); +void shutdown_uboot(void); int arch_execute(unsigned long address, int argc, char *argv[]); diff --git a/include/driver.h b/include/driver.h index 45097a3c05..fdb40eb8f0 100644 --- a/include/driver.h +++ b/include/driver.h @@ -103,6 +103,7 @@ struct device_d { struct list_head list; /* The list of all devices */ struct list_head children; /* our children */ struct list_head sibling; + struct list_head active; /* The list of all devices which have a driver */ struct device_d *parent; /* our parent, NULL if not present */ @@ -128,7 +129,7 @@ struct driver_d { int (*probe) (struct device_d *); /*! Called if an instance of a device is gone. */ - int (*remove)(struct device_d *); + void (*remove)(struct device_d *); /*! Called in response of reading from this device. Required */ ssize_t (*read) (struct device_d*, void* buf, size_t count, ulong offset, ulong flags); @@ -245,6 +246,11 @@ int mem_memmap(struct device_d *dev, void **map, int flags); /* Use this if you have nothing to do in your drivers probe function */ int dummy_probe(struct device_d *); +/* Iterate over all activated devices (i.e. the ones with drivers and shut + * them down. + */ +void devices_shutdown(void); + int generic_memmap_ro(struct device_d *dev, void **map, int flags); int generic_memmap_rw(struct device_d *dev, void **map, int flags); diff --git a/lib/driver.c b/lib/driver.c index 5aa643d03c..d722b09494 100644 --- a/lib/driver.c +++ b/lib/driver.c @@ -40,6 +40,8 @@ EXPORT_SYMBOL(device_list); LIST_HEAD(driver_list); EXPORT_SYMBOL(driver_list); +static LIST_HEAD(active); + struct device_d *get_device_by_id(const char *id) { struct device_d *dev; @@ -77,6 +79,8 @@ static int match(struct driver_d *drv, struct device_d *dev) dev->driver = drv; + list_add(&dev->active, &active); + return 0; } @@ -326,6 +330,16 @@ const char *dev_id(const struct device_d *dev) return buf; } +void devices_shutdown(void) +{ + struct device_d *dev; + + list_for_each_entry(dev, &active, active) { + if (dev->driver->remove) + dev->driver->remove(dev); + } +} + #ifdef CONFIG_CMD_DEVINFO static int do_devinfo ( cmd_tbl_t *cmdtp, int argc, char *argv[]) |