历史上的今天
返回首页

历史上的今天

今天是:2024年11月25日(星期一)

正在发生

2021年11月25日 | armv7对应的CACHE操作相关文件解析

2021-11-25 来源:eefocus

最近在使用TI的DRA726芯片。A15端需要访问图像,而图像是在外设空间的,用DMA拷贝到CACHE空间。


这样就导致了DMA的CACHE一致性的问题,需要在DMA之后清除所使用图像空间的数据CACHE。


以这个A15核心为例,解析一下ARM的CACHE操作,涉及的文件有:cacheflush.h   cache-v7.S  proc-macros.S  proc-v7.S

内存是OS中非常厉害,非常复杂的一套系统,科学严谨,每一部分都需要研究几本书才能够彻底明白。


CACHE最基本的就是加速原理,依据就是程序的局部性原理。


CACHE实际实施起来,细节就非常复杂了,比如启动的过程中,如何建立CACHE,从直接访问内存到CACHE访问等等具体问题。


这次主要就项目中的CACHE一致性问题,借机会给组员们一起分享了。


/*

 *  arch/arm/include/asm/cacheflush.h

 *

 *  Copyright (C) 1999-2002 Russell King

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation.

 */

#ifndef _ASMARM_CACHEFLUSH_H

#define _ASMARM_CACHEFLUSH_H

 

#include

 

#include

#include

#include

#include

 

#define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)

 

/*

 * This flag is used to indicate that the page pointed to by a pte is clean

 * and does not require cleaning before returning it to the user.

 */

#define PG_dcache_clean PG_arch_1

 

/*

 * MM Cache Management

 * ===================

 *

 * The arch/arm/mm/cache-*.S and arch/arm/mm/proc-*.S files

 * implement these methods.

 *

 * Start addresses are inclusive and end addresses are exclusive;

 * start addresses should be rounded down, end addresses up.

 *

 * See Documentation/cachetlb.txt for more information.

 * Please note that the implementation of these, and the required

 * effects are cache-type (VIVT/VIPT/PIPT) specific.

 *

 * flush_icache_all()

 *

 * Unconditionally clean and invalidate the entire icache.

 * Currently only needed for cache-v6.S and cache-v7.S, see

 * __flush_icache_all for the generic implementation.

 *

 * flush_kern_all()

 *

 * Unconditionally clean and invalidate the entire cache.

 *

 *     flush_kern_louis()

 *

 *             Flush data cache levels up to the level of unification

 *             inner shareable and invalidate the I-cache.

 *             Only needed from v7 onwards, falls back to flush_cache_all()

 *             for all other processor versions.

 *

 * flush_user_all()

 *

 * Clean and invalidate all user space cache entries

 * before a change of page tables.

 *

 * flush_user_range(start, end, flags)

 *

 * Clean and invalidate a range of cache entries in the

 * specified address space before a change of page tables.

 * - start - user start address (inclusive, page aligned)

 * - end   - user end address   (exclusive, page aligned)

 * - flags - vma->vm_flags field

 *

 * coherent_kern_range(start, end)

 *

 * Ensure coherency between the Icache and the Dcache in the

 * region described by start, end.  If you have non-snooping

 * Harvard caches, you need to implement this function.

 * - start  - virtual start address

 * - end    - virtual end address

 *

 * coherent_user_range(start, end)

 *

 * Ensure coherency between the Icache and the Dcache in the

 * region described by start, end.  If you have non-snooping

 * Harvard caches, you need to implement this function.

 * - start  - virtual start address

 * - end    - virtual end address

 *

 * flush_kern_dcache_area(kaddr, size)

 *

 * Ensure that the data held in page is written back.

 * - kaddr  - page address

 * - size   - region size

 *

 * DMA Cache Coherency

 * ===================

 *

 * dma_flush_range(start, end)

 *

 * Clean and invalidate the specified virtual address range.

 * - start  - virtual start address

 * - end    - virtual end address

 */

 

struct cpu_cache_fns {

void (*flush_icache_all)(void);

void (*flush_kern_all)(void);

void (*flush_kern_louis)(void);

void (*flush_user_all)(void);

void (*flush_user_range)(unsigned long, unsigned long, unsigned int);

 

void (*coherent_kern_range)(unsigned long, unsigned long);

int  (*coherent_user_range)(unsigned long, unsigned long);

void (*flush_kern_dcache_area)(void *, size_t);

 

void (*dma_map_area)(const void *, size_t, int);

void (*dma_unmap_area)(const void *, size_t, int);

 

void (*dma_flush_range)(const void *, const void *);

};

 

/*

 * Select the calling method

 */

#ifdef MULTI_CACHE

 

extern struct cpu_cache_fns cpu_cache;

 

#define __cpuc_flush_icache_all cpu_cache.flush_icache_all

#define __cpuc_flush_kern_all cpu_cache.flush_kern_all

