summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2009-02-21 01:17:10 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2009-03-19 12:21:18 +0100
commit0b5a776c1e9cc6dec8d5fa6d2f97eb8f19d3d325 (patch)
tree55e998b87b5b4e1cc9b34ffffc02d7ea851239f6
parent36ae69a2dcb443bd3d55086f2f620e0057c9d6a6 (diff)
downloadbarebox-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.c2
-rw-r--r--common/startup.c10
-rw-r--r--include/common.h1
-rw-r--r--include/driver.h8
-rw-r--r--lib/driver.c14
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[])