diff options
author | Guillaume LECERF <glecerf@gmail.com> | 2010-04-24 11:58:17 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-05-13 20:33:27 -0400 |
commit | 564b84978df2bf83d334940f1a1190702579f79f (patch) | |
tree | 10f7ce02b4c0bb876c3e2c24afdb6eb0ac7707a4 /drivers/mtd/chips | |
parent | 58598861227877bb481b9035d2a07283577a2274 (diff) |
mtd: cfi_cmdset_0002: do not fail on no extended query table as they are both optional
After looking at AMD's CFI specification [1], both of the extended query
tables are optional. Thus, it looks like relying that at least one of
those tables exist is a bug in cfi_cmdset_0002.
This patch inverts the logic and checks for unlock function pointers before
exiting on error. This approach leaves place to add a call to a fixup
function to try to handle chips compatible with the early AMD specification
from 1995 [2].
[1] http://www.amd.com/us-en/assets/content_type/DownloadableAssets/cfi_r20.pdf
[2] http://noel.feld.cvut.cz/hw/amd/20158a.pdf
Signed-off-by: Guillaume LECERF <glecerf@gmail.com>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/chips')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 89 |
1 files changed, 45 insertions, 44 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c16b8cecc3a8..ce38d3d049ef 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -357,65 +357,66 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
357 | 357 | ||
358 | if (cfi->cfi_mode==CFI_MODE_CFI){ | 358 | if (cfi->cfi_mode==CFI_MODE_CFI){ |
359 | unsigned char bootloc; | 359 | unsigned char bootloc; |
360 | /* | ||
361 | * It's a real CFI chip, not one for which the probe | ||
362 | * routine faked a CFI structure. So we read the feature | ||
363 | * table from it. | ||
364 | */ | ||
365 | __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; | 360 | __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; |
366 | struct cfi_pri_amdstd *extp; | 361 | struct cfi_pri_amdstd *extp; |
367 | 362 | ||
368 | extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); | 363 | extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); |
369 | if (!extp) { | 364 | if (extp) { |
370 | kfree(mtd); | 365 | /* |
371 | return NULL; | 366 | * It's a real CFI chip, not one for which the probe |
372 | } | 367 | * routine faked a CFI structure. |
373 | 368 | */ | |
374 | cfi_fixup_major_minor(cfi, extp); | 369 | cfi_fixup_major_minor(cfi, extp); |
375 | 370 | ||
376 | if (extp->MajorVersion != '1' || | 371 | if (extp->MajorVersion != '1' || |
377 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | 372 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { |
378 | printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " | 373 | printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " |
379 | "version %c.%c.\n", extp->MajorVersion, | 374 | "version %c.%c.\n", extp->MajorVersion, |
380 | extp->MinorVersion); | 375 | extp->MinorVersion); |
381 | kfree(extp); | 376 | kfree(extp); |
382 | kfree(mtd); | 377 | kfree(mtd); |
383 | return NULL; | 378 | return NULL; |
384 | } | 379 | } |
385 | 380 | ||
386 | /* Install our own private info structure */ | 381 | /* Install our own private info structure */ |
387 | cfi->cmdset_priv = extp; | 382 | cfi->cmdset_priv = extp; |
388 | 383 | ||
389 | /* Apply cfi device specific fixups */ | 384 | /* Apply cfi device specific fixups */ |
390 | cfi_fixup(mtd, cfi_fixup_table); | 385 | cfi_fixup(mtd, cfi_fixup_table); |
391 | 386 | ||
392 | #ifdef DEBUG_CFI_FEATURES | 387 | #ifdef DEBUG_CFI_FEATURES |
393 | /* Tell the user about it in lots of lovely detail */ | 388 | /* Tell the user about it in lots of lovely detail */ |
394 | cfi_tell_features(extp); | 389 | cfi_tell_features(extp); |
395 | #endif | 390 | #endif |
396 | 391 | ||
397 | bootloc = extp->TopBottom; | 392 | bootloc = extp->TopBottom; |
398 | if ((bootloc != 2) && (bootloc != 3)) { | 393 | if ((bootloc != 2) && (bootloc != 3)) { |
399 | printk(KERN_WARNING "%s: CFI does not contain boot " | 394 | printk(KERN_WARNING "%s: CFI does not contain boot " |
400 | "bank location. Assuming top.\n", map->name); | 395 | "bank location. Assuming top.\n", map->name); |
401 | bootloc = 2; | 396 | bootloc = 2; |
402 | } | 397 | } |
403 | 398 | ||
404 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { | 399 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { |
405 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); | 400 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); |
406 | 401 | ||
407 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { | 402 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { |
408 | int j = (cfi->cfiq->NumEraseRegions-1)-i; | 403 | int j = (cfi->cfiq->NumEraseRegions-1)-i; |
409 | __u32 swap; | 404 | __u32 swap; |
410 | 405 | ||
411 | swap = cfi->cfiq->EraseRegionInfo[i]; | 406 | swap = cfi->cfiq->EraseRegionInfo[i]; |
412 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; | 407 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; |
413 | cfi->cfiq->EraseRegionInfo[j] = swap; | 408 | cfi->cfiq->EraseRegionInfo[j] = swap; |
409 | } | ||
414 | } | 410 | } |
411 | /* Set the default CFI lock/unlock addresses */ | ||
412 | cfi->addr_unlock1 = 0x555; | ||
413 | cfi->addr_unlock2 = 0x2aa; | ||
414 | } | ||
415 | |||
416 | if (!cfi->addr_unlock1 || !cfi->addr_unlock2) { | ||
417 | kfree(mtd); | ||
418 | return NULL; | ||
415 | } | 419 | } |
416 | /* Set the default CFI lock/unlock addresses */ | ||
417 | cfi->addr_unlock1 = 0x555; | ||
418 | cfi->addr_unlock2 = 0x2aa; | ||
419 | 420 | ||
420 | } /* CFI mode */ | 421 | } /* CFI mode */ |
421 | else if (cfi->cfi_mode == CFI_MODE_JEDEC) { | 422 | else if (cfi->cfi_mode == CFI_MODE_JEDEC) { |