#define __cpuc_flush_kern_louis cpu_cache.flush_kern_louis

#define __cpuc_flush_user_all cpu_cache.flush_user_all

#define __cpuc_flush_user_range cpu_cache.flush_user_range

#define __cpuc_coherent_kern_range cpu_cache.coherent_kern_range

#define __cpuc_coherent_user_range cpu_cache.coherent_user_range

#define __cpuc_flush_dcache_area cpu_cache.flush_kern_dcache_area

 

/*

 * These are private to the dma-mapping API.  Do not use directly.

 * Their sole purpose is to ensure that data held in the cache

 * is visible to DMA, or data written by DMA to system memory is

 * visible to the CPU.

 */

#define dmac_map_area cpu_cache.dma_map_area

#define dmac_unmap_area cpu_cache.dma_unmap_area

#define dmac_flush_range cpu_cache.dma_flush_range

 

#else

 

extern void __cpuc_flush_icache_all(void);

extern void __cpuc_flush_kern_all(void);

extern void __cpuc_flush_kern_louis(void);

extern void __cpuc_flush_user_all(void);

extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);

extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);

extern int  __cpuc_coherent_user_range(unsigned long, unsigned long);

extern void __cpuc_flush_dcache_area(void *, size_t);

 

/*

 * These are private to the dma-mapping API.  Do not use directly.

 * Their sole purpose is to ensure that data held in the cache

 * is visible to DMA, or data written by DMA to system memory is

 * visible to the CPU.

 */

extern void dmac_map_area(const void *, size_t, int);

extern void dmac_unmap_area(const void *, size_t, int);

extern void dmac_flush_range(const void *, const void *);

 

#endif

 

/*

 * Copy user data from/to a page which is mapped into a different

 * processes address space.  Really, we want to allow our "user

 * space" model to handle this.

 */

extern void copy_to_user_page(struct vm_area_struct *, struct page *,

unsigned long, void *, const void *, unsigned long);

#define copy_from_user_page(vma, page, vaddr, dst, src, len)

do {

memcpy(dst, src, len);

} while (0)

 

/*

 * Convert calls to our calling convention.

 */

 

/* Invalidate I-cache */

#define __flush_icache_all_generic()

asm("mcr p15, 0, %0, c7, c5, 0"

    : : "r" (0));

 

/* Invalidate I-cache inner shareable */

#define __flush_icache_all_v7_smp()

asm("mcr p15, 0, %0, c7, c1, 0"

    : : "r" (0));

 

/*

 * Optimized __flush_icache_all for the common cases. Note that UP ARMv7

 * will fall through to use __flush_icache_all_generic.

 */

#if (defined(CONFIG_CPU_V7) &&

     (defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K))) ||

defined(CONFIG_SMP_ON_UP)

#define __flush_icache_preferred __cpuc_flush_icache_all

#elif __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)

#define __flush_icache_preferred __flush_icache_all_v7_smp

#elif __LINUX_ARM_ARCH__ == 6 && defined(CONFIG_ARM_ERRATA_411920)

#define __flush_icache_preferred __cpuc_flush_icache_all

#else

#define __flush_icache_preferred __flush_icache_all_generic

#endif

 

static inline void __flush_icache_all(void)

{

__flush_icache_preferred();

dsb();

}

 

/*

 * Flush caches up to Level of Unification Inner Shareable

 */

#define flush_cache_louis() __cpuc_flush_kern_louis()

 

#define flush_cache_all() __cpuc_flush_kern_all()

 

static inline void vivt_flush_cache_mm(struct mm_struct *mm)

{

if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))

__cpuc_flush_user_all();

}

 

static inline void

vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)

{

struct mm_struct *mm = vma->vm_mm;

 

if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))

__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),

vma->vm_flags);

}

 

static inline void

vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)

{

struct mm_struct *mm = vma->vm_mm;

 

if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {

unsigned long addr = user_addr & PAGE_MASK;

__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);

}

}

 

#ifndef CONFIG_CPU_CACHE_VIPT

#define flush_cache_mm(mm)

vivt_flush_cache_mm(mm)

#define flush_cache_range(vma,start,end)

vivt_flush_cache_range(vma,start,end)

#define flush_cache_page(vma,addr,pfn)

vivt_flush_cache_page(vma,addr,pfn)

#else

extern void flush_cache_mm(struct mm_struct *mm);

extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);

extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);

#endif

 

#define flush_cache_dup_mm(mm) flush_cache_mm(mm)

 

/*

 * flush_cache_user_range is used when we want to ensure that the

 * Harvard caches are synchronised for the user space address range.

 * This is used for the ARM private sys_cacheflush system call.

 */

#define flush_cache_user_range(s,e) __cpuc_coherent_user_range(s,e)

推荐阅读

史海拾趣

Fermionics Lasertech Inc公司的发展小趣事

