summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-11-29 11:52:47 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-11-29 11:52:47 -0600
commit674c572b8d08f323d0ccb4abd33b645829fa7163 (patch)
treec40f5ed2a0c8a67f4e36865afdffcf0ddce9662f
parentfdc526e875090915228594c122de65a1e54cb5c9 (diff)
downloadnuttx-674c572b8d08f323d0ccb4abd33b645829fa7163.tar.gz
nuttx-674c572b8d08f323d0ccb4abd33b645829fa7163.tar.bz2
nuttx-674c572b8d08f323d0ccb4abd33b645829fa7163.zip
SAMA5 NAND: Don't use HSMC interrupts. They occur to quickly and cause mysterious race conditions
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.c54
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.h13
-rw-r--r--nuttx/fs/nxffs/nxffs_blockstats.c2
3 files changed, 67 insertions, 2 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.c b/nuttx/arch/arm/src/sama5/sam_nand.c
index 42f374128..b1a3cc95a 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.c
+++ b/nuttx/arch/arm/src/sama5/sam_nand.c
@@ -662,6 +662,7 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
static void nand_wait_cmddone(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
int ret;
@@ -683,6 +684,12 @@ static void nand_wait_cmddone(struct sam_nandcs_s *priv)
g_nand.cmddone = false;
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_CMDDONE);
irqrestore(flags);
+
+#else
+ /* Poll for the CMDDONE event */
+
+ while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_CMDDONE) == 0);
+#endif
}
/****************************************************************************
@@ -701,6 +708,7 @@ static void nand_wait_cmddone(struct sam_nandcs_s *priv)
static void nand_setup_cmddone(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
/* Clear all pending interrupts. This must be done with interrupts
@@ -718,6 +726,11 @@ static void nand_setup_cmddone(struct sam_nandcs_s *priv)
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_CMDDONE);
irqrestore(flags);
+#else
+ /* Just clear any pending CMDDONE status */
+
+ nand_getreg(SAM_HSMC_SR);
+#endif
}
/****************************************************************************
@@ -736,6 +749,7 @@ static void nand_setup_cmddone(struct sam_nandcs_s *priv)
static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
int ret;
@@ -757,6 +771,12 @@ static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
g_nand.xfrdone = false;
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_XFRDONE);
irqrestore(flags);
+
+#else
+ /* Poll for the XFRDONE event */
+
+ while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_XFRDONE) == 0);
+#endif
}
/****************************************************************************
@@ -775,6 +795,7 @@ static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
/* Clear all pending interrupts. This must be done with interrupts
@@ -792,6 +813,11 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_XFRDONE);
irqrestore(flags);
+#else
+ /* Just clear any pending XFRDONE status */
+
+ nand_getreg(SAM_HSMC_SR);
+#endif
}
/****************************************************************************
@@ -810,6 +836,7 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
static void nand_wait_rbedge(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
int ret;
@@ -831,6 +858,12 @@ static void nand_wait_rbedge(struct sam_nandcs_s *priv)
g_nand.rbedge = false;
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_RBEDGE0);
irqrestore(flags);
+
+#else
+ /* Poll for the RBEDGE0 event */
+
+ while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_RBEDGE0) == 0);
+#endif
}
/****************************************************************************
@@ -849,6 +882,7 @@ static void nand_wait_rbedge(struct sam_nandcs_s *priv)
static void nand_setup_rbedge(struct sam_nandcs_s *priv)
{
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
/* Clear all pending interrupts. This must be done with interrupts
@@ -866,6 +900,12 @@ static void nand_setup_rbedge(struct sam_nandcs_s *priv)
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_RBEDGE0);
irqrestore(flags);
+
+#else
+ /* Just clear any pending RBEDGE0 status */
+
+ nand_getreg(SAM_HSMC_SR);
+#endif
}
/****************************************************************************
@@ -882,6 +922,7 @@ static void nand_setup_rbedge(struct sam_nandcs_s *priv)
*
****************************************************************************/
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
static int hsmc_interrupt(int irq, void *context)
{
uint32_t sr = nand_getreg(SAM_HSMC_SR);
@@ -924,6 +965,7 @@ static int hsmc_interrupt(int irq, void *context)
return OK;
}
+#endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */
/****************************************************************************
* Name: nand_wait_dma
@@ -1251,6 +1293,8 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
#endif
int buswidth;
+ fvdbg("nfcsram=%d buffer=%p buflen=%d\n", nfcsram, buffer, (int)buflen);
+
/* Get the buswidth */
buswidth = nandmodel_getbuswidth(&priv->raw.model);
@@ -1550,6 +1594,9 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
#endif
int buswidth;
+ fvdbg("nfcsram=%d buffer=%p buflen=%d offset=%d\n",
+ nfcsram, buffer, (int)buflen, (int)offset);
+
/* Get the buswidth */
buswidth = nandmodel_getbuswidth(&priv->raw.model);
@@ -2615,7 +2662,9 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
#if NAND_NBANKS > 1
sem_init(&g_nand.exclsem, 0, 1);
#endif
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
sem_init(&g_nand.waitsem, 0, 0);
+#endif
/* Enable the NAND FLASH Controller (The NFC is always used) */
@@ -2634,6 +2683,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
nand_putreg(SAM_HSMC_PMECCFG, 0);
#endif
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
/* Attach the CAN interrupt handler */
ret = irq_attach(SAM_IRQ_HSMC, hsmc_interrupt);
@@ -2642,15 +2692,17 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
fdbg("Failed to attach HSMC IRQ (%d)", SAM_IRQ_HSMC);
return NULL;
}
-
+#endif
/* Disable all interrupts at the HSMC */
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_ALL);
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
/* Enable the HSMC interrupts at the interrupt controller */
up_enable_irq(SAM_IRQ_HSMC);
g_nand.initialized = true;
+#endif
}
/* Initialize the NAND hardware for this CS */
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.h b/nuttx/arch/arm/src/sama5/sam_nand.h
index 2f6fa7313..88554a65f 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.h
+++ b/nuttx/arch/arm/src/sama5/sam_nand.h
@@ -233,6 +233,17 @@
#ifdef CONFIG_SAMA5_HAVE_NAND
+/* An early version of this driver used SMC interrupts to determine when
+ * NAND commands completed, transfers completed, and RB edges occurred. It
+ * turns out that those interrupts occurred so quickly that some really
+ * nasty race conditions were created. Rather than resolve those, I simply
+ * disabled the interrupt logic with this setting. The setting is retained
+ * in case, for some reason, someone wants to restore the interrupt-driven
+ * logic. Polling should be better solution in this case.
+ */
+
+#undef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
+
/****************************************************************************
* Public Types
****************************************************************************/
@@ -274,10 +285,12 @@ struct sam_nand_s
/* Dynamic state */
+#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
volatile bool cmddone; /* True: NFC command has completed */
volatile bool xfrdone; /* True: Transfer has completed */
volatile bool rbedge; /* True: Ready/busy edge detected */
sem_t waitsem; /* Used to wait for one of the above states */
+#endif
#ifdef CONFIG_SAMA5_HAVE_PMECC
uint8_t ecctab[CONFIG_MTD_NAND_MAX_PMECCSIZE];
diff --git a/nuttx/fs/nxffs/nxffs_blockstats.c b/nuttx/fs/nxffs/nxffs_blockstats.c
index d8f30a40e..89188a353 100644
--- a/nuttx/fs/nxffs/nxffs_blockstats.c
+++ b/nuttx/fs/nxffs/nxffs_blockstats.c
@@ -157,6 +157,6 @@ int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
fdbg(" Bad blocks: %d\n", stats->nbad);
fdbg(" Unformatted blocks: %d\n", stats->nunformat);
fdbg(" Corrupt blocks: %d\n", stats->ncorrupt);
- fdbg(" Undreadable blocks: %d\n", stats->nbadread);
+ fdbg(" Unreadable blocks: %d\n", stats->nbadread);
return OK;
}