mtd/drivers/mtd/chips cfi_cmdset_0001.c,1.162,1.163
Nicolas Pitre
nico at infradead.org
Mon Nov 15 15:56:35 EST 2004
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv19053/drivers/mtd/chips
Modified Files:
cfi_cmdset_0001.c
Log Message:
Determine number of hw partitions from extended query data instead of
hardcoding it.
Index: cfi_cmdset_0001.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0001.c,v
retrieving revision 1.162
retrieving revision 1.163
diff -u -r1.162 -r1.163
--- cfi_cmdset_0001.c 11 Nov 2004 11:13:19 -0000 1.162
+++ cfi_cmdset_0001.c 15 Nov 2004 20:56:31 -0000 1.163
@@ -67,7 +67,7 @@
struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
-static int cfi_intelext_partition_fixup(struct map_info *, struct cfi_private **);
+static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf);
@@ -235,6 +235,66 @@
{ 0, 0, NULL, NULL }
};
+static inline struct cfi_pri_intelext *
+read_pri_intelext(struct map_info *map, __u16 adr)
+{
+ struct cfi_pri_intelext *extp;
+ unsigned int extp_size = sizeof(*extp);
+
+ again:
+ extp = (struct cfi_pri_intelext *)cfi_read_pri(map, adr, extp_size, "Intel/Sharp");
+ if (!extp)
+ return NULL;
+
+ /* Do some byteswapping if necessary */
+ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+ extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+ extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+
+ if (extp->MajorVersion == '1' && extp->MinorVersion == '3') {
+ unsigned int extra_size = 0;
+ int nb_parts, i;
+
+ /* Protection Register info */
+ extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+
+ /* Burst Read info */
+ extra_size += 6;
+
+ /* Number of hardware-partitions */
+ extra_size += 1;
+ if (extp_size < sizeof(*extp) + extra_size)
+ goto need_more;
+ nb_parts = extp->extra[extra_size - 1];
+
+ for (i = 0; i < nb_parts; i++) {
+ struct cfi_intelext_regioninfo *rinfo;
+ rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
+ extra_size += sizeof(*rinfo);
+ if (extp_size < sizeof(*extp) + extra_size)
+ goto need_more;
+ rinfo->NumIdentPartitions=le16_to_cpu(rinfo->NumIdentPartitions);
+ extra_size += (rinfo->NumBlockTypes - 1)
+ * sizeof(struct cfi_intelext_blockinfo);
+ }
+
+ if (extp_size < sizeof(*extp) + extra_size) {
+ need_more:
+ extp_size = sizeof(*extp) + extra_size;
+ kfree(extp);
+ if (extp_size > 4096) {
+ printk(KERN_ERR
+ "%s: cfi_pri_intelext is too fat\n",
+ __FUNCTION__);
+ return NULL;
+ }
+ goto again;
+ }
+ }
+
+ return extp;
+}
+
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
* inter_module_get which will bump the use count of this module. The
@@ -278,22 +338,17 @@
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;
- extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
+ extp = read_pri_intelext(map, adr);
if (!extp) {
kfree(mtd);
return NULL;
}
-
- /* Do some byteswapping if necessary */
- extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
- extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
- extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
/* Install our own private info structure */
cfi->cmdset_priv = extp;
cfi_fixup(mtd, cfi_fixup_table);
-
+
#ifdef DEBUG_CFI_FEATURES
/* Tell the user about it in lots of lovely detail */
cfi_tell_features(extp);
@@ -378,7 +433,7 @@
/* This function has the potential to distort the reality
a bit and therefore should be called last. */
- if (cfi_intelext_partition_fixup(map, &cfi) != 0)
+ if (cfi_intelext_partition_fixup(mtd, &cfi) != 0)
goto setup_err;
__module_get(THIS_MODULE);
@@ -394,20 +449,16 @@
return NULL;
}
-static int cfi_intelext_partition_fixup(struct map_info *map,
+static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
struct cfi_private **pcfi)
{
+ struct map_info *map = mtd->priv;
struct cfi_private *cfi = *pcfi;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
/*
* Probing of multi-partition flash ships.
*
- * This is extremely crude at the moment and should probably be
- * extracted entirely from the Intel extended query data instead.
- * Right now a L18 flash is assumed if multiple operations is
- * detected.
- *
* To support multiple partitions when available, we simply arrange
* for each of them to have their own flchip structure even if they
* are on the same physical chip. This means completely recreating
@@ -416,20 +467,49 @@
* arrangement at this point. This can be rearranged in the future
* if someone feels motivated enough. --nico
*/
- if (extp && extp->FeatureSupport & (1 << 9)) {
+ if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3'
+ && extp->FeatureSupport & (1 << 9)) {
struct cfi_private *newcfi;
struct flchip *chip;
struct flchip_shared *shared;
- int numparts, partshift, numvirtchips, i, j;
+ int offs, numregions, numparts, partshift, numvirtchips, i, j;
+
+ /* Protection Register info */
+ offs = (extp->NumProtectionFields - 1) * (4 + 6);
+
+ /* Burst Read info */
+ offs += 6;
+
+ /* Number of partition regions */
+ numregions = extp->extra[offs];
+ offs += 1;
+
+ /* Number of hardware partitions */
+ numparts = 0;
+ for (i = 0; i < numregions; i++) {
+ struct cfi_intelext_regioninfo *rinfo;
+ rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[offs];
+ numparts += rinfo->NumIdentPartitions;
+ offs += sizeof(*rinfo)
+ + (rinfo->NumBlockTypes - 1) *
+ sizeof(struct cfi_intelext_blockinfo);
+ }
/*
- * The L18 flash memory array is divided
- * into multiple 8-Mbit partitions.
+ * All functions below currently rely on all chips having
+ * the same geometry so we'll just assume that all hardware
+ * partitions are of the same size too.
*/
- numparts = 1 << (cfi->cfiq->DevSize - 20);
- partshift = 20 + __ffs(cfi->interleave);
- numvirtchips = cfi->numchips * numparts;
+ partshift = cfi->chipshift - __ffs(numparts);
+ if ((1 << partshift) < mtd->erasesize) {
+ printk( KERN_ERR
+ "%s: bad number of hw partitions (%d)\n",
+ __FUNCTION__, numparts);
+ return -EINVAL;
+ }
+
+ numvirtchips = cfi->numchips * numparts;
newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
if (!newcfi)
return -ENOMEM;
@@ -459,10 +539,10 @@
}
}
- printk(KERN_DEBUG "%s: %d sets of %d interleaved chips "
- "--> %d partitions of %#x bytes\n",
+ printk(KERN_DEBUG "%s: %d set(s) of %d interleaved chips "
+ "--> %d partitions of %d KiB\n",
map->name, cfi->numchips, cfi->interleave,
- newcfi->numchips, 1<<newcfi->chipshift);
+ newcfi->numchips, 1<<(newcfi->chipshift-10));
map->fldrv_priv = newcfi;
*pcfi = newcfi;
More information about the linux-mtd-cvs
mailing list