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:
Petro Karashchenko 2022-09-16 15:26:49 +02:00 committed by Xiang Xiao
parent 9c229a0173
commit 4fc76ea661

View File

@ -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