mtd/drivers/mtd/chips cfi_cmdset_0001.c,1.141,1.142
Nicolas Pitre
nico at infradead.org
Tue Jun 8 17:26:24 EDT 2004
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv24202/drivers/mtd/chips
Modified Files:
cfi_cmdset_0001.c
Log Message:
Support for the multi hw partitions of the Intel L18 flash chips.
The non-partitioned cases should behave just like before.
However I'd like for someone else to look at the added logic for the
partitioned config in case I might have overlooked something.
Index: cfi_cmdset_0001.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0001.c,v
retrieving revision 1.141
retrieving revision 1.142
diff -u -r1.141 -r1.142
--- cfi_cmdset_0001.c 7 Jun 2004 03:28:59 -0000 1.141
+++ cfi_cmdset_0001.c 8 Jun 2004 21:26:21 -0000 1.142
@@ -81,17 +81,18 @@
static void cfi_tell_features(struct cfi_pri_intelext *extp)
{
int i;
- printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
- printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
- printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
- printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
- printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
- printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
- printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
- printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
- printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
- printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
- for (i=9; i<32; i++) {
+ printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+ printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+ printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+ printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+ printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+ printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+ printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+ printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+ printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+ printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+ printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
+ for (i=10; i<32; i++) {
if (extp->FeatureSupport & (1<<i))
printk(" - Unknown Bit %X: supported\n", i);
}
@@ -215,10 +216,35 @@
}
for (i=0; i< cfi->numchips; i++) {
- cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
- cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
- cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
- cfi->chips[i].ref_point_counter = 0;
+ struct flchip *chip = &cfi->chips[i];
+ chip->word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
+ chip->buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
+ chip->erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+ chip->ref_point_counter = 0;
+
+ /*
+ * Probing of multi-partition flash ships.
+ * This is extremely crude at the moment and should be
+ * extracted entirely from the Intel extended query
+ * data instead.
+ */
+ if (cfi->cmdset_priv) {
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+ if (extp->FeatureSupport & (1 << 9)) {
+ /*
+ * The L18 flash memory array is divided
+ * into multiple 8-Mbit partitions.
+ */
+ int nbparts = 1 << (cfi->cfiq->DevSize - 20);
+ chip->partshift = __ffs(cfi->interleave) + 20;
+ chip->parts = kmalloc(nbparts * sizeof(*chip->parts), GFP_KERNEL);
+ if (!chip->parts) {
+ kfree(extp);
+ return NULL;
+ }
+ memset(chip->parts, 0, nbparts * sizeof(*chip->parts));
+ }
+ }
}
map->fldrv = &cfi_intelext_chipdrv;
@@ -328,27 +354,82 @@
* *********** CHIP ACCESS FUNCTIONS ***********
*/
-static inline flstate_t get_state(struct flchip *chip, unsigned long adr)
+static flstate_t get_state(struct flchip *chip, unsigned long adr)
+{
+ flstate_t state = chip->state;
+ if (chip->parts) {
+ int part = (adr - chip->start) >> chip->partshift;
+ state = chip->parts[part].state;
+ }
+ return state;
+}
+
+static void set_state(struct flchip *chip, unsigned long adr, flstate_t mode)
{
- return chip->state;
+ if (!chip->parts) {
+ chip->state = mode;
+ } else {
+ int part = (adr - chip->start) >> chip->partshift;
+ chip->parts[part].state = mode;
+ /* erasing and writing are global states to the chip */
+ switch (mode) {
+ case FL_ERASING:
+ chip->in_progress_block_addr = adr;
+ case FL_ERASE_SUSPENDING:
+ case FL_ERASE_SUSPENDED:
+ case FL_WRITING:
+ case FL_WRITING_TO_BUFFER:
+ case FL_WRITE_SUSPENDING:
+ case FL_WRITE_SUSPENDED:
+ chip->state = mode;
+ default:
+ chip->state = FL_READY;
+ }
+ }
}
-static inline void set_state(struct flchip *chip, unsigned long adr, flstate_t mode)
+static flstate_t get_oldstate(struct flchip *chip, unsigned long adr)
{
- chip->state = mode;
+ flstate_t state = chip->oldstate;
+ if (chip->parts) {
+ int part = (adr - chip->start) >> chip->partshift;
+ state = chip->parts[part].oldstate;
+ }
+ return state;
}
-static inline flstate_t get_oldstate(struct flchip *chip, unsigned long adr)
+static void set_oldstate(struct flchip *chip, unsigned long adr, flstate_t mode)
{
- return chip->oldstate;
+ if (!chip->parts) {
+ chip->oldstate = mode;
+ } else {
+ int part = (adr - chip->start) >> chip->partshift;
+ chip->parts[part].oldstate = mode;
+ /* erasing and writing are still global states to the chip */
+ switch (mode) {
+ case FL_ERASING:
+ case FL_ERASE_SUSPENDING:
+ case FL_ERASE_SUSPENDED:
+ case FL_WRITING:
+ case FL_WRITING_TO_BUFFER:
+ case FL_WRITE_SUSPENDING:
+ case FL_WRITE_SUSPENDED:
+ chip->oldstate = mode;
+ default:
+ chip->oldstate = FL_READY;
+ }
+ }
}
-static inline void set_oldstate(struct flchip *chip, unsigned long adr, flstate_t mode)
+static inline int same_partition(struct flchip *chip,
+ unsigned long addr_a, unsigned long addr_b)
{
- chip->oldstate = mode;
+ if (!chip->parts)
+ return 1;
+ return (((addr_a ^ addr_b) >> chip->partshift) == 0);
}
-static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, flstate_t mode)
{
DECLARE_WAITQUEUE(wait, current);
struct cfi_private *cfi = map->fldrv_priv;
@@ -359,6 +440,22 @@
resettime:
timeo = jiffies + HZ;
retry:
+ if ( !same_partition(chip, adr, chip->in_progress_block_addr) &&
+ !(chip->state == FL_READY && chip->oldstate == FL_READY) &&
+ (mode == FL_WRITING || mode == FL_ERASING) ) {
+ /*
+ * OK. We have contension on the write/erase operations
+ * which are global to the chip and not per partition.
+ * So let's fight it over in the partition where the
+ * write/erase is currently occurring first.
+ */
+ int ret = get_chip(map, chip, chip->in_progress_block_addr, mode);
+ if (ret)
+ return ret;
+ chip->suspender_block_addr = adr;
+ timeo = jiffies + HZ;
+ }
+
switch (get_state(chip, adr)) {
case FL_STATUS:
@@ -451,6 +548,11 @@
{
struct cfi_private *cfi = map->fldrv_priv;
+ if ( !same_partition(chip, adr, chip->in_progress_block_addr) &&
+ same_partition(chip, adr, chip->suspender_block_addr) &&
+ chip->oldstate != FL_READY )
+ put_chip(map, chip, chip->in_progress_block_addr);
+
switch(get_oldstate(chip, adr)) {
case FL_ERASING:
/* What if one interleaved chip has finished and the
@@ -1722,10 +1824,13 @@
static void cfi_intelext_destroy(struct mtd_info *mtd)
{
+ int i;
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
kfree(cfi->cmdset_priv);
kfree(cfi->cfiq);
+ for (i = 0; i < cfi->numchips; i++)
+ kfree(cfi->chips[i].parts);
kfree(cfi);
kfree(mtd->eraseregions);
}
More information about the linux-mtd-cvs
mailing list