Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
69db4aa4
Commit
69db4aa4
authored
Oct 08, 2016
by
Brian Norris
Browse files
Options
Browse Files
Download
Plain Diff
Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux
Introduction of the MTD pairing scheme concept.
parents
f5b88de2
477b0229
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
212 additions
and
0 deletions
+212
-0
drivers/mtd/mtdcore.c
drivers/mtd/mtdcore.c
+104
-0
drivers/mtd/mtdpart.c
drivers/mtd/mtdpart.c
+1
-0
include/linux/mtd/mtd.h
include/linux/mtd/mtd.h
+107
-0
No files found.
drivers/mtd/mtdcore.c
View file @
69db4aa4
...
@@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
...
@@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
}
/**
* mtd_wunit_to_pairing_info - get pairing information of a wunit
* @mtd: pointer to new MTD device info structure
* @wunit: write unit we are interested in
* @info: returned pairing information
*
* Retrieve pairing information associated to the wunit.
* This is mainly useful when dealing with MLC/TLC NANDs where pages can be
* paired together, and where programming a page may influence the page it is
* paired with.
* The notion of page is replaced by the term wunit (write-unit) to stay
* consistent with the ->writesize field.
*
* The @wunit argument can be extracted from an absolute offset using
* mtd_offset_to_wunit(). @info is filled with the pairing information attached
* to @wunit.
*
* From the pairing info the MTD user can find all the wunits paired with
* @wunit using the following loop:
*
* for (i = 0; i < mtd_pairing_groups(mtd); i++) {
* info.pair = i;
* mtd_pairing_info_to_wunit(mtd, &info);
* ...
* }
*/
int
mtd_wunit_to_pairing_info
(
struct
mtd_info
*
mtd
,
int
wunit
,
struct
mtd_pairing_info
*
info
)
{
int
npairs
=
mtd_wunit_per_eb
(
mtd
)
/
mtd_pairing_groups
(
mtd
);
if
(
wunit
<
0
||
wunit
>=
npairs
)
return
-
EINVAL
;
if
(
mtd
->
pairing
&&
mtd
->
pairing
->
get_info
)
return
mtd
->
pairing
->
get_info
(
mtd
,
wunit
,
info
);
info
->
group
=
0
;
info
->
pair
=
wunit
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
mtd_wunit_to_pairing_info
);
/**
* mtd_wunit_to_pairing_info - get wunit from pairing information
* @mtd: pointer to new MTD device info structure
* @info: pairing information struct
*
* Returns a positive number representing the wunit associated to the info
* struct, or a negative error code.
*
* This is the reverse of mtd_wunit_to_pairing_info(), and can help one to
* iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info()
* doc).
*
* It can also be used to only program the first page of each pair (i.e.
* page attached to group 0), which allows one to use an MLC NAND in
* software-emulated SLC mode:
*
* info.group = 0;
* npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
* for (info.pair = 0; info.pair < npairs; info.pair++) {
* wunit = mtd_pairing_info_to_wunit(mtd, &info);
* mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit),
* mtd->writesize, &retlen, buf + (i * mtd->writesize));
* }
*/
int
mtd_pairing_info_to_wunit
(
struct
mtd_info
*
mtd
,
const
struct
mtd_pairing_info
*
info
)
{
int
ngroups
=
mtd_pairing_groups
(
mtd
);
int
npairs
=
mtd_wunit_per_eb
(
mtd
)
/
ngroups
;
if
(
!
info
||
info
->
pair
<
0
||
info
->
pair
>=
npairs
||
info
->
group
<
0
||
info
->
group
>=
ngroups
)
return
-
EINVAL
;
if
(
mtd
->
pairing
&&
mtd
->
pairing
->
get_wunit
)
return
mtd
->
pairing
->
get_wunit
(
mtd
,
info
);
return
info
->
pair
;
}
EXPORT_SYMBOL_GPL
(
mtd_pairing_info_to_wunit
);
/**
* mtd_pairing_groups - get the number of pairing groups
* @mtd: pointer to new MTD device info structure
*
* Returns the number of pairing groups.
*
* This number is usually equal to the number of bits exposed by a single
* cell, and can be used in conjunction with mtd_pairing_info_to_wunit()
* to iterate over all pages of a given pair.
*/
int
mtd_pairing_groups
(
struct
mtd_info
*
mtd
)
{
if
(
!
mtd
->
pairing
||
!
mtd
->
pairing
->
ngroups
)
return
1
;
return
mtd
->
pairing
->
ngroups
;
}
EXPORT_SYMBOL_GPL
(
mtd_pairing_groups
);
/**
/**
* add_mtd_device - register an MTD device
* add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure
* @mtd: pointer to new MTD device info structure
...
...
drivers/mtd/mtdpart.c
View file @
69db4aa4
...
@@ -409,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
...
@@ -409,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave
->
mtd
.
oobsize
=
master
->
oobsize
;
slave
->
mtd
.
oobsize
=
master
->
oobsize
;
slave
->
mtd
.
oobavail
=
master
->
oobavail
;
slave
->
mtd
.
oobavail
=
master
->
oobavail
;
slave
->
mtd
.
subpage_sft
=
master
->
subpage_sft
;
slave
->
mtd
.
subpage_sft
=
master
->
subpage_sft
;
slave
->
mtd
.
pairing
=
master
->
pairing
;
slave
->
mtd
.
name
=
name
;
slave
->
mtd
.
name
=
name
;
slave
->
mtd
.
owner
=
master
->
owner
;
slave
->
mtd
.
owner
=
master
->
owner
;
...
...
include/linux/mtd/mtd.h
View file @
69db4aa4
...
@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops {
...
@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops {
struct
mtd_oob_region
*
oobfree
);
struct
mtd_oob_region
*
oobfree
);
};
};
/**
* struct mtd_pairing_info - page pairing information
*
* @pair: pair id
* @group: group id
*
* The term "pair" is used here, even though TLC NANDs might group pages by 3
* (3 bits in a single cell). A pair should regroup all pages that are sharing
* the same cell. Pairs are then indexed in ascending order.
*
* @group is defining the position of a page in a given pair. It can also be
* seen as the bit position in the cell: page attached to bit 0 belongs to
* group 0, page attached to bit 1 belongs to group 1, etc.
*
* Example:
* The H27UCG8T2BTR-BC datasheet describes the following pairing scheme:
*
* group-0 group-1
*
* pair-0 page-0 page-4
* pair-1 page-1 page-5
* pair-2 page-2 page-8
* ...
* pair-127 page-251 page-255
*
*
* Note that the "group" and "pair" terms were extracted from Samsung and
* Hynix datasheets, and might be referenced under other names in other
* datasheets (Micron is describing this concept as "shared pages").
*/
struct
mtd_pairing_info
{
int
pair
;
int
group
;
};
/**
* struct mtd_pairing_scheme - page pairing scheme description
*
* @ngroups: number of groups. Should be related to the number of bits
* per cell.
* @get_info: converts a write-unit (page number within an erase block) into
* mtd_pairing information (pair + group). This function should
* fill the info parameter based on the wunit index or return
* -EINVAL if the wunit parameter is invalid.
* @get_wunit: converts pairing information into a write-unit (page) number.
* This function should return the wunit index pointed by the
* pairing information described in the info argument. It should
* return -EINVAL, if there's no wunit corresponding to the
* passed pairing information.
*
* See mtd_pairing_info documentation for a detailed explanation of the
* pair and group concepts.
*
* The mtd_pairing_scheme structure provides a generic solution to represent
* NAND page pairing scheme. Instead of exposing two big tables to do the
* write-unit <-> (pair + group) conversions, we ask the MTD drivers to
* implement the ->get_info() and ->get_wunit() functions.
*
* MTD users will then be able to query these information by using the
* mtd_pairing_info_to_wunit() and mtd_wunit_to_pairing_info() helpers.
*
* @ngroups is here to help MTD users iterating over all the pages in a
* given pair. This value can be retrieved by MTD users using the
* mtd_pairing_groups() helper.
*
* Examples are given in the mtd_pairing_info_to_wunit() and
* mtd_wunit_to_pairing_info() documentation.
*/
struct
mtd_pairing_scheme
{
int
ngroups
;
int
(
*
get_info
)(
struct
mtd_info
*
mtd
,
int
wunit
,
struct
mtd_pairing_info
*
info
);
int
(
*
get_wunit
)(
struct
mtd_info
*
mtd
,
const
struct
mtd_pairing_info
*
info
);
};
struct
module
;
/* only needed for owner field in mtd_info */
struct
module
;
/* only needed for owner field in mtd_info */
struct
mtd_info
{
struct
mtd_info
{
...
@@ -188,6 +264,9 @@ struct mtd_info {
...
@@ -188,6 +264,9 @@ struct mtd_info {
/* OOB layout description */
/* OOB layout description */
const
struct
mtd_ooblayout_ops
*
ooblayout
;
const
struct
mtd_ooblayout_ops
*
ooblayout
;
/* NAND pairing scheme, only provided for MLC/TLC NANDs */
const
struct
mtd_pairing_scheme
*
pairing
;
/* the ecc step size. */
/* the ecc step size. */
unsigned
int
ecc_step_size
;
unsigned
int
ecc_step_size
;
...
@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
...
@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
mtd
->
ooblayout
=
ooblayout
;
mtd
->
ooblayout
=
ooblayout
;
}
}
static
inline
void
mtd_set_pairing_scheme
(
struct
mtd_info
*
mtd
,
const
struct
mtd_pairing_scheme
*
pairing
)
{
mtd
->
pairing
=
pairing
;
}
static
inline
void
mtd_set_of_node
(
struct
mtd_info
*
mtd
,
static
inline
void
mtd_set_of_node
(
struct
mtd_info
*
mtd
,
struct
device_node
*
np
)
struct
device_node
*
np
)
{
{
...
@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
...
@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
return
ops
->
mode
==
MTD_OPS_AUTO_OOB
?
mtd
->
oobavail
:
mtd
->
oobsize
;
return
ops
->
mode
==
MTD_OPS_AUTO_OOB
?
mtd
->
oobavail
:
mtd
->
oobsize
;
}
}
int
mtd_wunit_to_pairing_info
(
struct
mtd_info
*
mtd
,
int
wunit
,
struct
mtd_pairing_info
*
info
);
int
mtd_pairing_info_to_wunit
(
struct
mtd_info
*
mtd
,
const
struct
mtd_pairing_info
*
info
);
int
mtd_pairing_groups
(
struct
mtd_info
*
mtd
);
int
mtd_erase
(
struct
mtd_info
*
mtd
,
struct
erase_info
*
instr
);
int
mtd_erase
(
struct
mtd_info
*
mtd
,
struct
erase_info
*
instr
);
int
mtd_point
(
struct
mtd_info
*
mtd
,
loff_t
from
,
size_t
len
,
size_t
*
retlen
,
int
mtd_point
(
struct
mtd_info
*
mtd
,
loff_t
from
,
size_t
len
,
size_t
*
retlen
,
void
**
virt
,
resource_size_t
*
phys
);
void
**
virt
,
resource_size_t
*
phys
);
...
@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
...
@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
return
do_div
(
sz
,
mtd
->
writesize
);
return
do_div
(
sz
,
mtd
->
writesize
);
}
}
static
inline
int
mtd_wunit_per_eb
(
struct
mtd_info
*
mtd
)
{
return
mtd
->
erasesize
/
mtd
->
writesize
;
}
static
inline
int
mtd_offset_to_wunit
(
struct
mtd_info
*
mtd
,
loff_t
offs
)
{
return
mtd_div_by_ws
(
mtd_mod_by_eb
(
offs
,
mtd
),
mtd
);
}
static
inline
loff_t
mtd_wunit_to_offset
(
struct
mtd_info
*
mtd
,
loff_t
base
,
int
wunit
)
{
return
base
+
(
wunit
*
mtd
->
writesize
);
}
static
inline
int
mtd_has_oob
(
const
struct
mtd_info
*
mtd
)
static
inline
int
mtd_has_oob
(
const
struct
mtd_info
*
mtd
)
{
{
return
mtd
->
_read_oob
&&
mtd
->
_write_oob
;
return
mtd
->
_read_oob
&&
mtd
->
_write_oob
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment