From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/mtd/nand/raw/nand_bbt.c | 610 +++++++++++++++++++++++++++---------------------------
1 files changed, 307 insertions(+), 303 deletions(-)
diff --git a/kernel/drivers/mtd/nand/raw/nand_bbt.c b/kernel/drivers/mtd/nand/raw/nand_bbt.c
index 39db352..344a24f 100644
--- a/kernel/drivers/mtd/nand/raw/nand_bbt.c
+++ b/kernel/drivers/mtd/nand/raw/nand_bbt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Overview:
* Bad block table support for the NAND driver
*
* Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*
* Description:
*
@@ -54,19 +51,19 @@
* Following assumptions are made:
* - bbts start at a page boundary, if autolocated on a block boundary
* - the space necessary for a bbt in FLASH does not exceed a block boundary
- *
*/
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/bbm.h>
-#include <linux/mtd/rawnand.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/string.h>
+
+#include "internals.h"
#define BBT_BLOCK_GOOD 0x00
#define BBT_BLOCK_WORN 0x01
@@ -75,8 +72,6 @@
#define BBT_ENTRY_MASK 0x03
#define BBT_ENTRY_SHIFT 2
-
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
{
@@ -159,7 +154,7 @@
/**
* read_bbt - [GENERIC] Read the bad block table starting from page
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @page: the starting page
* @num: the number of bbt descriptors to read
@@ -168,11 +163,11 @@
*
* Read the bad block table starting from page.
*/
-static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
- struct nand_bbt_descr *td, int offs)
+static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num,
+ struct nand_bbt_descr *td, int offs)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
int res, ret = 0, i, j, act = 0;
- struct nand_chip *this = mtd_to_nand(mtd);
size_t retlen, len, totlen;
loff_t from;
int bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -252,7 +247,7 @@
/**
* read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @chip: read the table for a specific chip, -1 read all chips; applies only if
@@ -261,24 +256,26 @@
* Read the bad block table for all chips starting at a given page. We assume
* that the bbt bits are in consecutive order.
*/
-static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+static int read_abs_bbt(struct nand_chip *this, uint8_t *buf,
+ struct nand_bbt_descr *td, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
+ u64 targetsize = nanddev_target_size(&this->base);
int res = 0, i;
if (td->options & NAND_BBT_PERCHIP) {
int offs = 0;
- for (i = 0; i < this->numchips; i++) {
+ for (i = 0; i < nanddev_ntargets(&this->base); i++) {
if (chip == -1 || chip == i)
- res = read_bbt(mtd, buf, td->pages[i],
- this->chipsize >> this->bbt_erase_shift,
+ res = read_bbt(this, buf, td->pages[i],
+ targetsize >> this->bbt_erase_shift,
td, offs);
if (res)
return res;
- offs += this->chipsize >> this->bbt_erase_shift;
+ offs += targetsize >> this->bbt_erase_shift;
}
} else {
- res = read_bbt(mtd, buf, td->pages[0],
+ res = read_bbt(this, buf, td->pages[0],
mtd->size >> this->bbt_erase_shift, td, 0);
if (res)
return res;
@@ -287,9 +284,10 @@
}
/* BBT marker is in the first page, no OOB */
-static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
- struct nand_bbt_descr *td)
+static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs,
+ struct nand_bbt_descr *td)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
size_t retlen;
size_t len;
@@ -302,7 +300,7 @@
/**
* scan_read_oob - [GENERIC] Scan data+OOB region to buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @offs: offset at which to scan
* @len: length of data region to read
@@ -311,9 +309,10 @@
* page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
* ECC condition (error or bitflip). May quit on the first (non-ECC) error.
*/
-static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs,
size_t len)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct mtd_oob_ops ops;
int res, ret = 0;
@@ -341,19 +340,20 @@
return ret;
}
-static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
- size_t len, struct nand_bbt_descr *td)
+static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs,
+ size_t len, struct nand_bbt_descr *td)
{
if (td->options & NAND_BBT_NO_OOB)
- return scan_read_data(mtd, buf, offs, td);
+ return scan_read_data(this, buf, offs, td);
else
- return scan_read_oob(mtd, buf, offs, len);
+ return scan_read_oob(this, buf, offs, len);
}
/* Scan write data with oob to flash */
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len,
uint8_t *buf, uint8_t *oob)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct mtd_oob_ops ops;
ops.mode = MTD_OPS_PLACE_OOB;
@@ -366,8 +366,9 @@
return mtd_write_oob(mtd, offs, &ops);
}
-static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
u32 ver_offs = td->veroffs;
if (!(td->options & NAND_BBT_NO_OOB))
@@ -377,7 +378,7 @@
/**
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @md: descriptor for the bad block table mirror
@@ -385,36 +386,38 @@
* Read the bad block table(s) for all chips starting at a given page. We
* assume that the bbt bits are in consecutive order.
*/
-static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void read_abs_bbts(struct nand_chip *this, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
- mtd->writesize, td);
- td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
+ scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift,
+ mtd->writesize, td);
+ td->version[0] = buf[bbt_get_ver_offs(this, td)];
pr_info("Bad block table at page %d, version 0x%02X\n",
td->pages[0], td->version[0]);
}
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
- mtd->writesize, md);
- md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
+ scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift,
+ mtd->writesize, md);
+ md->version[0] = buf[bbt_get_ver_offs(this, md)];
pr_info("Bad block table at page %d, version 0x%02X\n",
md->pages[0], md->version[0]);
}
}
/* Scan a given block partially */
-static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, int numpages)
+static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
+ loff_t offs, uint8_t *buf)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
+
struct mtd_oob_ops ops;
- int j, ret;
+ int ret, page_offset;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
@@ -422,12 +425,15 @@
ops.datbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
- for (j = 0; j < numpages; j++) {
+ page_offset = nand_bbm_get_next_page(this, 0);
+
+ while (page_offset >= 0) {
/*
* Read the full oob until read_oob is fixed to handle single
* byte reads for 16 bit buswidth.
*/
- ret = mtd_read_oob(mtd, offs, &ops);
+ ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize),
+ &ops);
/* Ignore ECC errors when checking for BBM */
if (ret && !mtd_is_bitflip_or_eccerr(ret))
return ret;
@@ -435,14 +441,15 @@
if (check_short_pattern(buf, bd))
return 1;
- offs += mtd->writesize;
+ page_offset = nand_bbm_get_next_page(this, page_offset + 1);
}
+
return 0;
}
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @bd: descriptor for the good/bad block search pattern
* @chip: create the table for a specific chip, -1 read all chips; applies only
@@ -451,46 +458,38 @@
* Create a bad block table by scanning the device for the given good/bad block
* identify pattern.
*/
-static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
- struct nand_bbt_descr *bd, int chip)
+static int create_bbt(struct nand_chip *this, uint8_t *buf,
+ struct nand_bbt_descr *bd, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- int i, numblocks, numpages;
- int startblock;
+ u64 targetsize = nanddev_target_size(&this->base);
+ struct mtd_info *mtd = nand_to_mtd(this);
+ int i, numblocks, startblock;
loff_t from;
pr_info("Scanning device for bad blocks\n");
-
- if (bd->options & NAND_BBT_SCAN2NDPAGE)
- numpages = 2;
- else
- numpages = 1;
if (chip == -1) {
numblocks = mtd->size >> this->bbt_erase_shift;
startblock = 0;
from = 0;
} else {
- if (chip >= this->numchips) {
+ if (chip >= nanddev_ntargets(&this->base)) {
pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
- chip + 1, this->numchips);
+ chip + 1, nanddev_ntargets(&this->base));
return -EINVAL;
}
- numblocks = this->chipsize >> this->bbt_erase_shift;
+ numblocks = targetsize >> this->bbt_erase_shift;
startblock = chip * numblocks;
numblocks += startblock;
from = (loff_t)startblock << this->bbt_erase_shift;
}
-
- if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
- from += mtd->erasesize - (mtd->writesize * numpages);
for (i = startblock; i < numblocks; i++) {
int ret;
BUG_ON(bd->options & NAND_BBT_NO_OOB);
- ret = scan_block_fast(mtd, bd, from, buf, numpages);
+ ret = scan_block_fast(this, bd, from, buf);
if (ret < 0)
return ret;
@@ -508,7 +507,7 @@
/**
* search_bbt - [GENERIC] scan the device for a specific bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @td: descriptor for the bad block table
*
@@ -521,9 +520,11 @@
*
* The bbt ident pattern resides in the oob area of the first page in a block.
*/
-static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+static int search_bbt(struct nand_chip *this, uint8_t *buf,
+ struct nand_bbt_descr *td)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ u64 targetsize = nanddev_target_size(&this->base);
+ struct mtd_info *mtd = nand_to_mtd(this);
int i, chips;
int startblock, block, dir;
int scanlen = mtd->writesize + mtd->oobsize;
@@ -541,8 +542,8 @@
/* Do we have a bbt per chip? */
if (td->options & NAND_BBT_PERCHIP) {
- chips = this->numchips;
- bbtblocks = this->chipsize >> this->bbt_erase_shift;
+ chips = nanddev_ntargets(&this->base);
+ bbtblocks = targetsize >> this->bbt_erase_shift;
startblock &= bbtblocks - 1;
} else {
chips = 1;
@@ -560,17 +561,17 @@
loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Read first page */
- scan_read(mtd, buf, offs, mtd->writesize, td);
+ scan_read(this, buf, offs, mtd->writesize, td);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
td->pages[i] = actblock << blocktopage;
if (td->options & NAND_BBT_VERSION) {
- offs = bbt_get_ver_offs(mtd, td);
+ offs = bbt_get_ver_offs(this, td);
td->version[i] = buf[offs];
}
break;
}
}
- startblock += this->chipsize >> this->bbt_erase_shift;
+ startblock += targetsize >> this->bbt_erase_shift;
}
/* Check, if we found a bbt for each requested chip */
for (i = 0; i < chips; i++) {
@@ -585,23 +586,23 @@
/**
* search_read_bbts - [GENERIC] scan the device for bad block table(s)
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @md: descriptor for the bad block table mirror
*
* Search and read the bad block table(s).
*/
-static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void search_read_bbts(struct nand_chip *this, uint8_t *buf,
struct nand_bbt_descr *td,
struct nand_bbt_descr *md)
{
/* Search the primary table */
- search_bbt(mtd, buf, td);
+ search_bbt(this, buf, td);
/* Search the mirror table */
if (md)
- search_bbt(mtd, buf, md);
+ search_bbt(this, buf, md);
}
/**
@@ -620,6 +621,7 @@
static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
struct nand_bbt_descr *md, int chip)
{
+ u64 targetsize = nanddev_target_size(&this->base);
int startblock, dir, page, numblocks, i;
/*
@@ -631,9 +633,9 @@
return td->pages[chip] >>
(this->bbt_erase_shift - this->page_shift);
- numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+ numblocks = (int)(targetsize >> this->bbt_erase_shift);
if (!(td->options & NAND_BBT_PERCHIP))
- numblocks *= this->numchips;
+ numblocks *= nanddev_ntargets(&this->base);
/*
* Automatic placement of the bad block table. Search direction
@@ -683,14 +685,13 @@
struct nand_bbt_descr *td,
int chip, int block)
{
- struct mtd_info *mtd = nand_to_mtd(this);
loff_t to;
int res;
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
to = (loff_t)block << this->bbt_erase_shift;
- res = this->block_markbad(mtd, to);
+ res = nand_markbad_bbm(this, to);
if (res)
pr_warn("nand_bbt: error %d while marking block %d bad\n",
res, block);
@@ -700,7 +701,7 @@
/**
* write_bbt - [GENERIC] (Re)write the bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @md: descriptor for the bad block table mirror
@@ -708,11 +709,12 @@
*
* (Re)write the bad block table.
*/
-static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+static int write_bbt(struct nand_chip *this, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
int chipsel)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ u64 targetsize = nanddev_target_size(&this->base);
+ struct mtd_info *mtd = nand_to_mtd(this);
struct erase_info einfo;
int i, res, chip = 0;
int bits, page, offs, numblocks, sft, sftmsk;
@@ -732,10 +734,10 @@
rcode = 0xff;
/* Write bad block table per chip rather than per device? */
if (td->options & NAND_BBT_PERCHIP) {
- numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+ numblocks = (int)(targetsize >> this->bbt_erase_shift);
/* Full device write or specific chip? */
if (chipsel == -1) {
- nrchips = this->numchips;
+ nrchips = nanddev_ntargets(&this->base);
} else {
nrchips = chipsel + 1;
chip = chipsel;
@@ -854,7 +856,7 @@
memset(&einfo, 0, sizeof(einfo));
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
- res = nand_erase_nand(mtd, &einfo, 1);
+ res = nand_erase_nand(this, &einfo, 1);
if (res < 0) {
pr_warn("nand_bbt: error while erasing BBT block %d\n",
res);
@@ -862,9 +864,9 @@
continue;
}
- res = scan_write_bbt(mtd, to, len, buf,
- td->options & NAND_BBT_NO_OOB ? NULL :
- &buf[len]);
+ res = scan_write_bbt(this, to, len, buf,
+ td->options & NAND_BBT_NO_OOB ?
+ NULL : &buf[len]);
if (res < 0) {
pr_warn("nand_bbt: error while writing BBT block %d\n",
res);
@@ -887,22 +889,23 @@
/**
* nand_memory_bbt - [GENERIC] create a memory based bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @bd: descriptor for the good/bad block search pattern
*
* The function creates a memory based bbt by scanning the device for
* manufacturer / software marked good / bad blocks.
*/
-static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt(struct nand_chip *this,
+ struct nand_bbt_descr *bd)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ u8 *pagebuf = nand_get_data_buf(this);
- return create_bbt(mtd, this->data_buf, bd, -1);
+ return create_bbt(this, pagebuf, bd, -1);
}
/**
* check_create - [GENERIC] create and write bbt(s) if necessary
- * @mtd: MTD device structure
+ * @this: the NAND device
* @buf: temporary buffer
* @bd: descriptor for the good/bad block search pattern
*
@@ -911,17 +914,17 @@
* for the chip/device. Update is necessary if one of the tables is missing or
* the version nr. of one table is less than the other.
*/
-static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+static int check_create(struct nand_chip *this, uint8_t *buf,
+ struct nand_bbt_descr *bd)
{
int i, chips, writeops, create, chipsel, res, res2;
- struct nand_chip *this = mtd_to_nand(mtd);
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
struct nand_bbt_descr *rd, *rd2;
/* Do we have a bbt per chip? */
if (td->options & NAND_BBT_PERCHIP)
- chips = this->numchips;
+ chips = nanddev_ntargets(&this->base);
else
chips = 1;
@@ -971,7 +974,7 @@
/* Create the table in memory by scanning the chip(s) */
if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
- create_bbt(mtd, buf, bd, chipsel);
+ create_bbt(this, buf, bd, chipsel);
td->version[i] = 1;
if (md)
@@ -980,7 +983,7 @@
/* Read back first? */
if (rd) {
- res = read_abs_bbt(mtd, buf, rd, chipsel);
+ res = read_abs_bbt(this, buf, rd, chipsel);
if (mtd_is_eccerr(res)) {
/* Mark table as invalid */
rd->pages[i] = -1;
@@ -991,7 +994,7 @@
}
/* If they weren't versioned, read both */
if (rd2) {
- res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+ res2 = read_abs_bbt(this, buf, rd2, chipsel);
if (mtd_is_eccerr(res2)) {
/* Mark table as invalid */
rd2->pages[i] = -1;
@@ -1013,14 +1016,14 @@
/* Write the bad block table to the device? */
if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
- res = write_bbt(mtd, buf, td, md, chipsel);
+ res = write_bbt(this, buf, td, md, chipsel);
if (res < 0)
return res;
}
/* Write the mirror bad block table to the device? */
if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
- res = write_bbt(mtd, buf, md, td, chipsel);
+ res = write_bbt(this, buf, md, td, chipsel);
if (res < 0)
return res;
}
@@ -1029,201 +1032,15 @@
}
/**
- * mark_bbt_regions - [GENERIC] mark the bad block table regions
- * @mtd: MTD device structure
- * @td: bad block table descriptor
- *
- * The bad block table regions are marked as "bad" to prevent accidental
- * erasures / writes. The regions are identified by the mark 0x02.
- */
-static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- int i, j, chips, block, nrblocks, update;
- uint8_t oldval;
-
- /* Do we have a bbt per chip? */
- if (td->options & NAND_BBT_PERCHIP) {
- chips = this->numchips;
- nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
- } else {
- chips = 1;
- nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
- }
-
- for (i = 0; i < chips; i++) {
- if ((td->options & NAND_BBT_ABSPAGE) ||
- !(td->options & NAND_BBT_WRITE)) {
- if (td->pages[i] == -1)
- continue;
- block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
- oldval = bbt_get_entry(this, block);
- bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
- if ((oldval != BBT_BLOCK_RESERVED) &&
- td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)block <<
- this->bbt_erase_shift);
- continue;
- }
- update = 0;
- if (td->options & NAND_BBT_LASTBLOCK)
- block = ((i + 1) * nrblocks) - td->maxblocks;
- else
- block = i * nrblocks;
- for (j = 0; j < td->maxblocks; j++) {
- oldval = bbt_get_entry(this, block);
- bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
- if (oldval != BBT_BLOCK_RESERVED)
- update = 1;
- block++;
- }
- /*
- * If we want reserved blocks to be recorded to flash, and some
- * new ones have been marked, then we need to update the stored
- * bbts. This should only happen once.
- */
- if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)(block - 1) <<
- this->bbt_erase_shift);
- }
-}
-
-/**
- * verify_bbt_descr - verify the bad block description
- * @mtd: MTD device structure
- * @bd: the table to verify
- *
- * This functions performs a few sanity checks on the bad block description
- * table.
- */
-static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- u32 pattern_len;
- u32 bits;
- u32 table_size;
-
- if (!bd)
- return;
-
- pattern_len = bd->len;
- bits = bd->options & NAND_BBT_NRBITS_MSK;
-
- BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
- !(this->bbt_options & NAND_BBT_USE_FLASH));
- BUG_ON(!bits);
-
- if (bd->options & NAND_BBT_VERSION)
- pattern_len++;
-
- if (bd->options & NAND_BBT_NO_OOB) {
- BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
- BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
- BUG_ON(bd->offs);
- if (bd->options & NAND_BBT_VERSION)
- BUG_ON(bd->veroffs != bd->len);
- BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
- }
-
- if (bd->options & NAND_BBT_PERCHIP)
- table_size = this->chipsize >> this->bbt_erase_shift;
- else
- table_size = mtd->size >> this->bbt_erase_shift;
- table_size >>= 3;
- table_size *= bits;
- if (bd->options & NAND_BBT_NO_OOB)
- table_size += pattern_len;
- BUG_ON(table_size > (1 << this->bbt_erase_shift));
-}
-
-/**
- * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
- * @mtd: MTD device structure
- * @bd: descriptor for the good/bad block search pattern
- *
- * The function checks, if a bad block table(s) is/are already available. If
- * not it scans the device for manufacturer marked good / bad blocks and writes
- * the bad block table(s) to the selected place.
- *
- * The bad block table memory is allocated here. It must be freed by calling
- * the nand_free_bbt function.
- */
-static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- int len, res;
- uint8_t *buf;
- struct nand_bbt_descr *td = this->bbt_td;
- struct nand_bbt_descr *md = this->bbt_md;
-
- len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
- /*
- * Allocate memory (2bit per block) and clear the memory bad block
- * table.
- */
- this->bbt = kzalloc(len, GFP_KERNEL);
- if (!this->bbt)
- return -ENOMEM;
-
- /*
- * If no primary table decriptor is given, scan the device to build a
- * memory based bad block table.
- */
- if (!td) {
- if ((res = nand_memory_bbt(mtd, bd))) {
- pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
- goto err;
- }
- return 0;
- }
- verify_bbt_descr(mtd, td);
- verify_bbt_descr(mtd, md);
-
- /* Allocate a temporary buffer for one eraseblock incl. oob */
- len = (1 << this->bbt_erase_shift);
- len += (len >> this->page_shift) * mtd->oobsize;
- buf = vmalloc(len);
- if (!buf) {
- res = -ENOMEM;
- goto err;
- }
-
- /* Is the bbt at a given page? */
- if (td->options & NAND_BBT_ABSPAGE) {
- read_abs_bbts(mtd, buf, td, md);
- } else {
- /* Search the bad block table using a pattern in oob */
- search_read_bbts(mtd, buf, td, md);
- }
-
- res = check_create(mtd, buf, bd);
- if (res)
- goto err;
-
- /* Prevent the bbt regions from erasing / writing */
- mark_bbt_region(mtd, td);
- if (md)
- mark_bbt_region(mtd, md);
-
- vfree(buf);
- return 0;
-
-err:
- kfree(this->bbt);
- this->bbt = NULL;
- return res;
-}
-
-/**
* nand_update_bbt - update bad block table(s)
- * @mtd: MTD device structure
+ * @this: the NAND device
* @offs: the offset of the newly marked block
*
* The function updates the bad block table(s).
*/
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+static int nand_update_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
int len, res = 0;
int chip, chipsel;
uint8_t *buf;
@@ -1255,17 +1072,207 @@
/* Write the bad block table to the device? */
if (td->options & NAND_BBT_WRITE) {
- res = write_bbt(mtd, buf, td, md, chipsel);
+ res = write_bbt(this, buf, td, md, chipsel);
if (res < 0)
goto out;
}
/* Write the mirror bad block table to the device? */
if (md && (md->options & NAND_BBT_WRITE)) {
- res = write_bbt(mtd, buf, md, td, chipsel);
+ res = write_bbt(this, buf, md, td, chipsel);
}
out:
kfree(buf);
+ return res;
+}
+
+/**
+ * mark_bbt_regions - [GENERIC] mark the bad block table regions
+ * @this: the NAND device
+ * @td: bad block table descriptor
+ *
+ * The bad block table regions are marked as "bad" to prevent accidental
+ * erasures / writes. The regions are identified by the mark 0x02.
+ */
+static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)
+{
+ u64 targetsize = nanddev_target_size(&this->base);
+ struct mtd_info *mtd = nand_to_mtd(this);
+ int i, j, chips, block, nrblocks, update;
+ uint8_t oldval;
+
+ /* Do we have a bbt per chip? */
+ if (td->options & NAND_BBT_PERCHIP) {
+ chips = nanddev_ntargets(&this->base);
+ nrblocks = (int)(targetsize >> this->bbt_erase_shift);
+ } else {
+ chips = 1;
+ nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+ }
+
+ for (i = 0; i < chips; i++) {
+ if ((td->options & NAND_BBT_ABSPAGE) ||
+ !(td->options & NAND_BBT_WRITE)) {
+ if (td->pages[i] == -1)
+ continue;
+ block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+ if ((oldval != BBT_BLOCK_RESERVED) &&
+ td->reserved_block_code)
+ nand_update_bbt(this, (loff_t)block <<
+ this->bbt_erase_shift);
+ continue;
+ }
+ update = 0;
+ if (td->options & NAND_BBT_LASTBLOCK)
+ block = ((i + 1) * nrblocks) - td->maxblocks;
+ else
+ block = i * nrblocks;
+ for (j = 0; j < td->maxblocks; j++) {
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+ if (oldval != BBT_BLOCK_RESERVED)
+ update = 1;
+ block++;
+ }
+ /*
+ * If we want reserved blocks to be recorded to flash, and some
+ * new ones have been marked, then we need to update the stored
+ * bbts. This should only happen once.
+ */
+ if (update && td->reserved_block_code)
+ nand_update_bbt(this, (loff_t)(block - 1) <<
+ this->bbt_erase_shift);
+ }
+}
+
+/**
+ * verify_bbt_descr - verify the bad block description
+ * @this: the NAND device
+ * @bd: the table to verify
+ *
+ * This functions performs a few sanity checks on the bad block description
+ * table.
+ */
+static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)
+{
+ u64 targetsize = nanddev_target_size(&this->base);
+ struct mtd_info *mtd = nand_to_mtd(this);
+ u32 pattern_len;
+ u32 bits;
+ u32 table_size;
+
+ if (!bd)
+ return;
+
+ pattern_len = bd->len;
+ bits = bd->options & NAND_BBT_NRBITS_MSK;
+
+ BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
+ !(this->bbt_options & NAND_BBT_USE_FLASH));
+ BUG_ON(!bits);
+
+ if (bd->options & NAND_BBT_VERSION)
+ pattern_len++;
+
+ if (bd->options & NAND_BBT_NO_OOB) {
+ BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
+ BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
+ BUG_ON(bd->offs);
+ if (bd->options & NAND_BBT_VERSION)
+ BUG_ON(bd->veroffs != bd->len);
+ BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
+ }
+
+ if (bd->options & NAND_BBT_PERCHIP)
+ table_size = targetsize >> this->bbt_erase_shift;
+ else
+ table_size = mtd->size >> this->bbt_erase_shift;
+ table_size >>= 3;
+ table_size *= bits;
+ if (bd->options & NAND_BBT_NO_OOB)
+ table_size += pattern_len;
+ BUG_ON(table_size > (1 << this->bbt_erase_shift));
+}
+
+/**
+ * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
+ * @this: the NAND device
+ * @bd: descriptor for the good/bad block search pattern
+ *
+ * The function checks, if a bad block table(s) is/are already available. If
+ * not it scans the device for manufacturer marked good / bad blocks and writes
+ * the bad block table(s) to the selected place.
+ *
+ * The bad block table memory is allocated here. It must be freed by calling
+ * the nand_free_bbt function.
+ */
+static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
+{
+ struct mtd_info *mtd = nand_to_mtd(this);
+ int len, res;
+ uint8_t *buf;
+ struct nand_bbt_descr *td = this->bbt_td;
+ struct nand_bbt_descr *md = this->bbt_md;
+
+ len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
+ /*
+ * Allocate memory (2bit per block) and clear the memory bad block
+ * table.
+ */
+ this->bbt = kzalloc(len, GFP_KERNEL);
+ if (!this->bbt)
+ return -ENOMEM;
+
+ /*
+ * If no primary table descriptor is given, scan the device to build a
+ * memory based bad block table.
+ */
+ if (!td) {
+ if ((res = nand_memory_bbt(this, bd))) {
+ pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
+ goto err_free_bbt;
+ }
+ return 0;
+ }
+ verify_bbt_descr(this, td);
+ verify_bbt_descr(this, md);
+
+ /* Allocate a temporary buffer for one eraseblock incl. oob */
+ len = (1 << this->bbt_erase_shift);
+ len += (len >> this->page_shift) * mtd->oobsize;
+ buf = vmalloc(len);
+ if (!buf) {
+ res = -ENOMEM;
+ goto err_free_bbt;
+ }
+
+ /* Is the bbt at a given page? */
+ if (td->options & NAND_BBT_ABSPAGE) {
+ read_abs_bbts(this, buf, td, md);
+ } else {
+ /* Search the bad block table using a pattern in oob */
+ search_read_bbts(this, buf, td, md);
+ }
+
+ res = check_create(this, buf, bd);
+ if (res)
+ goto err_free_buf;
+
+ /* Prevent the bbt regions from erasing / writing */
+ mark_bbt_region(this, td);
+ if (md)
+ mark_bbt_region(this, md);
+
+ vfree(buf);
+ return 0;
+
+err_free_buf:
+ vfree(buf);
+err_free_bbt:
+ kfree(this->bbt);
+ this->bbt = NULL;
return res;
}
@@ -1382,18 +1389,17 @@
return ret;
}
- return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern);
+ return nand_scan_bbt(this, this->badblock_pattern);
}
EXPORT_SYMBOL(nand_create_bbt);
/**
* nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
*/
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1402,13 +1408,12 @@
/**
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
* @allowbbt: allow access to bad block table region
*/
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block, res;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1430,12 +1435,11 @@
/**
* nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset of the bad block
*/
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block, ret = 0;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1445,7 +1449,7 @@
/* Update flash-based bad block table */
if (this->bbt_options & NAND_BBT_USE_FLASH)
- ret = nand_update_bbt(mtd, offs);
+ ret = nand_update_bbt(this, offs);
return ret;
}
--
Gitblit v1.6.2