x86: c_p_a clflush_cache_range fix
PATCH 2/5 x86: c_p_a clflush_cache_range fix
Because in i386 early boot stage, boot_cpu_data may be not available, which makes clflush_cach_range() into infinite loop, which is called by change_page_attr(). This patch fixes this by providing a default clflush_size of 64. But the better method may be providing a early_identify_cpu() for i386.
--- arch/x86/mm/pageattr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/mm/pageattr.c +4 -1
@@ -36,11 +36,14 @@ within(unsigned long addr, unsigned long*/ void clflush_cache_range (void *vaddr,unsigned int size) { +int clflush_size;void *vend = vaddr + size -1 ;mb (); -for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size) +/* In boot stage, boot_cpu_data may be not available */ + clflush_size = boot_cpu_data.x86_clflush_size ? :64 ; +for (; vaddr < vend; vaddr += clflush_size)clflush (vaddr);/* * Flush any possible final partial cacheline:
Quoted 5 lines · Ying
Because in i386 early boot stage,
boot_cpu_datamay be not available, which makesclflush_cach_range()into infinite loop, which is called bychange_page_attr(). This patch fixes this by providing a defaultclflush_sizeof 64. But the better method may be providing aearly_identify_cpu()for i386.
There already is one. arch/x86/kernel/cpu/common.c:early_cpu_detect Just set it to 64 there.
-Andi
Quoted 9 lines · Andi Kleen
Quoted 5 lines · Ying
Because in i386 early boot stage,
boot_cpu_datamay be not available, which makesclflush_cach_range()into infinite loop, which is called bychange_page_attr(). This patch fixes this by providing a defaultclflush_sizeof 64. But the better method may be providing aearly_identify_cpu()for i386.There already is one. arch/x86/kernel/cpu/common.c:early_cpu_detect Just set it to 64 there.
Thanks. The following is a new patch based on your reminding.
--------------------------------------------------------------------
Because in i386 early boot stage, boot_cpu_data may be not available, which makes clflush_cach_range() into infinite loop, which is called by change_page_attr(). This patch fixes this by setting boot_cpu_data.x86_clflush_size in early_cpu_detect().
--- arch/x86/kernel/cpu/common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/common.c +4 -1
@@ -274,8 +274,10 @@ void __init cpu_detect(struct cpuinfo_x8if (c->x86 >=0x6 ) c->x86_model += ((tfms >>16 ) &0xF ) <<4 ; c->x86_mask = tfms &15 ; -if (cap0 & (1 <<19 )) +if (cap0 & (1 <<19 )) { c->x86_cache_alignment = ((misc >>8 ) &0xff ) *8 ; + c->x86_clflush_size = ((misc >>8 ) &0xff ) *8 ; + } } }static void __cpuinit early_get_cap (struct cpuinfo_x86 *c)
@@ -317,6 +319,7 @@ static void __init early_cpu_detect(voidstruct cpuinfo_x86 *c = &boot_cpu_data; c->x86_cache_alignment =32 ; + c->x86_clflush_size =32 ;if (!have_cpuid_p ())return ;
arch/x86/kernel/cpu/common.c void __init cpu_detect(struct cpuinfo_x8 · line 280
Quoted 10 lines · Huang, Ying
+++
b/arch/x86/kernel/cpu/common.carch/x86/kernel/cpu/common.c +3
-1@@ -274,8 +274,10 @@ void __init cpu_detect(struct cpuinfo_x8if (c->x86 >=0x6 ) c->x86_model += ((tfms >>16 ) &0xF ) <<4 ; c->x86_mask = tfms &15 ; -if (cap0 & (1 <<19 )) +if (cap0 & (1 <<19 )) { c->x86_cache_alignment = ((misc >>8 ) &0xff ) *8 ; + c->x86_clflush_size = ((misc >>8 ) &0xff ) *8 ; + }
thanks!
arch/x86/kernel/cpu/common.c static void __init early_cpu_detect(void · line 322
Quoted 5 lines
arch/x86/kernel/cpu/common.c +1
-0@@ -317,6 +319,7 @@ static void __init early_cpu_detect(voidstruct cpuinfo_x86 *c = &boot_cpu_data; c->x86_cache_alignment =32 ; + c->x86_clflush_size =32 ;
i suspect 32 is a good lower limit (it's not a big issue to do too finegrained flushes, and CLFLUSH is valid with arbitrary alignment) - and this will be overriden with 64 later on.
Ingo