From c6851201c0c2f8e8c4bcc3903fe2512639901da8 Mon Sep 17 00:00:00 2001 From: Bob Feretich Date: Tue, 20 Nov 2018 14:03:42 -0600 Subject: [PATCH] This commit adds a new function arch_invalidate_dcache_by_addr(). It takes the same parameters as arch_invalidate_dcache(), but performs invalidation of only the lines in cache that need to be invalidated. This new function could be used as a a direct replacement for arch_invalidate_dcache(). The user of this invalidation are mmcsd_sdio currently. The mmcsd_sdio driver makes calls for dcache invalidation through the chip specific architecture function SDIO_DMARECVSETUP(). I changed the arch/arm/stm32f7 chips to use arch_invalidate_dcache_by_addr() instead of arch_invalidate_dcache(). This commit includes additional changes to mmcsd_sdio.c. I created SDIO_DMADELYDINVLDT() (DMA delayed invalidate) to invalidate store-into mode dcaches after the DMA transfer. I have been using SDIO_DMADELYDINVLDT() for several weeks now and it has fixed the problems that I previously reported regarding non-cache aligned buffer invalidation errors (for my store-through dcache). However, it does not permit use of unaligned DMA buffers for store-into mode dcaches. SDIO_DMADELYDINVLDT() is a NoOp unless the chip specific Kconfig file selects CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT. I have modified all the stm32f7 chips to select it. --- arch/arm/src/armv7-m/arch_invalidate_dcache.c | 79 +++++++++++++++++-- arch/arm/src/armv7-m/cache.h | 35 +++++++- arch/arm/src/armv7-m/nvic.h | 3 +- arch/arm/src/stm32f7/Kconfig | 14 ++++ arch/arm/src/stm32f7/stm32_sdmmc.c | 74 +++++++++++++++-- drivers/Kconfig | 4 + drivers/mmcsd/mmcsd_sdio.c | 10 +++ include/nuttx/sdio.h | 29 +++++++ 8 files changed, 232 insertions(+), 16 deletions(-) diff --git a/arch/arm/src/armv7-m/arch_invalidate_dcache.c b/arch/arm/src/armv7-m/arch_invalidate_dcache.c index d6175f2d10..4d8b600a3f 100644 --- a/arch/arm/src/armv7-m/arch_invalidate_dcache.c +++ b/arch/arm/src/armv7-m/arch_invalidate_dcache.c @@ -1,8 +1,9 @@ /**************************************************************************** * arch/arm/src/armv7-m/arch_invalidate_dcache.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt + * Bob Feretich * * Some logic in this header file derives from the ARM CMSIS core_cm7.h * header file which has a compatible 3-clause BSD license: @@ -48,10 +49,6 @@ #ifdef CONFIG_ARMV7M_DCACHE -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -62,7 +59,9 @@ * Description: * Invalidate the data cache within the specified region; we will be * performing a DMA operation in this region and we want to purge old data - * in the cache. + * in the cache. Note that this function invalidates all cache ways + * in sets that could be associated with the address range, regardless of + * whether the address range is contained in the cache or not. * * Input Parameters: * start - virtual start address of region @@ -147,4 +146,72 @@ void arch_invalidate_dcache(uintptr_t start, uintptr_t end) ARM_ISB(); } +/**************************************************************************** + * Name: arch_invalidate_dcache_by_addr + * + * Description: + * Invalidate the data cache within the specified region; we will be + * performing a DMA operation in this region and we want to purge old data + * in the cache. Note that this function only invalidates cache sets that + * contain data from this address range. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void arch_invalidate_dcache_by_addr(uintptr_t start, uintptr_t end) +{ + uint32_t ccsidr; + uint32_t sshift; + uint32_t ssize; + + /* Get the characteristics of the D-Cache */ + + ccsidr = getreg32(NVIC_CCSIDR); + sshift = CCSIDR_LSSHIFT(ccsidr) + 4; /* log2(cache-line-size-in-bytes) */ + + /* Invalidate the D-Cache containing this range of addresses */ + + ssize = (1 << sshift); + + /* Round down the start address to the nearest cache line boundary. + * + * sshift = 5 : Offset to the beginning of the set field + * (ssize - 1) = 0x007f : Mask of the set field + */ + + start &= ~(ssize - 1); + ARM_DSB(); + + do + { + /* The below store causes the cache to check its directory and + * determine if this address is contained in the cache. If so, it + * invalidate that cache line. Only the cache way containing the + * address is invalidated. If the address is not in the cache, then + * nothing is invalidated. + */ + + putreg32(start, NVIC_DCIMVAC); + + /* Increment the address by the size of one cache line. */ + + start += ssize; + } + while (start < end); + + ARM_DSB(); + ARM_ISB(); +} + #endif /* CONFIG_ARMV7M_DCACHE */ diff --git a/arch/arm/src/armv7-m/cache.h b/arch/arm/src/armv7-m/cache.h index d6b40b30a1..22897489fe 100644 --- a/arch/arm/src/armv7-m/cache.h +++ b/arch/arm/src/armv7-m/cache.h @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv7-m/cache.h * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Some logic in this header file derives from the ARM CMSIS core_cm7.h @@ -300,7 +300,9 @@ void arch_disable_dcache(void); * Description: * Invalidate the data cache within the specified region; we will be * performing a DMA operation in this region and we want to purge old data - * in the cache. + * in the cache. Note that this function invalidates all cache ways + * in sets that could be associated with the address range, regardless of + * whether the address range is contained in the cache or not. * * Input Parameters: * start - virtual start address of region @@ -322,6 +324,35 @@ void arch_invalidate_dcache(uintptr_t start, uintptr_t end); # define arch_invalidate_dcache(s,e) #endif +/**************************************************************************** + * Name: arch_invalidate_dcache_by_addr + * + * Description: + * Invalidate the data cache within the specified region; we will be + * performing a DMA operation in this region and we want to purge old data + * in the cache. Note that this function only invalidates cache sets that + * contain data from this address range. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +#ifdef CONFIG_ARMV7M_DCACHE +void arch_invalidate_dcache_by_addr(uintptr_t start, uintptr_t end); +#else +# define arch_invalidate_dcache_by_addr(s,e) +#endif + /**************************************************************************** * Name: arch_invalidate_dcache_all * diff --git a/arch/arm/src/armv7-m/nvic.h b/arch/arm/src/armv7-m/nvic.h index c0635104a2..b439a7b3eb 100644 --- a/arch/arm/src/armv7-m/nvic.h +++ b/arch/arm/src/armv7-m/nvic.h @@ -240,7 +240,7 @@ #define NVIC_MVFR2_OFFSET 0x0f48 /* Media and VFP Feature Register 2 */ #define NVIC_ICIALLU_OFFSET 0x0f50 /* I-Cache Invalidate All to PoU (Cortex-M7) */ #define NVIC_ICIMVAU_OFFSET 0x0f58 /* I-Cache Invalidate by MVA to PoU (Cortex-M7) */ -#define NVIC_DCIMVAU_OFFSET 0x0f5c /* D-Cache Invalidate by MVA to PoC (Cortex-M7) */ +#define NVIC_DCIMVAC_OFFSET 0x0f5c /* D-Cache Invalidate by MVA to PoC (Cortex-M7) */ #define NVIC_DCISW_OFFSET 0x0f60 /* D-Cache Invalidate by Set-way (Cortex-M7) */ #define NVIC_DCCMVAU_OFFSET 0x0f64 /* D-Cache Clean by MVA to PoU (Cortex-M7) */ #define NVIC_DCCMVAC_OFFSET 0x0f68 /* D-Cache Clean by MVA to PoC (Cortex-M7) */ @@ -429,6 +429,7 @@ #define NVIC_ICIALLU (ARMV7M_NVIC_BASE + NVIC_ICIALLU_OFFSET) #define NVIC_ICIMVAU (ARMV7M_NVIC_BASE + NVIC_ICIMVAU_OFFSET) #define NVIC_DCIMVAU (ARMV7M_NVIC_BASE + NVIC_DCIMVAU_OFFSET) +#define NVIC_DCIMVAC (ARMV7M_NVIC_BASE + NVIC_DCIMVAC_OFFSET) #define NVIC_DCISW (ARMV7M_NVIC_BASE + NVIC_DCISW_OFFSET) #define NVIC_DCCMVAU (ARMV7M_NVIC_BASE + NVIC_DCCMVAU_OFFSET) #define NVIC_DCCMVAC (ARMV7M_NVIC_BASE + NVIC_DCCMVAC_OFFSET) diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 1fb5a282c1..d64dcdbdcf 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -655,6 +655,7 @@ config STM32F7_STM32F722XX default n select STM32F7_STM32F72XX select ARCH_HAVE_FPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -671,6 +672,7 @@ config STM32F7_STM32F723XX default n select STM32F7_STM32F72XX select ARCH_HAVE_FPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -687,6 +689,7 @@ config STM32F7_STM32F745XX default n select STM32F7_STM32F74XX select ARCH_HAVE_FPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -706,6 +709,7 @@ config STM32F7_STM32F746XX default n select STM32F7_STM32F74XX select ARCH_HAVE_FPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -748,6 +752,7 @@ config STM32F7_STM32F765XX select STM32F7_STM32F76XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -797,6 +802,7 @@ config STM32F7_STM32F768XX # Revisit Wehn parts released select STM32F7_STM32F76XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -823,6 +829,7 @@ config STM32F7_STM32F768AX # Revisit When parts released select STM32F7_STM32F76XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -848,6 +855,7 @@ config STM32F7_STM32F769XX select STM32F7_STM32F76XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -874,6 +882,7 @@ config STM32F7_STM32F769AX # Revisit When parts released select STM32F7_STM32F76XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -899,6 +908,7 @@ config STM32F7_STM32F777XX select STM32F7_STM32F77XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -927,6 +937,7 @@ config STM32F7_STM32F778XX # Revisit when parts released select STM32F7_STM32F77XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -955,6 +966,7 @@ config STM32F7_STM32F778AX select STM32F7_STM32F77XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -982,6 +994,7 @@ config STM32F7_STM32F779XX select STM32F7_STM32F77XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM @@ -1010,6 +1023,7 @@ config STM32F7_STM32F779AX select STM32F7_STM32F77XX select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_SDIO_DELAYED_INVLDT select ARMV7M_HAVE_ICACHE select ARMV7M_HAVE_DCACHE select ARMV7M_HAVE_ITCM diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c index 4b9742d0b0..7e646f7807 100644 --- a/arch/arm/src/stm32f7/stm32_sdmmc.c +++ b/arch/arm/src/stm32f7/stm32_sdmmc.c @@ -4,6 +4,7 @@ * Copyright (C) 2009, 2011-2018 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane + * Bob Feretich * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,6 +64,7 @@ #include "chip.h" #include "up_arch.h" +#include "stm32_dtcm.h" #include "stm32_dma.h" #include "stm32_gpio.h" #include "stm32_sdmmc.h" @@ -563,7 +565,11 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, size_t buflen); static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, size_t buflen); +#ifdef CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT +static int stm32_dmadelydinvldt(FAR struct sdio_dev_s *dev, + FAR const uint8_t *buffer, size_t buflen); #endif +#endif /* CONFIG_STM32F7_SDMMC_DMA */ /* Initialization/uninitialization/reset ************************************/ @@ -612,14 +618,17 @@ struct stm32_dev_s g_sdmmcdev1 = #endif .dmarecvsetup = stm32_dmarecvsetup, .dmasendsetup = stm32_dmasendsetup, -#else +#ifdef CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT + .dmadelydinvldt = stm32_dmadelydinvldt, +#endif +#lse #ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT .dmapreflight = NULL, #endif .dmarecvsetup = stm32_recvsetup, .dmasendsetup = stm32_sendsetup, -#endif -#endif +#endif /* CONFIG_STM32F7_SDMMC_DMA */ +#endif /* CONFIG_SDIO_DMA*/ }, .base = STM32_SDMMC1_BASE, .nirq = STM32_IRQ_SDMMC1, @@ -687,6 +696,9 @@ struct stm32_dev_s g_sdmmcdev2 = #endif .dmarecvsetup = stm32_dmarecvsetup, .dmasendsetup = stm32_dmasendsetup, +#ifdef CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT + .dmadelydinvldt = stm32_dmadelydinvldt, +#endif #endif }, .base = STM32_SDMMC2_BASE, @@ -2524,7 +2536,7 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && - (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R5_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R5_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) { mcerr("ERROR: Wrong response CMD=%08x\n", cmd); @@ -3055,7 +3067,12 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Force RAM reread */ - arch_invalidate_dcache((uintptr_t)buffer,(uintptr_t)buffer + buflen); + if ((uintptr_t)buffer < DTCM_START || (uintptr_t)buffer + buflen > DTCM_END) + { +#if !defined(CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT) + arch_invalidate_dcache_by_addr((uintptr_t)buffer,(uintptr_t)buffer + buflen); +#endif + } /* Start the DMA */ @@ -3121,9 +3138,16 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, stm32_sampleinit(); stm32_sample(priv, SAMPLENDX_BEFORE_SETUP); - /* Flush cache to physical memory */ + /* Flush cache to physical memory when not in DTCM memory */ - arch_flush_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); + if ((uintptr_t)buffer < DTCM_START || (uintptr_t)buffer + buflen > DTCM_END) + { +#ifdef CONFIG_ARMV7M_DCACHE_WRITETHROUGH + arch_invalidate_dcache_by_addr((uintptr_t)buffer, (uintptr_t)buffer + buflen); +#else + arch_flush_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); +#endif + } /* Save the source buffer information for use by the interrupt handler */ @@ -3158,6 +3182,42 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, } #endif +/**************************************************************************** + * Name: stm32_dmadelydinvldt + * + * Description: + * Delayed D-cache invalidation. + * This function should be called after receive DMA completion to perform + * D-cache invalidation. This eliminates the need for cache aligned DMA + * buffers when the D-cache is in store-through mode. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA into + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_STM32F7_SDMMC_DMA +static int stm32_dmadelydinvldt(FAR struct sdio_dev_s *dev, + FAR const uint8_t *buffer, size_t buflen) +{ + /* Invaliate cache to physical memory when not in DTCM memory. */ + + if ((uintptr_t)buffer < DTCM_START || + (uintptr_t)buffer + buflen > DTCM_END) + { + arch_invalidate_dcache_by_addr((uintptr_t)buffer, + (uintptr_t)buffer + buflen); + } + + return OK; +} +#endif + /**************************************************************************** * Initialization/uninitialization/reset ****************************************************************************/ diff --git a/drivers/Kconfig b/drivers/Kconfig index 907ed4250e..71e813a3b1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -237,6 +237,10 @@ config ARCH_HAVE_SDIO_PREFLIGHT bool default n +config ARCH_HAVE_SDIO_DELAYED_INVLDT + bool + default n + menuconfig MMCSD bool "MMC/SD Driver Support" default n diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 3f8df0b53d..be7fd548be 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -3,6 +3,7 @@ * * Copyright (C) 2009-2013, 2016-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt + * Bob Feretich * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1408,6 +1409,9 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, MMCSD_BLOCK_RDATADELAY); +#ifdef CONFIG_SDIO_DMA + SDIO_DMADELYDINVLDT(priv->dev, buffer, priv->blocksize); +#endif if (ret != OK) { ferr("ERROR: CMD17 transfer failed: %d\n", ret); @@ -1550,6 +1554,10 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, /* Send STOP_TRANSMISSION */ ret = mmcsd_stoptransmission(priv); +#ifdef CONFIG_SDIO_DMA + SDIO_DMADELYDINVLDT(priv->dev, buffer, priv->blocksize * nblocks); +#endif + if (ret != OK) { ferr("ERROR: mmcsd_stoptransmission failed: %d\n", ret); @@ -1794,6 +1802,8 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, * * Description: * Write multiple, contiguous blocks of data to the physical device. + * This function expects that the data to be written is contained in + * one large buffer that is pointed to by buffer. * ****************************************************************************/ diff --git a/include/nuttx/sdio.h b/include/nuttx/sdio.h index 96217db363..12230fd11e 100644 --- a/include/nuttx/sdio.h +++ b/include/nuttx/sdio.h @@ -814,6 +814,31 @@ # define SDIO_DMARECVSETUP(dev,buffer,len) (-ENOSYS) #endif +/**************************************************************************** + * Name: SDIO_DMADELYDINVLDT + * + * Description: + * Delayed D-cache invalidation. + * This function should be called after receive DMA completion to perform + * D-cache invalidation. This eliminates the need for cache aligned DMA + * buffers when the D-cache is in store-through mode. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA from + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT) +# define SDIO_DMADELYDINVLDT(dev,buffer,len) ((dev)->dmadelydinvldt(dev,buffer,len)) +#else +# define SDIO_DMADELYDINVLDT(dev,buffer,len) (OK) +#endif + /**************************************************************************** * Name: SDIO_DMASENDSETUP * @@ -949,7 +974,11 @@ struct sdio_dev_s size_t buflen); int (*dmasendsetup)(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, size_t buflen); +#ifdef CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT + int (*dmadelydinvldt)(FAR struct sdio_dev_s *dev, + FAR const uint8_t *buffer, size_t buflen); #endif +#endif /* CONFIG_SDIO_DMA */ }; /****************************************************************************