nuttx/arch/arm/src/armv7-m/cache.h
Bob Feretich c6851201c0 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.
2018-11-20 14:03:42 -06:00

508 lines
14 KiB
C

/****************************************************************************
* arch/arm/src/armv7-m/cache.h
*
* Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Some logic in this header file derives from the ARM CMSIS core_cm7.h
* header file which has a compatible 3-clause BSD license:
*
* Copyright (c) 2009 - 2014 ARM LIMITED. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name ARM, NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_ARMV7_M_CACHE_H
#define __ARCH_ARM_SRC_ARMV7_M_CACHE_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "up_arch.h"
#include "nvic.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Cache Size ID (CCSIDR) register macros used by inline functions
* Given the value of the CCSIDR reginer (n):
*
* CCSIDR_WAYS - Returns the (number of ways) - 1
* CCSIDR_SETS - Returns the (number of sets) - 1
* CCSIDR_LSSHIFT - Returns log2(cache line size in words) - 2
* Eg. 0 -> 4 words
* 1 -> 8 words
* ...
*/
#define CCSIDR_WAYS(n) \
(((n) & NVIC_CCSIDR_ASSOCIATIVITY_MASK) >> NVIC_CCSIDR_ASSOCIATIVITY_SHIFT)
#define CCSIDR_SETS(n) \
(((n) & NVIC_CCSIDR_NUMSETS_MASK) >> NVIC_CCSIDR_NUMSETS_SHIFT)
#define CCSIDR_LSSHIFT(n) \
(((n) & NVIC_CCSIDR_LINESIZE_MASK) >> NVIC_CCSIDR_LINESIZE_SHIFT)
/* intrinsics are used in these inline functions */
#define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory")
#define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory")
#define arm_dmb(n) __asm__ __volatile__ ("dmb " #n : : : "memory")
#define ARM_DSB() arm_dsb(15)
#define ARM_ISB() arm_isb(15)
#define ARM_DMB() arm_dmb(15)
/****************************************************************************
* Inline Functions
****************************************************************************/
#ifndef __ASSEMBLY__
/****************************************************************************
* Name: arm_clz
*
* Description:
* Access to CLZ instructions
*
* Input Parameters:
* value - The value to perform the CLZ operation on
*
* Returned Value:
* None
*
****************************************************************************/
static inline uint32_t arm_clz(unsigned int value)
{
uint32_t ret;
__asm__ __volatile__ ("clz %0, %1" : "=r"(ret) : "r"(value));
return ret;
}
/****************************************************************************
* Name: arch_enable_icache
*
* Description:
* Enable the I-Cache
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline void arch_enable_icache(void)
{
#ifdef CONFIG_ARMV7M_ICACHE
uint32_t regval;
ARM_DSB();
ARM_ISB();
/* Invalidate the entire I-Cache */
putreg32(0, NVIC_ICIALLU);
/* Enable the I-Cache */
regval = getreg32(NVIC_CFGCON);
regval |= NVIC_CFGCON_IC;
putreg32(regval, NVIC_CFGCON);
ARM_DSB();
ARM_ISB();
#endif
}
/****************************************************************************
* Name: arch_disable_icache
*
* Description:
* Disable the I-Cache
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline void arch_disable_icache(void)
{
#ifdef CONFIG_ARMV7M_ICACHE
uint32_t regval;
ARM_DSB();
ARM_ISB();
/* Disable the I-Cache */
regval = getreg32(NVIC_CFGCON);
regval &= ~NVIC_CFGCON_IC;
putreg32(regval, NVIC_CFGCON);
/* Invalidate the entire I-Cache */
putreg32(0, NVIC_ICIALLU);
ARM_DSB();
ARM_ISB();
#endif
}
/****************************************************************************
* Name: arch_invalidate_icache_all
*
* Description:
* Invalidate the entire contents of I cache.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline void arch_invalidate_icache_all(void)
{
#ifdef CONFIG_ARMV7M_ICACHE
ARM_DSB();
ARM_ISB();
/* Invalidate the entire I-Cache */
putreg32(0, NVIC_ICIALLU);
ARM_DSB();
ARM_ISB();
#endif
}
/****************************************************************************
* Name: arch_dcache_writethrough
*
* Description:
* Configure the D-Cache for Write-Through operation.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#if defined(CONFIG_ARMV7M_DCACHE) && defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
static inline void arch_dcache_writethrough(void)
{
uint32_t regval = getreg32(NVIC_CACR);
regval |= NVIC_CACR_FORCEWT;
putreg32(regval, NVIC_CACR);
}
#else
# define arch_dcache_writethrough()
#endif
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: arch_enable_dcache
*
* Description:
* Enable the D-Cache
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_ARMV7M_DCACHE
void arch_enable_dcache(void);
#else
# define arch_enable_dcache()
#endif
/****************************************************************************
* Name: arch_disable_dcache
*
* Description:
* Disable the D-Cache
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_ARMV7M_DCACHE
void arch_disable_dcache(void);
#else
# define arch_disable_dcache()
#endif
/****************************************************************************
* Name: arch_invalidate_dcache
*
* 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 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
* 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(uintptr_t start, uintptr_t end);
#else
# 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
*
* Description:
* Invalidate the entire contents of D cache.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_ARMV7M_DCACHE
void arch_invalidate_dcache_all(void);
#else
# define arch_invalidate_dcache_all()
#endif
/****************************************************************************
* Name: arch_clean_dcache
*
* Description:
* Clean the data cache within the specified region by flushing the
* contents of the data cache to memory.
*
* NOTE: This operation is un-necessary if the DCACHE is configured in
* write-through mode.
*
* 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.
*
****************************************************************************/
#if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
void arch_clean_dcache(uintptr_t start, uintptr_t end);
#else
# define arch_clean_dcache(s,e)
#endif
/****************************************************************************
* Name: arch_clean_dcache_all
*
* Description:
* Clean the entire data cache within the specified region by flushing the
* contents of the data cache to memory.
*
* NOTE: This operation is un-necessary if the DCACHE is configured in
* write-through mode.
*
* Input Parameters:
* None
*
* 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.
*
****************************************************************************/
#if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
void arch_clean_dcache_all(void);
#else
# define arch_clean_dcache_all()
#endif
/****************************************************************************
* Name: arch_flush_dcache
*
* Description:
* Flush the data cache within the specified region by cleaning and
* invalidating the D cache.
*
* NOTE: If DCACHE write-through is configured, then this operation is the
* same as arch_invalidate_cache().
*
* 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
#ifdef CONFIG_ARMV7M_DCACHE_WRITETHROUGH
# define arch_flush_dcache(s,e) arch_invalidate_dcache(s,e)
#else
void arch_flush_dcache(uintptr_t start, uintptr_t end);
#endif
#else
# define arch_flush_dcache(s,e)
#endif
/****************************************************************************
* Name: arch_flush_dcache_all
*
* Description:
* Flush the entire data cache by cleaning and invalidating the D cache.
*
* NOTE: If DCACHE write-through is configured, then this operation is the
* same as arch_invalidate_cache_all().
*
* Input Parameters:
* None
*
* 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
#ifdef CONFIG_ARMV7M_DCACHE_WRITETHROUGH
# define arch_flush_dcache_all() arch_invalidate_dcache_all()
#else
void arch_flush_dcache_all(void);
#endif
#else
# define arch_flush_dcache_all()
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_ARMV7_M_CACHE_H */