diff options
author | Nicolas Pitre <nico@cam.org> | 2005-03-31 20:59:56 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 07:06:28 -0400 |
commit | 963a6fb0a0d336d0513083b7e4b5c3ff9d6d2061 (patch) | |
tree | d7f6ccfbef2fe150d3073d17d333f90d1ce304a6 /drivers/mtd | |
parent | 8048d2fc38c9559ce37b46c21fa734c5cb9bcdb2 (diff) |
[MTD] Add reboot notifier to Intel NOR flash driver
to make sure the flash is in array mode whenever we're about to
reboot. This is especially useful to allow "soft" reboot to work
which consists of branching back into the bootloader.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index b482a4e48e48..dc257eb6932f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0001.c,v 1.173 2005/03/30 23:57:30 tpoynor Exp $ | 7 | * $Id: cfi_cmdset_0001.c,v 1.174 2005/04/01 01:59:52 nico Exp $ |
8 | * | 8 | * |
9 | * | 9 | * |
10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/reboot.h> | ||
32 | #include <linux/mtd/xip.h> | 33 | #include <linux/mtd/xip.h> |
33 | #include <linux/mtd/map.h> | 34 | #include <linux/mtd/map.h> |
34 | #include <linux/mtd/mtd.h> | 35 | #include <linux/mtd/mtd.h> |
@@ -66,6 +67,7 @@ static int cfi_intelext_get_user_prot_info (struct mtd_info *, | |||
66 | #endif | 67 | #endif |
67 | static int cfi_intelext_suspend (struct mtd_info *); | 68 | static int cfi_intelext_suspend (struct mtd_info *); |
68 | static void cfi_intelext_resume (struct mtd_info *); | 69 | static void cfi_intelext_resume (struct mtd_info *); |
70 | static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *); | ||
69 | 71 | ||
70 | static void cfi_intelext_destroy(struct mtd_info *); | 72 | static void cfi_intelext_destroy(struct mtd_info *); |
71 | 73 | ||
@@ -333,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
333 | mtd->resume = cfi_intelext_resume; | 335 | mtd->resume = cfi_intelext_resume; |
334 | mtd->flags = MTD_CAP_NORFLASH; | 336 | mtd->flags = MTD_CAP_NORFLASH; |
335 | mtd->name = map->name; | 337 | mtd->name = map->name; |
336 | 338 | ||
339 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | ||
340 | |||
337 | if (cfi->cfi_mode == CFI_MODE_CFI) { | 341 | if (cfi->cfi_mode == CFI_MODE_CFI) { |
338 | /* | 342 | /* |
339 | * It's a real CFI chip, not one for which the probe | 343 | * It's a real CFI chip, not one for which the probe |
@@ -446,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
446 | goto setup_err; | 450 | goto setup_err; |
447 | 451 | ||
448 | __module_get(THIS_MODULE); | 452 | __module_get(THIS_MODULE); |
453 | register_reboot_notifier(&mtd->reboot_notifier); | ||
449 | return mtd; | 454 | return mtd; |
450 | 455 | ||
451 | setup_err: | 456 | setup_err: |
@@ -2301,10 +2306,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd) | |||
2301 | } | 2306 | } |
2302 | } | 2307 | } |
2303 | 2308 | ||
2309 | static int cfi_intelext_reset(struct mtd_info *mtd) | ||
2310 | { | ||
2311 | struct map_info *map = mtd->priv; | ||
2312 | struct cfi_private *cfi = map->fldrv_priv; | ||
2313 | int i, ret; | ||
2314 | |||
2315 | for (i=0; i < cfi->numchips; i++) { | ||
2316 | struct flchip *chip = &cfi->chips[i]; | ||
2317 | |||
2318 | /* force the completion of any ongoing operation | ||
2319 | and switch to array mode so any bootloader in | ||
2320 | flash is accessible for soft reboot. */ | ||
2321 | spin_lock(chip->mutex); | ||
2322 | ret = get_chip(map, chip, chip->start, FL_SYNCING); | ||
2323 | if (!ret) { | ||
2324 | map_write(map, CMD(0xff), chip->start); | ||
2325 | chip->state = FL_READY; | ||
2326 | } | ||
2327 | spin_unlock(chip->mutex); | ||
2328 | } | ||
2329 | |||
2330 | return 0; | ||
2331 | } | ||
2332 | |||
2333 | static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, | ||
2334 | void *v) | ||
2335 | { | ||
2336 | struct mtd_info *mtd; | ||
2337 | |||
2338 | mtd = container_of(nb, struct mtd_info, reboot_notifier); | ||
2339 | cfi_intelext_reset(mtd); | ||
2340 | return NOTIFY_DONE; | ||
2341 | } | ||
2342 | |||
2304 | static void cfi_intelext_destroy(struct mtd_info *mtd) | 2343 | static void cfi_intelext_destroy(struct mtd_info *mtd) |
2305 | { | 2344 | { |
2306 | struct map_info *map = mtd->priv; | 2345 | struct map_info *map = mtd->priv; |
2307 | struct cfi_private *cfi = map->fldrv_priv; | 2346 | struct cfi_private *cfi = map->fldrv_priv; |
2347 | cfi_intelext_reset(mtd); | ||
2348 | unregister_reboot_notifier(&mtd->reboot_notifier); | ||
2308 | kfree(cfi->cmdset_priv); | 2349 | kfree(cfi->cmdset_priv); |
2309 | kfree(cfi->cfiq); | 2350 | kfree(cfi->cfiq); |
2310 | kfree(cfi->chips[0].priv); | 2351 | kfree(cfi->chips[0].priv); |