| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Overview: |
|---|
| 3 | 4 | * Bad block table support for the NAND driver |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | 7 | * |
|---|
| 11 | 8 | * Description: |
|---|
| 12 | 9 | * |
|---|
| .. | .. |
|---|
| 54 | 51 | * Following assumptions are made: |
|---|
| 55 | 52 | * - bbts start at a page boundary, if autolocated on a block boundary |
|---|
| 56 | 53 | * - the space necessary for a bbt in FLASH does not exceed a block boundary |
|---|
| 57 | | - * |
|---|
| 58 | 54 | */ |
|---|
| 59 | 55 | |
|---|
| 60 | 56 | #include <linux/slab.h> |
|---|
| 61 | 57 | #include <linux/types.h> |
|---|
| 62 | 58 | #include <linux/mtd/mtd.h> |
|---|
| 63 | 59 | #include <linux/mtd/bbm.h> |
|---|
| 64 | | -#include <linux/mtd/rawnand.h> |
|---|
| 65 | 60 | #include <linux/bitops.h> |
|---|
| 66 | 61 | #include <linux/delay.h> |
|---|
| 67 | 62 | #include <linux/vmalloc.h> |
|---|
| 68 | 63 | #include <linux/export.h> |
|---|
| 69 | 64 | #include <linux/string.h> |
|---|
| 65 | + |
|---|
| 66 | +#include "internals.h" |
|---|
| 70 | 67 | |
|---|
| 71 | 68 | #define BBT_BLOCK_GOOD 0x00 |
|---|
| 72 | 69 | #define BBT_BLOCK_WORN 0x01 |
|---|
| .. | .. |
|---|
| 75 | 72 | |
|---|
| 76 | 73 | #define BBT_ENTRY_MASK 0x03 |
|---|
| 77 | 74 | #define BBT_ENTRY_SHIFT 2 |
|---|
| 78 | | - |
|---|
| 79 | | -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs); |
|---|
| 80 | 75 | |
|---|
| 81 | 76 | static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) |
|---|
| 82 | 77 | { |
|---|
| .. | .. |
|---|
| 159 | 154 | |
|---|
| 160 | 155 | /** |
|---|
| 161 | 156 | * read_bbt - [GENERIC] Read the bad block table starting from page |
|---|
| 162 | | - * @mtd: MTD device structure |
|---|
| 157 | + * @this: NAND chip object |
|---|
| 163 | 158 | * @buf: temporary buffer |
|---|
| 164 | 159 | * @page: the starting page |
|---|
| 165 | 160 | * @num: the number of bbt descriptors to read |
|---|
| .. | .. |
|---|
| 168 | 163 | * |
|---|
| 169 | 164 | * Read the bad block table starting from page. |
|---|
| 170 | 165 | */ |
|---|
| 171 | | -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, |
|---|
| 172 | | - struct nand_bbt_descr *td, int offs) |
|---|
| 166 | +static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num, |
|---|
| 167 | + struct nand_bbt_descr *td, int offs) |
|---|
| 173 | 168 | { |
|---|
| 169 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 174 | 170 | int res, ret = 0, i, j, act = 0; |
|---|
| 175 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 176 | 171 | size_t retlen, len, totlen; |
|---|
| 177 | 172 | loff_t from; |
|---|
| 178 | 173 | int bits = td->options & NAND_BBT_NRBITS_MSK; |
|---|
| .. | .. |
|---|
| 252 | 247 | |
|---|
| 253 | 248 | /** |
|---|
| 254 | 249 | * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page |
|---|
| 255 | | - * @mtd: MTD device structure |
|---|
| 250 | + * @this: NAND chip object |
|---|
| 256 | 251 | * @buf: temporary buffer |
|---|
| 257 | 252 | * @td: descriptor for the bad block table |
|---|
| 258 | 253 | * @chip: read the table for a specific chip, -1 read all chips; applies only if |
|---|
| .. | .. |
|---|
| 261 | 256 | * Read the bad block table for all chips starting at a given page. We assume |
|---|
| 262 | 257 | * that the bbt bits are in consecutive order. |
|---|
| 263 | 258 | */ |
|---|
| 264 | | -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) |
|---|
| 259 | +static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, |
|---|
| 260 | + struct nand_bbt_descr *td, int chip) |
|---|
| 265 | 261 | { |
|---|
| 266 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 262 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 263 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 267 | 264 | int res = 0, i; |
|---|
| 268 | 265 | |
|---|
| 269 | 266 | if (td->options & NAND_BBT_PERCHIP) { |
|---|
| 270 | 267 | int offs = 0; |
|---|
| 271 | | - for (i = 0; i < this->numchips; i++) { |
|---|
| 268 | + for (i = 0; i < nanddev_ntargets(&this->base); i++) { |
|---|
| 272 | 269 | if (chip == -1 || chip == i) |
|---|
| 273 | | - res = read_bbt(mtd, buf, td->pages[i], |
|---|
| 274 | | - this->chipsize >> this->bbt_erase_shift, |
|---|
| 270 | + res = read_bbt(this, buf, td->pages[i], |
|---|
| 271 | + targetsize >> this->bbt_erase_shift, |
|---|
| 275 | 272 | td, offs); |
|---|
| 276 | 273 | if (res) |
|---|
| 277 | 274 | return res; |
|---|
| 278 | | - offs += this->chipsize >> this->bbt_erase_shift; |
|---|
| 275 | + offs += targetsize >> this->bbt_erase_shift; |
|---|
| 279 | 276 | } |
|---|
| 280 | 277 | } else { |
|---|
| 281 | | - res = read_bbt(mtd, buf, td->pages[0], |
|---|
| 278 | + res = read_bbt(this, buf, td->pages[0], |
|---|
| 282 | 279 | mtd->size >> this->bbt_erase_shift, td, 0); |
|---|
| 283 | 280 | if (res) |
|---|
| 284 | 281 | return res; |
|---|
| .. | .. |
|---|
| 287 | 284 | } |
|---|
| 288 | 285 | |
|---|
| 289 | 286 | /* BBT marker is in the first page, no OOB */ |
|---|
| 290 | | -static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, |
|---|
| 291 | | - struct nand_bbt_descr *td) |
|---|
| 287 | +static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs, |
|---|
| 288 | + struct nand_bbt_descr *td) |
|---|
| 292 | 289 | { |
|---|
| 290 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 293 | 291 | size_t retlen; |
|---|
| 294 | 292 | size_t len; |
|---|
| 295 | 293 | |
|---|
| .. | .. |
|---|
| 302 | 300 | |
|---|
| 303 | 301 | /** |
|---|
| 304 | 302 | * scan_read_oob - [GENERIC] Scan data+OOB region to buffer |
|---|
| 305 | | - * @mtd: MTD device structure |
|---|
| 303 | + * @this: NAND chip object |
|---|
| 306 | 304 | * @buf: temporary buffer |
|---|
| 307 | 305 | * @offs: offset at which to scan |
|---|
| 308 | 306 | * @len: length of data region to read |
|---|
| .. | .. |
|---|
| 311 | 309 | * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" |
|---|
| 312 | 310 | * ECC condition (error or bitflip). May quit on the first (non-ECC) error. |
|---|
| 313 | 311 | */ |
|---|
| 314 | | -static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, |
|---|
| 312 | +static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs, |
|---|
| 315 | 313 | size_t len) |
|---|
| 316 | 314 | { |
|---|
| 315 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 317 | 316 | struct mtd_oob_ops ops; |
|---|
| 318 | 317 | int res, ret = 0; |
|---|
| 319 | 318 | |
|---|
| .. | .. |
|---|
| 341 | 340 | return ret; |
|---|
| 342 | 341 | } |
|---|
| 343 | 342 | |
|---|
| 344 | | -static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, |
|---|
| 345 | | - size_t len, struct nand_bbt_descr *td) |
|---|
| 343 | +static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs, |
|---|
| 344 | + size_t len, struct nand_bbt_descr *td) |
|---|
| 346 | 345 | { |
|---|
| 347 | 346 | if (td->options & NAND_BBT_NO_OOB) |
|---|
| 348 | | - return scan_read_data(mtd, buf, offs, td); |
|---|
| 347 | + return scan_read_data(this, buf, offs, td); |
|---|
| 349 | 348 | else |
|---|
| 350 | | - return scan_read_oob(mtd, buf, offs, len); |
|---|
| 349 | + return scan_read_oob(this, buf, offs, len); |
|---|
| 351 | 350 | } |
|---|
| 352 | 351 | |
|---|
| 353 | 352 | /* Scan write data with oob to flash */ |
|---|
| 354 | | -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, |
|---|
| 353 | +static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len, |
|---|
| 355 | 354 | uint8_t *buf, uint8_t *oob) |
|---|
| 356 | 355 | { |
|---|
| 356 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 357 | 357 | struct mtd_oob_ops ops; |
|---|
| 358 | 358 | |
|---|
| 359 | 359 | ops.mode = MTD_OPS_PLACE_OOB; |
|---|
| .. | .. |
|---|
| 366 | 366 | return mtd_write_oob(mtd, offs, &ops); |
|---|
| 367 | 367 | } |
|---|
| 368 | 368 | |
|---|
| 369 | | -static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) |
|---|
| 369 | +static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td) |
|---|
| 370 | 370 | { |
|---|
| 371 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 371 | 372 | u32 ver_offs = td->veroffs; |
|---|
| 372 | 373 | |
|---|
| 373 | 374 | if (!(td->options & NAND_BBT_NO_OOB)) |
|---|
| .. | .. |
|---|
| 377 | 378 | |
|---|
| 378 | 379 | /** |
|---|
| 379 | 380 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page |
|---|
| 380 | | - * @mtd: MTD device structure |
|---|
| 381 | + * @this: NAND chip object |
|---|
| 381 | 382 | * @buf: temporary buffer |
|---|
| 382 | 383 | * @td: descriptor for the bad block table |
|---|
| 383 | 384 | * @md: descriptor for the bad block table mirror |
|---|
| .. | .. |
|---|
| 385 | 386 | * Read the bad block table(s) for all chips starting at a given page. We |
|---|
| 386 | 387 | * assume that the bbt bits are in consecutive order. |
|---|
| 387 | 388 | */ |
|---|
| 388 | | -static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, |
|---|
| 389 | +static void read_abs_bbts(struct nand_chip *this, uint8_t *buf, |
|---|
| 389 | 390 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) |
|---|
| 390 | 391 | { |
|---|
| 391 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 392 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 392 | 393 | |
|---|
| 393 | 394 | /* Read the primary version, if available */ |
|---|
| 394 | 395 | if (td->options & NAND_BBT_VERSION) { |
|---|
| 395 | | - scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, |
|---|
| 396 | | - mtd->writesize, td); |
|---|
| 397 | | - td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; |
|---|
| 396 | + scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift, |
|---|
| 397 | + mtd->writesize, td); |
|---|
| 398 | + td->version[0] = buf[bbt_get_ver_offs(this, td)]; |
|---|
| 398 | 399 | pr_info("Bad block table at page %d, version 0x%02X\n", |
|---|
| 399 | 400 | td->pages[0], td->version[0]); |
|---|
| 400 | 401 | } |
|---|
| 401 | 402 | |
|---|
| 402 | 403 | /* Read the mirror version, if available */ |
|---|
| 403 | 404 | if (md && (md->options & NAND_BBT_VERSION)) { |
|---|
| 404 | | - scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, |
|---|
| 405 | | - mtd->writesize, md); |
|---|
| 406 | | - md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; |
|---|
| 405 | + scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift, |
|---|
| 406 | + mtd->writesize, md); |
|---|
| 407 | + md->version[0] = buf[bbt_get_ver_offs(this, md)]; |
|---|
| 407 | 408 | pr_info("Bad block table at page %d, version 0x%02X\n", |
|---|
| 408 | 409 | md->pages[0], md->version[0]); |
|---|
| 409 | 410 | } |
|---|
| 410 | 411 | } |
|---|
| 411 | 412 | |
|---|
| 412 | 413 | /* Scan a given block partially */ |
|---|
| 413 | | -static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, |
|---|
| 414 | | - loff_t offs, uint8_t *buf, int numpages) |
|---|
| 414 | +static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, |
|---|
| 415 | + loff_t offs, uint8_t *buf) |
|---|
| 415 | 416 | { |
|---|
| 417 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 418 | + |
|---|
| 416 | 419 | struct mtd_oob_ops ops; |
|---|
| 417 | | - int j, ret; |
|---|
| 420 | + int ret, page_offset; |
|---|
| 418 | 421 | |
|---|
| 419 | 422 | ops.ooblen = mtd->oobsize; |
|---|
| 420 | 423 | ops.oobbuf = buf; |
|---|
| .. | .. |
|---|
| 422 | 425 | ops.datbuf = NULL; |
|---|
| 423 | 426 | ops.mode = MTD_OPS_PLACE_OOB; |
|---|
| 424 | 427 | |
|---|
| 425 | | - for (j = 0; j < numpages; j++) { |
|---|
| 428 | + page_offset = nand_bbm_get_next_page(this, 0); |
|---|
| 429 | + |
|---|
| 430 | + while (page_offset >= 0) { |
|---|
| 426 | 431 | /* |
|---|
| 427 | 432 | * Read the full oob until read_oob is fixed to handle single |
|---|
| 428 | 433 | * byte reads for 16 bit buswidth. |
|---|
| 429 | 434 | */ |
|---|
| 430 | | - ret = mtd_read_oob(mtd, offs, &ops); |
|---|
| 435 | + ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize), |
|---|
| 436 | + &ops); |
|---|
| 431 | 437 | /* Ignore ECC errors when checking for BBM */ |
|---|
| 432 | 438 | if (ret && !mtd_is_bitflip_or_eccerr(ret)) |
|---|
| 433 | 439 | return ret; |
|---|
| .. | .. |
|---|
| 435 | 441 | if (check_short_pattern(buf, bd)) |
|---|
| 436 | 442 | return 1; |
|---|
| 437 | 443 | |
|---|
| 438 | | - offs += mtd->writesize; |
|---|
| 444 | + page_offset = nand_bbm_get_next_page(this, page_offset + 1); |
|---|
| 439 | 445 | } |
|---|
| 446 | + |
|---|
| 440 | 447 | return 0; |
|---|
| 441 | 448 | } |
|---|
| 442 | 449 | |
|---|
| 443 | 450 | /** |
|---|
| 444 | 451 | * create_bbt - [GENERIC] Create a bad block table by scanning the device |
|---|
| 445 | | - * @mtd: MTD device structure |
|---|
| 452 | + * @this: NAND chip object |
|---|
| 446 | 453 | * @buf: temporary buffer |
|---|
| 447 | 454 | * @bd: descriptor for the good/bad block search pattern |
|---|
| 448 | 455 | * @chip: create the table for a specific chip, -1 read all chips; applies only |
|---|
| .. | .. |
|---|
| 451 | 458 | * Create a bad block table by scanning the device for the given good/bad block |
|---|
| 452 | 459 | * identify pattern. |
|---|
| 453 | 460 | */ |
|---|
| 454 | | -static int create_bbt(struct mtd_info *mtd, uint8_t *buf, |
|---|
| 455 | | - struct nand_bbt_descr *bd, int chip) |
|---|
| 461 | +static int create_bbt(struct nand_chip *this, uint8_t *buf, |
|---|
| 462 | + struct nand_bbt_descr *bd, int chip) |
|---|
| 456 | 463 | { |
|---|
| 457 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 458 | | - int i, numblocks, numpages; |
|---|
| 459 | | - int startblock; |
|---|
| 464 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 465 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 466 | + int i, numblocks, startblock; |
|---|
| 460 | 467 | loff_t from; |
|---|
| 461 | 468 | |
|---|
| 462 | 469 | pr_info("Scanning device for bad blocks\n"); |
|---|
| 463 | | - |
|---|
| 464 | | - if (bd->options & NAND_BBT_SCAN2NDPAGE) |
|---|
| 465 | | - numpages = 2; |
|---|
| 466 | | - else |
|---|
| 467 | | - numpages = 1; |
|---|
| 468 | 470 | |
|---|
| 469 | 471 | if (chip == -1) { |
|---|
| 470 | 472 | numblocks = mtd->size >> this->bbt_erase_shift; |
|---|
| 471 | 473 | startblock = 0; |
|---|
| 472 | 474 | from = 0; |
|---|
| 473 | 475 | } else { |
|---|
| 474 | | - if (chip >= this->numchips) { |
|---|
| 476 | + if (chip >= nanddev_ntargets(&this->base)) { |
|---|
| 475 | 477 | pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", |
|---|
| 476 | | - chip + 1, this->numchips); |
|---|
| 478 | + chip + 1, nanddev_ntargets(&this->base)); |
|---|
| 477 | 479 | return -EINVAL; |
|---|
| 478 | 480 | } |
|---|
| 479 | | - numblocks = this->chipsize >> this->bbt_erase_shift; |
|---|
| 481 | + numblocks = targetsize >> this->bbt_erase_shift; |
|---|
| 480 | 482 | startblock = chip * numblocks; |
|---|
| 481 | 483 | numblocks += startblock; |
|---|
| 482 | 484 | from = (loff_t)startblock << this->bbt_erase_shift; |
|---|
| 483 | 485 | } |
|---|
| 484 | | - |
|---|
| 485 | | - if (this->bbt_options & NAND_BBT_SCANLASTPAGE) |
|---|
| 486 | | - from += mtd->erasesize - (mtd->writesize * numpages); |
|---|
| 487 | 486 | |
|---|
| 488 | 487 | for (i = startblock; i < numblocks; i++) { |
|---|
| 489 | 488 | int ret; |
|---|
| 490 | 489 | |
|---|
| 491 | 490 | BUG_ON(bd->options & NAND_BBT_NO_OOB); |
|---|
| 492 | 491 | |
|---|
| 493 | | - ret = scan_block_fast(mtd, bd, from, buf, numpages); |
|---|
| 492 | + ret = scan_block_fast(this, bd, from, buf); |
|---|
| 494 | 493 | if (ret < 0) |
|---|
| 495 | 494 | return ret; |
|---|
| 496 | 495 | |
|---|
| .. | .. |
|---|
| 508 | 507 | |
|---|
| 509 | 508 | /** |
|---|
| 510 | 509 | * search_bbt - [GENERIC] scan the device for a specific bad block table |
|---|
| 511 | | - * @mtd: MTD device structure |
|---|
| 510 | + * @this: NAND chip object |
|---|
| 512 | 511 | * @buf: temporary buffer |
|---|
| 513 | 512 | * @td: descriptor for the bad block table |
|---|
| 514 | 513 | * |
|---|
| .. | .. |
|---|
| 521 | 520 | * |
|---|
| 522 | 521 | * The bbt ident pattern resides in the oob area of the first page in a block. |
|---|
| 523 | 522 | */ |
|---|
| 524 | | -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) |
|---|
| 523 | +static int search_bbt(struct nand_chip *this, uint8_t *buf, |
|---|
| 524 | + struct nand_bbt_descr *td) |
|---|
| 525 | 525 | { |
|---|
| 526 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 526 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 527 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 527 | 528 | int i, chips; |
|---|
| 528 | 529 | int startblock, block, dir; |
|---|
| 529 | 530 | int scanlen = mtd->writesize + mtd->oobsize; |
|---|
| .. | .. |
|---|
| 541 | 542 | |
|---|
| 542 | 543 | /* Do we have a bbt per chip? */ |
|---|
| 543 | 544 | if (td->options & NAND_BBT_PERCHIP) { |
|---|
| 544 | | - chips = this->numchips; |
|---|
| 545 | | - bbtblocks = this->chipsize >> this->bbt_erase_shift; |
|---|
| 545 | + chips = nanddev_ntargets(&this->base); |
|---|
| 546 | + bbtblocks = targetsize >> this->bbt_erase_shift; |
|---|
| 546 | 547 | startblock &= bbtblocks - 1; |
|---|
| 547 | 548 | } else { |
|---|
| 548 | 549 | chips = 1; |
|---|
| .. | .. |
|---|
| 560 | 561 | loff_t offs = (loff_t)actblock << this->bbt_erase_shift; |
|---|
| 561 | 562 | |
|---|
| 562 | 563 | /* Read first page */ |
|---|
| 563 | | - scan_read(mtd, buf, offs, mtd->writesize, td); |
|---|
| 564 | + scan_read(this, buf, offs, mtd->writesize, td); |
|---|
| 564 | 565 | if (!check_pattern(buf, scanlen, mtd->writesize, td)) { |
|---|
| 565 | 566 | td->pages[i] = actblock << blocktopage; |
|---|
| 566 | 567 | if (td->options & NAND_BBT_VERSION) { |
|---|
| 567 | | - offs = bbt_get_ver_offs(mtd, td); |
|---|
| 568 | + offs = bbt_get_ver_offs(this, td); |
|---|
| 568 | 569 | td->version[i] = buf[offs]; |
|---|
| 569 | 570 | } |
|---|
| 570 | 571 | break; |
|---|
| 571 | 572 | } |
|---|
| 572 | 573 | } |
|---|
| 573 | | - startblock += this->chipsize >> this->bbt_erase_shift; |
|---|
| 574 | + startblock += targetsize >> this->bbt_erase_shift; |
|---|
| 574 | 575 | } |
|---|
| 575 | 576 | /* Check, if we found a bbt for each requested chip */ |
|---|
| 576 | 577 | for (i = 0; i < chips; i++) { |
|---|
| .. | .. |
|---|
| 585 | 586 | |
|---|
| 586 | 587 | /** |
|---|
| 587 | 588 | * search_read_bbts - [GENERIC] scan the device for bad block table(s) |
|---|
| 588 | | - * @mtd: MTD device structure |
|---|
| 589 | + * @this: NAND chip object |
|---|
| 589 | 590 | * @buf: temporary buffer |
|---|
| 590 | 591 | * @td: descriptor for the bad block table |
|---|
| 591 | 592 | * @md: descriptor for the bad block table mirror |
|---|
| 592 | 593 | * |
|---|
| 593 | 594 | * Search and read the bad block table(s). |
|---|
| 594 | 595 | */ |
|---|
| 595 | | -static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, |
|---|
| 596 | +static void search_read_bbts(struct nand_chip *this, uint8_t *buf, |
|---|
| 596 | 597 | struct nand_bbt_descr *td, |
|---|
| 597 | 598 | struct nand_bbt_descr *md) |
|---|
| 598 | 599 | { |
|---|
| 599 | 600 | /* Search the primary table */ |
|---|
| 600 | | - search_bbt(mtd, buf, td); |
|---|
| 601 | + search_bbt(this, buf, td); |
|---|
| 601 | 602 | |
|---|
| 602 | 603 | /* Search the mirror table */ |
|---|
| 603 | 604 | if (md) |
|---|
| 604 | | - search_bbt(mtd, buf, md); |
|---|
| 605 | + search_bbt(this, buf, md); |
|---|
| 605 | 606 | } |
|---|
| 606 | 607 | |
|---|
| 607 | 608 | /** |
|---|
| .. | .. |
|---|
| 620 | 621 | static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, |
|---|
| 621 | 622 | struct nand_bbt_descr *md, int chip) |
|---|
| 622 | 623 | { |
|---|
| 624 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 623 | 625 | int startblock, dir, page, numblocks, i; |
|---|
| 624 | 626 | |
|---|
| 625 | 627 | /* |
|---|
| .. | .. |
|---|
| 631 | 633 | return td->pages[chip] >> |
|---|
| 632 | 634 | (this->bbt_erase_shift - this->page_shift); |
|---|
| 633 | 635 | |
|---|
| 634 | | - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); |
|---|
| 636 | + numblocks = (int)(targetsize >> this->bbt_erase_shift); |
|---|
| 635 | 637 | if (!(td->options & NAND_BBT_PERCHIP)) |
|---|
| 636 | | - numblocks *= this->numchips; |
|---|
| 638 | + numblocks *= nanddev_ntargets(&this->base); |
|---|
| 637 | 639 | |
|---|
| 638 | 640 | /* |
|---|
| 639 | 641 | * Automatic placement of the bad block table. Search direction |
|---|
| .. | .. |
|---|
| 683 | 685 | struct nand_bbt_descr *td, |
|---|
| 684 | 686 | int chip, int block) |
|---|
| 685 | 687 | { |
|---|
| 686 | | - struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 687 | 688 | loff_t to; |
|---|
| 688 | 689 | int res; |
|---|
| 689 | 690 | |
|---|
| 690 | 691 | bbt_mark_entry(this, block, BBT_BLOCK_WORN); |
|---|
| 691 | 692 | |
|---|
| 692 | 693 | to = (loff_t)block << this->bbt_erase_shift; |
|---|
| 693 | | - res = this->block_markbad(mtd, to); |
|---|
| 694 | + res = nand_markbad_bbm(this, to); |
|---|
| 694 | 695 | if (res) |
|---|
| 695 | 696 | pr_warn("nand_bbt: error %d while marking block %d bad\n", |
|---|
| 696 | 697 | res, block); |
|---|
| .. | .. |
|---|
| 700 | 701 | |
|---|
| 701 | 702 | /** |
|---|
| 702 | 703 | * write_bbt - [GENERIC] (Re)write the bad block table |
|---|
| 703 | | - * @mtd: MTD device structure |
|---|
| 704 | + * @this: NAND chip object |
|---|
| 704 | 705 | * @buf: temporary buffer |
|---|
| 705 | 706 | * @td: descriptor for the bad block table |
|---|
| 706 | 707 | * @md: descriptor for the bad block table mirror |
|---|
| .. | .. |
|---|
| 708 | 709 | * |
|---|
| 709 | 710 | * (Re)write the bad block table. |
|---|
| 710 | 711 | */ |
|---|
| 711 | | -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, |
|---|
| 712 | +static int write_bbt(struct nand_chip *this, uint8_t *buf, |
|---|
| 712 | 713 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, |
|---|
| 713 | 714 | int chipsel) |
|---|
| 714 | 715 | { |
|---|
| 715 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 716 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 717 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 716 | 718 | struct erase_info einfo; |
|---|
| 717 | 719 | int i, res, chip = 0; |
|---|
| 718 | 720 | int bits, page, offs, numblocks, sft, sftmsk; |
|---|
| .. | .. |
|---|
| 732 | 734 | rcode = 0xff; |
|---|
| 733 | 735 | /* Write bad block table per chip rather than per device? */ |
|---|
| 734 | 736 | if (td->options & NAND_BBT_PERCHIP) { |
|---|
| 735 | | - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); |
|---|
| 737 | + numblocks = (int)(targetsize >> this->bbt_erase_shift); |
|---|
| 736 | 738 | /* Full device write or specific chip? */ |
|---|
| 737 | 739 | if (chipsel == -1) { |
|---|
| 738 | | - nrchips = this->numchips; |
|---|
| 740 | + nrchips = nanddev_ntargets(&this->base); |
|---|
| 739 | 741 | } else { |
|---|
| 740 | 742 | nrchips = chipsel + 1; |
|---|
| 741 | 743 | chip = chipsel; |
|---|
| .. | .. |
|---|
| 854 | 856 | memset(&einfo, 0, sizeof(einfo)); |
|---|
| 855 | 857 | einfo.addr = to; |
|---|
| 856 | 858 | einfo.len = 1 << this->bbt_erase_shift; |
|---|
| 857 | | - res = nand_erase_nand(mtd, &einfo, 1); |
|---|
| 859 | + res = nand_erase_nand(this, &einfo, 1); |
|---|
| 858 | 860 | if (res < 0) { |
|---|
| 859 | 861 | pr_warn("nand_bbt: error while erasing BBT block %d\n", |
|---|
| 860 | 862 | res); |
|---|
| .. | .. |
|---|
| 862 | 864 | continue; |
|---|
| 863 | 865 | } |
|---|
| 864 | 866 | |
|---|
| 865 | | - res = scan_write_bbt(mtd, to, len, buf, |
|---|
| 866 | | - td->options & NAND_BBT_NO_OOB ? NULL : |
|---|
| 867 | | - &buf[len]); |
|---|
| 867 | + res = scan_write_bbt(this, to, len, buf, |
|---|
| 868 | + td->options & NAND_BBT_NO_OOB ? |
|---|
| 869 | + NULL : &buf[len]); |
|---|
| 868 | 870 | if (res < 0) { |
|---|
| 869 | 871 | pr_warn("nand_bbt: error while writing BBT block %d\n", |
|---|
| 870 | 872 | res); |
|---|
| .. | .. |
|---|
| 887 | 889 | |
|---|
| 888 | 890 | /** |
|---|
| 889 | 891 | * nand_memory_bbt - [GENERIC] create a memory based bad block table |
|---|
| 890 | | - * @mtd: MTD device structure |
|---|
| 892 | + * @this: NAND chip object |
|---|
| 891 | 893 | * @bd: descriptor for the good/bad block search pattern |
|---|
| 892 | 894 | * |
|---|
| 893 | 895 | * The function creates a memory based bbt by scanning the device for |
|---|
| 894 | 896 | * manufacturer / software marked good / bad blocks. |
|---|
| 895 | 897 | */ |
|---|
| 896 | | -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) |
|---|
| 898 | +static inline int nand_memory_bbt(struct nand_chip *this, |
|---|
| 899 | + struct nand_bbt_descr *bd) |
|---|
| 897 | 900 | { |
|---|
| 898 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 901 | + u8 *pagebuf = nand_get_data_buf(this); |
|---|
| 899 | 902 | |
|---|
| 900 | | - return create_bbt(mtd, this->data_buf, bd, -1); |
|---|
| 903 | + return create_bbt(this, pagebuf, bd, -1); |
|---|
| 901 | 904 | } |
|---|
| 902 | 905 | |
|---|
| 903 | 906 | /** |
|---|
| 904 | 907 | * check_create - [GENERIC] create and write bbt(s) if necessary |
|---|
| 905 | | - * @mtd: MTD device structure |
|---|
| 908 | + * @this: the NAND device |
|---|
| 906 | 909 | * @buf: temporary buffer |
|---|
| 907 | 910 | * @bd: descriptor for the good/bad block search pattern |
|---|
| 908 | 911 | * |
|---|
| .. | .. |
|---|
| 911 | 914 | * for the chip/device. Update is necessary if one of the tables is missing or |
|---|
| 912 | 915 | * the version nr. of one table is less than the other. |
|---|
| 913 | 916 | */ |
|---|
| 914 | | -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) |
|---|
| 917 | +static int check_create(struct nand_chip *this, uint8_t *buf, |
|---|
| 918 | + struct nand_bbt_descr *bd) |
|---|
| 915 | 919 | { |
|---|
| 916 | 920 | int i, chips, writeops, create, chipsel, res, res2; |
|---|
| 917 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 918 | 921 | struct nand_bbt_descr *td = this->bbt_td; |
|---|
| 919 | 922 | struct nand_bbt_descr *md = this->bbt_md; |
|---|
| 920 | 923 | struct nand_bbt_descr *rd, *rd2; |
|---|
| 921 | 924 | |
|---|
| 922 | 925 | /* Do we have a bbt per chip? */ |
|---|
| 923 | 926 | if (td->options & NAND_BBT_PERCHIP) |
|---|
| 924 | | - chips = this->numchips; |
|---|
| 927 | + chips = nanddev_ntargets(&this->base); |
|---|
| 925 | 928 | else |
|---|
| 926 | 929 | chips = 1; |
|---|
| 927 | 930 | |
|---|
| .. | .. |
|---|
| 971 | 974 | |
|---|
| 972 | 975 | /* Create the table in memory by scanning the chip(s) */ |
|---|
| 973 | 976 | if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) |
|---|
| 974 | | - create_bbt(mtd, buf, bd, chipsel); |
|---|
| 977 | + create_bbt(this, buf, bd, chipsel); |
|---|
| 975 | 978 | |
|---|
| 976 | 979 | td->version[i] = 1; |
|---|
| 977 | 980 | if (md) |
|---|
| .. | .. |
|---|
| 980 | 983 | |
|---|
| 981 | 984 | /* Read back first? */ |
|---|
| 982 | 985 | if (rd) { |
|---|
| 983 | | - res = read_abs_bbt(mtd, buf, rd, chipsel); |
|---|
| 986 | + res = read_abs_bbt(this, buf, rd, chipsel); |
|---|
| 984 | 987 | if (mtd_is_eccerr(res)) { |
|---|
| 985 | 988 | /* Mark table as invalid */ |
|---|
| 986 | 989 | rd->pages[i] = -1; |
|---|
| .. | .. |
|---|
| 991 | 994 | } |
|---|
| 992 | 995 | /* If they weren't versioned, read both */ |
|---|
| 993 | 996 | if (rd2) { |
|---|
| 994 | | - res2 = read_abs_bbt(mtd, buf, rd2, chipsel); |
|---|
| 997 | + res2 = read_abs_bbt(this, buf, rd2, chipsel); |
|---|
| 995 | 998 | if (mtd_is_eccerr(res2)) { |
|---|
| 996 | 999 | /* Mark table as invalid */ |
|---|
| 997 | 1000 | rd2->pages[i] = -1; |
|---|
| .. | .. |
|---|
| 1013 | 1016 | |
|---|
| 1014 | 1017 | /* Write the bad block table to the device? */ |
|---|
| 1015 | 1018 | if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { |
|---|
| 1016 | | - res = write_bbt(mtd, buf, td, md, chipsel); |
|---|
| 1019 | + res = write_bbt(this, buf, td, md, chipsel); |
|---|
| 1017 | 1020 | if (res < 0) |
|---|
| 1018 | 1021 | return res; |
|---|
| 1019 | 1022 | } |
|---|
| 1020 | 1023 | |
|---|
| 1021 | 1024 | /* Write the mirror bad block table to the device? */ |
|---|
| 1022 | 1025 | if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { |
|---|
| 1023 | | - res = write_bbt(mtd, buf, md, td, chipsel); |
|---|
| 1026 | + res = write_bbt(this, buf, md, td, chipsel); |
|---|
| 1024 | 1027 | if (res < 0) |
|---|
| 1025 | 1028 | return res; |
|---|
| 1026 | 1029 | } |
|---|
| .. | .. |
|---|
| 1029 | 1032 | } |
|---|
| 1030 | 1033 | |
|---|
| 1031 | 1034 | /** |
|---|
| 1032 | | - * mark_bbt_regions - [GENERIC] mark the bad block table regions |
|---|
| 1033 | | - * @mtd: MTD device structure |
|---|
| 1034 | | - * @td: bad block table descriptor |
|---|
| 1035 | | - * |
|---|
| 1036 | | - * The bad block table regions are marked as "bad" to prevent accidental |
|---|
| 1037 | | - * erasures / writes. The regions are identified by the mark 0x02. |
|---|
| 1038 | | - */ |
|---|
| 1039 | | -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) |
|---|
| 1040 | | -{ |
|---|
| 1041 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1042 | | - int i, j, chips, block, nrblocks, update; |
|---|
| 1043 | | - uint8_t oldval; |
|---|
| 1044 | | - |
|---|
| 1045 | | - /* Do we have a bbt per chip? */ |
|---|
| 1046 | | - if (td->options & NAND_BBT_PERCHIP) { |
|---|
| 1047 | | - chips = this->numchips; |
|---|
| 1048 | | - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); |
|---|
| 1049 | | - } else { |
|---|
| 1050 | | - chips = 1; |
|---|
| 1051 | | - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); |
|---|
| 1052 | | - } |
|---|
| 1053 | | - |
|---|
| 1054 | | - for (i = 0; i < chips; i++) { |
|---|
| 1055 | | - if ((td->options & NAND_BBT_ABSPAGE) || |
|---|
| 1056 | | - !(td->options & NAND_BBT_WRITE)) { |
|---|
| 1057 | | - if (td->pages[i] == -1) |
|---|
| 1058 | | - continue; |
|---|
| 1059 | | - block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); |
|---|
| 1060 | | - oldval = bbt_get_entry(this, block); |
|---|
| 1061 | | - bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); |
|---|
| 1062 | | - if ((oldval != BBT_BLOCK_RESERVED) && |
|---|
| 1063 | | - td->reserved_block_code) |
|---|
| 1064 | | - nand_update_bbt(mtd, (loff_t)block << |
|---|
| 1065 | | - this->bbt_erase_shift); |
|---|
| 1066 | | - continue; |
|---|
| 1067 | | - } |
|---|
| 1068 | | - update = 0; |
|---|
| 1069 | | - if (td->options & NAND_BBT_LASTBLOCK) |
|---|
| 1070 | | - block = ((i + 1) * nrblocks) - td->maxblocks; |
|---|
| 1071 | | - else |
|---|
| 1072 | | - block = i * nrblocks; |
|---|
| 1073 | | - for (j = 0; j < td->maxblocks; j++) { |
|---|
| 1074 | | - oldval = bbt_get_entry(this, block); |
|---|
| 1075 | | - bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); |
|---|
| 1076 | | - if (oldval != BBT_BLOCK_RESERVED) |
|---|
| 1077 | | - update = 1; |
|---|
| 1078 | | - block++; |
|---|
| 1079 | | - } |
|---|
| 1080 | | - /* |
|---|
| 1081 | | - * If we want reserved blocks to be recorded to flash, and some |
|---|
| 1082 | | - * new ones have been marked, then we need to update the stored |
|---|
| 1083 | | - * bbts. This should only happen once. |
|---|
| 1084 | | - */ |
|---|
| 1085 | | - if (update && td->reserved_block_code) |
|---|
| 1086 | | - nand_update_bbt(mtd, (loff_t)(block - 1) << |
|---|
| 1087 | | - this->bbt_erase_shift); |
|---|
| 1088 | | - } |
|---|
| 1089 | | -} |
|---|
| 1090 | | - |
|---|
| 1091 | | -/** |
|---|
| 1092 | | - * verify_bbt_descr - verify the bad block description |
|---|
| 1093 | | - * @mtd: MTD device structure |
|---|
| 1094 | | - * @bd: the table to verify |
|---|
| 1095 | | - * |
|---|
| 1096 | | - * This functions performs a few sanity checks on the bad block description |
|---|
| 1097 | | - * table. |
|---|
| 1098 | | - */ |
|---|
| 1099 | | -static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) |
|---|
| 1100 | | -{ |
|---|
| 1101 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1102 | | - u32 pattern_len; |
|---|
| 1103 | | - u32 bits; |
|---|
| 1104 | | - u32 table_size; |
|---|
| 1105 | | - |
|---|
| 1106 | | - if (!bd) |
|---|
| 1107 | | - return; |
|---|
| 1108 | | - |
|---|
| 1109 | | - pattern_len = bd->len; |
|---|
| 1110 | | - bits = bd->options & NAND_BBT_NRBITS_MSK; |
|---|
| 1111 | | - |
|---|
| 1112 | | - BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && |
|---|
| 1113 | | - !(this->bbt_options & NAND_BBT_USE_FLASH)); |
|---|
| 1114 | | - BUG_ON(!bits); |
|---|
| 1115 | | - |
|---|
| 1116 | | - if (bd->options & NAND_BBT_VERSION) |
|---|
| 1117 | | - pattern_len++; |
|---|
| 1118 | | - |
|---|
| 1119 | | - if (bd->options & NAND_BBT_NO_OOB) { |
|---|
| 1120 | | - BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); |
|---|
| 1121 | | - BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); |
|---|
| 1122 | | - BUG_ON(bd->offs); |
|---|
| 1123 | | - if (bd->options & NAND_BBT_VERSION) |
|---|
| 1124 | | - BUG_ON(bd->veroffs != bd->len); |
|---|
| 1125 | | - BUG_ON(bd->options & NAND_BBT_SAVECONTENT); |
|---|
| 1126 | | - } |
|---|
| 1127 | | - |
|---|
| 1128 | | - if (bd->options & NAND_BBT_PERCHIP) |
|---|
| 1129 | | - table_size = this->chipsize >> this->bbt_erase_shift; |
|---|
| 1130 | | - else |
|---|
| 1131 | | - table_size = mtd->size >> this->bbt_erase_shift; |
|---|
| 1132 | | - table_size >>= 3; |
|---|
| 1133 | | - table_size *= bits; |
|---|
| 1134 | | - if (bd->options & NAND_BBT_NO_OOB) |
|---|
| 1135 | | - table_size += pattern_len; |
|---|
| 1136 | | - BUG_ON(table_size > (1 << this->bbt_erase_shift)); |
|---|
| 1137 | | -} |
|---|
| 1138 | | - |
|---|
| 1139 | | -/** |
|---|
| 1140 | | - * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) |
|---|
| 1141 | | - * @mtd: MTD device structure |
|---|
| 1142 | | - * @bd: descriptor for the good/bad block search pattern |
|---|
| 1143 | | - * |
|---|
| 1144 | | - * The function checks, if a bad block table(s) is/are already available. If |
|---|
| 1145 | | - * not it scans the device for manufacturer marked good / bad blocks and writes |
|---|
| 1146 | | - * the bad block table(s) to the selected place. |
|---|
| 1147 | | - * |
|---|
| 1148 | | - * The bad block table memory is allocated here. It must be freed by calling |
|---|
| 1149 | | - * the nand_free_bbt function. |
|---|
| 1150 | | - */ |
|---|
| 1151 | | -static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) |
|---|
| 1152 | | -{ |
|---|
| 1153 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1154 | | - int len, res; |
|---|
| 1155 | | - uint8_t *buf; |
|---|
| 1156 | | - struct nand_bbt_descr *td = this->bbt_td; |
|---|
| 1157 | | - struct nand_bbt_descr *md = this->bbt_md; |
|---|
| 1158 | | - |
|---|
| 1159 | | - len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; |
|---|
| 1160 | | - /* |
|---|
| 1161 | | - * Allocate memory (2bit per block) and clear the memory bad block |
|---|
| 1162 | | - * table. |
|---|
| 1163 | | - */ |
|---|
| 1164 | | - this->bbt = kzalloc(len, GFP_KERNEL); |
|---|
| 1165 | | - if (!this->bbt) |
|---|
| 1166 | | - return -ENOMEM; |
|---|
| 1167 | | - |
|---|
| 1168 | | - /* |
|---|
| 1169 | | - * If no primary table decriptor is given, scan the device to build a |
|---|
| 1170 | | - * memory based bad block table. |
|---|
| 1171 | | - */ |
|---|
| 1172 | | - if (!td) { |
|---|
| 1173 | | - if ((res = nand_memory_bbt(mtd, bd))) { |
|---|
| 1174 | | - pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); |
|---|
| 1175 | | - goto err; |
|---|
| 1176 | | - } |
|---|
| 1177 | | - return 0; |
|---|
| 1178 | | - } |
|---|
| 1179 | | - verify_bbt_descr(mtd, td); |
|---|
| 1180 | | - verify_bbt_descr(mtd, md); |
|---|
| 1181 | | - |
|---|
| 1182 | | - /* Allocate a temporary buffer for one eraseblock incl. oob */ |
|---|
| 1183 | | - len = (1 << this->bbt_erase_shift); |
|---|
| 1184 | | - len += (len >> this->page_shift) * mtd->oobsize; |
|---|
| 1185 | | - buf = vmalloc(len); |
|---|
| 1186 | | - if (!buf) { |
|---|
| 1187 | | - res = -ENOMEM; |
|---|
| 1188 | | - goto err; |
|---|
| 1189 | | - } |
|---|
| 1190 | | - |
|---|
| 1191 | | - /* Is the bbt at a given page? */ |
|---|
| 1192 | | - if (td->options & NAND_BBT_ABSPAGE) { |
|---|
| 1193 | | - read_abs_bbts(mtd, buf, td, md); |
|---|
| 1194 | | - } else { |
|---|
| 1195 | | - /* Search the bad block table using a pattern in oob */ |
|---|
| 1196 | | - search_read_bbts(mtd, buf, td, md); |
|---|
| 1197 | | - } |
|---|
| 1198 | | - |
|---|
| 1199 | | - res = check_create(mtd, buf, bd); |
|---|
| 1200 | | - if (res) |
|---|
| 1201 | | - goto err; |
|---|
| 1202 | | - |
|---|
| 1203 | | - /* Prevent the bbt regions from erasing / writing */ |
|---|
| 1204 | | - mark_bbt_region(mtd, td); |
|---|
| 1205 | | - if (md) |
|---|
| 1206 | | - mark_bbt_region(mtd, md); |
|---|
| 1207 | | - |
|---|
| 1208 | | - vfree(buf); |
|---|
| 1209 | | - return 0; |
|---|
| 1210 | | - |
|---|
| 1211 | | -err: |
|---|
| 1212 | | - kfree(this->bbt); |
|---|
| 1213 | | - this->bbt = NULL; |
|---|
| 1214 | | - return res; |
|---|
| 1215 | | -} |
|---|
| 1216 | | - |
|---|
| 1217 | | -/** |
|---|
| 1218 | 1035 | * nand_update_bbt - update bad block table(s) |
|---|
| 1219 | | - * @mtd: MTD device structure |
|---|
| 1036 | + * @this: the NAND device |
|---|
| 1220 | 1037 | * @offs: the offset of the newly marked block |
|---|
| 1221 | 1038 | * |
|---|
| 1222 | 1039 | * The function updates the bad block table(s). |
|---|
| 1223 | 1040 | */ |
|---|
| 1224 | | -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs) |
|---|
| 1041 | +static int nand_update_bbt(struct nand_chip *this, loff_t offs) |
|---|
| 1225 | 1042 | { |
|---|
| 1226 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1043 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 1227 | 1044 | int len, res = 0; |
|---|
| 1228 | 1045 | int chip, chipsel; |
|---|
| 1229 | 1046 | uint8_t *buf; |
|---|
| .. | .. |
|---|
| 1255 | 1072 | |
|---|
| 1256 | 1073 | /* Write the bad block table to the device? */ |
|---|
| 1257 | 1074 | if (td->options & NAND_BBT_WRITE) { |
|---|
| 1258 | | - res = write_bbt(mtd, buf, td, md, chipsel); |
|---|
| 1075 | + res = write_bbt(this, buf, td, md, chipsel); |
|---|
| 1259 | 1076 | if (res < 0) |
|---|
| 1260 | 1077 | goto out; |
|---|
| 1261 | 1078 | } |
|---|
| 1262 | 1079 | /* Write the mirror bad block table to the device? */ |
|---|
| 1263 | 1080 | if (md && (md->options & NAND_BBT_WRITE)) { |
|---|
| 1264 | | - res = write_bbt(mtd, buf, md, td, chipsel); |
|---|
| 1081 | + res = write_bbt(this, buf, md, td, chipsel); |
|---|
| 1265 | 1082 | } |
|---|
| 1266 | 1083 | |
|---|
| 1267 | 1084 | out: |
|---|
| 1268 | 1085 | kfree(buf); |
|---|
| 1086 | + return res; |
|---|
| 1087 | +} |
|---|
| 1088 | + |
|---|
| 1089 | +/** |
|---|
| 1090 | + * mark_bbt_regions - [GENERIC] mark the bad block table regions |
|---|
| 1091 | + * @this: the NAND device |
|---|
| 1092 | + * @td: bad block table descriptor |
|---|
| 1093 | + * |
|---|
| 1094 | + * The bad block table regions are marked as "bad" to prevent accidental |
|---|
| 1095 | + * erasures / writes. The regions are identified by the mark 0x02. |
|---|
| 1096 | + */ |
|---|
| 1097 | +static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) |
|---|
| 1098 | +{ |
|---|
| 1099 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 1100 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 1101 | + int i, j, chips, block, nrblocks, update; |
|---|
| 1102 | + uint8_t oldval; |
|---|
| 1103 | + |
|---|
| 1104 | + /* Do we have a bbt per chip? */ |
|---|
| 1105 | + if (td->options & NAND_BBT_PERCHIP) { |
|---|
| 1106 | + chips = nanddev_ntargets(&this->base); |
|---|
| 1107 | + nrblocks = (int)(targetsize >> this->bbt_erase_shift); |
|---|
| 1108 | + } else { |
|---|
| 1109 | + chips = 1; |
|---|
| 1110 | + nrblocks = (int)(mtd->size >> this->bbt_erase_shift); |
|---|
| 1111 | + } |
|---|
| 1112 | + |
|---|
| 1113 | + for (i = 0; i < chips; i++) { |
|---|
| 1114 | + if ((td->options & NAND_BBT_ABSPAGE) || |
|---|
| 1115 | + !(td->options & NAND_BBT_WRITE)) { |
|---|
| 1116 | + if (td->pages[i] == -1) |
|---|
| 1117 | + continue; |
|---|
| 1118 | + block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); |
|---|
| 1119 | + oldval = bbt_get_entry(this, block); |
|---|
| 1120 | + bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); |
|---|
| 1121 | + if ((oldval != BBT_BLOCK_RESERVED) && |
|---|
| 1122 | + td->reserved_block_code) |
|---|
| 1123 | + nand_update_bbt(this, (loff_t)block << |
|---|
| 1124 | + this->bbt_erase_shift); |
|---|
| 1125 | + continue; |
|---|
| 1126 | + } |
|---|
| 1127 | + update = 0; |
|---|
| 1128 | + if (td->options & NAND_BBT_LASTBLOCK) |
|---|
| 1129 | + block = ((i + 1) * nrblocks) - td->maxblocks; |
|---|
| 1130 | + else |
|---|
| 1131 | + block = i * nrblocks; |
|---|
| 1132 | + for (j = 0; j < td->maxblocks; j++) { |
|---|
| 1133 | + oldval = bbt_get_entry(this, block); |
|---|
| 1134 | + bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); |
|---|
| 1135 | + if (oldval != BBT_BLOCK_RESERVED) |
|---|
| 1136 | + update = 1; |
|---|
| 1137 | + block++; |
|---|
| 1138 | + } |
|---|
| 1139 | + /* |
|---|
| 1140 | + * If we want reserved blocks to be recorded to flash, and some |
|---|
| 1141 | + * new ones have been marked, then we need to update the stored |
|---|
| 1142 | + * bbts. This should only happen once. |
|---|
| 1143 | + */ |
|---|
| 1144 | + if (update && td->reserved_block_code) |
|---|
| 1145 | + nand_update_bbt(this, (loff_t)(block - 1) << |
|---|
| 1146 | + this->bbt_erase_shift); |
|---|
| 1147 | + } |
|---|
| 1148 | +} |
|---|
| 1149 | + |
|---|
| 1150 | +/** |
|---|
| 1151 | + * verify_bbt_descr - verify the bad block description |
|---|
| 1152 | + * @this: the NAND device |
|---|
| 1153 | + * @bd: the table to verify |
|---|
| 1154 | + * |
|---|
| 1155 | + * This functions performs a few sanity checks on the bad block description |
|---|
| 1156 | + * table. |
|---|
| 1157 | + */ |
|---|
| 1158 | +static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd) |
|---|
| 1159 | +{ |
|---|
| 1160 | + u64 targetsize = nanddev_target_size(&this->base); |
|---|
| 1161 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 1162 | + u32 pattern_len; |
|---|
| 1163 | + u32 bits; |
|---|
| 1164 | + u32 table_size; |
|---|
| 1165 | + |
|---|
| 1166 | + if (!bd) |
|---|
| 1167 | + return; |
|---|
| 1168 | + |
|---|
| 1169 | + pattern_len = bd->len; |
|---|
| 1170 | + bits = bd->options & NAND_BBT_NRBITS_MSK; |
|---|
| 1171 | + |
|---|
| 1172 | + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && |
|---|
| 1173 | + !(this->bbt_options & NAND_BBT_USE_FLASH)); |
|---|
| 1174 | + BUG_ON(!bits); |
|---|
| 1175 | + |
|---|
| 1176 | + if (bd->options & NAND_BBT_VERSION) |
|---|
| 1177 | + pattern_len++; |
|---|
| 1178 | + |
|---|
| 1179 | + if (bd->options & NAND_BBT_NO_OOB) { |
|---|
| 1180 | + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); |
|---|
| 1181 | + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); |
|---|
| 1182 | + BUG_ON(bd->offs); |
|---|
| 1183 | + if (bd->options & NAND_BBT_VERSION) |
|---|
| 1184 | + BUG_ON(bd->veroffs != bd->len); |
|---|
| 1185 | + BUG_ON(bd->options & NAND_BBT_SAVECONTENT); |
|---|
| 1186 | + } |
|---|
| 1187 | + |
|---|
| 1188 | + if (bd->options & NAND_BBT_PERCHIP) |
|---|
| 1189 | + table_size = targetsize >> this->bbt_erase_shift; |
|---|
| 1190 | + else |
|---|
| 1191 | + table_size = mtd->size >> this->bbt_erase_shift; |
|---|
| 1192 | + table_size >>= 3; |
|---|
| 1193 | + table_size *= bits; |
|---|
| 1194 | + if (bd->options & NAND_BBT_NO_OOB) |
|---|
| 1195 | + table_size += pattern_len; |
|---|
| 1196 | + BUG_ON(table_size > (1 << this->bbt_erase_shift)); |
|---|
| 1197 | +} |
|---|
| 1198 | + |
|---|
| 1199 | +/** |
|---|
| 1200 | + * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) |
|---|
| 1201 | + * @this: the NAND device |
|---|
| 1202 | + * @bd: descriptor for the good/bad block search pattern |
|---|
| 1203 | + * |
|---|
| 1204 | + * The function checks, if a bad block table(s) is/are already available. If |
|---|
| 1205 | + * not it scans the device for manufacturer marked good / bad blocks and writes |
|---|
| 1206 | + * the bad block table(s) to the selected place. |
|---|
| 1207 | + * |
|---|
| 1208 | + * The bad block table memory is allocated here. It must be freed by calling |
|---|
| 1209 | + * the nand_free_bbt function. |
|---|
| 1210 | + */ |
|---|
| 1211 | +static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) |
|---|
| 1212 | +{ |
|---|
| 1213 | + struct mtd_info *mtd = nand_to_mtd(this); |
|---|
| 1214 | + int len, res; |
|---|
| 1215 | + uint8_t *buf; |
|---|
| 1216 | + struct nand_bbt_descr *td = this->bbt_td; |
|---|
| 1217 | + struct nand_bbt_descr *md = this->bbt_md; |
|---|
| 1218 | + |
|---|
| 1219 | + len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; |
|---|
| 1220 | + /* |
|---|
| 1221 | + * Allocate memory (2bit per block) and clear the memory bad block |
|---|
| 1222 | + * table. |
|---|
| 1223 | + */ |
|---|
| 1224 | + this->bbt = kzalloc(len, GFP_KERNEL); |
|---|
| 1225 | + if (!this->bbt) |
|---|
| 1226 | + return -ENOMEM; |
|---|
| 1227 | + |
|---|
| 1228 | + /* |
|---|
| 1229 | + * If no primary table descriptor is given, scan the device to build a |
|---|
| 1230 | + * memory based bad block table. |
|---|
| 1231 | + */ |
|---|
| 1232 | + if (!td) { |
|---|
| 1233 | + if ((res = nand_memory_bbt(this, bd))) { |
|---|
| 1234 | + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); |
|---|
| 1235 | + goto err_free_bbt; |
|---|
| 1236 | + } |
|---|
| 1237 | + return 0; |
|---|
| 1238 | + } |
|---|
| 1239 | + verify_bbt_descr(this, td); |
|---|
| 1240 | + verify_bbt_descr(this, md); |
|---|
| 1241 | + |
|---|
| 1242 | + /* Allocate a temporary buffer for one eraseblock incl. oob */ |
|---|
| 1243 | + len = (1 << this->bbt_erase_shift); |
|---|
| 1244 | + len += (len >> this->page_shift) * mtd->oobsize; |
|---|
| 1245 | + buf = vmalloc(len); |
|---|
| 1246 | + if (!buf) { |
|---|
| 1247 | + res = -ENOMEM; |
|---|
| 1248 | + goto err_free_bbt; |
|---|
| 1249 | + } |
|---|
| 1250 | + |
|---|
| 1251 | + /* Is the bbt at a given page? */ |
|---|
| 1252 | + if (td->options & NAND_BBT_ABSPAGE) { |
|---|
| 1253 | + read_abs_bbts(this, buf, td, md); |
|---|
| 1254 | + } else { |
|---|
| 1255 | + /* Search the bad block table using a pattern in oob */ |
|---|
| 1256 | + search_read_bbts(this, buf, td, md); |
|---|
| 1257 | + } |
|---|
| 1258 | + |
|---|
| 1259 | + res = check_create(this, buf, bd); |
|---|
| 1260 | + if (res) |
|---|
| 1261 | + goto err_free_buf; |
|---|
| 1262 | + |
|---|
| 1263 | + /* Prevent the bbt regions from erasing / writing */ |
|---|
| 1264 | + mark_bbt_region(this, td); |
|---|
| 1265 | + if (md) |
|---|
| 1266 | + mark_bbt_region(this, md); |
|---|
| 1267 | + |
|---|
| 1268 | + vfree(buf); |
|---|
| 1269 | + return 0; |
|---|
| 1270 | + |
|---|
| 1271 | +err_free_buf: |
|---|
| 1272 | + vfree(buf); |
|---|
| 1273 | +err_free_bbt: |
|---|
| 1274 | + kfree(this->bbt); |
|---|
| 1275 | + this->bbt = NULL; |
|---|
| 1269 | 1276 | return res; |
|---|
| 1270 | 1277 | } |
|---|
| 1271 | 1278 | |
|---|
| .. | .. |
|---|
| 1382 | 1389 | return ret; |
|---|
| 1383 | 1390 | } |
|---|
| 1384 | 1391 | |
|---|
| 1385 | | - return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern); |
|---|
| 1392 | + return nand_scan_bbt(this, this->badblock_pattern); |
|---|
| 1386 | 1393 | } |
|---|
| 1387 | 1394 | EXPORT_SYMBOL(nand_create_bbt); |
|---|
| 1388 | 1395 | |
|---|
| 1389 | 1396 | /** |
|---|
| 1390 | 1397 | * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved |
|---|
| 1391 | | - * @mtd: MTD device structure |
|---|
| 1398 | + * @this: NAND chip object |
|---|
| 1392 | 1399 | * @offs: offset in the device |
|---|
| 1393 | 1400 | */ |
|---|
| 1394 | | -int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) |
|---|
| 1401 | +int nand_isreserved_bbt(struct nand_chip *this, loff_t offs) |
|---|
| 1395 | 1402 | { |
|---|
| 1396 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1397 | 1403 | int block; |
|---|
| 1398 | 1404 | |
|---|
| 1399 | 1405 | block = (int)(offs >> this->bbt_erase_shift); |
|---|
| .. | .. |
|---|
| 1402 | 1408 | |
|---|
| 1403 | 1409 | /** |
|---|
| 1404 | 1410 | * nand_isbad_bbt - [NAND Interface] Check if a block is bad |
|---|
| 1405 | | - * @mtd: MTD device structure |
|---|
| 1411 | + * @this: NAND chip object |
|---|
| 1406 | 1412 | * @offs: offset in the device |
|---|
| 1407 | 1413 | * @allowbbt: allow access to bad block table region |
|---|
| 1408 | 1414 | */ |
|---|
| 1409 | | -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) |
|---|
| 1415 | +int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt) |
|---|
| 1410 | 1416 | { |
|---|
| 1411 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1412 | 1417 | int block, res; |
|---|
| 1413 | 1418 | |
|---|
| 1414 | 1419 | block = (int)(offs >> this->bbt_erase_shift); |
|---|
| .. | .. |
|---|
| 1430 | 1435 | |
|---|
| 1431 | 1436 | /** |
|---|
| 1432 | 1437 | * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT |
|---|
| 1433 | | - * @mtd: MTD device structure |
|---|
| 1438 | + * @this: NAND chip object |
|---|
| 1434 | 1439 | * @offs: offset of the bad block |
|---|
| 1435 | 1440 | */ |
|---|
| 1436 | | -int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) |
|---|
| 1441 | +int nand_markbad_bbt(struct nand_chip *this, loff_t offs) |
|---|
| 1437 | 1442 | { |
|---|
| 1438 | | - struct nand_chip *this = mtd_to_nand(mtd); |
|---|
| 1439 | 1443 | int block, ret = 0; |
|---|
| 1440 | 1444 | |
|---|
| 1441 | 1445 | block = (int)(offs >> this->bbt_erase_shift); |
|---|
| .. | .. |
|---|
| 1445 | 1449 | |
|---|
| 1446 | 1450 | /* Update flash-based bad block table */ |
|---|
| 1447 | 1451 | if (this->bbt_options & NAND_BBT_USE_FLASH) |
|---|
| 1448 | | - ret = nand_update_bbt(mtd, offs); |
|---|
| 1452 | + ret = nand_update_bbt(this, offs); |
|---|
| 1449 | 1453 | |
|---|
| 1450 | 1454 | return ret; |
|---|
| 1451 | 1455 | } |
|---|