zoukankan      html  css  js  c++  java
  • Linux Kernel之flush_cache_all在ARM平台下是如何实现的【转】

    转自:http://blog.csdn.net/u011461299/article/details/10199989

    在驱动程序的设计中,我们可能会用到flush_cache_all将ARM cache的内容刷新到RAM,这是因为ARM Linux中cache一般会被设定为write back的。而通常象DMA是访问不了cache,所以如果我们需要启动DMA将RAM中的内容写到Flash中或LCD framebuffer,那么我们就需要调用flush_cache_all将cache中最新的内容刷新到RAM中。如果不这样做在LCD中可能会出现花屏。本文主要分析在ARM平台上到底如何实现的。

    1.1                   flush_cache_all在ARM Linux中的实现

    在include/asm-arm/cacheflush.h中:

    #define flush_cache_all()             __cpuc_flush_kern_all()

    #define __cpuc_flush_kern_all            cpu_cache.flush_kern_all

    在setup_processor():

    list = lookup_processor_type(processor_id);

    //根据processor id找到对应ARM CPU(常见的如ARM926)相关的信息,存在list中。如果想把事情彻底搞清楚,必然要问processor_id是怎么来。它是在Linux Kernel启动时候从ARM chip中读出来。如果以后有机会大家一起讨论ARM Linux的启动全过程,可以详细分析。

          cpu_cache = *list->cache;

    而lookup_processor_type定义在arch/arm/kernel/head-comman.S中:相应的assembler code如下:

         .type __lookup_processor_type, %function

    __lookup_processor_type:

       adr   r3, 3f

       ldmda       r3, {r5 - r7}

       sub  r3, r3, r7                      @ get offset between virt&phys

       add  r5, r5, r3                      @ convert virt addresses to

       add  r6, r6, r3                      @ physical address space

    1:         ldmia        r5, {r3, r4}                    @ value, mask

       and  r4, r4, r9                      @ mask wanted bits

       teq    r3, r4

       beq  2f

       add  r5, r5, #PROC_INFO_SZ            @ sizeof(proc_info_list)

       cmp r5, r6

       blo    1b

       mov  r5, #0                                    @ unknown processor

    2:         mov  pc, lr

    /*

     * This provides a C-API version of the above function.

     */

    ENTRY(lookup_processor_type)

       stmfd        sp!, {r4 - r7, r9, lr}

       mov  r9, r0

       bl      __lookup_processor_type

       mov  r0, r5

       ldmfd        sp!, {r4 - r7, r9, pc}

    /*

     * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for

     * more information about the __proc_info and __arch_info structures.

     */

       .long          __proc_info_begin

       .long          __proc_info_end

    3:         .long          .

       .long          __arch_info_begin

       .long          __arch_info_end

    它其实就是到__proc_info_begin开始的section中去找到对应当前SOC中用的CPU Cache相关的operation list

    再由arch/arm/kernel/vmlinux.lds.S可以__proc_info_begin就是section *(.proc.info.init)的开始地址。

                __proc_info_begin = .;

                       *(.proc.info.init)

                __proc_info_end = .;

    而我们知道我们所用是ARM926,所以其定义在arch/arm/mm/proc-arm926.S:

         .section ".proc.info.init", #alloc, #execinstr

         .type       __arm926_proc_info,#object

    __arm926_proc_info:

      .long       0x41069260                  @ ARM926EJ-S (v5TEJ)

      .long       0xff0ffff0

      .long   PMD_TYPE_SECT |

             PMD_SECT_BUFFERABLE |

             PMD_SECT_CACHEABLE |

             PMD_BIT4 |

             PMD_SECT_AP_WRITE |

             PMD_SECT_AP_READ

      .long   PMD_TYPE_SECT |

             PMD_BIT4 |

             PMD_SECT_AP_WRITE |

             PMD_SECT_AP_READ

      b     __arm926_setup

      .long       cpu_arch_name

      .long       cpu_elf_name

      .long         HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA

      .long       cpu_arm926_name

      .long       arm926_processor_functions

      .long       v4wbi_tlb_fns

      .long       v4wb_user_fns

      .long       arm926_cache_fns

         .size       __arm926_proc_info, . - __arm926_proc_info

    arm926_cache_fns定义在同一个文件中,如下:

    ENTRY(arm926_cache_fns)

      .long       arm926_flush_kern_cache_all

      .long       arm926_flush_user_cache_all

      .long       arm926_flush_user_cache_range

      .long       arm926_coherent_kern_range

      .long       arm926_coherent_user_range

      .long       arm926_flush_kern_dcache_page

      .long       arm926_dma_inv_range

      .long       arm926_dma_clean_range

      .long       arm926_dma_flush_range

    它所对应的struct的定义:(include/asm-arm/cacheflush.h)

    struct cpu_cache_fns {

      void (*flush_kern_all)(void);

      void (*flush_user_all)(void);

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

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

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

      void (*flush_kern_dcache_page)(void *);

      void (*dma_inv_range)(const void *, const void *);

      void (*dma_clean_range)(const void *, const void *);

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

    };

    所以其实flush_cache_all 在我们的项目中就是arm926_flush_kern_cache_all:其实现在同一个文件中:

    /*

     *   flush_kern_cache_all()

    *  Clean and invalidate the entire cache.

     */

    ENTRY(arm926_flush_kern_cache_all)

      mov r2, #VM_EXEC

      mov ip, #0

    __flush_whole_cache:

    #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH

      mcr  p15, 0, ip, c7, c6, 0              @ invalidate D cache

    #else

    1:      mrc  p15, 0, r15, c7, c14, 3   @ test,clean,invalidate

      bne  1b

    #endif

      tst   r2, #VM_EXEC

      mcrne     p15, 0, ip, c7, c5, 0              @ invalidate I cache

      mcrne     p15, 0, ip, c7, c10, 4            @ drain WB

      mov pc, lr

    最后我们它不仅仅flush 所有的cache(包括ICache和DCache),也flush了Write Buffer。

  • 相关阅读:
    php 人员权限管理(RBAC)
    CSS3的@keyframes用法详解
    phpcms安装与使用
    PDO 数据访问抽象层
    ajax的分页查询
    php 增删改查范例(3)
    php 增删改查范例(2)
    maven部署项目流程(区分环境)
    springboot分环境打包(maven动态选择环境)
    Guava Cache -- MapMaker.makeComputingMap测试
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5896366.html
Copyright © 2011-2022 走看看