linux booting過程中會(huì)打印CACHE的寫機(jī)制,打印信息如下:
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writealloc
以上打印信息來自于函數(shù)
build_mem_type_table(void)
它的調(diào)用棧如下:
setup_arch
|
#ifdef CONFIG_MMU
early_mm_init(mdesc);
#endif
|
early_mm_init()
|
build_mem_type_table();
build_mem_type_table()函數(shù)的功能是獲取當(dāng)前CPU的CACHE類型,據(jù)此初始化mem_type。kernel根據(jù)mem_types數(shù)據(jù)結(jié)構(gòu)的值,做后續(xù)的其他處理。
由于build_mem_type_table()
屬于early_mm_init()
的一部分,因此,從early_mm_init()
入手,逐步解析CACHE的寫機(jī)制。
early_mm_init(mdesc)
early_mm_init()能否得到執(zhí)行,取決于當(dāng)前kernel是否使能了MMU。
該函數(shù)的定義位于setup.c中
void __init early_mm_init(const struct machine_desc *mdesc)
{
build_mem_type_table();
early_paging_init(mdesc);
}
函數(shù)參數(shù)是struct machine_desc指針。數(shù)據(jù)結(jié)構(gòu)machine_desc描述了CPU的硬件信息及一些初始化函數(shù)。
struct machine_desc {
unsigned int nr;
const char *name;
unsigned long atag_offset;
const char *const *dt_compat;
unsigned int nr_irqs;
#ifdef CONFIG_ZONE_DMA
phys_addr_t dma_zone_size;
#endif
unsigned int video_start;
unsigned int video_end;
unsigned char reserve_lp0 :1;
unsigned char reserve_lp1 :1;
unsigned char reserve_lp2 :1;
enum reboot_mode reboot_mode;
unsigned l2c_aux_val;
unsigned l2c_aux_mask;
void (*l2c_write_sec)(unsigned long, unsigned);
const struct smp_operations *smp;
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **);
void (*dt_fixup)(void);
long long (*pv_fixup)(void);
void (*reserve)(void);
void (*map_io)(void);
void (*init_early)(void);
void (*init_irq)(void);
void (*init_time)(void);
void (*init_machine)(void);
void (*init_late)(void);
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
void (*restart)(enum reboot_mode, const char *);
};
通過解析設(shè)備樹鏡像得到mdesc成員的具體值是什么。
if (atags_vaddr) {
mdesc = setup_machine_fdt(atags_vaddr);
if (mdesc)
memblock_reserve(__atags_pointer,
fdt_totalsize(atags_vaddr));
}
build_mem_type_table()
這個(gè)函數(shù)的核心作用是初始化struct mem_type數(shù)據(jù)結(jié)構(gòu),定義如下:
struct mem_type {
pteval_t prot_pte;
pteval_t prot_pte_s2;
pmdval_t prot_l1;
pmdval_t prot_sect;
unsigned int domain;
};
該數(shù)據(jù)結(jié)構(gòu)的歷史:
author Russell King < rmk@dyn-67.arm.linux.org.uk > 2007-04-21 10:47:29 +0100
committer Russell King < rmk+kernel@arm.linux.org.uk > 2007-04-21 20:36:00 +0100
[ARM] mm 5: Use mem_types table in ioremap
We really want to be using the memory type table in ioremap, so we
only have to do the CPU type fixups in one place.
Signed-off-by: Russell King < rmk+kernel@arm.linux.org.uk >
Diffstat (limited to 'arch/arm/mm/mm.h')
-rw-r--r-- arch/arm/mm/mm.h 9
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a44e309706354..66f8612c5e5b9 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
+struct mem_type {
+ unsigned int prot_pte;
+ unsigned int prot_l1;
+ unsigned int prot_sect;
+ unsigned int domain;
+};
+
+const struct mem_type *get_mem_type(unsigned int type);
+
從commit信息中可以看到,struct mem_type最初的目的是給ioremap使用的,在這個(gè)patch中,增加了struct mem_type以及get_mem_type()。
到目前為止,這個(gè)數(shù)據(jù)結(jié)構(gòu)的作用已經(jīng)不僅限上面提及的內(nèi)容。更為主要的作用是根據(jù)mem類型創(chuàng)建內(nèi)核頁表。
build_mem_type_table()函數(shù)根據(jù)ARM內(nèi)核版本號(hào)例化不同的mem類型。 包括ARM v5/6/7。
int cpu_arch = cpu_architecture();
在mmu.c的init_default_cache_policy中會(huì)對(duì)cachepolicy進(jìn)行初始化。
mmu.c (arch\\arm\\mm) line 64 : static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
init_default_cache_policy in mmu.c (arch\\arm\\mm) : cachepolicy = i;
根據(jù)不同的CPU 架構(gòu)類型對(duì)cachepolicy變量重新賦值。
build_mem_type_table in mmu.c (arch\\arm\\mm) : if (cachepolicy > CPOLICY_BUFFERED)
build_mem_type_table in mmu.c (arch\\arm\\mm) : cachepolicy = CPOLICY_BUFFERED;
build_mem_type_table in mmu.c (arch\\arm\\mm) : if (cachepolicy > CPOLICY_WRITETHROUGH)
build_mem_type_table in mmu.c (arch\\arm\\mm) : cachepolicy = CPOLICY_WRITETHROUGH;
build_mem_type_table in mmu.c (arch\\arm\\mm) : if (cachepolicy >= CPOLICY_WRITEALLOC)
build_mem_type_table in mmu.c (arch\\arm\\mm) : cachepolicy = CPOLICY_WRITEBACK;
build_mem_type_table in mmu.c (arch\\arm\\mm) : if (cachepolicy != CPOLICY_WRITEALLOC) {
build_mem_type_table in mmu.c (arch\\arm\\mm) : cachepolicy = CPOLICY_WRITEALLOC;
內(nèi)核中定義了4中CACHE 寫策略,分別是:
#define CPOLICY_BUFFERED 1
#define CPOLICY_WRITETHROUGH 2
#define CPOLICY_WRITEBACK 3
#define CPOLICY_WRITEALLOC 4
最后,根據(jù)cachepolicy的值例化數(shù)據(jù)結(jié)構(gòu)struct cachepolicy *cp,
cp = &cache_policies[cachepolicy];
在我的環(huán)境中,cachepolicy的值為4,其對(duì)應(yīng)的CACHE屬性為writealloc。
static struct cachepolicy cache_policies[] __initdata = {
{
.policy = "uncached",
.cr_mask = CR_W|CR_C,
.pmd = PMD_SECT_UNCACHED,
.pte = L_PTE_MT_UNCACHED,
.pte_s2 = s2_policy(L_PTE_S2_MT_UNCACHED),
}, {
.policy = "buffered",
.cr_mask = CR_C,
.pmd = PMD_SECT_BUFFERED,
.pte = L_PTE_MT_BUFFERABLE,
.pte_s2 = s2_policy(L_PTE_S2_MT_UNCACHED),
}, {
.policy = "writethrough",
.cr_mask = 0,
.pmd = PMD_SECT_WT,
.pte = L_PTE_MT_WRITETHROUGH,
.pte_s2 = s2_policy(L_PTE_S2_MT_WRITETHROUGH),
}, {
.policy = "writeback",
.cr_mask = 0,
.pmd = PMD_SECT_WB,
.pte = L_PTE_MT_WRITEBACK,
.pte_s2 = s2_policy(L_PTE_S2_MT_WRITEBACK),
}, {
.policy = "writealloc",
.cr_mask = 0,
.pmd = PMD_SECT_WBWA,
.pte = L_PTE_MT_WRITEALLOC,
.pte_s2 = s2_policy(L_PTE_S2_MT_WRITEBACK),
}
};
writealloc結(jié)合了write back的功能,而write back是在CACHE hit時(shí)所采取的策略,alloc是在CACHE miss所采取的策略,當(dāng)發(fā)生CACHE miss時(shí),會(huì)從主存中讀取數(shù)據(jù)并更新CACHE line到CACHE緩存中。對(duì)于SMP ARM而言,普遍采取的是這種CACHE 策略,結(jié)合ARM 的SCU完成緩存一致性的處理。可以查看ARM的如下寄存器確定CACHE所支持的策略類型。
CACHE寫策略
下圖是一個(gè)標(biāo)準(zhǔn)的ARM處理器的芯片版圖布局,使用SRAM作為L(zhǎng)1 CACHE,它在ARM core這一區(qū)域。通過DDR SDRAM interface訪問位于芯片外部的主存DDR memory。簡(jiǎn)單而論,從二者布局布線的角度看,訪問外部DDR memory的cycle明顯高于內(nèi)部L1 CACHE。
當(dāng)CPU執(zhí)行數(shù)據(jù)寫操作時(shí),首先檢查待寫入的內(nèi)存地址是否在CACHE中,若在CACHE中則稱之為Hit,反之為Miss。在Hit命中的前提下,CACHE寫策略分為Write back和Write through。
Write through
CACHE工作于write through模式時(shí),數(shù)據(jù)同時(shí)更新到CACHE和主存當(dāng)中。這種操作模式簡(jiǎn)單可靠,適用于寫操作比較少的應(yīng)用場(chǎng)景,或者預(yù)防突然斷電的數(shù)據(jù)恢復(fù)機(jī)制中。當(dāng)然,由于同時(shí)更新CACHE和外部主存,這種寫模式的延時(shí)比較大。
Write back
CACHE工作于write through模式時(shí),數(shù)據(jù)僅更新到CACHE中而不會(huì)立即更新到主存。基于Belady’s Anomaly, LRU, FIFO, LIFO等算法,當(dāng)CACHE中的數(shù)據(jù)需要被替換時(shí),原數(shù)據(jù)會(huì)被更新到主存當(dāng)中。在CACHE的每一個(gè)block中,使用一個(gè)dirty位來標(biāo)記當(dāng)前數(shù)據(jù)是否需要被替換,若dirty位被置位1,則需要將數(shù)據(jù)更新到主存。
-
SMP
+關(guān)注
關(guān)注
0文章
72瀏覽量
19635 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
592瀏覽量
27360 -
ARM處理器
+關(guān)注
關(guān)注
6文章
360瀏覽量
41668 -
MMU
+關(guān)注
關(guān)注
0文章
91瀏覽量
18268 -
cache技術(shù)
+關(guān)注
關(guān)注
0文章
41瀏覽量
1048
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論