SAMA5 NAND: PMECC logic was reading past the end of the user buffer

This commit is contained in:
Gregory Nutt 2013-12-04 13:14:26 -06:00
parent ae01f868b2
commit adc0b36c8f
2 changed files with 42 additions and 18 deletions

View File

@ -1556,7 +1556,7 @@ static int nand_smc_read16(uintptr_t src, uint8_t *dest, size_t buflen)
****************************************************************************/
static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
uint8_t *buffer, size_t buflen)
uint8_t *buffer, size_t buflen)
{
uintptr_t src;
#ifdef CONFIG_SAMA5_NAND_DMA
@ -1642,15 +1642,13 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
* Name: nand_read_pmecc
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers.
* Reads the data area of a page of a NAND FLASH into the provided buffer.
*
* Input parameters:
* priv - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to read resides.
* page - Number of the page to read inside the given block.
* data - Buffer where the data area will be stored.
* spare - Buffer where the spare area will be stored.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
@ -1733,7 +1731,7 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN | HSMC_CLE_DATA_EN,
COMMAND_READ_1, COMMAND_READ_2, 0, rowaddr);
/* Reset the ECC module*/
/* Reset the PMECC module */
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_RST);
@ -1741,14 +1739,24 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_DATA);
regval = nand_getreg(SAM_HSMC_PMECCEADDR);
ret = nand_read(priv, true, (uint8_t *)data, pagesize + (regval + 1));
/* Read the data area */
ret = nand_read(priv, true, (uint8_t *)data, pagesize);
if (ret < 0)
{
fdbg("ERROR: nand_read for data region failed: %d\n", ret);
return ret;
}
/* Read the spare area into priv->raw.spare */
ret = nand_read(priv, true, priv->raw.spare, priv->raw.model.sparesize);
if (ret < 0)
{
fdbg("ERROR: nand_read for spare region failed: %d\n", ret);
return ret;
}
/* Wait until the kernel of the PMECC is not busy */
while((nand_getreg(SAM_HSMC_PMECCSR) & HSMC_PMECCSR_BUSY) != 0);
@ -2079,7 +2087,7 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
#ifdef CONFIG_SAMA5_HAVE_PMECC
static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, void *data)
unsigned int page, void *data)
{
uint32_t regval;
uint16_t sparesize;
@ -2101,9 +2109,9 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
goto errout;
}
/* Start by reading the spare data */
sparesize = nandmodel_getsparesize(&priv->raw.model);
/* Read page data into the user data buffer and spared data
* into the priv->raw.spare buffer.
*/
ret = nand_read_pmecc(priv, block, page, data);
if (ret < 0)
@ -2112,12 +2120,22 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
goto errout;
}
/* Check if any sector is corrupted */
regval = nand_getreg(SAM_HSMC_PMECCISR);
if (regval)
{
/* Check if the spare area was erased */
fdbg("ERROR: block=%d page=%d Corrupted sectors: %08x\n",
block, page, regval);
nand_readpage_noecc(priv, block, page, NULL, priv->raw.spare);
/* Check if the spare area was erased
* REVISIT: Necessary to re-read. Isn't the spare data alread
* intack in priv->raw.spare from nand_read_pmecc()?
*/
//nand_readpage_noecc(priv, block, page, NULL, priv->raw.spare);
sparesize = nandmodel_getsparesize(&priv->raw.model);
for (i = 0 ; i < sparesize; i++)
{
if (priv->raw.spare[i] != 0xff)
@ -2130,6 +2148,8 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
if (i >= sparesize)
{
/* Clear sector errors */
regval = 0;
}
}
@ -2300,7 +2320,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
ret = -EPERM;
}
nand_nfc_cleale(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2,0, 0, 0);
nand_nfc_cleale(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_wait_ready(priv);
}

View File

@ -592,7 +592,7 @@ static int32_t pmecc_errorlocation(uint32_t bitsize)
****************************************************************************/
#ifndef CONFIG_SAMA5_PMECC_EMBEDDEDALGO
static uint32_t pmecc_errorcorrection(uint32_t sectorbase,
static uint32_t pmecc_errorcorrection(uintptr_t sectorbase,
uint32_t extrabytes, uint32_t nerrors)
{
uint32_t *errpos;
@ -681,10 +681,10 @@ static uint32_t pmecc_errorcorrection(uint32_t sectorbase,
****************************************************************************/
#ifndef CONFIG_SAMA5_PMECC_EMBEDDEDALGO
static uint32_t pmecc_correctionalgo(uint32_t isr, uint32_t data)
static uint32_t pmecc_correctionalgo(uint32_t isr, uintptr_t data)
{
uintptr_t sectorbase;
uint32_t sector = 0;
uint32_t sectorbase;
uint32_t sectorsz;
int32_t nerrors;
unsigned int mm;
@ -1152,7 +1152,11 @@ int pmecc_configure(struct sam_nandcs_s *priv, bool protected)
return -ENOSPC;
}
g_pmecc.desc.sparesize = g_pmecc.desc.eccend;
/* Save the size of the spare area.
* REVISIT: Could we save a bit by setting this to eccend?
*/
g_pmecc.desc.sparesize = priv->raw.model.sparesize;
//g_pmecc.desc.nandwr = PMECC_CFG_NANDWR; /* NAND write access */
g_pmecc.desc.nandwr = 0; /* NAND Read access */