From 2be17cd41f1e791e63aaf0e8cb0b47f33738b72d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 25 Nov 2013 13:53:58 -0600 Subject: [PATCH] SAMA5 NAND: Fix a few race conditions --- arch/arm/src/sama5/sam_nand.c | 28 ++++++++++++------- drivers/mtd/mtd_nand.c | 51 +++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index 07933477ad..a1dd18f368 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -678,10 +678,12 @@ static void nand_setup_cmddone(struct sam_nandcs_s *priv) { irqstate_t flags; - /* Clear all pending interrupts */ + /* Clear all pending interrupts. This must be done with interrupts + * enabled or we could lose interrupts. + */ - flags = irqsave(); nand_getreg(SAM_HSMC_SR); + flags = irqsave(); /* Mark CMDDONE not received */ @@ -749,10 +751,12 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv) { irqstate_t flags; - /* Clear all pending interrupts */ + /* Clear all pending interrupts. This must be done with interrupts + * enabled or we could lose interrupts. + */ - flags = irqsave(); nand_getreg(SAM_HSMC_SR); + flags = irqsave(); /* Mark XFRDONE not received */ @@ -820,10 +824,12 @@ static void nand_setup_rbedge(struct sam_nandcs_s *priv) { irqstate_t flags; - /* Clear all pending interrupts */ + /* Clear all pending interrupts. This must be done with interrupts + * enabled or we could lose interrupts. + */ - flags = irqsave(); nand_getreg(SAM_HSMC_SR); + flags = irqsave(); /* Mark RBEDGE0 not received */ @@ -915,6 +921,7 @@ static int nand_wait_dma(struct sam_nandcs_s *priv) } } + fvdbg("Awakened: result=%d\n", priv->result); priv->dmadone = false; return priv->result; } @@ -967,6 +974,9 @@ static int nand_dma_read(struct sam_nandcs_s *priv, DEBUGASSERT(priv->dma); + fvdbg("vsrc=%08x vdest=%08x nbytes=%d\n", + (int)vsrc, (int)vdest, (int)nbytes); + /* Invalidate the destination memory buffer before performing the DMA (so * that nothing gets flushed later, corrupting the DMA transfer, and so * that memory will be re-cached after the DMA completes). @@ -1254,7 +1264,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram, static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block, unsigned int page, void *data) { - uint32_t rawaddr; + uint32_t rowaddr; uint32_t regval; uint16_t pagesize; uint16_t sparesize; @@ -1305,7 +1315,7 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block, /* Calculate actual address of the page */ - rawaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page; + rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page; /* Reset and enable the PMECC */ @@ -1323,7 +1333,7 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block, nand_nfc_configure(priv, HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN | HSMC_CLE_DATA_EN, - COMMAND_READ_1, COMMAND_READ_2, 0, rawaddr); + COMMAND_READ_1, COMMAND_READ_2, 0, rowaddr); /* Reset the ECC module*/ diff --git a/drivers/mtd/mtd_nand.c b/drivers/mtd/mtd_nand.c index c090da9d19..519e5f7af6 100755 --- a/drivers/mtd/mtd_nand.c +++ b/drivers/mtd/mtd_nand.c @@ -200,13 +200,14 @@ static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block) ret = NAND_RAWREAD(raw, block, 0, 0, spare); if (ret < 0) { - fdbg("ERROR: Cannot read page #0 of block #%d\n", block); + fdbg("ERROR: Failed to read page 0 of block %d\n", block); return ret; } nandscheme_readbadblockmarker(scheme, spare, &marker); if (marker != 0xff) { + fvdbg("Page 0 block %d marker=%02x\n", block, marker); return BADBLOCK; } @@ -215,13 +216,14 @@ static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block) ret = NAND_RAWREAD(raw, block, 1, 0, spare); if (ret < 0) { - fdbg("ERROR: Cannot read page #1 of block #%d\n", block); + fdbg("ERROR: Failed to read page 1 of block %d\n", block); return ret; } nandscheme_readbadblockmarker(scheme, spare, &marker); if (marker != 0xff) { + fvdbg("Page 1 block %d marker=%02x\n", block, marker); return BADBLOCK; } @@ -239,7 +241,7 @@ static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block) * nand - Pointer to a struct nand_dev_s instance. * * Returned Value: - * None + * OK (always) * ****************************************************************************/ @@ -250,6 +252,10 @@ static int nand_devscan(FAR struct nand_dev_s *nand) FAR struct nand_model_s *model; off_t nblocks; off_t block; +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + off_t good; + unsigned int ngood; +#endif int ret; DEBUGASSERT(nand && nand->raw); @@ -263,10 +269,14 @@ static int nand_devscan(FAR struct nand_dev_s *nand) /* Initialize block statuses */ - fvdbg("Retrieving bad block information ...\n"); + fvdbg("Retrieving bad block information. nblocks=%d\n", nblocks); /* Retrieve block status from their first page spare area */ +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + ngood = 0; +#endif + for (block = 0; block < nblocks; block++) { /* Read spare of first page */ @@ -274,6 +284,13 @@ static int nand_devscan(FAR struct nand_dev_s *nand) ret = nand_checkblock(nand, block); if (ret != GOODBLOCK) { +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + if (ngood > 0) + { + fvdbg("Good blocks: %u - %u\n", good, good + ngood); + ngood = 0; + } +#endif if (ret == BADBLOCK) { fvdbg("Block %u is bad\n", (unsigned int)block); @@ -284,8 +301,26 @@ static int nand_devscan(FAR struct nand_dev_s *nand) (unsigned int)block, ret); } } +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + else + { + if (ngood == 0) + { + good = block; + } + + ngood++; + } +#endif } +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + if (ngood > 0) + { + fvdbg("Good blocks: %u - %u\n", good, good + ngood); + } +#endif + return OK; } #endif /* CONFIG_MTD_NAND_BLOCKCHECK */ @@ -918,13 +953,7 @@ FAR struct mtd_dev_s *nand_initialize(FAR struct nand_raw_s *raw) /* Scan the device for bad blocks */ - ret = nand_devscan(nand); - if (ret < 0) - { - fdbg("ERROR: nandspare_intialize failed\n", ret); - kfree(nand); - return NULL; - } + (void)nand_devscan(nand); /* Return the implementation-specific state structure as the MTD device */