Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933990Ab0D3Sbz (ORCPT ); Fri, 30 Apr 2010 14:31:55 -0400 Received: from [69.28.251.93] ([69.28.251.93]:43460 "EHLO b32.net" rhost-flags-FAIL-FAIL-OK-OK) by vger.kernel.org with ESMTP id S933126Ab0D3Sbm (ORCPT ); Fri, 30 Apr 2010 14:31:42 -0400 From: Kevin Cernekee Date: Thu, 29 Apr 2010 10:26:56 -0700 Subject: [PATCHv3] mtd: cfi_cmdset_0002: Add reboot notifier for AMD flashes Message-Id: <471a5dfa1495f2d33e41435e4d37852ad489b112@localhost.localdomain> In-Reply-To: <1272519262.7750.66.camel@localhost> References: <1272519262.7750.66.camel@localhost> To: , Cc: , User-Agent: vim 7.1 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3773 Lines: 124 Ensure that the flash device is in a quiescent state before rebooting. The implementation is closely modeled after the cfi_cmdset_0001 reboot notifier, commit 963a6fb0a0d336d0513083b7e4b5c3ff9d6d2061 . Signed-off-by: Kevin Cernekee --- drivers/mtd/chips/cfi_cmdset_0002.c | 56 +++++++++++++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c93e47d..c16b8ce 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,7 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_amdstd_sync (struct mtd_info *); static int cfi_amdstd_suspend (struct mtd_info *); static void cfi_amdstd_resume (struct mtd_info *); +static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *); static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static void cfi_amdstd_destroy(struct mtd_info *); @@ -351,6 +353,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->name = map->name; mtd->writesize = 1; + mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; + if (cfi->cfi_mode==CFI_MODE_CFI){ unsigned char bootloc; /* @@ -487,6 +491,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) #endif __module_get(THIS_MODULE); + register_reboot_notifier(&mtd->reboot_notifier); return mtd; setup_err: @@ -628,6 +633,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr chip->state = FL_READY; return 0; + case FL_SHUTDOWN: + /* The machine is rebooting */ + return -EIO; + case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) @@ -1918,11 +1927,58 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) } } + +/* + * Ensure that the flash device is put back into read array mode before + * unloading the driver or rebooting. On some systems, rebooting while + * the flash is in query/program/erase mode will prevent the CPU from + * fetching the bootloader code, requiring a hard reset or power cycle. + */ +static int cfi_amdstd_reset(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i, ret; + struct flchip *chip; + + for (i = 0; i < cfi->numchips; i++) { + + chip = &cfi->chips[i]; + + mutex_lock(&chip->mutex); + + ret = get_chip(map, chip, chip->start, FL_SHUTDOWN); + if (!ret) { + map_write(map, CMD(0xF0), chip->start); + chip->state = FL_SHUTDOWN; + put_chip(map, chip, chip->start); + } + + mutex_unlock(&chip->mutex); + } + + return 0; +} + + +static int cfi_amdstd_reboot(struct notifier_block *nb, unsigned long val, + void *v) +{ + struct mtd_info *mtd; + + mtd = container_of(nb, struct mtd_info, reboot_notifier); + cfi_amdstd_reset(mtd); + return NOTIFY_DONE; +} + + static void cfi_amdstd_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; + cfi_amdstd_reset(mtd); + unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi); -- 1.6.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/