arch/arm/samv7: fix random corruption of data after SDIO RX DMA transaction
use time based timeout calculation instead of cycle based minor styling fixes Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
This commit is contained in:
parent
9c229a0173
commit
4fc76ea661
@ -120,10 +120,10 @@
|
|||||||
#undef HSCMI_NORXDMA /* Define to disable RX DMA */
|
#undef HSCMI_NORXDMA /* Define to disable RX DMA */
|
||||||
#undef HSCMI_NOTXDMA /* Define to disable TX DMA */
|
#undef HSCMI_NOTXDMA /* Define to disable TX DMA */
|
||||||
|
|
||||||
/* Timing */
|
/* Timing : 100mS short timeout, 2 seconds for long one */
|
||||||
|
|
||||||
#define HSMCI_CMDTIMEOUT (100000)
|
#define HSMCI_CMDTIMEOUT MSEC2TICK(100)
|
||||||
#define HSMCI_LONGTIMEOUT (0x7fffffff)
|
#define HSMCI_LONGTIMEOUT MSEC2TICK(2000)
|
||||||
|
|
||||||
/* Big DTIMER setting */
|
/* Big DTIMER setting */
|
||||||
|
|
||||||
@ -404,16 +404,17 @@ static bool sam_checkreg(struct sam_dev_s *priv, bool wr,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint32_t sam_getreg(struct sam_dev_s *priv,
|
static inline uint32_t sam_getreg(struct sam_dev_s *priv,
|
||||||
unsigned int offset);
|
unsigned int offset);
|
||||||
static inline void sam_putreg(struct sam_dev_s *priv, uint32_t value,
|
static inline void sam_putreg(struct sam_dev_s *priv, uint32_t value,
|
||||||
unsigned int offset);
|
unsigned int offset);
|
||||||
|
|
||||||
static inline void sam_configwaitints(struct sam_dev_s *priv,
|
static inline void sam_configwaitints(struct sam_dev_s *priv,
|
||||||
uint32_t waitmask, sdio_eventset_t waitevents);
|
uint32_t waitmask,
|
||||||
|
sdio_eventset_t waitevents);
|
||||||
static void sam_disablewaitints(struct sam_dev_s *priv,
|
static void sam_disablewaitints(struct sam_dev_s *priv,
|
||||||
sdio_eventset_t wkupevent);
|
sdio_eventset_t wkupevent);
|
||||||
static inline void sam_configxfrints(struct sam_dev_s *priv,
|
static inline void sam_configxfrints(struct sam_dev_s *priv,
|
||||||
uint32_t xfrmask);
|
uint32_t xfrmask);
|
||||||
static void sam_disablexfrints(struct sam_dev_s *priv);
|
static void sam_disablexfrints(struct sam_dev_s *priv);
|
||||||
static inline void sam_enableints(struct sam_dev_s *priv);
|
static inline void sam_enableints(struct sam_dev_s *priv);
|
||||||
|
|
||||||
@ -458,14 +459,14 @@ static void sam_cmddump(struct sam_dev_s *priv);
|
|||||||
|
|
||||||
static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result);
|
static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result);
|
||||||
static inline uintptr_t hsmci_regaddr(struct sam_dev_s *priv,
|
static inline uintptr_t hsmci_regaddr(struct sam_dev_s *priv,
|
||||||
unsigned int offset);
|
unsigned int offset);
|
||||||
|
|
||||||
/* Data Transfer Helpers ****************************************************/
|
/* Data Transfer Helpers ****************************************************/
|
||||||
|
|
||||||
static void sam_eventtimeout(wdparm_t arg);
|
static void sam_eventtimeout(wdparm_t arg);
|
||||||
static void sam_endwait(struct sam_dev_s *priv, sdio_eventset_t wkupevent);
|
static void sam_endwait(struct sam_dev_s *priv, sdio_eventset_t wkupevent);
|
||||||
static void sam_endtransfer(struct sam_dev_s *priv,
|
static void sam_endtransfer(struct sam_dev_s *priv,
|
||||||
sdio_eventset_t wkupevent);
|
sdio_eventset_t wkupevent);
|
||||||
static void sam_notransfer(struct sam_dev_s *priv);
|
static void sam_notransfer(struct sam_dev_s *priv);
|
||||||
|
|
||||||
/* Interrupt Handling *******************************************************/
|
/* Interrupt Handling *******************************************************/
|
||||||
@ -481,48 +482,48 @@ static sdio_capset_t sam_capabilities(struct sdio_dev_s *dev);
|
|||||||
static sdio_statset_t sam_status(struct sdio_dev_s *dev);
|
static sdio_statset_t sam_status(struct sdio_dev_s *dev);
|
||||||
static void sam_widebus(struct sdio_dev_s *dev, bool enable);
|
static void sam_widebus(struct sdio_dev_s *dev, bool enable);
|
||||||
static void sam_clock(struct sdio_dev_s *dev,
|
static void sam_clock(struct sdio_dev_s *dev,
|
||||||
enum sdio_clock_e rate);
|
enum sdio_clock_e rate);
|
||||||
static int sam_attach(struct sdio_dev_s *dev);
|
static int sam_attach(struct sdio_dev_s *dev);
|
||||||
|
|
||||||
/* Command/Status/Data Transfer */
|
/* Command/Status/Data Transfer */
|
||||||
|
|
||||||
static int sam_sendcmd(struct sdio_dev_s *dev, uint32_t cmd,
|
static int sam_sendcmd(struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
uint32_t arg);
|
uint32_t arg);
|
||||||
static void sam_blocksetup(struct sdio_dev_s *dev, unsigned int blocklen,
|
static void sam_blocksetup(struct sdio_dev_s *dev, unsigned int blocklen,
|
||||||
unsigned int nblocks);
|
unsigned int nblocks);
|
||||||
static int sam_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer,
|
static int sam_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer,
|
||||||
size_t nbytes);
|
size_t nbytes);
|
||||||
static int sam_sendsetup(struct sdio_dev_s *dev,
|
static int sam_sendsetup(struct sdio_dev_s *dev,
|
||||||
const uint8_t *buffer, size_t nbytes);
|
const uint8_t *buffer, size_t nbytes);
|
||||||
static int sam_cancel(struct sdio_dev_s *dev);
|
static int sam_cancel(struct sdio_dev_s *dev);
|
||||||
static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd);
|
static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd);
|
||||||
static int sam_recvshort(struct sdio_dev_s *dev, uint32_t cmd,
|
static int sam_recvshort(struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
uint32_t *rshort);
|
uint32_t *rshort);
|
||||||
static int sam_recvlong(struct sdio_dev_s *dev, uint32_t cmd,
|
static int sam_recvlong(struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
uint32_t rlong[4]);
|
uint32_t rlong[4]);
|
||||||
static int sam_recvnotimpl(struct sdio_dev_s *dev, uint32_t cmd,
|
static int sam_recvnotimpl(struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
uint32_t *rnotimpl);
|
uint32_t *rnotimpl);
|
||||||
|
|
||||||
/* EVENT handler */
|
/* EVENT handler */
|
||||||
|
|
||||||
static void sam_waitenable(struct sdio_dev_s *dev,
|
static void sam_waitenable(struct sdio_dev_s *dev,
|
||||||
sdio_eventset_t eventset, uint32_t timeout);
|
sdio_eventset_t eventset, uint32_t timeout);
|
||||||
static sdio_eventset_t sam_eventwait(struct sdio_dev_s *dev);
|
static sdio_eventset_t sam_eventwait(struct sdio_dev_s *dev);
|
||||||
static void sam_callbackenable(struct sdio_dev_s *dev,
|
static void sam_callbackenable(struct sdio_dev_s *dev,
|
||||||
sdio_eventset_t eventset);
|
sdio_eventset_t eventset);
|
||||||
static int sam_registercallback(struct sdio_dev_s *dev,
|
static int sam_registercallback(struct sdio_dev_s *dev,
|
||||||
worker_t callback, void *arg);
|
worker_t callback, void *arg);
|
||||||
|
|
||||||
/* DMA */
|
/* DMA */
|
||||||
|
|
||||||
#ifdef CONFIG_SAMV7_HSMCI_DMA
|
#ifdef CONFIG_SAMV7_HSMCI_DMA
|
||||||
#ifndef HSCMI_NORXDMA
|
#ifndef HSCMI_NORXDMA
|
||||||
static int sam_dmarecvsetup(struct sdio_dev_s *dev,
|
static int sam_dmarecvsetup(struct sdio_dev_s *dev,
|
||||||
uint8_t *buffer, size_t buflen);
|
uint8_t *buffer, size_t buflen);
|
||||||
#endif
|
#endif
|
||||||
#ifndef HSCMI_NOTXDMA
|
#ifndef HSCMI_NOTXDMA
|
||||||
static int sam_dmasendsetup(struct sdio_dev_s *dev,
|
static int sam_dmasendsetup(struct sdio_dev_s *dev,
|
||||||
const uint8_t *buffer, size_t buflen);
|
const uint8_t *buffer, size_t buflen);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1572,6 +1573,21 @@ static int sam_hsmci_interrupt(int irq, void *context, void *arg)
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* If buffer is not NULL that means that RX DMA is finished.
|
||||||
|
* We need to invalidate RX buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->buffer != NULL)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(priv->remaining > 0);
|
||||||
|
|
||||||
|
up_invalidate_dcache((uintptr_t)priv->buffer,
|
||||||
|
(uintptr_t)priv->buffer +
|
||||||
|
priv->remaining);
|
||||||
|
priv->buffer = NULL;
|
||||||
|
priv->remaining = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* End the transfer */
|
/* End the transfer */
|
||||||
|
|
||||||
sam_endtransfer(priv, SDIOWAIT_TRANSFERDONE);
|
sam_endtransfer(priv, SDIOWAIT_TRANSFERDONE);
|
||||||
@ -2388,6 +2404,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd)
|
|||||||
struct sam_dev_s *priv = (struct sam_dev_s *)dev;
|
struct sam_dev_s *priv = (struct sam_dev_s *)dev;
|
||||||
uint32_t sr;
|
uint32_t sr;
|
||||||
uint32_t pending;
|
uint32_t pending;
|
||||||
|
clock_t watchtime;
|
||||||
int32_t timeout;
|
int32_t timeout;
|
||||||
|
|
||||||
switch (cmd & MMCSD_RESPONSE_MASK)
|
switch (cmd & MMCSD_RESPONSE_MASK)
|
||||||
@ -2415,6 +2432,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd)
|
|||||||
|
|
||||||
/* Then wait for the response (or timeout) */
|
/* Then wait for the response (or timeout) */
|
||||||
|
|
||||||
|
watchtime = clock_systime_ticks();
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
/* Did a Command-Response sequence termination event occur? */
|
/* Did a Command-Response sequence termination event occur? */
|
||||||
@ -2464,7 +2482,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (--timeout <= 0)
|
else if (clock_systime_ticks() - watchtime > timeout)
|
||||||
{
|
{
|
||||||
mcerr("ERROR: Timeout cmd: %08" PRIx32 " events: %08" PRIx32
|
mcerr("ERROR: Timeout cmd: %08" PRIx32 " events: %08" PRIx32
|
||||||
" SR: %08" PRIx32 "\n",
|
" SR: %08" PRIx32 "\n",
|
||||||
@ -3008,9 +3026,11 @@ static int sam_dmarecvsetup(struct sdio_dev_s *dev, uint8_t *buffer,
|
|||||||
|
|
||||||
/* Start the DMA */
|
/* Start the DMA */
|
||||||
|
|
||||||
priv->dmabusy = true;
|
priv->dmabusy = true;
|
||||||
priv->xfrbusy = true;
|
priv->xfrbusy = true;
|
||||||
priv->txbusy = false;
|
priv->txbusy = false;
|
||||||
|
priv->buffer = (uint32_t *)buffer;
|
||||||
|
priv->remaining = buflen;
|
||||||
sam_dmastart(priv->dma, sam_dmacallback, priv);
|
sam_dmastart(priv->dma, sam_dmacallback, priv);
|
||||||
|
|
||||||
/* Configure transfer-related interrupts. Transfer interrupts are not
|
/* Configure transfer-related interrupts. Transfer interrupts are not
|
||||||
|
Loading…
Reference in New Issue
Block a user