面对日益激烈的市场竞争,Fermionics Lasertech Inc公司始终坚持以创新为驱动力。他们不断投入研发资金,引进高端人才,加强与高校和科研机构的合作,共同推动激光技术的创新。公司成功研发出了一系列具有自主知识产权的新型激光器,不仅提升了产品性能,还降低了生产成本,使公司在激烈的市场竞争中保持领先地位。

大毅科技公司的发展小趣事

随着业务的不断增长,大毅科技意识到需要扩大生产规模以满足市场需求。于是,公司开始在大陆地区寻找合适的生产基地,最终在东莞、清溪、苏州等地设立了生产基地。这一举措不仅降低了生产成本,还提高了生产效率,使大毅科技能够更好地服务全球客户。同时,这也体现了大毅科技对全球市场的战略眼光和布局。

Global Power Technology Co., Ltd公司的发展小趣事
首先检查电源插头是否插紧,电源插座是否有电;若电源正常,可能是电路板故障,需联系专业维修人员检查并更换电路板。
Abundance Enterprise Company公司的发展小趣事

随着国内市场的逐渐饱和,Abundance Enterprise Company开始积极拓展国际市场。公司积极参与国际电子展览和交流活动,与全球知名电子企业建立了广泛的合作关系。同时,公司还在海外设立了多个分支机构,进一步拓展国际业务。这些举措不仅提升了公司的国际影响力,也为公司的长期发展奠定了坚实基础。

格瑞宝(GP)公司的发展小趣事

为了更好地服务客户和市场,格瑞宝在深圳、南京等地设立了分公司等派出机构。这些分公司的设立不仅加强了公司在华南、华东等地区的业务覆盖能力,也提高了公司的市场响应速度和客户服务水平。通过区域布局的优化,格瑞宝能够更加灵活地应对市场变化,抓住发展机遇,实现更快速的发展。

Emerson Embedded Power公司的发展小趣事

在电子行业的早期,Emerson Embedded Power就开始注重技术创新。该公司不断投入研发资源,开发高效、可靠的电源解决方案,以满足不断增长的市场需求。其创新的电源管理技术不仅提高了设备的性能,还降低了能源消耗,赢得了客户的广泛认可。

问答坊 | AI 解惑

51编程规范

不知道对大家有没有用…

查看全部问答>

求助:视频线的干扰问题如何解决?

视频线要走电线杆,但是是高压的,电磁干扰非常大,大家有什么好的办法么?…

查看全部问答>

分布式控制系统

分布式控制系统 分布式控制系统 (distributed control systems,简称DCS),又称为分散控制系统,分散型控制系统,集散控制系统.行业内业称4C技术既Control控制技术;Computer 计算机技术;Communication 通信技术;Cathode Ray Tube CRT显示技术。   ...…

查看全部问答>

探秘中国IC设计公司发展迷局(一) 

2000年到2009年十年间,中国的IC设计公司的命运跌宕起伏。十年来,始终没有一家IC公司能够在中国市场扛起旗帜,可谓是各领风骚一二年。天天谈芯 成立于1999年10月的中星微电子,除了CMOS数码图像处理芯片“星光N号”取得成功,公司依靠“星光中国 ...…

查看全部问答>

USB注册表问题

系统中USB项的注册表下有三个子项: ClientDrivers, FunctionDrivers, LoadClients. 这三项有什么区别和联系吗? …

查看全部问答>

菜鸟向各位请教,bsp编译过程

dir makefile def 和sources文件在编译时各起什么作用?…

查看全部问答>

音频驱动问题,大家指教。在线等!!!!!!!!!

lock_kernel();         mixer.busy = 0;         module_put(dmasound.mach.owner);         unlock_kernel(); --------------lock_kernel();  unlock_kernel();----- ...…

查看全部问答>

想问一下,我打通ZigBee串口,每次只可读写一次,不知道是那里的毛病,并且用linux下的串口也是这样,希望大家指导一下,谢谢

想问一下,我打通ZigBee串口,每次只可读写一次,不知道是那里的毛病,并且用linux下的串口也是这样,希望大家指导一下,谢谢…

查看全部问答>

关于EVC4.0的数据库问题

在网上搜了很多EVC4.0用ADO访问数据的,大多数都说是使用ADOCE3.1,就是那一堆注册什么Dll的,并有一个例子。我在WM5.0的机子上试过了,有一个DLL无法注册,程序可以正常运行(至少那个例子是正常运行了),有人说在Wince 4.2和WM5.0上没有实验过。 ...…

查看全部问答>

51单片机做从I2C,能做到400KHz的通讯速度吗?

51单片机做从I2C,实现51单片机的模块作为一个标准的I2C设备,连接在标准的I2C总线上,晶体是使用的22.1184MHz,能实现400KHz的速度吗?有做过这方面的高手没有?…

查看全部问答>