Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.infradead.org/~kmpark/onenand-mtd-2.6

+174 -22
+1
drivers/mtd/onenand/generic.c
··· 61 61 } 62 62 63 63 info->onenand.mmcontrol = pdata->mmcontrol; 64 + info->onenand.irq = platform_get_irq(pdev, 0); 64 65 65 66 info->mtd.name = pdev->dev.bus_id; 66 67 info->mtd.priv = &info->onenand;
+167 -21
drivers/mtd/onenand/onenand_base.c
··· 13 13 #include <linux/module.h> 14 14 #include <linux/init.h> 15 15 #include <linux/sched.h> 16 + #include <linux/interrupt.h> 16 17 #include <linux/jiffies.h> 17 18 #include <linux/mtd/mtd.h> 18 19 #include <linux/mtd/onenand.h> ··· 331 330 332 331 if (interrupt & ONENAND_INT_READ) { 333 332 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); 334 - if (ecc & ONENAND_ECC_2BIT_ALL) { 333 + if (ecc) { 335 334 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); 336 - return -EBADMSG; 335 + if (ecc & ONENAND_ECC_2BIT_ALL) 336 + mtd->ecc_stats.failed++; 337 + else if (ecc & ONENAND_ECC_1BIT_ALL) 338 + mtd->ecc_stats.corrected++; 337 339 } 338 340 } 339 341 340 342 return 0; 343 + } 344 + 345 + /* 346 + * onenand_interrupt - [DEFAULT] onenand interrupt handler 347 + * @param irq onenand interrupt number 348 + * @param dev_id interrupt data 349 + * 350 + * complete the work 351 + */ 352 + static irqreturn_t onenand_interrupt(int irq, void *data) 353 + { 354 + struct onenand_chip *this = (struct onenand_chip *) data; 355 + 356 + /* To handle shared interrupt */ 357 + if (!this->complete.done) 358 + complete(&this->complete); 359 + 360 + return IRQ_HANDLED; 361 + } 362 + 363 + /* 364 + * onenand_interrupt_wait - [DEFAULT] wait until the command is done 365 + * @param mtd MTD device structure 366 + * @param state state to select the max. timeout value 367 + * 368 + * Wait for command done. 369 + */ 370 + static int onenand_interrupt_wait(struct mtd_info *mtd, int state) 371 + { 372 + struct onenand_chip *this = mtd->priv; 373 + 374 + /* To prevent soft lockup */ 375 + touch_softlockup_watchdog(); 376 + 377 + wait_for_completion(&this->complete); 378 + 379 + return onenand_wait(mtd, state); 380 + } 381 + 382 + /* 383 + * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait 384 + * @param mtd MTD device structure 385 + * @param state state to select the max. timeout value 386 + * 387 + * Try interrupt based wait (It is used one-time) 388 + */ 389 + static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state) 390 + { 391 + struct onenand_chip *this = mtd->priv; 392 + unsigned long remain, timeout; 393 + 394 + /* We use interrupt wait first */ 395 + this->wait = onenand_interrupt_wait; 396 + 397 + /* To prevent soft lockup */ 398 + touch_softlockup_watchdog(); 399 + 400 + timeout = msecs_to_jiffies(100); 401 + remain = wait_for_completion_timeout(&this->complete, timeout); 402 + if (!remain) { 403 + printk(KERN_INFO "OneNAND: There's no interrupt. " 404 + "We use the normal wait\n"); 405 + 406 + /* Release the irq */ 407 + free_irq(this->irq, this); 408 + 409 + this->wait = onenand_wait; 410 + } 411 + 412 + return onenand_wait(mtd, state); 413 + } 414 + 415 + /* 416 + * onenand_setup_wait - [OneNAND Interface] setup onenand wait method 417 + * @param mtd MTD device structure 418 + * 419 + * There's two method to wait onenand work 420 + * 1. polling - read interrupt status register 421 + * 2. interrupt - use the kernel interrupt method 422 + */ 423 + static void onenand_setup_wait(struct mtd_info *mtd) 424 + { 425 + struct onenand_chip *this = mtd->priv; 426 + int syscfg; 427 + 428 + init_completion(&this->complete); 429 + 430 + if (this->irq <= 0) { 431 + this->wait = onenand_wait; 432 + return; 433 + } 434 + 435 + if (request_irq(this->irq, &onenand_interrupt, 436 + IRQF_SHARED, "onenand", this)) { 437 + /* If we can't get irq, use the normal wait */ 438 + this->wait = onenand_wait; 439 + return; 440 + } 441 + 442 + /* Enable interrupt */ 443 + syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); 444 + syscfg |= ONENAND_SYS_CFG1_IOBE; 445 + this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); 446 + 447 + this->wait = onenand_try_interrupt_wait; 341 448 } 342 449 343 450 /** ··· 718 609 size_t *retlen, u_char *buf) 719 610 { 720 611 struct onenand_chip *this = mtd->priv; 612 + struct mtd_ecc_stats stats; 721 613 int read = 0, column; 722 614 int thislen; 723 615 int ret = 0; ··· 737 627 738 628 /* TODO handling oob */ 739 629 630 + stats = mtd->ecc_stats; 740 631 while (read < len) { 741 632 thislen = min_t(int, mtd->writesize, len - read); 742 633 ··· 779 668 * retlen == desired len and result == -EBADMSG 780 669 */ 781 670 *retlen = read; 782 - return ret; 671 + 672 + if (mtd->ecc_stats.failed - stats.failed) 673 + return -EBADMSG; 674 + 675 + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 783 676 } 784 677 785 678 /** ··· 1244 1129 onenand_release_device(mtd); 1245 1130 } 1246 1131 1247 - 1248 1132 /** 1249 1133 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad 1250 1134 * @param mtd MTD device structure ··· 1310 1196 } 1311 1197 1312 1198 /** 1313 - * onenand_unlock - [MTD Interface] Unlock block(s) 1199 + * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s) 1314 1200 * @param mtd MTD device structure 1315 1201 * @param ofs offset relative to mtd start 1316 - * @param len number of bytes to unlock 1202 + * @param len number of bytes to lock or unlock 1317 1203 * 1318 - * Unlock one or more blocks 1204 + * Lock or unlock one or more blocks 1319 1205 */ 1320 - static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 1206 + static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd) 1321 1207 { 1322 1208 struct onenand_chip *this = mtd->priv; 1323 1209 int start, end, block, value, status; 1210 + int wp_status_mask; 1324 1211 1325 1212 start = ofs >> this->erase_shift; 1326 1213 end = len >> this->erase_shift; 1214 + 1215 + if (cmd == ONENAND_CMD_LOCK) 1216 + wp_status_mask = ONENAND_WP_LS; 1217 + else 1218 + wp_status_mask = ONENAND_WP_US; 1327 1219 1328 1220 /* Continuous lock scheme */ 1329 1221 if (this->options & ONENAND_HAS_CONT_LOCK) { ··· 1337 1217 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); 1338 1218 /* Set end block address */ 1339 1219 this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); 1340 - /* Write unlock command */ 1341 - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); 1220 + /* Write lock command */ 1221 + this->command(mtd, cmd, 0, 0); 1342 1222 1343 1223 /* There's no return value */ 1344 - this->wait(mtd, FL_UNLOCKING); 1224 + this->wait(mtd, FL_LOCKING); 1345 1225 1346 1226 /* Sanity check */ 1347 1227 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) ··· 1350 1230 1351 1231 /* Check lock status */ 1352 1232 status = this->read_word(this->base + ONENAND_REG_WP_STATUS); 1353 - if (!(status & ONENAND_WP_US)) 1233 + if (!(status & wp_status_mask)) 1354 1234 printk(KERN_ERR "wp status = 0x%x\n", status); 1355 1235 1356 1236 return 0; ··· 1366 1246 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); 1367 1247 /* Set start block address */ 1368 1248 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); 1369 - /* Write unlock command */ 1370 - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); 1249 + /* Write lock command */ 1250 + this->command(mtd, cmd, 0, 0); 1371 1251 1372 1252 /* There's no return value */ 1373 - this->wait(mtd, FL_UNLOCKING); 1253 + this->wait(mtd, FL_LOCKING); 1374 1254 1375 1255 /* Sanity check */ 1376 1256 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) ··· 1379 1259 1380 1260 /* Check lock status */ 1381 1261 status = this->read_word(this->base + ONENAND_REG_WP_STATUS); 1382 - if (!(status & ONENAND_WP_US)) 1262 + if (!(status & wp_status_mask)) 1383 1263 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); 1384 1264 } 1385 1265 1386 1266 return 0; 1267 + } 1268 + 1269 + /** 1270 + * onenand_lock - [MTD Interface] Lock block(s) 1271 + * @param mtd MTD device structure 1272 + * @param ofs offset relative to mtd start 1273 + * @param len number of bytes to unlock 1274 + * 1275 + * Lock one or more blocks 1276 + */ 1277 + static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 1278 + { 1279 + return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); 1280 + } 1281 + 1282 + /** 1283 + * onenand_unlock - [MTD Interface] Unlock block(s) 1284 + * @param mtd MTD device structure 1285 + * @param ofs offset relative to mtd start 1286 + * @param len number of bytes to unlock 1287 + * 1288 + * Unlock one or more blocks 1289 + */ 1290 + static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 1291 + { 1292 + return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); 1387 1293 } 1388 1294 1389 1295 /** ··· 1456 1310 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); 1457 1311 1458 1312 /* There's no return value */ 1459 - this->wait(mtd, FL_UNLOCKING); 1313 + this->wait(mtd, FL_LOCKING); 1460 1314 1461 1315 /* Sanity check */ 1462 1316 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) ··· 1480 1334 return 0; 1481 1335 } 1482 1336 1483 - mtd->unlock(mtd, 0x0, this->chipsize); 1337 + onenand_unlock(mtd, 0x0, this->chipsize); 1484 1338 1485 1339 return 0; 1486 1340 } ··· 1908 1762 /* Read manufacturer and device IDs from Register */ 1909 1763 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); 1910 1764 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); 1911 - ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID); 1765 + ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); 1912 1766 1913 1767 /* Check OneNAND device */ 1914 1768 if (maf_id != bram_maf_id || dev_id != bram_dev_id) ··· 1992 1846 if (!this->command) 1993 1847 this->command = onenand_command; 1994 1848 if (!this->wait) 1995 - this->wait = onenand_wait; 1849 + onenand_setup_wait(mtd); 1996 1850 1997 1851 if (!this->read_bufferram) 1998 1852 this->read_bufferram = onenand_read_bufferram; ··· 2068 1922 mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; 2069 1923 #endif 2070 1924 mtd->sync = onenand_sync; 2071 - mtd->lock = NULL; 1925 + mtd->lock = onenand_lock; 2072 1926 mtd->unlock = onenand_unlock; 2073 1927 mtd->suspend = onenand_suspend; 2074 1928 mtd->resume = onenand_resume;
+1
drivers/mtd/onenand/onenand_bbt.c
··· 100 100 bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); 101 101 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 102 102 i >> 1, (unsigned int) from); 103 + mtd->ecc_stats.badblocks++; 103 104 break; 104 105 } 105 106 }
+4 -1
include/linux/mtd/onenand.h
··· 13 13 #define __LINUX_MTD_ONENAND_H 14 14 15 15 #include <linux/spinlock.h> 16 + #include <linux/completion.h> 16 17 #include <linux/mtd/onenand_regs.h> 17 18 #include <linux/mtd/bbm.h> 18 19 ··· 34 33 FL_WRITING, 35 34 FL_ERASING, 36 35 FL_SYNCING, 37 - FL_UNLOCKING, 38 36 FL_LOCKING, 39 37 FL_RESETING, 40 38 FL_OTPING, ··· 119 119 void (*mmcontrol)(struct mtd_info *mtd, int sync_read); 120 120 int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); 121 121 int (*scan_bbt)(struct mtd_info *mtd); 122 + 123 + struct completion complete; 124 + int irq; 122 125 123 126 spinlock_t chip_lock; 124 127 wait_queue_head_t wq;
+1
include/linux/mtd/onenand_regs.h
··· 179 179 * ECC Status Reigser FF00h (R) 180 180 */ 181 181 #define ONENAND_ECC_1BIT (1 << 0) 182 + #define ONENAND_ECC_1BIT_ALL (0x5555) 182 183 #define ONENAND_ECC_2BIT (1 << 1) 183 184 #define ONENAND_ECC_2BIT_ALL (0xAAAA) 184 185