mtd: msm_qpic_nand: Add support to read one codeword

When the read requests received from upper layer are less
than 516 bytes, then instead of reading the entire page, we
can read only one codeword, thereby improving the read
performance. This support is only applicable if the data
requested lies in first codeword of the page.

Modem KPI markers:
All units in seconds

| Parameter                  | With OCW | W/o OCW | Delta |
| Modem out of reset         | 30.8725  | 32.4930 | 1.6205|

NAND Perf Stats:
Obtained by reading 1GB data. All units in usec

| Parameter                  | With OCW | W/o OCW | Delta |
| min_read_time_us           | 89       | 461     | 372   |
| total_read_time_us         | 31933843 | 32068374| 865772|.

Change-Id: I1df9ea7b9193a900b38e3d7a4fe38e2212bbf705
Signed-off-by: Anjana Hari <ahari@codeaurora.org>
This commit is contained in:
Anjana Hari 2020-06-18 22:24:24 +05:30 • committed by Gerrit - the friendly Code Review server
commit 12cd6098b0

View file

@ -17,6 +17,7 @@
#define MAX_DESC 16
#define SMEM_AARM_PARTITION_TABLE 9
#define SMEM_APPS 0
#define ONE_CODEWORD_SIZE 516
/*
* Get the DMA memory for requested amount of size. It returns the pointer
@ -1076,10 +1077,16 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read,
err = -EINVAL;
goto out;
}
args->page_count = ops->len / (mtd->writesize + mtd->oobsize);
if (ops->len <= ONE_CODEWORD_SIZE)
args->page_count = 1;
else
args->page_count = ops->len /
(mtd->writesize + mtd->oobsize);
} else if (ops->mode == MTD_OPS_AUTO_OOB) {
if (ops->datbuf && (ops->len % mtd->writesize) != 0) {
if (ops->datbuf && (ops->len %
((ops->len <= ONE_CODEWORD_SIZE) ?
ONE_CODEWORD_SIZE : mtd->writesize)) != 0) {
/* when ops->datbuf is NULL, ops->len can be ooblen */
pr_err("unsupported data len %d for AUTO mode\n",
ops->len);
@ -1092,7 +1099,10 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read,
if ((args->page_count == 0) && (ops->ooblen))
args->page_count = 1;
} else if (ops->datbuf) {
args->page_count = ops->len / mtd->writesize;
if (ops->len <= ONE_CODEWORD_SIZE)
args->page_count = 1;
else
args->page_count = ops->len / mtd->writesize;
}
}
@ -1138,12 +1148,20 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip,
struct msm_nand_rw_params *args,
struct msm_nand_rw_reg_data *data)
{
/*
* While reading one codeword, CW_PER_PAGE bits of QPIC_NAND_DEV0_CFG0
* should be set to 0, which implies 1 codeword per page. 'n' below,
* is used to configure cfg0 for reading one full page or one single
* codeword.
*/
int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1;
if (args->read) {
if (ops->mode != MTD_OPS_RAW) {
data->cmd = MSM_NAND_CMD_PAGE_READ_ECC;
data->cfg0 =
(chip->cfg0 & ~(7U << CW_PER_PAGE)) |
(((args->cwperpage-1) - args->start_sector)
(((args->cwperpage-n) - args->start_sector)
<< CW_PER_PAGE);
data->cfg1 = chip->cfg1;
data->ecc_bch_cfg = chip->ecc_bch_cfg;
@ -1151,7 +1169,7 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip,
data->cmd = MSM_NAND_CMD_PAGE_READ_ALL;
data->cfg0 =
(chip->cfg0_raw & ~(7U << CW_PER_PAGE)) |
(((args->cwperpage-1) - args->start_sector)
(((args->cwperpage-n) - args->start_sector)
<< CW_PER_PAGE);
data->cfg1 = chip->cfg1_raw;
data->ecc_bch_cfg = chip->ecc_cfg_raw;
@ -1195,6 +1213,11 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops,
uint32_t offset, size, last_read;
struct sps_command_element *curr_ce, *start_ce;
uint32_t *flags_ptr, *num_ce_ptr;
/*
* Variable to configure read_location register parameters
* while reading one codeword or one full page
*/
int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1;
if (curr_cw == args->start_sector) {
curr_ce = start_ce = &cmd_list->setup_desc.ce[0];
@ -1287,10 +1310,15 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops,
if (ops->mode == MTD_OPS_AUTO_OOB) {
if (ops->datbuf) {
offset = 0;
size = (curr_cw < (args->cwperpage - 1)) ? 516 :
(512 - ((args->cwperpage - 1) << 2));
last_read = (curr_cw < (args->cwperpage - 1)) ? 1 :
(ops->oobbuf ? 0 : 1);
if (ops->len <= ONE_CODEWORD_SIZE) {
size = ONE_CODEWORD_SIZE;
last_read = 1;
} else {
size = (curr_cw < (args->cwperpage - 1)) ? 516 :
(512 - ((args->cwperpage - 1) << 2));
last_read = (curr_cw < (args->cwperpage - 1)) ?
1 : (ops->oobbuf ? 0 : 1);
}
rdata = (offset << 0) | (size << 16) |
(last_read << 31);
@ -1306,7 +1334,7 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops,
curr_ce++;
}
}
if (curr_cw == (args->cwperpage - 1) && ops->oobbuf) {
if (curr_cw == (args->cwperpage - n) && ops->oobbuf) {
offset = 512 - ((args->cwperpage - 1) << 2);
size = (args->cwperpage) << 2;
if (size > args->oob_len_cmd)
@ -1364,6 +1392,11 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
uint32_t sectordatasize, sectoroobsize;
uint32_t sps_flags = 0;
int err = 0;
/*
* Variable to configure sectordatasize and sectoroobsize
* while reading one codeword or one full page.
*/
int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1;
if (args->read)
data_pipe_handle = info->sps.data_prod.handle;
@ -1372,7 +1405,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
if (ops->mode == MTD_OPS_RAW) {
if (ecc_parity_bytes && args->read) {
if (curr_cw == (args->cwperpage - 1))
if (curr_cw == (args->cwperpage - n))
sps_flags |= SPS_IOVEC_FLAG_INT;
/* read only ecc bytes */
@ -1387,7 +1420,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
sectordatasize = chip->cw_size;
if (!args->read)
sps_flags = SPS_IOVEC_FLAG_EOT;
if (curr_cw == (args->cwperpage - 1))
if (curr_cw == (args->cwperpage - n))
sps_flags |= SPS_IOVEC_FLAG_INT;
err = sps_transfer_one(data_pipe_handle,
@ -1400,8 +1433,13 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
}
} else if (ops->mode == MTD_OPS_AUTO_OOB) {
if (ops->datbuf) {
sectordatasize = (curr_cw < (args->cwperpage - 1))
? 516 : (512 - ((args->cwperpage - 1) << 2));
if (ops->len <= ONE_CODEWORD_SIZE)
sectordatasize = ONE_CODEWORD_SIZE;
else
sectordatasize =
(curr_cw < (args->cwperpage - 1))
? 516 :
(512 - ((args->cwperpage - 1) << 2));
if (!args->read) {
sps_flags = SPS_IOVEC_FLAG_EOT;
@ -1409,7 +1447,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
ops->oobbuf)
sps_flags = 0;
}
if ((curr_cw == (args->cwperpage - 1)) && !ops->oobbuf)
if ((curr_cw == (args->cwperpage - n)) && !ops->oobbuf)
sps_flags |= SPS_IOVEC_FLAG_INT;
err = sps_transfer_one(data_pipe_handle,
@ -1421,7 +1459,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
args->data_dma_addr_curr += sectordatasize;
}
if (ops->oobbuf && (curr_cw == (args->cwperpage - 1))) {
if (ops->oobbuf && (curr_cw == (args->cwperpage - n))) {
sectoroobsize = args->cwperpage << 2;
if (sectoroobsize > args->oob_len_data)
sectoroobsize = args->oob_len_data;
@ -2590,6 +2628,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
data.addr0 = (rw_params.page << 16) | rw_params.oob_col;
data.addr1 = (rw_params.page >> 16) & 0xff;
if (ops->len <= ONE_CODEWORD_SIZE)
cwperpage = 1;
for (n = rw_params.start_sector; n < cwperpage; n++) {
struct sps_command_element *curr_ce, *start_ce;
@ -2667,7 +2708,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
} else if (ops->mode == MTD_OPS_AUTO_OOB) {
if (ops->datbuf)
submitted_num_desc = cwperpage -
rw_params.start_sector;
rw_params.start_sector;
if (ops->oobbuf)
submitted_num_desc++;
}
@ -2846,7 +2887,10 @@ free_dma:
}
validate_mtd_params_failed:
if (ops->mode != MTD_OPS_RAW)
ops->retlen = mtd->writesize * pages_read;
if (ops->len <= ONE_CODEWORD_SIZE)
ops->retlen = ONE_CODEWORD_SIZE;
else
ops->retlen = mtd->writesize * pages_read;
else
ops->retlen = (mtd->writesize + mtd->oobsize) * pages_read;
ops->oobretlen = ops->ooblen - rw_params.oob_len_data;
@ -2917,8 +2961,11 @@ static int msm_nand_read_partial_page(struct mtd_info *mtd,
ops->datbuf = no_copy ? actual_buf : bounce_buf;
if (info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ)
err = msm_nand_read_pagescope(mtd, aligned_from, ops);
else
else {
if ((len <= ONE_CODEWORD_SIZE) && (offset == 0))
ops->len = ONE_CODEWORD_SIZE;
err = msm_nand_read_oob(mtd, aligned_from, ops);
}
if (err == -EUCLEAN) {
is_euclean = 1;
err = 0;