diff options
Diffstat (limited to 'drivers/mtd/inftlcore.c')
-rw-r--r-- | drivers/mtd/inftlcore.c | 60 |
1 files changed, 28 insertions, 32 deletions
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 39eb53f6551f..8a544890173d 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) | 2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) |
3 | * | 3 | * |
4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
@@ -7,7 +7,7 @@ | |||
7 | * (c) 1999 Machine Vision Holdings, Inc. | 7 | * (c) 1999 Machine Vision Holdings, Inc. |
8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
9 | * | 9 | * |
10 | * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $ | 10 | * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -113,23 +113,21 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
113 | 113 | ||
114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { | 114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { |
115 | /* | 115 | /* |
116 | Oh no we don't have | 116 | Oh no we don't have |
117 | mbd.size == heads * cylinders * sectors | 117 | mbd.size == heads * cylinders * sectors |
118 | */ | 118 | */ |
119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " | 119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " |
120 | "match size of 0x%lx.\n", inftl->mbd.size); | 120 | "match size of 0x%lx.\n", inftl->mbd.size); |
121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " | 121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " |
122 | "(== 0x%lx sects)\n", | 122 | "(== 0x%lx sects)\n", |
123 | inftl->cylinders, inftl->heads , inftl->sectors, | 123 | inftl->cylinders, inftl->heads , inftl->sectors, |
124 | (long)inftl->cylinders * (long)inftl->heads * | 124 | (long)inftl->cylinders * (long)inftl->heads * |
125 | (long)inftl->sectors ); | 125 | (long)inftl->sectors ); |
126 | } | 126 | } |
127 | 127 | ||
128 | if (add_mtd_blktrans_dev(&inftl->mbd)) { | 128 | if (add_mtd_blktrans_dev(&inftl->mbd)) { |
129 | if (inftl->PUtable) | 129 | kfree(inftl->PUtable); |
130 | kfree(inftl->PUtable); | 130 | kfree(inftl->VUtable); |
131 | if (inftl->VUtable) | ||
132 | kfree(inftl->VUtable); | ||
133 | kfree(inftl); | 131 | kfree(inftl); |
134 | return; | 132 | return; |
135 | } | 133 | } |
@@ -147,10 +145,8 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev) | |||
147 | 145 | ||
148 | del_mtd_blktrans_dev(dev); | 146 | del_mtd_blktrans_dev(dev); |
149 | 147 | ||
150 | if (inftl->PUtable) | 148 | kfree(inftl->PUtable); |
151 | kfree(inftl->PUtable); | 149 | kfree(inftl->VUtable); |
152 | if (inftl->VUtable) | ||
153 | kfree(inftl->VUtable); | ||
154 | kfree(inftl); | 150 | kfree(inftl); |
155 | } | 151 | } |
156 | 152 | ||
@@ -223,7 +219,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
223 | "Virtual Unit Chain %d!\n", thisVUC); | 219 | "Virtual Unit Chain %d!\n", thisVUC); |
224 | return BLOCK_NIL; | 220 | return BLOCK_NIL; |
225 | } | 221 | } |
226 | 222 | ||
227 | /* | 223 | /* |
228 | * Scan to find the Erase Unit which holds the actual data for each | 224 | * Scan to find the Erase Unit which holds the actual data for each |
229 | * 512-byte block within the Chain. | 225 | * 512-byte block within the Chain. |
@@ -264,7 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
264 | "Unit Chain 0x%x\n", thisVUC); | 260 | "Unit Chain 0x%x\n", thisVUC); |
265 | return BLOCK_NIL; | 261 | return BLOCK_NIL; |
266 | } | 262 | } |
267 | 263 | ||
268 | thisEUN = inftl->PUtable[thisEUN]; | 264 | thisEUN = inftl->PUtable[thisEUN]; |
269 | } | 265 | } |
270 | 266 | ||
@@ -295,15 +291,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
295 | */ | 291 | */ |
296 | if (BlockMap[block] == BLOCK_NIL) | 292 | if (BlockMap[block] == BLOCK_NIL) |
297 | continue; | 293 | continue; |
298 | 294 | ||
299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
300 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, | 296 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, |
301 | &retlen, movebuf); | 297 | &retlen, movebuf); |
302 | if (ret < 0) { | 298 | if (ret < 0) { |
303 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
304 | BlockMap[block]) + (block * SECTORSIZE), | 300 | BlockMap[block]) + (block * SECTORSIZE), |
305 | SECTORSIZE, &retlen, movebuf); | 301 | SECTORSIZE, &retlen, movebuf); |
306 | if (ret != -EIO) | 302 | if (ret != -EIO) |
307 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " | 303 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " |
308 | "away on retry?\n"); | 304 | "away on retry?\n"); |
309 | } | 305 | } |
@@ -355,7 +351,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
355 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) | 351 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) |
356 | { | 352 | { |
357 | /* | 353 | /* |
358 | * This is the part that needs some cleverness applied. | 354 | * This is the part that needs some cleverness applied. |
359 | * For now, I'm doing the minimum applicable to actually | 355 | * For now, I'm doing the minimum applicable to actually |
360 | * get the thing to work. | 356 | * get the thing to work. |
361 | * Wear-levelling and other clever stuff needs to be implemented | 357 | * Wear-levelling and other clever stuff needs to be implemented |
@@ -414,7 +410,7 @@ static int nrbits(unsigned int val, int bitcount) | |||
414 | } | 410 | } |
415 | 411 | ||
416 | /* | 412 | /* |
417 | * INFTL_findwriteunit: Return the unit number into which we can write | 413 | * INFTL_findwriteunit: Return the unit number into which we can write |
418 | * for this block. Make it available if it isn't already. | 414 | * for this block. Make it available if it isn't already. |
419 | */ | 415 | */ |
420 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | 416 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) |
@@ -463,10 +459,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | |||
463 | * Invalid block. Don't use it any more. | 459 | * Invalid block. Don't use it any more. |
464 | * Must implement. | 460 | * Must implement. |
465 | */ | 461 | */ |
466 | break; | 462 | break; |
467 | } | 463 | } |
468 | 464 | ||
469 | if (!silly--) { | 465 | if (!silly--) { |
470 | printk(KERN_WARNING "INFTL: infinite loop in " | 466 | printk(KERN_WARNING "INFTL: infinite loop in " |
471 | "Virtual Unit Chain 0x%x\n", thisVUC); | 467 | "Virtual Unit Chain 0x%x\n", thisVUC); |
472 | return 0xffff; | 468 | return 0xffff; |
@@ -482,7 +478,7 @@ hitused: | |||
482 | 478 | ||
483 | 479 | ||
484 | /* | 480 | /* |
485 | * OK. We didn't find one in the existing chain, or there | 481 | * OK. We didn't find one in the existing chain, or there |
486 | * is no existing chain. Allocate a new one. | 482 | * is no existing chain. Allocate a new one. |
487 | */ | 483 | */ |
488 | writeEUN = INFTL_findfreeblock(inftl, 0); | 484 | writeEUN = INFTL_findfreeblock(inftl, 0); |
@@ -506,8 +502,8 @@ hitused: | |||
506 | if (writeEUN == BLOCK_NIL) { | 502 | if (writeEUN == BLOCK_NIL) { |
507 | /* | 503 | /* |
508 | * Ouch. This should never happen - we should | 504 | * Ouch. This should never happen - we should |
509 | * always be able to make some room somehow. | 505 | * always be able to make some room somehow. |
510 | * If we get here, we've allocated more storage | 506 | * If we get here, we've allocated more storage |
511 | * space than actual media, or our makefreeblock | 507 | * space than actual media, or our makefreeblock |
512 | * routine is missing something. | 508 | * routine is missing something. |
513 | */ | 509 | */ |
@@ -518,7 +514,7 @@ hitused: | |||
518 | INFTL_dumpVUchains(inftl); | 514 | INFTL_dumpVUchains(inftl); |
519 | #endif | 515 | #endif |
520 | return BLOCK_NIL; | 516 | return BLOCK_NIL; |
521 | } | 517 | } |
522 | } | 518 | } |
523 | 519 | ||
524 | /* | 520 | /* |
@@ -543,7 +539,7 @@ hitused: | |||
543 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; | 539 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; |
544 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; | 540 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; |
545 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; | 541 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; |
546 | 542 | ||
547 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); | 543 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); |
548 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); | 544 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); |
549 | oob.u.a.ANAC = anac; | 545 | oob.u.a.ANAC = anac; |
@@ -562,7 +558,7 @@ hitused: | |||
562 | oob.u.b.parityPerField = parity; | 558 | oob.u.b.parityPerField = parity; |
563 | oob.u.b.discarded = 0xaa; | 559 | oob.u.b.discarded = 0xaa; |
564 | 560 | ||
565 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + | 561 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + |
566 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); | 562 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); |
567 | 563 | ||
568 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; | 564 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; |
@@ -602,7 +598,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
602 | "Virtual Unit Chain %d!\n", thisVUC); | 598 | "Virtual Unit Chain %d!\n", thisVUC); |
603 | return; | 599 | return; |
604 | } | 600 | } |
605 | 601 | ||
606 | /* | 602 | /* |
607 | * Scan through the Erase Units to determine whether any data is in | 603 | * Scan through the Erase Units to determine whether any data is in |
608 | * each of the 512-byte blocks within the Chain. | 604 | * each of the 512-byte blocks within the Chain. |
@@ -642,7 +638,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
642 | "Unit Chain 0x%x\n", thisVUC); | 638 | "Unit Chain 0x%x\n", thisVUC); |
643 | return; | 639 | return; |
644 | } | 640 | } |
645 | 641 | ||
646 | thisEUN = inftl->PUtable[thisEUN]; | 642 | thisEUN = inftl->PUtable[thisEUN]; |
647 | } | 643 | } |
648 | 644 | ||
@@ -758,7 +754,7 @@ foundit: | |||
758 | return 0; | 754 | return 0; |
759 | } | 755 | } |
760 | 756 | ||
761 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, | 757 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, |
762 | char *buffer) | 758 | char *buffer) |
763 | { | 759 | { |
764 | struct INFTLrecord *inftl = (void *)mbd; | 760 | struct INFTLrecord *inftl = (void *)mbd; |
@@ -893,7 +889,7 @@ extern char inftlmountrev[]; | |||
893 | 889 | ||
894 | static int __init init_inftl(void) | 890 | static int __init init_inftl(void) |
895 | { | 891 | { |
896 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, " | 892 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " |
897 | "inftlmount.c %s\n", inftlmountrev); | 893 | "inftlmount.c %s\n", inftlmountrev); |
898 | 894 | ||
899 | return register_mtd_blktrans(&inftl_tr); | 895 | return register_mtd_blktrans(&inftl_tr); |