mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2024-11-24 14:06:15 +00:00
f183ce35b8
_oob_read returns number of bitflips on success while bbt_nand_read should return 0. Fixes: 2d49e49b18 ("mediatek: bmt: use generic mtd api") Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
138 lines
3.2 KiB
C
138 lines
3.2 KiB
C
#ifndef __MTK_BMT_PRIV_H
|
|
#define __MTK_BMT_PRIV_H
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/of.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/mtd/mtk_bmt.h>
|
|
#include <linux/debugfs.h>
|
|
|
|
#define MAIN_SIGNATURE_OFFSET 0
|
|
#define OOB_SIGNATURE_OFFSET 1
|
|
|
|
#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__)
|
|
|
|
struct mtk_bmt_ops {
|
|
char *sig;
|
|
unsigned int sig_len;
|
|
int (*init)(struct device_node *np);
|
|
bool (*remap_block)(u16 block, u16 mapped_block, int copy_len);
|
|
void (*unmap_block)(u16 block);
|
|
int (*get_mapping_block)(int block);
|
|
int (*debug)(void *data, u64 val);
|
|
};
|
|
|
|
struct bbbt;
|
|
struct nmbm_instance;
|
|
|
|
struct bmt_desc {
|
|
struct mtd_info *mtd;
|
|
unsigned char *bbt_buf;
|
|
unsigned char *data_buf;
|
|
|
|
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
|
struct mtd_oob_ops *ops);
|
|
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
|
struct mtd_oob_ops *ops);
|
|
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
|
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
|
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
|
|
|
const struct mtk_bmt_ops *ops;
|
|
|
|
union {
|
|
struct bbbt *bbt;
|
|
struct nmbm_instance *ni;
|
|
};
|
|
|
|
struct dentry *debugfs_dir;
|
|
|
|
u32 table_size;
|
|
u32 pg_size;
|
|
u32 blk_size;
|
|
u16 pg_shift;
|
|
u16 blk_shift;
|
|
/* bbt logical address */
|
|
u16 pool_lba;
|
|
/* bbt physical address */
|
|
u16 pool_pba;
|
|
/* Maximum count of bad blocks that the vendor guaranteed */
|
|
u16 bb_max;
|
|
/* Total blocks of the Nand Chip */
|
|
u16 total_blks;
|
|
/* The block(n) BMT is located at (bmt_tbl[n]) */
|
|
u16 bmt_blk_idx;
|
|
/* How many pages needs to store 'struct bbbt' */
|
|
u32 bmt_pgs;
|
|
|
|
const __be32 *remap_range;
|
|
int remap_range_len;
|
|
|
|
/* to compensate for driver level remapping */
|
|
u8 oob_offset;
|
|
};
|
|
|
|
extern struct bmt_desc bmtd;
|
|
extern const struct mtk_bmt_ops mtk_bmt_v2_ops;
|
|
extern const struct mtk_bmt_ops mtk_bmt_bbt_ops;
|
|
extern const struct mtk_bmt_ops mtk_bmt_nmbm_ops;
|
|
|
|
static inline u32 blk_pg(u16 block)
|
|
{
|
|
return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift));
|
|
}
|
|
|
|
static inline int
|
|
bbt_nand_read(u32 page, unsigned char *dat, int dat_len,
|
|
unsigned char *fdm, int fdm_len)
|
|
{
|
|
struct mtd_oob_ops ops = {
|
|
.mode = MTD_OPS_PLACE_OOB,
|
|
.ooboffs = bmtd.oob_offset,
|
|
.oobbuf = fdm,
|
|
.ooblen = fdm_len,
|
|
.datbuf = dat,
|
|
.len = dat_len,
|
|
};
|
|
int ret;
|
|
|
|
ret = bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops);
|
|
if (ret < 0)
|
|
return ret;
|
|
if (ret)
|
|
pr_info("%s: %d bitflips\n", __func__, ret);
|
|
return 0;
|
|
}
|
|
|
|
static inline int bbt_nand_erase(u16 block)
|
|
{
|
|
struct mtd_info *mtd = bmtd.mtd;
|
|
struct erase_info instr = {
|
|
.addr = (loff_t)block << bmtd.blk_shift,
|
|
.len = bmtd.blk_size,
|
|
};
|
|
|
|
return bmtd._erase(mtd, &instr);
|
|
}
|
|
|
|
static inline int write_bmt(u16 block, unsigned char *dat)
|
|
{
|
|
struct mtd_oob_ops ops = {
|
|
.mode = MTD_OPS_PLACE_OOB,
|
|
.ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset,
|
|
.oobbuf = bmtd.ops->sig,
|
|
.ooblen = bmtd.ops->sig_len,
|
|
.datbuf = dat,
|
|
.len = bmtd.bmt_pgs << bmtd.pg_shift,
|
|
};
|
|
loff_t addr = (loff_t)block << bmtd.blk_shift;
|
|
|
|
return bmtd._write_oob(bmtd.mtd, addr, &ops);
|
|
}
|
|
|
|
int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset);
|
|
bool mapping_block_in_range(int block, int *start, int *end);
|
|
|
|
#endif
|