summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-11-25 13:53:58 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-11-25 13:53:58 -0600
commit9c60ac0adfa13460a6a670e864039b7030074495 (patch)
tree984d4858bd3d3c98f5c1ad2c267a0aedcaf83305
parentd0ae57d1bdbaa17cb2731778d5a63bb816eb222c (diff)
downloadnuttx-9c60ac0adfa13460a6a670e864039b7030074495.tar.gz
nuttx-9c60ac0adfa13460a6a670e864039b7030074495.tar.bz2
nuttx-9c60ac0adfa13460a6a670e864039b7030074495.zip
SAMA5 NAND: Fix a few race conditions
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.c28
-rwxr-xr-xnuttx/drivers/mtd/mtd_nand.c51
2 files changed, 59 insertions, 20 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.c b/nuttx/arch/arm/src/sama5/sam_nand.c
index 07933477a..a1dd18f36 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.c
+++ b/nuttx/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/nuttx/drivers/mtd/mtd_nand.c b/nuttx/drivers/mtd/mtd_nand.c
index c090da9d1..519e5f7af 100755
--- a/nuttx/drivers/mtd/mtd_nand.c
+++ b/nuttx/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 */