* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.c,v 1.13 2003/06/25 11:50:37 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.19 2004/07/13 22:33:32 dwmw2 Exp $
*/
#include <linux/kernel.h>
EXPORT_SYMBOL(mtd_do_chip_probe);
-struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
+static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
{
- unsigned long base=0;
struct cfi_private cfi;
struct cfi_private *retcfi;
- struct flchip chip[MAX_CFI_CHIPS];
- int i;
+ unsigned long *chip_map;
+ int i, j, mapsize;
+ int max_chips;
memset(&cfi, 0, sizeof(cfi));
- memset(&chip[0], 0, sizeof(chip));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
return NULL;
}
#endif
- chip[0].start = 0;
- chip[0].state = FL_READY;
cfi.chipshift = cfi.cfiq->DevSize;
- switch(cfi.interleave) {
-#ifdef CFIDEV_INTERLEAVE_1
- case 1:
- break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_2
- case 2:
+ if (cfi_interleave_is_1(&cfi)) {
+ ;
+ } else if (cfi_interleave_is_2(&cfi)) {
cfi.chipshift++;
- break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_4
- case 4:
- cfi.chipshift+=2;
- break;
-#endif
- default:
+ } else if (cfi_interleave_is_4((&cfi))) {
+ cfi.chipshift += 2;
+ } else if (cfi_interleave_is_8(&cfi)) {
+ cfi.chipshift += 3;
+ } else {
BUG();
}
cfi.numchips = 1;
+ /*
+ * Allocate memory for bitmap of valid chips.
+ * Align bitmap storage size to full byte.
+ */
+ max_chips = map->size >> cfi.chipshift;
+ mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
+ chip_map = kmalloc(mapsize, GFP_KERNEL);
+ if (!chip_map) {
+ printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
+ kfree(cfi.cfiq);
+ return NULL;
+ }
+ memset (chip_map, 0, mapsize);
+
+ set_bit(0, chip_map); /* Mark first chip valid */
+
/*
* Now probe for other chips, checking sensibly for aliases while
* we're at it. The new_chip probe above should have let the first
* chip in read mode.
- *
- * NOTE: Here, we're checking if there is room for another chip
- * the same size within the mapping. Therefore,
- * base + chipsize <= map->size is the correct thing to do,
- * because, base + chipsize would be the _first_ byte of the
- * next chip, not the one we're currently pondering.
*/
- for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
- base += (1<<cfi.chipshift))
- cp->probe_chip(map, base, &chip[0], &cfi);
+ for (i = 1; i < max_chips; i++) {
+ cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
+ }
/*
* Now allocate the space for the structures we need to return to
if (!retcfi) {
printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
kfree(cfi.cfiq);
+ kfree(chip_map);
return NULL;
}
memcpy(retcfi, &cfi, sizeof(cfi));
- memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-
- /* Fix up the stuff that breaks when you move it */
- for (i=0; i< retcfi->numchips; i++) {
- init_waitqueue_head(&retcfi->chips[i].wq);
- spin_lock_init(&retcfi->chips[i]._spinlock);
- retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
+ memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
+
+ for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
+ if(test_bit(i, chip_map)) {
+ struct flchip *pchip = &retcfi->chips[j++];
+
+ pchip->start = (i << cfi.chipshift);
+ pchip->state = FL_READY;
+ init_waitqueue_head(&pchip->wq);
+ spin_lock_init(&pchip->_spinlock);
+ pchip->mutex = &pchip->_spinlock;
+ }
}
+ kfree(chip_map);
return retcfi;
}
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi)
{
- switch (map->buswidth) {
-#ifdef CFIDEV_BUSWIDTH_1
- case CFIDEV_BUSWIDTH_1:
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
- break;
-#endif /* CFIDEV_BUSWITDH_1 */
-
-#ifdef CFIDEV_BUSWIDTH_2
- case CFIDEV_BUSWIDTH_2:
-#ifdef CFIDEV_INTERLEAVE_1
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
- break;
-#endif /* CFIDEV_BUSWIDTH_2 */
-
-#ifdef CFIDEV_BUSWIDTH_4
- case CFIDEV_BUSWIDTH_4:
-#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
- cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
- break;
-#endif /* CFIDEV_BUSWIDTH_4 */
-
-#ifdef CFIDEV_BUSWIDTH_8
- case CFIDEV_BUSWIDTH_8:
-#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
- cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
-#ifdef CFIDEV_INTERLEAVE_8
- cfi->interleave = CFIDEV_INTERLEAVE_8;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_8 */
- break;
-#endif /* CFIDEV_BUSWIDTH_8 */
-
- default:
- printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
- return 0;
+ int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
+ int max_chips = map_bankwidth(map); /* And minimum 1 */
+ int nr_chips, type;
+
+ for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+
+ if (!cfi_interleave_supported(nr_chips))
+ continue;
+
+ cfi->interleave = nr_chips;
+
+ for (type = 0; type < 3; type++) {
+ cfi->device_type = 1<<type;
+
+ if (cp->probe_chip(map, 0, NULL, cfi))
+ return 1;
+ }
}
return 0;
}
-
typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
extern cfi_cmdset_fn_t cfi_cmdset_0001;