mtd: resync with Linux-3.7.1

This patch is essentially an update of u-boot MTD subsystem to
the state of Linux-3.7.1 with exclusion of some bits:

- the update is concentrated on NAND, no onenand or CFI/NOR/SPI
flashes interfaces are updated EXCEPT for API changes.

- new large NAND chips support is there, though some updates
have got in Linux-3.8.-rc1, (which will follow on top of this patch).

To produce this update I used tag v3.7.1 of linux-stable repository.

The update was made using application of relevant patches,
with changes relevant to U-Boot-only stuff sticked together
to keep bisectability. Then all changes were grouped together
to this patch.

Signed-off-by: Sergey Lapin <slapin@ossfans.org>
[scottwood@freescale.com: some eccstrength and build fixes]
Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
Sergey Lapin 2013-01-14 03:46:50 +00:00 committed by Scott Wood
parent a1b81ab26f
commit dfe64e2c89
48 changed files with 2204 additions and 1702 deletions

View file

@ -9,7 +9,8 @@
#include <linux/types.h>
#include <div64.h>
#include <linux/mtd/mtd-abi.h>
#include <mtd/mtd-abi.h>
#include <asm/errno.h>
#define MTD_CHAR_MAJOR 90
#define MTD_BLOCK_MAJOR 31
@ -65,22 +66,6 @@ struct mtd_erase_region_info {
unsigned long *lockmap; /* If keeping bitmap of locks */
};
/*
* oob operation modes
*
* MTD_OOB_PLACE: oob data are placed at the given offset
* MTD_OOB_AUTO: oob data are automatically placed at the free areas
* which are defined by the ecclayout
* MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data
* is inserted into the data. Thats a raw image of the
* flash contents.
*/
typedef enum {
MTD_OOB_PLACE,
MTD_OOB_AUTO,
MTD_OOB_RAW,
} mtd_oob_mode_t;
/**
* struct mtd_oob_ops - oob operation operands
* @mode: operation mode
@ -92,7 +77,7 @@ typedef enum {
* @ooblen: number of oob bytes to write/read
* @oobretlen: number of oob bytes written/read
* @ooboffs: offset of oob data in the oob area (only relevant when
* mode = MTD_OOB_PLACE)
* mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW)
* @datbuf: data buffer - if NULL only oob data are read/written
* @oobbuf: oob data buffer
*
@ -101,7 +86,7 @@ typedef enum {
* OOB area.
*/
struct mtd_oob_ops {
mtd_oob_mode_t mode;
unsigned int mode;
size_t len;
size_t retlen;
size_t ooblen;
@ -133,13 +118,25 @@ struct mtd_info {
u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
u_int32_t oobavail; /* Available OOB bytes per block */
/*
* read ops return -EUCLEAN if max number of bitflips corrected on any
* one region comprising an ecc step equals or exceeds this value.
* Settable by driver, else defaults to ecc_strength. User can override
* in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
* see Documentation/ABI/testing/sysfs-class-mtd for more detail.
*/
unsigned int bitflip_threshold;
/* Kernel-only stuff starts here. */
const char *name;
int index;
/* ecc layout structure pointer - read only ! */
/* ECC layout structure pointer - read only! */
struct nand_ecclayout *ecclayout;
/* max number of correctible bit errors per ecc step */
unsigned int ecc_strength;
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
*/
@ -147,25 +144,17 @@ struct mtd_info {
struct mtd_erase_region_info *eraseregions;
/*
* Erase is an asynchronous operation. Device drivers are supposed
* to call instr->callback() whenever the operation completes, even
* if it completes with a failure.
* Callers are supposed to pass a callback function and wait for it
* to be called before writing to the block.
* Do not call via these pointers, use corresponding mtd_*()
* wrappers instead.
*/
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
/* phys is optional and may be set to NULL */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, phys_addr_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
void (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
/* In blackbox flight recorder like scenarios we want to make successful
writes in interrupt context. panic_write() is only intended to be
@ -174,24 +163,35 @@ struct mtd_info {
longer, this function can break locks and delay to ensure the write
succeeds (but not sleep). */
int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_oob) (struct mtd_info *mtd, loff_t from,
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,
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
size_t len);
int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf);
int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
size_t len);
int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf);
int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, u_char *buf);
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
size_t len);
void (*_sync) (struct mtd_info *mtd);
int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
/*
* Methods to access the protection register area, present in some
* flash devices. The user data is one time programmable but the
* factory data is read only.
* If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver.
*/
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
int (*_get_device) (struct mtd_info *mtd);
void (*_put_device) (struct mtd_info *mtd);
/* XXX U-BOOT XXX */
#if 0
@ -201,18 +201,6 @@ struct mtd_info {
*/
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
#endif
/* Sync */
void (*sync) (struct mtd_info *mtd);
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
/* Bad block management functions */
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
/* XXX U-BOOT XXX */
#if 0
struct notifier_block reboot_notifier; /* default mode before reboot */
@ -227,15 +215,59 @@ struct mtd_info {
struct module *owner;
int usecount;
/* If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver.
* The driver may register its callbacks. These callbacks are not
* supposed to be called by MTD users */
int (*get_device) (struct mtd_info *mtd);
void (*put_device) (struct mtd_info *mtd);
};
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf);
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf);
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf);
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
ops->retlen = ops->oobretlen = 0;
if (!mtd->_write_oob)
return -EOPNOTSUPP;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
return mtd->_write_oob(mtd, to, ops);
}
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
size_t len);
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
size_t len);
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, u_char *buf);
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
/* XXX U-BOOT XXX */
#if 0
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
#endif
static inline void mtd_sync(struct mtd_info *mtd)
{
if (mtd->_sync)
mtd->_sync(mtd);
}
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
{
do_div(sz, mtd->erasesize);
@ -247,6 +279,16 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
return do_div(sz, mtd->erasesize);
}
static inline int mtd_has_oob(const struct mtd_info *mtd)
{
return mtd->_read_oob && mtd->_write_oob;
}
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
{
return !!mtd->_block_isbad;
}
/* Kernel-side ioctl definitions */
extern int add_mtd_device(struct mtd_info *mtd);
@ -269,12 +311,6 @@ struct mtd_notifier {
extern void register_mtd_user (struct mtd_notifier *new);
extern int unregister_mtd_user (struct mtd_notifier *old);
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen);
#endif
#ifdef CONFIG_MTD_PARTITIONS
@ -296,17 +332,34 @@ static inline void mtd_erase_callback(struct erase_info *instr)
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
#ifdef CONFIG_MTD_DEBUG
#define pr_debug(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
#define MTDDEBUG(n, args...) \
do { \
if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
printk(KERN_INFO args); \
} while(0)
#else /* CONFIG_MTD_DEBUG */
#define pr_debug(args...)
#define MTDDEBUG(n, args...) \
do { \
if (0) \
printk(KERN_INFO args); \
} while(0)
#endif /* CONFIG_MTD_DEBUG */
#define pr_info(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
#define pr_warn(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
#define pr_err(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
static inline int mtd_is_bitflip(int err) {
return err == -EUCLEAN;
}
static inline int mtd_is_eccerr(int err) {
return err == -EBADMSG;
}
static inline int mtd_is_bitflip_or_eccerr(int err) {
return mtd_is_bitflip(err) || mtd_is_eccerr(err);
}
#endif /* __MTD_MTD_H__ */