From dc464ad88e7b7c5e0014a1784edcdb2fdcb448fd Mon Sep 17 00:00:00 2001 From: Jon Povey Date: Mon, 17 May 2010 16:16:22 +0900 Subject: [PATCH] NAND/davinci: Fix segfault for hwecc4_infix reads Page reads using hwecc4_infix layout segfaulted for check_bad_blocks because the read assumed a valid data buffer, which check_bad_blocks does not use (it only passes a 6 byte buffer for the start of OOB). This version copes with undersized or missing data or oob buffers and uses random read commands within the page to skip unwanted areas of data/OOB for speed. NOTE: Running check_bad_blocks with this layout will be reading infix OOB locations, not manufacturer bad block markers. This means that if you check blocks written in infix layout they will appear good, but manufacturer- marked bad blocks may also appear good. If you want to scan for manufactuer-marked bad blocks, you need to enable raw_access before running check_bad_blocks, or use the non-infix layout. Signed-off-by: Jon Povey CC: David Brownell --- src/flash/nand/davinci.c | 74 +++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 96cbfeae..90219c69 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -338,6 +338,27 @@ static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_ target_write_u8(target, info->addr, page >> 24); } +static int davinci_seek_column(struct nand_device *nand, uint16_t column) +{ + struct davinci_nand *info = nand->controller_priv; + struct target *target = info->target; + + /* Random read, we must have issued a page read already */ + target_write_u8(target, info->cmd, NAND_CMD_RNDOUT); + + target_write_u8(target, info->addr, column); + + if (nand->page_size > 512) { + target_write_u8(target, info->addr, column >> 8); + target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART); + } + + if (!davinci_nand_ready(nand, 100)) + return ERROR_NAND_OPERATION_TIMEOUT; + + return ERROR_OK; +} + static int davinci_writepage_tail(struct nand_device *nand, uint8_t *oob, uint32_t oob_size) { @@ -599,6 +620,10 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { + int read_size; + int want_col, at_col; + int ret; + davinci_write_pagecmd(nand, NAND_CMD_READ0, page); /* large page devices need a start command */ @@ -610,18 +635,43 @@ static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page, /* NOTE: not bothering to compute and use ECC data for now */ - do { - /* write 512 bytes */ - davinci_read_block_data(nand, data, 512); - data += 512; - data_size -= 512; - - /* read this "out-of-band" data -- infix */ - davinci_read_block_data(nand, oob, 16); - oob += 16; - oob_size -= 16; - } while (data_size); - + want_col = 0; + at_col = 0; + while ((data && data_size) || (oob && oob_size)) { + + if (data && data_size) { + if (want_col != at_col) { + /* Reads are slow, so seek past them when we can */ + ret = davinci_seek_column(nand, want_col); + if (ret != ERROR_OK) + return ret; + at_col = want_col; + } + /* read 512 bytes or data_size, whichever is smaller*/ + read_size = data_size > 512 ? 512 : data_size; + davinci_read_block_data(nand, data, read_size); + data += read_size; + data_size -= read_size; + at_col += read_size; + } + want_col += 512; + + if (oob && oob_size) { + if (want_col != at_col) { + ret = davinci_seek_column(nand, want_col); + if (ret != ERROR_OK) + return ret; + at_col = want_col; + } + /* read this "out-of-band" data -- infix */ + read_size = oob_size > 16 ? 16 : oob_size; + davinci_read_block_data(nand, oob, read_size); + oob += read_size; + oob_size -= read_size; + at_col += read_size; + } + want_col += 16; + } return ERROR_OK; } -- 2.39.5