?? mtd.patch
字號:
static int cfi_intelext_suspend(struct mtd_info *mtd) { struct map_info *map = mtd->priv;@@ -2125,10 +2397,46 @@ } } +static int cfi_intelext_reset(struct mtd_info *mtd)+{+ struct map_info *map = mtd->priv;+ struct cfi_private *cfi = map->fldrv_priv;+ int i, ret;++ for (i=0; i < cfi->numchips; i++) {+ struct flchip *chip = &cfi->chips[i];++ /* force the completion of any ongoing operation+ and switch to array mode so any bootloader in + flash is accessible for soft reboot. */+ spin_lock(chip->mutex);+ ret = get_chip(map, chip, chip->start, FL_SYNCING);+ if (!ret) {+ map_write(map, CMD(0xff), chip->start);+ chip->state = FL_READY;+ }+ spin_unlock(chip->mutex);+ }++ return 0;+}++static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,+ void *v)+{+ struct mtd_info *mtd;++ mtd = container_of(nb, struct mtd_info, reboot_notifier);+ cfi_intelext_reset(mtd);+ return NOTIFY_DONE;+}+ static void cfi_intelext_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv;+ cfi_intelext_reset(mtd);+ unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi->chips[0].priv);@@ -2136,20 +2444,23 @@ kfree(mtd->eraseregions); } -static char im_name_1[]="cfi_cmdset_0001";-static char im_name_3[]="cfi_cmdset_0003";+static char im_name_0001[] = "cfi_cmdset_0001";+static char im_name_0003[] = "cfi_cmdset_0003";+static char im_name_0200[] = "cfi_cmdset_0200"; static int __init cfi_intelext_init(void) {- inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);- inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);+ inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);+ inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);+ inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); return 0; } static void __exit cfi_intelext_exit(void) {- inter_module_unregister(im_name_1);- inter_module_unregister(im_name_3);+ inter_module_unregister(im_name_0001);+ inter_module_unregister(im_name_0003);+ inter_module_unregister(im_name_0200); } module_init(cfi_intelext_init);diff -Naur linux26-cvs/drivers/mtd/chips/cfi_cmdset_0002.c linux26-new/drivers/mtd/chips/cfi_cmdset_0002.c--- linux26-cvs/drivers/mtd/chips/cfi_cmdset_0002.c 2005-08-25 12:05:58.000000000 -0500+++ linux26-new/drivers/mtd/chips/cfi_cmdset_0002.c 2005-08-25 14:09:02.000000000 -0500@@ -4,16 +4,20 @@ * * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>+ * Copyright (C) 2005 MontaVista Software Inc. <source@mvista.com> * * 2_by_8 routines added by Simon Munton * * 4_by_16 work by Carolyn J. Smith *+ * XIP support hooks by Vitaly Wool (based on code for Intel flash + * by Nicolas Pitre)+ * * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com * * This code is GPL *- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $+ * $Id: cfi_cmdset_0002.c,v 1.120 2005/07/20 21:01:13 tpoynor Exp $ * */ @@ -34,6 +38,7 @@ #include <linux/mtd/map.h> #include <linux/mtd/mtd.h> #include <linux/mtd/cfi.h>+#include <linux/mtd/xip.h> #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0@@ -43,6 +48,7 @@ #define MANUFACTURER_AMD 0x0001 #define MANUFACTURER_SST 0x00BF #define SST49LF004B 0x0060+#define SST49LF008A 0x005a static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);@@ -191,6 +197,7 @@ }; static struct cfi_fixup jedec_fixup_table[] = { { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },+ { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, { 0, 0, NULL, NULL } }; @@ -246,6 +253,16 @@ return NULL; } + if (extp->MajorVersion != '1' ||+ (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {+ printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "+ "version %c.%c.\n", extp->MajorVersion,+ extp->MinorVersion);+ kfree(extp);+ kfree(mtd);+ return NULL;+ }+ /* Install our own private info structure */ cfi->cmdset_priv = extp; @@ -391,7 +408,7 @@ * correctly and is therefore not done (particulary with interleaved chips * as each chip must be checked independantly of the others). */-static int chip_ready(struct map_info *map, unsigned long addr)+static int __xipram chip_ready(struct map_info *map, unsigned long addr) { map_word d, t; @@ -401,6 +418,32 @@ return map_word_equal(map, d, t); } +/*+ * Return true if the chip is ready and has the correct value.+ *+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any+ * non-suspended sector) and it is indicated by no bits toggling.+ *+ * Error are indicated by toggling bits or bits held with the wrong value,+ * or with bits toggling.+ *+ * Note that anything more complicated than checking if no bits are toggling+ * (including checking DQ5 for an error status) is tricky to get working+ * correctly and is therefore not done (particulary with interleaved chips+ * as each chip must be checked independantly of the others).+ *+ */+static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)+{+ map_word oldd, curd;++ oldd = map_read(map, addr);+ curd = map_read(map, addr);++ return map_word_equal(map, oldd, curd) && + map_word_equal(map, curd, expected);+}+ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { DECLARE_WAITQUEUE(wait, current);@@ -420,12 +463,12 @@ if (time_after(jiffies, timeo)) { printk(KERN_ERR "Waiting for chip to be ready timed out.\n");- cfi_spin_unlock(chip->mutex);+ spin_unlock(chip->mutex); return -EIO; }- cfi_spin_unlock(chip->mutex);+ spin_unlock(chip->mutex); cfi_udelay(1);- cfi_spin_lock(chip->mutex);+ spin_lock(chip->mutex); /* Someone else might have been playing with it. */ goto retry; }@@ -473,15 +516,23 @@ return -EIO; } - cfi_spin_unlock(chip->mutex);+ spin_unlock(chip->mutex); cfi_udelay(1);- cfi_spin_lock(chip->mutex);+ spin_lock(chip->mutex); /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. So we can just loop here. */ } chip->state = FL_READY; return 0; + case FL_XIP_WHILE_ERASING:+ if (mode != FL_READY && mode != FL_POINT &&+ (!cfip || !(cfip->EraseSuspend&2)))+ goto sleep;+ chip->oldstate = chip->state;+ chip->state = FL_READY;+ return 0;+ case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY)@@ -491,10 +542,10 @@ sleep: set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait);- cfi_spin_unlock(chip->mutex);+ spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait);- cfi_spin_lock(chip->mutex);+ spin_lock(chip->mutex); goto resettime; } }@@ -512,6 +563,11 @@ chip->state = FL_ERASING; break; + case FL_XIP_WHILE_ERASING:+ chip->state = chip->oldstate;+ chip->oldstate = FL_READY;+ break;+ case FL_READY: case FL_STATUS: /* We should really make set_vpp() count, rather than doing this */@@ -523,6 +579,198 @@ wake_up(&chip->wq); } +#ifdef CONFIG_MTD_XIP++/*+ * No interrupt what so ever can be serviced while the flash isn't in array+ * mode. This is ensured by the xip_disable() and xip_enable() functions+ * enclosing any code path where the flash is known not to be in array mode.+ * And within a XIP disabled code path, only functions marked with __xipram+ * may be called and nothing else (it's a good thing to inspect generated+ * assembly to make sure inline functions were actually inlined and that gcc+ * didn't emit calls to its own support functions). Also configuring MTD CFI+ * support to a single buswidth and a single interleave is also recommended.+ */++static void xip_disable(struct map_info *map, struct flchip *chip,+ unsigned long adr)+{+ /* TODO: chips with no XIP use should ignore and return */+ (void) map_read(map, adr); /* ensure mmu mapping is up to date */+ local_irq_disable();+}++static void __xipram xip_enable(struct map_info *map, struct flchip *chip,+ unsigned long adr)+{+ struct cfi_private *cfi = map->fldrv_priv;++ if (chip->state != FL_POINT && chip->state != FL_READY) {+ map_write(map, CMD(0xf0), adr);+ chip->state = FL_READY;+ }+ (void) map_read(map, adr);+ xip_iprefetch();+ local_irq_enable();+}++/*+ * When a delay is required for the flash operation to complete, the+ * xip_udelay() function is polling for both the given timeout and pending+ * (but still masked) hardware interrupts. Whenever there is an interrupt+ * pending then the flash erase operation is suspended, array mode restored + * and interrupts unmasked. Task scheduling might also happen at that+ * point. The CPU eventually returns from the interrupt or the call to+ * schedule() and the suspended flash operation is resumed for the remaining+ * of the delay period.+ *+ * Warning: this function _will_ fool interrupt latency tracing tools.+ */++static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,+ unsigned long adr, int usec)+{+ struct cfi_private *cfi = map->fldrv_priv;+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;+ map_word status, OK = CMD(0x80);+ unsigned long suspended, start = xip_currtime();+ flstate_t oldstate;++ do {+ cpu_relax();+ if (xip_irqpending() && extp &&+ ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&+ (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {+ /*+ * Let's suspend the erase operation when supported. + * Note that we currently don't try to suspend + * interleaved chips if there is already another + * operation suspended (imagine what happens+ * when one chip was already done with the current+ * operation while another chip suspended it, then+ * we resume the whole thing at once). Yes, it+ * can happen!+ */+ map_write(map, CMD(0xb0), adr);+ usec -= xip_elapsed_since(start);+ suspended = xip_currtime();+ do {+ if (xip_elapsed_since(suspended) > 100000) {+ /*+ * The chip doesn't want to suspend+ * after waiting for 100 msecs.+ * This is a critical error but there+ * is not much we can do here.+ */+ return;+ }+ status = map_read(map, adr);+ } while (!map_word_andequal(map, status, OK, OK));++ /* Suspend succeeded */+ oldstate = chip->state;+ if (!map_word_bitsset(map, status, CMD(0x40)))+ break;+ chip->state = FL_XIP_WHILE_ERASING;+ chip->erase_suspended = 1;+ map_write(map, CMD(0xf0), adr);+ (void) map_read(map, adr);+ asm volatile (".rep 8; nop; .endr");+ local_irq_enable();+ spin_unlock(chip->mutex);+ asm volatile (".rep 8; nop; .endr");+ cond_resched();++ /*+ * We're back. However someone else might have+ * decided to go write to the chip if we are in+ * a suspended erase state. If so let's wait+ * until it's done.+ */+ spin_lock(chip->mutex);+ while (chip->state != FL_XIP_WHILE_ERASING) {+ DECLARE_WAITQUEUE(wait, current);+ set_current_state(TASK_UNINTERRUPTIBLE);+ add_wait_queue(&chip->wq, &wait);+ spin_unlock(chip->mutex);+ schedule();+ remove_wait_queue(&chip->wq, &wait);+ spin_lock(chip->mutex);+ }+ /* Disallow XIP again */+ local_irq_disable();++ /* Resume the write or erase operation */+ map_write(map, CMD(0x30), adr);+ chip->state = oldstate;+ start = xip_currtime();+ } else if (usec >= 1000000/HZ) {+ /*+ * Try to save on CPU power when waiting delay+ * is at least a system timer tick period.+ * No need to be extremely accurate here.+ */+ xip_cpu_idle();+ }+ status = map_read(map, adr);+ } while (!map_word_andequal(map, status, OK, OK)+ && xip_elapsed_since(start) < usec);+}++#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)++/*+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while+ * the flash is actively programming or erasing since we have to poll for+ * the operation to complete anyway. We can't do that in a generic way with+ * a XIP setup so do it before the actual flash operation in this case+ * and stub it out from INVALIDATE_CACHE_UDELAY.+ */+#define XIP_INVAL_CACHED_RANGE(map, from, size) \+ INVALIDATE_CACHED_RANGE(map, from, size)++#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \+ UDELAY(map, chip, adr, usec)++/*+ * Extra notes:+ *+ * Activating this XIP support changes the way the code works a bit. For+ * example the code to suspend the current process when concurrent access+
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -