Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
U
u-boot-stm32
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sami Nurmenniemi
u-boot-stm32
Commits
05ff4de5
Commit
05ff4de5
authored
Mar 10, 2017
by
Dmitry Konyshev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
RM1349 Backport newer NAND bad block table management code
parent
0de06cfb
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
360 additions
and
130 deletions
+360
-130
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_bbt.c
+328
-127
include/linux/mtd/bbm.h
include/linux/mtd/bbm.h
+22
-3
include/linux/mtd/nand.h
include/linux/mtd/nand.h
+10
-0
No files found.
drivers/mtd/nand/nand_bbt.c
View file @
05ff4de5
...
...
@@ -13,27 +13,36 @@
* Description:
*
* When nand_scan_bbt is called, then it tries to find the bad block table
* depending on the options in the bbt descriptor(s). If a bbt is found
* then the contents are read and the memory based bbt is created. If a
* mirrored bbt is selected then the mirror is searched too and the
* versions are compared. If the mirror has a greater version number
* than the mirror bbt is used to build the memory based bbt.
* depending on the options in the BBT descriptor(s). If no flash based BBT
* (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory
* marked good / bad blocks. This information is used to create a memory BBT.
* Once a new bad block is discovered then the "factory" information is updated
* on the device.
* If a flash based BBT is specified then the function first tries to find the
* BBT on flash. If a BBT is found then the contents are read and the memory
* based BBT is created. If a mirrored BBT is selected then the mirror is
* searched too and the versions are compared. If the mirror has a greater
* version number than the mirror BBT is used to build the memory based BBT.
* If the tables are not versioned, then we "or" the bad block information.
* If one of the
bbt'
s is out of date or does not exist it is (re)created.
* If no
bbt
exists at all then the device is scanned for factory marked
* If one of the
BBT
s is out of date or does not exist it is (re)created.
* If no
BBT
exists at all then the device is scanned for factory marked
* good / bad blocks and the bad block tables are created.
*
* For manufacturer created
bbt
s like the one found on M-SYS DOC devices
* the
bbt
is searched and read but never created
* For manufacturer created
BBT
s like the one found on M-SYS DOC devices
* the
BBT
is searched and read but never created
*
* The autogenerated bad block table is located in the last good blocks
* The auto
generated bad block table is located in the last good blocks
* of the device. The table is mirrored, so it can be updated eventually.
* The table is marked in the oob area with an ident pattern and a version
* number which indicates which of both tables is more up to date.
* The table is marked in the OOB area with an ident pattern and a version
* number which indicates which of both tables is more up to date. If the NAND
* controller needs the complete OOB area for the ECC information then the
* option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern
* and the version byte into the data area and the OOB area will remain
* untouched.
*
* The table uses 2 bits per block
* 11b: block is good
* 00b: block is factory marked bad
* 11b:
block is good
* 00b:
block is factory marked bad
* 01b, 10b: block is marked bad due to wear
*
* The memory bad block table uses the following scheme:
...
...
@@ -55,21 +64,20 @@
#include <linux/mtd/compat.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/bitops.h>
#include <asm/errno.h>
/* XXX U-BOOT XXX */
#if 0
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/compatmac.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#endif
static
int
check_pattern_no_oob
(
uint8_t
*
buf
,
struct
nand_bbt_descr
*
td
)
{
int
ret
;
ret
=
memcmp
(
buf
,
td
->
pattern
,
td
->
len
);
if
(
!
ret
)
return
ret
;
return
-
1
;
}
/**
* check_pattern - [GENERIC] check if a pattern is in the buffer
...
...
@@ -89,6 +97,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
int
i
,
end
=
0
;
uint8_t
*
p
=
buf
;
if
(
td
->
options
&
NAND_BBT_NO_OOB
)
return
check_pattern_no_oob
(
buf
,
td
);
end
=
paglen
+
td
->
offs
;
if
(
td
->
options
&
NAND_BBT_SCANEMPTY
)
{
for
(
i
=
0
;
i
<
end
;
i
++
)
{
...
...
@@ -104,6 +115,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
return
-
1
;
}
/* Check both positions 1 and 6 for pattern? */
if
(
td
->
options
&
NAND_BBT_SCANBYTE1AND6
)
{
if
(
td
->
options
&
NAND_BBT_SCANEMPTY
)
{
p
+=
td
->
len
;
end
+=
NAND_SMALL_BADBLOCK_POS
-
td
->
offs
;
/* Check region between positions 1 and 6 */
for
(
i
=
0
;
i
<
NAND_SMALL_BADBLOCK_POS
-
td
->
offs
-
td
->
len
;
i
++
)
{
if
(
*
p
++
!=
0xff
)
return
-
1
;
}
}
else
{
p
+=
NAND_SMALL_BADBLOCK_POS
-
td
->
offs
;
}
/* Compare the pattern */
for
(
i
=
0
;
i
<
td
->
len
;
i
++
)
{
if
(
p
[
i
]
!=
td
->
pattern
[
i
])
return
-
1
;
}
}
if
(
td
->
options
&
NAND_BBT_SCANEMPTY
)
{
p
+=
td
->
len
;
end
+=
td
->
len
;
...
...
@@ -135,36 +168,74 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
if
(
p
[
td
->
offs
+
i
]
!=
td
->
pattern
[
i
])
return
-
1
;
}
/* Need to check location 1 AND 6? */
if
(
td
->
options
&
NAND_BBT_SCANBYTE1AND6
)
{
for
(
i
=
0
;
i
<
td
->
len
;
i
++
)
{
if
(
p
[
NAND_SMALL_BADBLOCK_POS
+
i
]
!=
td
->
pattern
[
i
])
return
-
1
;
}
}
return
0
;
}
/**
* add_marker_len - compute the length of the marker in data area
* @td: BBT descriptor used for computation
*
* The length will be 0 if the markeris located in OOB area.
*/
static
u32
add_marker_len
(
struct
nand_bbt_descr
*
td
)
{
u32
len
;
if
(
!
(
td
->
options
&
NAND_BBT_NO_OOB
))
return
0
;
len
=
td
->
len
;
if
(
td
->
options
&
NAND_BBT_VERSION
)
len
++
;
return
len
;
}
/**
* read_bbt - [GENERIC] Read the bad block table starting from page
* @mtd: MTD device structure
* @buf: temporary buffer
* @page: the starting page
* @num: the number of bbt descriptors to read
* @
bits: number of bits per block
* @
td: the bbt describtion table
* @offs: offset in the memory table
* @reserved_block_code: Pattern to identify reserved blocks
*
* Read the bad block table starting from page.
*
*/
static
int
read_bbt
(
struct
mtd_info
*
mtd
,
uint8_t
*
buf
,
int
page
,
int
num
,
int
bits
,
int
offs
,
int
reserved_block_code
)
struct
nand_bbt_descr
*
td
,
int
offs
)
{
int
res
,
i
,
j
,
act
=
0
;
struct
nand_chip
*
this
=
mtd
->
priv
;
size_t
retlen
,
len
,
totlen
;
loff_t
from
;
int
bits
=
td
->
options
&
NAND_BBT_NRBITS_MSK
;
uint8_t
msk
=
(
uint8_t
)
((
1
<<
bits
)
-
1
);
u32
marker_len
;
int
reserved_block_code
=
td
->
reserved_block_code
;
totlen
=
(
num
*
bits
)
>>
3
;
marker_len
=
add_marker_len
(
td
);
from
=
((
loff_t
)
page
)
<<
this
->
page_shift
;
while
(
totlen
)
{
len
=
min
(
totlen
,
(
size_t
)
(
1
<<
this
->
bbt_erase_shift
));
if
(
marker_len
)
{
/*
* In case the BBT marker is not in the OOB area it
* will be just in the first page.
*/
len
-=
marker_len
;
from
+=
marker_len
;
marker_len
=
0
;
}
res
=
mtd
->
read
(
mtd
,
from
,
len
,
&
retlen
,
buf
);
if
(
res
<
0
)
{
if
(
retlen
!=
len
)
{
...
...
@@ -183,9 +254,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
continue
;
if
(
reserved_block_code
&&
(
tmp
==
reserved_block_code
))
{
printk
(
KERN_DEBUG
"nand_read_bbt: Reserved block at 0x%012llx
\n
"
,
(
loff_t
)((
offs
<<
2
)
+
(
act
>>
1
))
<<
this
->
bbt_erase_shift
);
(
loff_t
)((
offs
<<
2
)
+
(
act
>>
1
))
<<
this
->
bbt_erase_shift
);
this
->
bbt
[
offs
+
(
act
>>
3
)]
|=
0x2
<<
(
act
&
0x06
);
mtd
->
ecc_stats
.
bbtblocks
++
;
continue
;
...
...
@@ -193,8 +262,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
/* Leave it for now, if its matured we can move this
* message to MTD_DEBUG_LEVEL0 */
printk
(
KERN_DEBUG
"nand_read_bbt: Bad block at 0x%012llx
\n
"
,
(
loff_t
)((
offs
<<
2
)
+
(
act
>>
1
))
<<
this
->
bbt_erase_shift
);
(
loff_t
)((
offs
<<
2
)
+
(
act
>>
1
))
<<
this
->
bbt_erase_shift
);
/* Factory marked bad or worn out ? */
if
(
tmp
==
0
)
this
->
bbt
[
offs
+
(
act
>>
3
)]
|=
0x3
<<
(
act
&
0x06
);
...
...
@@ -224,42 +292,86 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
{
struct
nand_chip
*
this
=
mtd
->
priv
;
int
res
=
0
,
i
;
int
bits
;
bits
=
td
->
options
&
NAND_BBT_NRBITS_MSK
;
if
(
td
->
options
&
NAND_BBT_PERCHIP
)
{
int
offs
=
0
;
for
(
i
=
0
;
i
<
this
->
numchips
;
i
++
)
{
if
(
chip
==
-
1
||
chip
==
i
)
res
=
read_bbt
(
mtd
,
buf
,
td
->
pages
[
i
],
this
->
chipsize
>>
this
->
bbt_erase_shift
,
bits
,
offs
,
td
->
reserved_block_code
);
res
=
read_bbt
(
mtd
,
buf
,
td
->
pages
[
i
],
this
->
chipsize
>>
this
->
bbt_erase_shift
,
td
,
offs
);
if
(
res
)
return
res
;
offs
+=
this
->
chipsize
>>
(
this
->
bbt_erase_shift
+
2
);
}
}
else
{
res
=
read_bbt
(
mtd
,
buf
,
td
->
pages
[
0
],
mtd
->
size
>>
this
->
bbt_erase_shift
,
bits
,
0
,
td
->
reserved_block_code
);
res
=
read_bbt
(
mtd
,
buf
,
td
->
pages
[
0
],
mtd
->
size
>>
this
->
bbt_erase_shift
,
td
,
0
);
if
(
res
)
return
res
;
}
return
0
;
}
/*
* BBT marker is in the first page, no OOB.
*/
static
int
scan_read_raw_data
(
struct
mtd_info
*
mtd
,
uint8_t
*
buf
,
loff_t
offs
,
struct
nand_bbt_descr
*
td
)
{
size_t
retlen
;
size_t
len
;
len
=
td
->
len
;
if
(
td
->
options
&
NAND_BBT_VERSION
)
len
++
;
return
mtd
->
read
(
mtd
,
offs
,
len
,
&
retlen
,
buf
);
}
/*
* Scan read raw data from flash
*/
static
int
scan_read_raw
(
struct
mtd_info
*
mtd
,
uint8_t
*
buf
,
loff_t
offs
,
static
int
scan_read_raw
_oob
(
struct
mtd_info
*
mtd
,
uint8_t
*
buf
,
loff_t
offs
,
size_t
len
)
{
struct
mtd_oob_ops
ops
;
int
res
;
ops
.
mode
=
MTD_OOB_RAW
;
ops
.
ooboffs
=
0
;
ops
.
ooblen
=
mtd
->
oobsize
;
ops
.
oobbuf
=
buf
;
ops
.
datbuf
=
buf
;
ops
.
len
=
len
;
return
mtd
->
read_oob
(
mtd
,
offs
,
&
ops
);
while
(
len
>
0
)
{
if
(
len
<=
mtd
->
writesize
)
{
ops
.
oobbuf
=
buf
+
len
;
ops
.
datbuf
=
buf
;
ops
.
len
=
len
;
return
mtd
->
read_oob
(
mtd
,
offs
,
&
ops
);
}
else
{
ops
.
oobbuf
=
buf
+
mtd
->
writesize
;
ops
.
datbuf
=
buf
;
ops
.
len
=
mtd
->
writesize
;
res
=
mtd
->
read_oob
(
mtd
,
offs
,
&
ops
);
if
(
res
)
return
res
;
}
buf
+=
mtd
->
oobsize
+
mtd
->
writesize
;
len
-=
mtd
->
writesize
;
}
return
0
;
}
static
int
scan_read_raw
(
struct
mtd_info
*
mtd
,
uint8_t
*
buf
,
loff_t
offs
,
size_t
len
,
struct
nand_bbt_descr
*
td
)
{
if
(
td
->
options
&
NAND_BBT_NO_OOB
)
return
scan_read_raw_data
(
mtd
,
buf
,
offs
,
td
);
else
return
scan_read_raw_oob
(
mtd
,
buf
,
offs
,
len
);
}
/*
...
...
@@ -280,6 +392,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
return
mtd
->
write_oob
(
mtd
,
offs
,
&
ops
);
}
static
u32
bbt_get_ver_offs
(
struct
mtd_info
*
mtd
,
struct
nand_bbt_descr
*
td
)
{
u32
ver_offs
=
td
->
veroffs
;
if
(
!
(
td
->
options
&
NAND_BBT_NO_OOB
))
ver_offs
+=
mtd
->
writesize
;
return
ver_offs
;
}
/**
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
* @mtd: MTD device structure
...
...
@@ -298,18 +419,18 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the primary version, if available */
if
(
td
->
options
&
NAND_BBT_VERSION
)
{
scan_read_raw
(
mtd
,
buf
,
(
loff_t
)
td
->
pages
[
0
]
<<
this
->
page_shift
,
mtd
->
writesize
);
td
->
version
[
0
]
=
buf
[
mtd
->
writesize
+
td
->
veroffs
];
scan_read_raw
(
mtd
,
buf
,
(
loff_t
)
td
->
pages
[
0
]
<<
this
->
page_shift
,
mtd
->
writesize
,
td
);
td
->
version
[
0
]
=
buf
[
bbt_get_ver_offs
(
mtd
,
td
)
];
printk
(
KERN_DEBUG
"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_raw
(
mtd
,
buf
,
(
loff_t
)
md
->
pages
[
0
]
<<
this
->
page_shift
,
mtd
->
writesize
);
md
->
version
[
0
]
=
buf
[
mtd
->
writesize
+
md
->
veroffs
];
scan_read_raw
(
mtd
,
buf
,
(
loff_t
)
md
->
pages
[
0
]
<<
this
->
page_shift
,
mtd
->
writesize
,
td
);
md
->
version
[
0
]
=
buf
[
bbt_get_ver_offs
(
mtd
,
md
)
];
printk
(
KERN_DEBUG
"Bad block table at page %d, version 0x%02X
\n
"
,
md
->
pages
[
0
],
md
->
version
[
0
]);
}
...
...
@@ -325,7 +446,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
{
int
ret
,
j
;
ret
=
scan_read_raw
(
mtd
,
buf
,
offs
,
readlen
);
ret
=
scan_read_raw
_oob
(
mtd
,
buf
,
offs
,
readlen
);
if
(
ret
)
return
ret
;
...
...
@@ -389,16 +510,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
loff_t
from
;
size_t
readlen
;
MTDDEBUG
(
MTD_DEBUG_LEVEL0
,
"Scanning device for bad blocks
\n
"
);
MTDDEBUG
(
MTD_DEBUG_LEVEL0
,
"Scanning device for bad blocks
\n
"
);
if
(
bd
->
options
&
NAND_BBT_SCANALLPAGES
)
len
=
1
<<
(
this
->
bbt_erase_shift
-
this
->
page_shift
);
else
{
if
(
bd
->
options
&
NAND_BBT_SCAN2NDPAGE
)
len
=
2
;
else
len
=
1
;
}
else
if
(
bd
->
options
&
NAND_BBT_SCAN2NDPAGE
)
len
=
2
;
else
len
=
1
;
if
(
!
(
bd
->
options
&
NAND_BBT_SCANEMPTY
))
{
/* We need only read few bytes from the OOB area */
...
...
@@ -428,9 +547,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
from
=
(
loff_t
)
startblock
<<
(
this
->
bbt_erase_shift
-
1
);
}
if
(
this
->
options
&
NAND_BBT_SCANLASTPAGE
)
from
+=
mtd
->
erasesize
-
(
mtd
->
writesize
*
len
);
for
(
i
=
startblock
;
i
<
numblocks
;)
{
int
ret
;
BUG_ON
(
bd
->
options
&
NAND_BBT_NO_OOB
);
if
(
bd
->
options
&
NAND_BBT_SCANALLPAGES
)
ret
=
scan_block_full
(
mtd
,
bd
,
from
,
buf
,
readlen
,
scanlen
,
len
);
...
...
@@ -442,7 +566,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
if
(
ret
)
{
this
->
bbt
[
i
>>
3
]
|=
0x03
<<
(
i
&
0x6
);
MTDDEBUG
(
MTD_DEBUG_LEVEL0
,
MTDDEBUG
(
MTD_DEBUG_LEVEL0
,
"Bad eraseblock %d at 0x%012llx
\n
"
,
i
>>
1
,
(
unsigned
long
long
)
from
);
mtd
->
ecc_stats
.
badblocks
++
;
...
...
@@ -475,7 +599,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
{
struct
nand_chip
*
this
=
mtd
->
priv
;
int
i
,
chips
;
int
bits
,
startblock
,
block
,
dir
;
int
startblock
,
block
,
dir
;
int
scanlen
=
mtd
->
writesize
+
mtd
->
oobsize
;
int
bbtblocks
;
int
blocktopage
=
this
->
bbt_erase_shift
-
this
->
page_shift
;
...
...
@@ -499,9 +623,6 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
bbtblocks
=
mtd
->
size
>>
this
->
bbt_erase_shift
;
}
/* Number of bits for each erase block in the bbt */
bits
=
td
->
options
&
NAND_BBT_NRBITS_MSK
;
for
(
i
=
0
;
i
<
chips
;
i
++
)
{
/* Reset version information */
td
->
version
[
i
]
=
0
;
...
...
@@ -513,11 +634,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
loff_t
offs
=
(
loff_t
)
actblock
<<
this
->
bbt_erase_shift
;
/* Read first page */
scan_read_raw
(
mtd
,
buf
,
offs
,
mtd
->
writesize
);
scan_read_raw
(
mtd
,
buf
,
offs
,
mtd
->
writesize
,
td
);
if
(
!
check_pattern
(
buf
,
scanlen
,
mtd
->
writesize
,
td
))
{
td
->
pages
[
i
]
=
actblock
<<
blocktopage
;
if
(
td
->
options
&
NAND_BBT_VERSION
)
{
td
->
version
[
i
]
=
buf
[
mtd
->
writesize
+
td
->
veroffs
];
offs
=
bbt_get_ver_offs
(
mtd
,
td
);
td
->
version
[
i
]
=
buf
[
offs
];
}
break
;
}
...
...
@@ -701,12 +823,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
memset
(
&
buf
[
offs
],
0xff
,
(
size_t
)
(
numblocks
>>
sft
));
ooboffs
=
len
+
(
pageoffs
*
mtd
->
oobsize
);
}
else
if
(
td
->
options
&
NAND_BBT_NO_OOB
)
{
ooboffs
=
0
;
offs
=
td
->
len
;
/* the version byte */
if
(
td
->
options
&
NAND_BBT_VERSION
)
offs
++
;
/* Calc length */
len
=
(
size_t
)
(
numblocks
>>
sft
);
len
+=
offs
;
/* Make it page aligned ! */
len
=
ALIGN
(
len
,
mtd
->
writesize
);
/* Preset the buffer with 0xff */
memset
(
buf
,
0xff
,
len
);
/* Pattern is located at the begin of first page */
memcpy
(
buf
,
td
->
pattern
,
td
->
len
);
}
else
{
/* Calc length */
len
=
(
size_t
)
(
numblocks
>>
sft
);
/* Make it page aligned ! */
len
=
(
len
+
(
mtd
->
writesize
-
1
))
&
~
(
mtd
->
writesize
-
1
);
len
=
ALIGN
(
len
,
mtd
->
writesize
);
/* Preset the buffer with 0xff */
memset
(
buf
,
0xff
,
len
+
(
len
>>
this
->
page_shift
)
*
mtd
->
oobsize
);
...
...
@@ -740,13 +876,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
if
(
res
<
0
)
goto
outerr
;
res
=
scan_write_bbt
(
mtd
,
to
,
len
,
buf
,
&
buf
[
len
]);
res
=
scan_write_bbt
(
mtd
,
to
,
len
,
buf
,
td
->
options
&
NAND_BBT_NO_OOB
?
NULL
:
&
buf
[
len
]);
if
(
res
<
0
)
goto
outerr
;
printk
(
KERN_DEBUG
"Bad block table written to 0x%012llx, "
"version 0x%02X
\n
"
,
(
unsigned
long
long
)
to
,
td
->
version
[
chip
]);
printk
(
KERN_DEBUG
"Bad block table written to 0x%012llx, version "
"0x%02X
\n
"
,
(
unsigned
long
long
)
to
,
td
->
version
[
chip
]);
/* Mark it as used */
td
->
pages
[
chip
]
=
page
;
...
...
@@ -807,7 +944,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
rd2
=
NULL
;
/* Per chip or per device ? */
chipsel
=
(
td
->
options
&
NAND_BBT_PERCHIP
)
?
i
:
-
1
;
/* Mirrored table avilable ? */
/* Mirrored table av
a
ilable ? */
if
(
md
)
{
if
(
td
->
pages
[
i
]
==
-
1
&&
md
->
pages
[
i
]
==
-
1
)
{
writeops
=
0x03
;
...
...
@@ -861,7 +998,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
continue
;
/* Create the table in memory by scanning the chip(s) */
create_bbt
(
mtd
,
buf
,
bd
,
chipsel
);
if
(
!
(
this
->
options
&
NAND_CREATE_EMPTY_BBT
))
create_bbt
(
mtd
,
buf
,
bd
,
chipsel
);
td
->
version
[
i
]
=
1
;
if
(
md
)
...
...
@@ -926,8 +1064,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
newval
=
oldval
|
(
0x2
<<
(
block
&
0x06
));
this
->
bbt
[(
block
>>
3
)]
=
newval
;
if
((
oldval
!=
newval
)
&&
td
->
reserved_block_code
)
nand_update_bbt
(
mtd
,
(
loff_t
)
block
<<
(
this
->
bbt_erase_shift
-
1
));
nand_update_bbt
(
mtd
,
(
loff_t
)
block
<<
(
this
->
bbt_erase_shift
-
1
));
continue
;
}
update
=
0
;
...
...
@@ -948,11 +1085,58 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
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
-
2
)
<<
(
this
->
bbt_erase_shift
-
1
));
nand_update_bbt
(
mtd
,
(
loff_t
)(
block
-
2
)
<<
(
this
->
bbt_erase_shift
-
1
));
}
}
/**
* 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
->
priv
;
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
->
options
&
NAND_USE_FLASH_BBT_NO_OOB
)
&&
!
(
this
->
options
&
NAND_USE_FLASH_BBT
));
BUG_ON
(
!
bits
);
if
(
bd
->
options
&
NAND_BBT_VERSION
)
pattern_len
++
;
if
(
bd
->
options
&
NAND_BBT_NO_OOB
)
{
BUG_ON
(
!
(
this
->
options
&
NAND_USE_FLASH_BBT
));
BUG_ON
(
!
(
this
->
options
&
NAND_USE_FLASH_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
...
...
@@ -994,15 +1178,13 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
}
return
res
;
}
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
;
#ifdef CONFIG_NAND_BBT_BLOCK_BUFFER
buf
=
(
uint8_t
*
)
CONFIG_NAND_BBT_BLOCK_BUFFER
;
#else
buf
=
vmalloc
(
len
);
#endif
if
(
!
buf
)
{
printk
(
KERN_ERR
"nand_bbt: Out of memory
\n
"
);
kfree
(
this
->
bbt
);
...
...
@@ -1026,9 +1208,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
if
(
md
)
mark_bbt_region
(
mtd
,
md
);
#ifndef CONFIG_NAND_BBT_BLOCK_BUFFER
vfree
(
buf
);
#endif
return
res
;
}
...
...
@@ -1095,34 +1275,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
* while scanning a device for factory marked good / bad blocks. */
static
uint8_t
scan_ff_pattern
[]
=
{
0xff
,
0xff
};
static
struct
nand_bbt_descr
smallpage_memorybased
=
{
.
options
=
NAND_BBT_SCAN2NDPAGE
,
.
offs
=
5
,
.
len
=
1
,
.
pattern
=
scan_ff_pattern
};
static
struct
nand_bbt_descr
largepage_memorybased
=
{
.
options
=
0
,
.
offs
=
0
,
.
len
=
2
,
.
pattern
=
scan_ff_pattern
};
static
struct
nand_bbt_descr
smallpage_flashbased
=
{
.
options
=
NAND_BBT_SCAN2NDPAGE
,
.
offs
=
5
,
.
len
=
1
,
.
pattern
=
scan_ff_pattern
};
static
struct
nand_bbt_descr
largepage_flashbased
=
{
.
options
=
NAND_BBT_SCAN2NDPAGE
,
.
offs
=
0
,
.
len
=
2
,
.
pattern
=
scan_ff_pattern
};
static
uint8_t
scan_agand_pattern
[]
=
{
0x1C
,
0x71
,
0xC7
,
0x1C
,
0x71
,
0xC7
};
static
struct
nand_bbt_descr
agand_flashbased
=
{
...
...
@@ -1157,6 +1309,59 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.
pattern
=
mirror_pattern
};
static
struct
nand_bbt_descr
bbt_main_no_bbt_descr
=
{
.
options
=
NAND_BBT_LASTBLOCK
|
NAND_BBT_CREATE
|
NAND_BBT_WRITE