Work around yet another ChibiOS DMA/Cache bug

This commit is contained in:
inmarket 2017-10-02 13:25:54 +10:00
parent 8bf95a1128
commit cd4c389e48
2 changed files with 47 additions and 20 deletions

View File

@ -12,26 +12,39 @@
#include "gfile_fatfs_wrapper.h" #include "gfile_fatfs_wrapper.h"
#if HAL_USE_MMC_SPI && HAL_USE_SDC #if HAL_USE_MMC_SPI && HAL_USE_SDC
#error "cannot specify both MMC_SPI and SDC drivers" #error "cannot specify both MMC_SPI and SDC drivers"
#endif #endif
#if HAL_USE_MMC_SPI #if HAL_USE_MMC_SPI
extern MMCDriver MMCD1; extern MMCDriver MMCD1;
#elif HAL_USE_SDC #elif HAL_USE_SDC
extern SDCDriver SDCD1; extern SDCDriver SDCD1;
#else #else
#error "MMC_SPI or SDC driver must be specified" #error "MMC_SPI or SDC driver must be specified"
#endif #endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */ /* Correspondence between physical drive number and physical drive. */
#define MMC 0 #define MMC 0
#define SDC 0 #define SDC 0
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Initialize a Drive */
// WOW - Bugs galore!!! (in ChibiOS)
// Bugs:
// 1. ChibiOS DMA operations do not do the appropriate cache flushing or invalidating
// on cpu's that require it eg STM32F7 series.
// Instead they provide explicit dmaBufferInvalidate and dmaBufferFlush calls
// and rely on the user to explicitly flush the cache.
// Solution: We explicitly flush the cache after any possible DMA operation.
// 2. Unfortunately these explicit routines also have a bug. They assume that the
// specified data structure is aligned on a cache line boundary - not a good assumption.
// Solution: We increase the size provided to ChibiOS so that it does it properly.
// This assumes of course that we know the size of the cpu cache line.
#define CPU_CACHE_LINE_SIZE 32
#define CACHE_FLUSH(buf, sz) dmaBufferFlush((buf), (sz)+(CPU_CACHE_LINE_SIZE-1))
#define CACHE_INVALIDATE(buf, sz) dmaBufferInvalidate((buf), (sz)+(CPU_CACHE_LINE_SIZE-1))
/* Initialize a Drive */
DSTATUS disk_initialize ( DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */ BYTE drv /* Physical drive nmuber (0..) */
) )
@ -116,7 +129,7 @@ DRESULT disk_read (
return RES_NOTRDY; return RES_NOTRDY;
if (mmcStartSequentialRead(&MMCD1, sector)) if (mmcStartSequentialRead(&MMCD1, sector))
return RES_ERROR; return RES_ERROR;
dmaBufferFlush(buff, MMCSD_BLOCK_SIZE*count); CACHE_FLUSH(buff, MMCSD_BLOCK_SIZE*count);
while (count > 0) { while (count > 0) {
if (mmcSequentialRead(&MMCD1, buff)) if (mmcSequentialRead(&MMCD1, buff))
return RES_ERROR; return RES_ERROR;
@ -125,16 +138,16 @@ DRESULT disk_read (
} }
if (mmcStopSequentialRead(&MMCD1)) if (mmcStopSequentialRead(&MMCD1))
return RES_ERROR; return RES_ERROR;
dmaBufferInvalidate(buff, MMCSD_BLOCK_SIZE*count); CACHE_INVALIDATE(buff, MMCSD_BLOCK_SIZE*count);
return RES_OK; return RES_OK;
#else #else
case SDC: case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY) if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY; return RES_NOTRDY;
dmaBufferFlush(buff, MMCSD_BLOCK_SIZE*count); CACHE_FLUSH(buff, MMCSD_BLOCK_SIZE*count);
if (sdcRead(&SDCD1, sector, buff, count)) if (sdcRead(&SDCD1, sector, buff, count))
return RES_ERROR; return RES_ERROR;
dmaBufferInvalidate(buff, MMCSD_BLOCK_SIZE*count); CACHE_INVALIDATE(buff, MMCSD_BLOCK_SIZE*count);
return RES_OK; return RES_OK;
#endif #endif
} }
@ -163,7 +176,7 @@ DRESULT disk_write (
return RES_WRPRT; return RES_WRPRT;
if (mmcStartSequentialWrite(&MMCD1, sector)) if (mmcStartSequentialWrite(&MMCD1, sector))
return RES_ERROR; return RES_ERROR;
dmaBufferFlush(buff, MMCSD_BLOCK_SIZE*count); CACHE_FLUSH(buff, MMCSD_BLOCK_SIZE*count);
while (count > 0) { while (count > 0) {
if (mmcSequentialWrite(&MMCD1, buff)) if (mmcSequentialWrite(&MMCD1, buff))
return RES_ERROR; return RES_ERROR;
@ -177,7 +190,7 @@ DRESULT disk_write (
case SDC: case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY) if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY; return RES_NOTRDY;
dmaBufferFlush(buff, MMCSD_BLOCK_SIZE*count); CACHE_FLUSH(buff, MMCSD_BLOCK_SIZE*count);
if (sdcWrite(&SDCD1, sector, buff, count)) if (sdcWrite(&SDCD1, sector, buff, count))
return RES_ERROR; return RES_ERROR;
return RES_OK; return RES_OK;
@ -247,7 +260,7 @@ DRESULT disk_ioctl (
DWORD get_fattime(void) { DWORD get_fattime(void) {
RTCDateTime timespec; RTCDateTime timespec;
rtcGetTime(&RTCD1, &timespec); rtcGetTime(&RTCD1, &timespec);
return rtcConvertDateTimeToFAT(&timespec); return rtcConvertDateTimeToFAT(&timespec);
} }

View File

@ -10,21 +10,35 @@
#if GFX_USE_GFILE && GFILE_NEED_PETITFS && GFX_USE_OS_CHIBIOS && !GFILE_PETITFS_EXTERNAL_LIB #if GFX_USE_GFILE && GFILE_NEED_PETITFS && GFX_USE_OS_CHIBIOS && !GFILE_PETITFS_EXTERNAL_LIB
#include "gfile_petitfs_wrapper.h" #include "gfile_petitfs_wrapper.h"
#include <string.h> #include <string.h>
#if HAL_USE_MMC_SPI && HAL_USE_SDC #if HAL_USE_MMC_SPI && HAL_USE_SDC
#error "cannot specify both MMC_SPI and SDC drivers" #error "cannot specify both MMC_SPI and SDC drivers"
#endif #endif
#if HAL_USE_MMC_SPI #if HAL_USE_MMC_SPI
extern MMCDriver MMCD1; extern MMCDriver MMCD1;
#elif HAL_USE_SDC #elif HAL_USE_SDC
extern SDCDriver SDCD1; extern SDCDriver SDCD1;
#else #else
#error "MMC_SPI or SDC driver must be specified" #error "MMC_SPI or SDC driver must be specified"
#endif #endif
// WOW - Bugs galore!!! (in ChibiOS)
// Bugs:
// 1. ChibiOS DMA operations do not do the appropriate cache flushing or invalidating
// on cpu's that require it eg STM32F7 series.
// Instead they provide explicit dmaBufferInvalidate and dmaBufferFlush calls
// and rely on the user to explicitly flush the cache.
// Solution: We explicitly flush the cache after any possible DMA operation.
// 2. Unfortunately these explicit routines also have a bug. They assume that the
// specified data structure is aligned on a cache line boundary - not a good assumption.
// Solution: We increase the size provided to ChibiOS so that it does it properly.
// This assumes of course that we know the size of the cpu cache line.
#define CPU_CACHE_LINE_SIZE 32
#define CACHE_FLUSH(buf, sz) dmaBufferFlush((buf), (sz)+(CPU_CACHE_LINE_SIZE-1))
#define CACHE_INVALIDATE(buf, sz) dmaBufferInvalidate((buf), (sz)+(CPU_CACHE_LINE_SIZE-1))
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Initialize a Drive */ /* Initialize a Drive */
@ -72,7 +86,7 @@ DRESULT disk_readp (
return RES_ERROR; return RES_ERROR;
#endif #endif
sectpos = sector; sectpos = sector;
dmaBufferInvalidate(sectBuf, sizeof(sectBuf)); CACHE_INVALIDATE(sectBuf, sizeof(sectBuf));
} }
memcpy(buff, sectBuf + offset, count); memcpy(buff, sectBuf + offset, count);
return RES_OK; return RES_OK;