Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba507073 authored by Anjana Hari's avatar Anjana Hari
Browse files

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 Image Start Loading  | 13.5542  | 14.6176 | 1.0634|
| Modem out of reset         | 19.8452  | 20.9962 | 1.151 |

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

| Parameter                  | With OCW | W/o OCW | Delta |
| min_read_time_us           | 70       | 340.6   | 270.6 |
| total_read_time_us         | 17737604 | 18603376| 865772|.

Change-Id: I1df9ea7b9193a900b38e3d7a4fe38e2212bbf705
Signed-off-by: default avatarAnjana Hari <ahari@codeaurora.org>
parent 32496ef3
Loading
Loading
Loading
Loading
+67 −19
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#define MAX_DESC 16
#define SMEM_AARM_PARTITION_TABLE 9
#define SMEM_APPS 0
#define ONE_CODEWORD_SIZE 516

static bool enable_euclean;
static bool enable_perfstats;

@@ -1183,10 +1185,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);
@@ -1199,6 +1207,9 @@ 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) {
			if (ops->len <= ONE_CODEWORD_SIZE)
				args->page_count = 1;
			else
				args->page_count = ops->len / mtd->writesize;
		}
	}
@@ -1245,12 +1256,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;
@@ -1258,7 +1277,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;
@@ -1302,6 +1321,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];
@@ -1394,10 +1418,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;
			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);
				last_read = (curr_cw < (args->cwperpage - 1)) ?
					1 : (ops->oobbuf ? 0 : 1);
			}
			rdata = (offset << 0) | (size << 16) |
				(last_read << 31);

@@ -1413,7 +1442,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)
@@ -1471,6 +1500,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;
@@ -1479,7 +1513,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 */
@@ -1494,7 +1528,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,
@@ -1507,8 +1541,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;
@@ -1516,7 +1555,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,
@@ -1528,7 +1567,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;
@@ -2755,6 +2794,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;

@@ -3052,6 +3094,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
	}
validate_mtd_params_failed:
	if (ops->mode != MTD_OPS_RAW)
		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;
@@ -3125,8 +3170,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;