aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorHuang Shijie <b32955@freescale.com>2014-01-02 22:01:42 -0500
committerBrian Norris <computersforpeace@gmail.com>2014-03-11 01:42:31 -0400
commitb8e2931d168724ca95d275f4f825636bff82a9e8 (patch)
tree61961baf8a7c1febcc405b6eeb60affe681d3ab1 /drivers/mtd/nand
parent4a57d670a9edb56d7cbc8d9075c7b242e0670ecf (diff)
mtd: gpmi: add subpage read support
1) Why add the subpage read support? The page size of the nand chip becomes larger and larger, the imx6 has to supports the 16K page or even bigger page. But sometimes, the upper layer only needs a small part of the page, such as 512 bytes or less. For example, ubiattach may only read 64 bytes per page. 2) We only enable the subpage read support when it meets the conditions: <1> the chip is imx6 (or later chips) which can supports large nand page. <2> the size of ECC parity is byte aligned. If the size of ECC parity is not byte aligned, the calling of NAND_CMD_RNDOUT will fail. 3) What does this patch do? This patch will fake a virtual small page for the subpage read, and call the gpmi_ecc_read_page() to do the real work. In order to fake a virtual small page, the patch changes the BCH registers and the bch_geometry{}. After the subpage read finished, we will restore them back. 4) Performace: 4.1) Tested with Toshiba TC58NVG2S0F(4096 + 224) with the following command: #ubiattach /dev/ubi_ctrl -m 4 The detail information of /dev/mtd4 shows below: -------------------------------------------------------------- #mtdinfo /dev/mtd4 mtd4 Name: test Type: nand Eraseblock size: 262144 bytes, 256.0 KiB Amount of eraseblocks: 1856 (486539264 bytes, 464.0 MiB) Minimum input/output unit size: 4096 bytes Sub-page size: 4096 bytes OOB size: 224 bytes Character device major/minor: 90:8 Bad blocks are allowed: true Device is writable: true -------------------------------------------------------------- 4.2) Before this patch: -------------------------------------------------------------- [ 94.530495] UBI: attaching mtd4 to ubi0 [ 98.928850] UBI: scanning is finished [ 98.953594] UBI: attached mtd4 (name "test", size 464 MiB) to ubi0 [ 98.958562] UBI: PEB size: 262144 bytes (256 KiB), LEB size: 253952 bytes [ 98.964076] UBI: min./max. I/O unit sizes: 4096/4096, sub-page size 4096 [ 98.969518] UBI: VID header offset: 4096 (aligned 4096), data offset: 8192 [ 98.975128] UBI: good PEBs: 1856, bad PEBs: 0, corrupted PEBs: 0 [ 98.979843] UBI: user volume: 1, internal volumes: 1, max. volumes count: 128 [ 98.985878] UBI: max/mean erase counter: 2/1, WL threshold: 4096, image sequence number: 2024916145 [ 98.993635] UBI: available PEBs: 0, total reserved PEBs: 1856, PEBs reserved for bad PEB handling: 40 [ 99.001807] UBI: background thread "ubi_bgt0d" started, PID 831 -------------------------------------------------------------- The attach time is about 98.9 - 94.5 = 4.4s 4.3) After this patch: -------------------------------------------------------------- [ 286.464906] UBI: attaching mtd4 to ubi0 [ 289.186129] UBI: scanning is finished [ 289.211416] UBI: attached mtd4 (name "test", size 464 MiB) to ubi0 [ 289.216360] UBI: PEB size: 262144 bytes (256 KiB), LEB size: 253952 bytes [ 289.221858] UBI: min./max. I/O unit sizes: 4096/4096, sub-page size 4096 [ 289.227293] UBI: VID header offset: 4096 (aligned 4096), data offset: 8192 [ 289.232878] UBI: good PEBs: 1856, bad PEBs: 0, corrupted PEBs: 0 [ 289.237628] UBI: user volume: 0, internal volumes: 1, max. volumes count: 128 [ 289.243553] UBI: max/mean erase counter: 1/1, WL threshold: 4096, image sequence number: 2024916145 [ 289.251348] UBI: available PEBs: 1812, total reserved PEBs: 44, PEBs reserved for bad PEB handling: 40 [ 289.259417] UBI: background thread "ubi_bgt0d" started, PID 847 -------------------------------------------------------------- The attach time is about 289.18 - 286.46 = 2.7s 4.4) The conclusion: We achieve (4.4 - 2.7) / 4.4 = 38.6% faster in the ubiattach. Signed-off-by: Huang Shijie <b32955@freescale.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 5aaa7f541ea1..bb77f750e75a 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -27,6 +27,7 @@
27#include <linux/of_device.h> 27#include <linux/of_device.h>
28#include <linux/of_mtd.h> 28#include <linux/of_mtd.h>
29#include "gpmi-nand.h" 29#include "gpmi-nand.h"
30#include "bch-regs.h"
30 31
31/* Resource names for the GPMI NAND driver. */ 32/* Resource names for the GPMI NAND driver. */
32#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" 33#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
@@ -1049,6 +1050,90 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1049 return max_bitflips; 1050 return max_bitflips;
1050} 1051}
1051 1052
1053/* Fake a virtual small page for the subpage read */
1054static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
1055 uint32_t offs, uint32_t len, uint8_t *buf, int page)
1056{
1057 struct gpmi_nand_data *this = chip->priv;
1058 void __iomem *bch_regs = this->resources.bch_regs;
1059 struct bch_geometry old_geo = this->bch_geometry;
1060 struct bch_geometry *geo = &this->bch_geometry;
1061 int size = chip->ecc.size; /* ECC chunk size */
1062 int meta, n, page_size;
1063 u32 r1_old, r2_old, r1_new, r2_new;
1064 unsigned int max_bitflips;
1065 int first, last, marker_pos;
1066 int ecc_parity_size;
1067 int col = 0;
1068
1069 /* The size of ECC parity */
1070 ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
1071
1072 /* Align it with the chunk size */
1073 first = offs / size;
1074 last = (offs + len - 1) / size;
1075
1076 /*
1077 * Find the chunk which contains the Block Marker. If this chunk is
1078 * in the range of [first, last], we have to read out the whole page.
1079 * Why? since we had swapped the data at the position of Block Marker
1080 * to the metadata which is bound with the chunk 0.
1081 */
1082 marker_pos = geo->block_mark_byte_offset / size;
1083 if (last >= marker_pos && first <= marker_pos) {
1084 dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n",
1085 page, first, last, marker_pos);
1086 return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
1087 }
1088
1089 meta = geo->metadata_size;
1090 if (first) {
1091 col = meta + (size + ecc_parity_size) * first;
1092 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
1093
1094 meta = 0;
1095 buf = buf + first * size;
1096 }
1097
1098 /* Save the old environment */
1099 r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
1100 r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
1101
1102 /* change the BCH registers and bch_geometry{} */
1103 n = last - first + 1;
1104 page_size = meta + (size + ecc_parity_size) * n;
1105
1106 r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
1107 BM_BCH_FLASH0LAYOUT0_META_SIZE);
1108 r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
1109 | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
1110 writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
1111
1112 r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
1113 r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
1114 writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
1115
1116 geo->ecc_chunk_count = n;
1117 geo->payload_size = n * size;
1118 geo->page_size = page_size;
1119 geo->auxiliary_status_offset = ALIGN(meta, 4);
1120
1121 dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
1122 page, offs, len, col, first, n, page_size);
1123
1124 /* Read the subpage now */
1125 this->swap_block_mark = false;
1126 max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page);
1127
1128 /* Restore */
1129 writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
1130 writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
1131 this->bch_geometry = old_geo;
1132 this->swap_block_mark = true;
1133
1134 return max_bitflips;
1135}
1136
1052static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, 1137static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
1053 const uint8_t *buf, int oob_required) 1138 const uint8_t *buf, int oob_required)
1054{ 1139{
@@ -1566,6 +1651,17 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
1566 ecc->layout = &gpmi_hw_ecclayout; 1651 ecc->layout = &gpmi_hw_ecclayout;
1567 1652
1568 /* 1653 /*
1654 * We only enable the subpage read when:
1655 * (1) the chip is imx6, and
1656 * (2) the size of the ECC parity is byte aligned.
1657 */
1658 if (GPMI_IS_MX6Q(this) &&
1659 ((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
1660 ecc->read_subpage = gpmi_ecc_read_subpage;
1661 chip->options |= NAND_SUBPAGE_READ;
1662 }
1663
1664 /*
1569 * Can we enable the extra features? such as EDO or Sync mode. 1665 * Can we enable the extra features? such as EDO or Sync mode.
1570 * 1666 *
1571 * We do not check the return value now. That's means if we fail in 1667 * We do not check the return value now. That's means if we fail in