MIPS: Loongson: new features and improvements
Subsystems (5)
v5 cover MIPS: Loongson: new features and improvements
This patchset is prepared for the next 4.21 release for Linux/MIPS. It add Loongson-3A R2.1 basic support, adds "model name" and "CPU MHz" knobs in /proc/cpuinfo which is needed by some userspace tools, adds Loongson-3 kexec/kdump support, and introduces WAR_LLSC_MB to improve stability.
V1 -> V2:
1, Add Loongson-3A R3.1 basic support.
2, Fix CPU UART irq delivery problem.
3, Improve code and descriptions (Thank James Hogan). 4, Sync the code to upstream.
V2 -> V3:
1, Remove merged patches.
2, Improve code and descriptions (Thank James Hogan). 3, Sync the code to upstream.
V3 -> V4:
1, Remove merged patches.
2, Improve kdump support.
3, Sync the code to upstream.
V4 -> V5:
1, Remove merged patches.
2, Add Loongson-3A R2.1 support.
3, Improve kexec/kdump support.
4, Sync the code to upstream.
Huacai Chen(8):
MIPS: Loongson: Add Loongson-3A R2.1 basic support.
MIPS: c-r4k: Add r4k_blast_scache_node for Loongson-3.
MIPS: Ensure pmd_present() returns false after pmd_mknotpresent().
MIPS: Add __cpu_full_name[] to make CPU names more human-readable.
MIPS: Align kernel load address to 64KB.
MIPS: Reserve extra memory for crash dump.
MIPS: Loongson: Add kexec/kdump support.
MIPS: Loongson: Introduce and use WAR_LLSC_MB.
--- arch/mips/boot/compressed/calc_vmlinuz_load_addr.c | 7 +- arch/mips/include/asm/atomic.h | 36 ++++++-- arch/mips/include/asm/barrier.h | 6 ++ arch/mips/include/asm/bitops.h | 15 ++++ arch/mips/include/asm/cmpxchg.h | 9 +- arch/mips/include/asm/cpu-info.h | 2 + arch/mips/include/asm/cpu.h | 3 +- arch/mips/include/asm/edac.h | 5 +- arch/mips/include/asm/futex.h | 18 ++-- arch/mips/include/asm/local.h | 10 ++- arch/mips/include/asm/mach-loongson64/boot_param.h | 1 + .../asm/mach-loongson64/kernel-entry-init.h | 4 +- arch/mips/include/asm/mach-loongson64/mmzone.h | 1 + arch/mips/include/asm/mmzone.h | 8 ++ arch/mips/include/asm/pgtable-64.h | 5 ++ arch/mips/include/asm/pgtable.h | 5 +- arch/mips/include/asm/r4kcache.h | 21 +++++ arch/mips/include/asm/time.h | 2 + arch/mips/kernel/cpu-probe.c | 28 +++++-- arch/mips/kernel/idle.c | 2 +- arch/mips/kernel/proc.c | 6 ++ arch/mips/kernel/relocate_kernel.S | 26 ++++++ arch/mips/kernel/setup.c | 51 ++++++++++++ arch/mips/kernel/syscall.c | 2 + arch/mips/kernel/time.c | 2 + arch/mips/loongson64/Platform | 3 + arch/mips/loongson64/common/env.c | 23 +++++- arch/mips/loongson64/common/reset.c | 95 ++++++++++++++++++++++ arch/mips/loongson64/loongson-3/smp.c | 9 +- arch/mips/loongson64/loongson-3/smp.h | 1 + arch/mips/mm/c-r4k.c | 46 +++++++++-- arch/mips/mm/tlbex.c | 11 +++ drivers/platform/mips/cpu_hwmon.c | 3 +- 33 files changed, 421 insertions(+), 45 deletions(-)
--
2.7.0
PATCH v5 1/8 MIPS: Loongson: Add Loongson-3A R2.1 basic support
Loongson-3A R2.1 is the bugfix revision of Loongson-3A R2.
All Loongson-3 CPU family:
Code-name Brand-name PRId Loongson-3A R1 Loongson-3A1000 0x6305 Loongson-3A R2 Loongson-3A2000 0x6308 Loongson-3A R2.1 Loongson-3A2000 0x630c Loongson-3A R3 Loongson-3A3000 0x6309 Loongson-3A R3.1 Loongson-3A3000 0x630d Loongson-3B R1 Loongson-3B1000 0x6306 Loongson-3B R2 Loongson-3B1500 0x6307
--- arch/mips/include/asm/cpu.h | 3 ++- arch/mips/include/asm/mach-loongson64/kernel-entry-init.h | 4 ++-- arch/mips/kernel/cpu-probe.c | 3 ++- arch/mips/kernel/idle.c | 2 +- arch/mips/loongson64/common/env.c | 3 ++- arch/mips/loongson64/loongson-3/smp.c | 3 ++- arch/mips/mm/c-r4k.c | 2 +- drivers/platform/mips/cpu_hwmon.c | 3 ++- 8 files changed, 14 insertions(+), 9 deletions(-)
arch/mips/include/asm/cpu.h +2 -1
@@ -248,8 +248,9 @@#define PRID_REV_LOONGSON3A_R1 0x0005#define PRID_REV_LOONGSON3B_R1 0x0006#define PRID_REV_LOONGSON3B_R2 0x0007 -#define PRID_REV_LOONGSON3A_R2 0x0008 +#define PRID_REV_LOONGSON3A_R2_0 0x0008#define PRID_REV_LOONGSON3A_R3_0 0x0009 +#define PRID_REV_LOONGSON3A_R2_1 0x000c#define PRID_REV_LOONGSON3A_R3_1 0x000d/*
arch/mips/include/asm/mach-loongson64/kernel-entry-init.h +2 -2
@@ -31,7 +31,7 @@/* Enable STFill Buffer */ mfc0 t0,CP0_PRID andi t0, (PRID_IMP_MASK | PRID_REV_MASK) - slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2) + slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2_0) bnez t0, 1f mfc0 t0, CP0_CONFIG6 or t0, 0x100
@@ -60,7 +60,7 @@/* Enable STFill Buffer */ mfc0 t0,CP0_PRID andi t0, (PRID_IMP_MASK | PRID_REV_MASK) - slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2) + slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2_0) bnez t0, 1f mfc0 t0, CP0_CONFIG6 or t0, 0x100
arch/mips/kernel/cpu-probe.c +2 -1
@@ -1871,7 +1871,8 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)switch (c->processor_id &PRID_IMP_MASK ) {case PRID_IMP_LOONGSON_64 :/* Loongson-2/3 */ switch (c->processor_id &PRID_REV_MASK ) { -case PRID_REV_LOONGSON3A_R2 : +case PRID_REV_LOONGSON3A_R2_0 : +case PRID_REV_LOONGSON3A_R2_1 : c->cputype =CPU_LOONGSON3 ; __cpu_name[cpu] ="ICT Loongson-3" ;set_elf_platform (cpu,"loongson3a" );
arch/mips/kernel/idle.c +1 -1
@@ -184,7 +184,7 @@ void __init check_wait(void) cpu_wait = r4k_wait;break ;case CPU_LOONGSON3 : -if ((c->processor_id &PRID_REV_MASK ) >=PRID_REV_LOONGSON3A_R2 ) +if ((c->processor_id &PRID_REV_MASK ) >=PRID_REV_LOONGSON3A_R2_0 ) cpu_wait = r4k_wait;break ;
arch/mips/loongson64/common/env.c +2 -1
@@ -197,7 +197,8 @@ void __init prom_init_env(void) cpu_clock_freq =797000000 ;break ;case PRID_REV_LOONGSON3A_R1 : -case PRID_REV_LOONGSON3A_R2 : +case PRID_REV_LOONGSON3A_R2_0 : +case PRID_REV_LOONGSON3A_R2_1 :case PRID_REV_LOONGSON3A_R3_0 :case PRID_REV_LOONGSON3A_R3_1 : cpu_clock_freq =900000000 ;
arch/mips/loongson64/loongson-3/smp.c +2 -1
@@ -682,7 +682,8 @@ void play_dead(void) play_dead_at_ckseg1 = (void *)CKSEG1ADDR ((unsigned long )loongson3a_r1_play_dead);break ; -case PRID_REV_LOONGSON3A_R2 : +case PRID_REV_LOONGSON3A_R2_0 : +case PRID_REV_LOONGSON3A_R2_1 :case PRID_REV_LOONGSON3A_R3_0 :case PRID_REV_LOONGSON3A_R3_1 : play_dead_at_ckseg1 =
arch/mips/mm/c-r4k.c +1 -1
@@ -1352,7 +1352,7 @@ static void probe_pcache(void) c->dcache.ways * c->dcache.linesz; c->dcache.waybit =0 ; -if ((prid &PRID_REV_MASK ) >=PRID_REV_LOONGSON3A_R2 ) +if ((prid &PRID_REV_MASK ) >=PRID_REV_LOONGSON3A_R2_0 ) c->options |=MIPS_CPU_PREFETCH ;break ;
drivers/platform/mips/cpu_hwmon.c +2 -1
@@ -25,9 +25,10 @@ int loongson3_cpu_temp(int cpu)case PRID_REV_LOONGSON3A_R1 : reg = (reg >>8 ) &0xff ;break ; -case PRID_REV_LOONGSON3A_R2 :case PRID_REV_LOONGSON3B_R1 :case PRID_REV_LOONGSON3B_R2 : +case PRID_REV_LOONGSON3A_R2_0 : +case PRID_REV_LOONGSON3A_R2_1 : reg = ((reg >>8 ) &0xff ) -100 ;break ;case PRID_REV_LOONGSON3A_R3_0 :
Signature · 1 line
2.7.0
Paul Burton
AppliedRe: [PATCH V5 1/8] MIPS: Loongson: Add Loongson-3A R2.1 basic support
Hello,
Quoted 13 lines · Huacai Chen
Loongson-3A R2.1 is the bugfix revision of Loongson-3A R2.
All Loongson-3 CPU family:
Code-name Brand-name PRId Loongson-3A R1 Loongson-3A1000 0x6305 Loongson-3A R2 Loongson-3A2000 0x6308 Loongson-3A R2.1 Loongson-3A2000 0x630c Loongson-3A R3 Loongson-3A3000 0x6309 Loongson-3A R3.1 Loongson-3A3000 0x630d Loongson-3B R1 Loongson-3B1000 0x6306 Loongson-3B R2 Loongson-3B1500 0x6307
Quoted 1 line
Signed-off-by Huacai Chen <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
PATCH v5 2/8 MIPS: c-r4k: Add r4k_blast_scache_node for Loongson-3
In reply to Huacai ChenFor multi-node Loongson-3 (NUMA configuration), r4k_blast_scache() can only flush Node-0's scache. So we add r4k_blast_scache_node() by using (CAC_BASE | (node_id << NODE_ADDRSPACE_SHIFT)) instead of CKSEG0 as the start address.
--- arch/mips/include/asm/mach-loongson64/mmzone.h | 1 + arch/mips/include/asm/mmzone.h | 8 +++++ arch/mips/include/asm/r4kcache.h | 25 +++++++++++++++ arch/mips/mm/c-r4k.c | 44 ++++++++++++++++++++++---- 4 files changed, 71 insertions(+), 7 deletions(-)
arch/mips/include/asm/mach-loongson64/mmzone.h +1 -0
@@ -21,6 +21,7 @@#define NODE3_ADDRSPACE_OFFSET 0x300000000000UL#define pa_to_nid (addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) +#define nid_to_addrbase (nid) ((nid) << NODE_ADDRSPACE_SHIFT)#define LEVELS_PER_SLICE 128
arch/mips/include/asm/mmzone.h +8 -0
@@ -9,6 +9,14 @@#include <asm/page.h> #include <mmzone.h> +#ifndef pa_to_nid +#define pa_to_nid (addr) 0 +#endif + +#ifndef nid_to_addrbase +#define nid_to_addrbase (nid) 0 +#endif +#ifdef CONFIG_DISCONTIGMEM #define pfn_to_nid (pfn) pa_to_nid((pfn) << PAGE_SHIFT)
arch/mips/include/asm/r4kcache.h +21 -0
@@ -674,4 +674,25 @@ __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , ) __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , ) __BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, , ) +/* Currently, this is very specific to Loongson-3 */ +#define __BUILD_BLAST_CACHE_NODE(pfx, desc, indexop, hitop, lsize) \ +static inline void blast_##pfx##cache##lsize##_node(long node) \ +{ \ + unsigned long start = CAC_BASE | nid_to_addrbase(node); \ + unsigned long end = start + current_cpu_data.desc.waysize; \ + unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit; \ + unsigned long ws_end = current_cpu_data.desc.ways << \ + current_cpu_data.desc.waybit; \ + unsigned long ws, addr; \ + \ + for (ws = 0; ws < ws_end; ws += ws_inc) \ + for (addr = start; addr < end; addr += lsize * 32) \ + cache##lsize##_unroll32(addr|ws, indexop); \ +} + +__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16) +__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32) +__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) +__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) +#endif /* _ASM_R4KCACHE_H */
arch/mips/mm/c-r4k.c +37 -7
79 lines not on this page · raw message
Signature · 1 line
2.7.0
Paul Burton
AppliedRe: [PATCH V5 2/8] MIPS: c-r4k: Add r4k_blast_scache_node for Loongson-3
Hello,
Quoted 7 lines · Huacai Chen
For multi-node Loongson-3 (NUMA configuration),
r4k_blast_scache()can only flush Node-0's scache. So we addr4k_blast_scache_node()by using (CAC_BASE| (node_id<<NODE_ADDRSPACE_SHIFT)) instead of CKSEG0 as the start address.Cc <[email protected]> # 3.15+Signed-off-by Huacai Chen <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
PATCH v5 3/8 MIPS: Ensure pmd_present() returns false after pmd_mknotpresent()
In reply to Huacai ChenThis patch is borrowed from ARM64 to ensure pmd_present() returns false after pmd_mknotpresent(). This is needed for THP.
Cc: <[email protected]> # 3.8+
References: 5bb1cc0ff9a6 ("arm64: Ensure pmd_present() returns false after pmd_mknotpresent()")
--- arch/mips/include/asm/pgtable-64.h | 5 +++++ 1 file changed, 5 insertions(+)
arch/mips/include/asm/pgtable-64.h +5 -0
@@ -265,6 +265,11 @@ static inline int pmd_bad(pmd_t pmd)static inline int pmd_present (pmd_t pmd) { +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT +if (unlikely (pmd_val (pmd) & _PAGE_HUGE)) +return pmd_val (pmd) & _PAGE_PRESENT; +#endif +return pmd_val (pmd) != (unsigned long ) invalid_pte_table; }
Signature · 1 line
2.7.0
Paul Burton
AppliedRe: [PATCH V5 3/8] MIPS: Ensure pmd_present() returns false after pmd_mknotpresent()
Hello,
Quoted 7 lines · Huacai Chen
This patch is borrowed from ARM64 to ensure
pmd_present()returns false afterpmd_mknotpresent(). This is needed for THP.Cc: <[email protected]> # 3.8+
References:5bb1cc0ff9a6("arm64: Ensurepmd_present()returns false afterpmd_mknotpresent()")Reviewed-by James Hogan <[email protected]>Signed-off-by Huacai Chen <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
PATCH v5 4/8 MIPS: Add __cpu_full_name[] to make CPU names more human-readable
In reply to Huacai ChenIn /proc/cpuinfo, we keep "cpu model" as is, since GCC should use it for -march=native. Besides, we add __cpu_full_name[] to describe the processor in a more human-readable manner. The full name is displayed as "model name" in cpuinfo, which is needed by some userspace tools such as gnome-system-monitor.
The CPU frequency in "model name" is the default value (highest), and there is also a "CPU MHz" whose value can be changed by cpufreq.
This is only used by Loongson now (ICT is dropped in cpu name, and cpu name can be overwritten by BIOS).
--- arch/mips/include/asm/cpu-info.h | 2 ++ arch/mips/include/asm/mach-loongson64/boot_param.h | 1 + arch/mips/include/asm/time.h | 2 ++ arch/mips/kernel/cpu-probe.c | 25 ++++++++++++++++------ arch/mips/kernel/proc.c | 6 ++++++ arch/mips/kernel/time.c | 2 ++ arch/mips/loongson64/common/env.c | 13 +++++++++++ arch/mips/loongson64/loongson-3/smp.c | 1 + arch/mips/loongson64/loongson-3/smp.h | 1 + 9 files changed, 47 insertions(+), 6 deletions(-)
arch/mips/include/asm/cpu-info.h +2 -0
@@ -116,7 +116,9 @@ extern void cpu_probe(void);extern void cpu_report (void );extern const char *__cpu_name[]; +extern const char *__cpu_full_name[];#define cpu_name_string () __cpu_name[raw_smp_processor_id()] +#define cpu_full_name_string () __cpu_full_name[raw_smp_processor_id()]struct seq_file ;struct notifier_block ;
arch/mips/include/asm/mach-loongson64/boot_param.h +1 -0
@@ -58,6 +58,7 @@ struct efi_cpuinfo_loongson {u16 reserved_cores_mask;u32 cpu_clock_freq;/* cpu_clock */ u32 nr_cpus; +char cpuname[64 ]; } __packed;#define MAX_UARTS 64
arch/mips/include/asm/time.h +2 -0
@@ -26,6 +26,8 @@ extern spinlock_t rtc_lock;*/ extern void plat_time_init (void ); +extern unsigned int mips_cpu_frequency; +/* * mips_hpt_frequency - must be set if you intend to use an R4k-compatible * counter as a timer interrupt source.
arch/mips/kernel/cpu-probe.c +19 -6
@@ -1500,30 +1500,40 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)switch (c->processor_id &PRID_REV_MASK ) {case PRID_REV_LOONGSON2E : c->cputype =CPU_LOONGSON2 ; - __cpu_name[cpu] ="ICT Loongson-2" ; + __cpu_name[cpu] ="Loongson-2" ;set_elf_platform (cpu,"loongson2e" );set_isa (c,MIPS_CPU_ISA_III ); c->fpu_msk31 |=FPU_CSR_CONDX ; + __cpu_full_name[cpu] ="Loongson-2E" ;break ;case PRID_REV_LOONGSON2F : c->cputype =CPU_LOONGSON2 ; - __cpu_name[cpu] ="ICT Loongson-2" ; + __cpu_name[cpu] ="Loongson-2" ;set_elf_platform (cpu,"loongson2f" );set_isa (c,MIPS_CPU_ISA_III ); c->fpu_msk31 |=FPU_CSR_CONDX ; + __cpu_full_name[cpu] ="Loongson-2F" ;break ;case PRID_REV_LOONGSON3A_R1 : c->cputype =CPU_LOONGSON3 ; - __cpu_name[cpu] ="ICT Loongson-3" ; + __cpu_name[cpu] ="Loongson-3" ;set_elf_platform (cpu,"loongson3a" );set_isa (c,MIPS_CPU_ISA_M64R1 ); + __cpu_full_name[cpu] ="Loongson-3A R1 (Loongson-3A1000)" ;break ;case PRID_REV_LOONGSON3B_R1 : + c->cputype =CPU_LOONGSON3 ; + __cpu_name[cpu] ="Loongson-3" ; +set_elf_platform (cpu,"loongson3b" ); +set_isa (c,MIPS_CPU_ISA_M64R1 ); + __cpu_full_name[cpu] ="Loongson-3B R1 (Loongson-3B1000)" ; +break ;case PRID_REV_LOONGSON3B_R2 : c->cputype =CPU_LOONGSON3 ; - __cpu_name[cpu] ="ICT Loongson-3" ; + __cpu_name[cpu] ="Loongson-3" ;set_elf_platform (cpu,"loongson3b" );set_isa (c,MIPS_CPU_ISA_M64R1 ); + __cpu_full_name[cpu] ="Loongson-3B R2 (Loongson-3B1500)" ;break ; }
@@ -1874,16 +1884,18 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)case PRID_REV_LOONGSON3A_R2_0 :case PRID_REV_LOONGSON3A_R2_1 : c->cputype =CPU_LOONGSON3 ; - __cpu_name[cpu] ="ICT Loongson-3" ; + __cpu_name[cpu] ="Loongson-3" ;set_elf_platform (cpu,"loongson3a" );set_isa (c,MIPS_CPU_ISA_M64R2 ); + __cpu_full_name[cpu] ="Loongson-3A R2 (Loongson-3A2000)" ;break ;case PRID_REV_LOONGSON3A_R3_0 :case PRID_REV_LOONGSON3A_R3_1 : c->cputype =CPU_LOONGSON3 ; - __cpu_name[cpu] ="ICT Loongson-3" ; + __cpu_name[cpu] ="Loongson-3" ;set_elf_platform (cpu,"loongson3a" );set_isa (c,MIPS_CPU_ISA_M64R2 ); + __cpu_full_name[cpu] ="Loongson-3A R3 (Loongson-3A3000)" ;break ; }
@@ -2003,6 +2015,7 @@ EXPORT_SYMBOL(__ua_limit);#endif const char *__cpu_name[NR_CPUS ]; +const char *__cpu_full_name[NR_CPUS ];const char *__elf_platform;void cpu_probe (void )
arch/mips/kernel/proc.c +6 -0
@@ -15,6 +15,7 @@#include <asm/mipsregs.h> #include <asm/processor.h> #include <asm/prom.h> +#include <asm/time.h> unsigned int vced_count, vcei_count;
@@ -63,6 +64,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)seq_printf (m, fmt, __cpu_name[n], (version >>4 ) &0x0f , version &0x0f , (fp_vers >>4 ) &0x0f , fp_vers &0x0f ); +if (__cpu_full_name[n]) +seq_printf (m,"model name\t\t: %s\n" , __cpu_full_name[n]); +if (mips_cpu_frequency) +seq_printf (m,"CPU MHz\t\t\t: %u.%02u\n" , + mips_cpu_frequency /1000000 , (mips_cpu_frequency /10000 ) %100 );seq_printf (m,"BogoMIPS\t\t: %u.%02u\n" , cpu_data[n].udelay_val / (500000 /HZ ), (cpu_data[n].udelay_val / (5000 /HZ )) %100 );
arch/mips/kernel/time.c +2 -0
@@ -54,6 +54,8 @@ EXPORT_SYMBOL(perf_irq);* 2) calculate a couple of cached variables for later usage */ +unsigned int mips_cpu_frequency; +EXPORT_SYMBOL_GPL (mips_cpu_frequency);unsigned int mips_hpt_frequency;EXPORT_SYMBOL_GPL (mips_hpt_frequency);
arch/mips/loongson64/common/env.c +13 -0
@@ -18,6 +18,7 @@* option) any later version. */ #include <linux/export.h> +#include <asm/time.h> #include <asm/bootinfo.h> #include <loongson.h> #include <boot_param.h>
@@ -25,6 +26,7 @@u32 cpu_clock_freq;EXPORT_SYMBOL (cpu_clock_freq); +char cpu_full_name[64 ];struct efi_memory_map_loongson *loongson_memmap;struct loongson_system_configuration loongson_sysconf;
@@ -45,6 +47,7 @@ do { \void __init prom_init_env (void ) {/* pmon passes arguments in 32bit pointers */ +char freq[12 ];unsigned int processor_id;#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
@@ -151,6 +154,10 @@ void __init prom_init_env(void) loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + loongson_sysconf.cores_per_node -1 ) / loongson_sysconf.cores_per_node; +if (!strncmp (ecpu->cpuname,"Loongson" ,8 )) +strncpy (cpu_full_name, ecpu->cpuname,sizeof (cpu_full_name)); +if (cpu_full_name[0 ] ==0 ) +strncpy (cpu_full_name, __cpu_full_name[0 ],sizeof (cpu_full_name)); loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr; loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
@@ -212,5 +219,11 @@ void __init prom_init_env(void)break ; } } + mips_cpu_frequency = cpu_clock_freq;pr_info ("CpuClock = %u\n" , cpu_clock_freq); + +/* Append default cpu frequency with round-off */ +sprintf (freq," @ %uMHz" , (cpu_clock_freq +500000 ) /1000000 ); +strncat (cpu_full_name, freq,sizeof (cpu_full_name)); + __cpu_full_name[0 ] = cpu_full_name; }
arch/mips/loongson64/loongson-3/smp.c +1 -0
@@ -341,6 +341,7 @@ static void loongson3_init_secondary(void) initcount = core0_c0count[cpu] + i/2 ;write_c0_count (initcount); + __cpu_full_name[cpu] = cpu_full_name; }static void loongson3_smp_finish (void )
arch/mips/loongson64/loongson-3/smp.h +1 -0
@@ -3,6 +3,7 @@#define __LOONGSON_SMP_H_/* for Loongson-3 smp support */ +extern char cpu_full_name[64 ];extern unsigned long long smp_group[4 ];/* 4 groups(nodes) in maximum in numa case */
Signature · 1 line
2.7.0
Re: [PATCH V5 4/8] MIPS: Add __cpu_full_name[] to make CPU names more human-readable
Hi Huacai,
Quoted 2 lines · Huacai Chen
In
/proc/cpuinfo, we keep "cpu model" as is, since GCC should use it for -march=native.
Keeping "cpu model", ie. __cpu_name, as-is sounds good...
Quoted 2 lines
This is only used by Loongson now (ICT is dropped in cpu name, and cpu name can be overwritten by BIOS).
...but you don't do that because you remove "ICT " from it.
Quoted 5 lines
arch/mips/kernel/cpu-probe.c +0
-0
arch/mips/kernel/cpu-probe.c static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) · line 1508
Quoted 10 lines
arch/mips/kernel/cpu-probe.c +2
-1@@ -1500,30 +1500,40 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)switch (c->processor_id &PRID_REV_MASK ) {case PRID_REV_LOONGSON2E : c->cputype =CPU_LOONGSON2 ; - __cpu_name[cpu] ="ICT Loongson-2" ; + __cpu_name[cpu] ="Loongson-2" ;set_elf_platform (cpu,"loongson2e" );set_isa (c,MIPS_CPU_ISA_III ); c->fpu_msk31 |=FPU_CSR_CONDX ; + __cpu_full_name[cpu] ="Loongson-2E" ;break ;
ie. here you've changed the "cpu model" output, and you do the same for other cases.
arch/mips/loongson64/common/env.c void __init prom_init_env(void) · line 226
Quoted 13 lines
arch/mips/loongson64/common/env.c +4
-0@@ -212,5 +219,11 @@ void __init prom_init_env(void)break ; } } + mips_cpu_frequency = cpu_clock_freq;pr_info ("CpuClock = %u\n" , cpu_clock_freq); + +/* Append default cpu frequency with round-off */ +sprintf (freq," @ %uMHz" , (cpu_clock_freq +500000 ) /1000000 );
This would be clearer using DIV_ROUND_CLOSEST(cpu_clock_freq, 1000000).
Thanks,
Paul
PATCH v5 5/8 MIPS: Align kernel load address to 64KB
In reply to Huacai ChenKEXEC needs the new kernel's load address to be aligned on a page boundary (see sanity_check_segment_list()), but on MIPS the default vmlinuz load address is only explicitly aligned to 16 bytes.
Since the largest PAGE_SIZE supported by MIPS kernels is 64KB, increase the alignment calculated by calc_vmlinuz_load_addr to 64KB.
--- arch/mips/boot/compressed/calc_vmlinuz_load_addr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/mips/boot/compressed/calc_vmlinuz_load_addr.c +4 -3
@@ -13,6 +13,7 @@#include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include "../../../../include/linux/sizes.h" int main (int argc,char *argv[]) {
@@ -45,11 +46,11 @@ int main(int argc, char *argv[]) vmlinuz_load_addr = vmlinux_load_addr + vmlinux_size;/* -* Align with 16 bytes: "greater than that used for any standard data -* types by a MIPS compiler." -- See MIPS Run Linux (Second Edition). +* Align with 64KB: KEXEC needs load sections to be aligned to PAGE_SIZE, +* which may be as large as 64KB depending on the kernel configuration. */ - vmlinuz_load_addr += (16 - vmlinux_size %16 ); + vmlinuz_load_addr += (SZ_64K - vmlinux_size %SZ_64K );printf ("0x%llx\n" , vmlinuz_load_addr);
Signature · 1 line
2.7.0
Paul Burton
AppliedRe: [PATCH V5 5/8] MIPS: Align kernel load address to 64KB
Hello,
Quoted 9 lines · Huacai Chen
KEXEC needs the new kernel's load address to be aligned on a page boundary (see
sanity_check_segment_list()), but on MIPS the default vmlinuz load address is only explicitly aligned to 16 bytes.Since the largest
PAGE_SIZEsupported by MIPS kernels is 64KB, increase the alignment calculated bycalc_vmlinuz_load_addrto 64KB.Cc <[email protected]> # 2.6.36+Signed-off-by Huacai Chen <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
PATCH v5 6/8 MIPS: Reserve extra memory for crash dump
In reply to Huacai ChenTraditionally, MIPS's contiguous low memory can be as less as 256M, so crashkernel=X@Y may be unable to large enough in some cases. Moreover, for the "multi numa node + sparse memory model" case, it is attempt to allocate section_mem_maps on every node. Thus, if the total memory of a node is more than 1GB, we reserve the top 128MB for the crash kernel.
--- arch/mips/kernel/setup.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
arch/mips/kernel/setup.c +51 -0
@@ -27,6 +27,7 @@#include <linux/dma-contiguous.h> #include <linux/decompress/generic.h> #include <linux/of_fdt.h> +#include <linux/crash_dump.h> #include <asm/addrspace.h> #include <asm/bootinfo.h>
@@ -756,6 +757,48 @@ static void __init request_crashkernel(struct resource *res)#define BUILTIN_EXTEND_WITH_PROM \ IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND) +/* Traditionally, MIPS's contiguous low memory is 256M, so crashkernel=X@Y is +* unable to be large enough in some cases. Thus, if the total memory of a node +* is more than 1GB, we reserve the top 128MB for the crash kernel */ +static void reserve_crashm_region (int node,unsigned long s0,unsigned long e0) +{ +#ifdef CONFIG_KEXEC +if (crashk_res.start == crashk_res.end) +return ; + +if ((e0 - s0) <= (SZ_1G >>PAGE_SHIFT )) +return ; + + s0 = e0 - (SZ_128M >>PAGE_SHIFT ); + +memblock_reserve (PFN_PHYS (s0), (e0 - s0) <<PAGE_SHIFT ); +#endif +} + +static void reserve_oldmem_region (int node,unsigned long s0,unsigned long e0) +{ +#ifdef CONFIG_CRASH_DUMP +unsigned long s1, e1; + +if (!is_kdump_kernel ()) +return ; + +if ((e0 - s0) > (SZ_1G >>PAGE_SHIFT )) + e0 = e0 - (SZ_128M >>PAGE_SHIFT ); + +/* boot_mem_map.map[0] is crashk_res reserved by primary kernel */ + s1 =PFN_UP (boot_mem_map.map[0 ].addr); + e1 =PFN_DOWN (boot_mem_map.map[0 ].addr + boot_mem_map.map[0 ].size); + +if (node ==0 ) { +memblock_reserve (PFN_PHYS (s0), (s1 - s0) <<PAGE_SHIFT ); +memblock_reserve (PFN_PHYS (e1), (e0 - e1) <<PAGE_SHIFT ); + }else { +memblock_reserve (PFN_PHYS (s0), (e0 - s0) <<PAGE_SHIFT ); + } +#endif +} +/* * arch_mem_init - initialize memory management subsystem *
@@ -780,6 +823,8 @@ static void __init request_crashkernel(struct resource *res)*/ static void __init arch_mem_init (char **cmdline_p) { +unsigned int node; +unsigned long start_pfn, end_pfn;struct memblock_region *reg;extern void plat_mem_setup (void );
@@ -877,6 +922,12 @@ static void __init arch_mem_init(char **cmdline_p)memblock_reserve (crashk_res.start, crashk_res.end - crashk_res.start +1 );#endif +for_each_online_node (node) { +get_pfn_range_for_nid (node, &start_pfn, &end_pfn); +reserve_crashm_region (node, start_pfn, end_pfn); +reserve_oldmem_region (node, start_pfn, end_pfn); + } +device_tree_init ();sparse_init ();plat_swiotlb_setup ();
Signature · 1 line
2.7.0
PATCH v5 7/8 MIPS: Loongson64: Add kexec/kdump support
In reply to Huacai ChenAdd kexec/kdump support for Loongson64 by:
1, Provide Loongson-specific kexec functions: loongson_kexec_prepare,
loongson_kexec_shutdown and loongson_crash_shutdown;
2, Provide Loongson-specific code in kexec_smp_wait;
3, Clear mailbox in loongson3_smp_setup() since KEXEC bypass BIOS; 4, KEXEC always run at boot-cpu, but KDUMP may triggered at non-boot-
cpu. Loongson64 assume boot-cpu is the first possible cpu, so fix boot_cpu_id in prom_init_env();
--- arch/mips/kernel/relocate_kernel.S | 26 ++++++++++ arch/mips/loongson64/common/env.c | 7 +++ arch/mips/loongson64/common/reset.c | 95 +++++++++++++++++++++++++++++++++++ arch/mips/loongson64/loongson-3/smp.c | 5 ++ 4 files changed, 133 insertions(+)
arch/mips/kernel/relocate_kernel.S +26 -0
@@ -135,6 +135,32 @@ LEAF(kexec_smp_wait) #else sync #endif + +#ifdef CONFIG_CPU_LOONGSON3 + /* s0:prid s1:initfn */ + /* t0:base t1:cpuid t2:node t9:count */ + mfc0 t1, CP0_EBASE + andi t1, MIPS_EBASE_CPUNUM + dli t0, 0x900000003ff01000 /* mailbox base */ + dins t0, t1, 8, 2 /* insert core id*/ + dext t2, t1, 2, 2 + dins t0, t2, 44, 2 /* insert node id */ + mfc0 s0, CP0_PRID + andi s0, s0, 0xf + blt s0, 0x6, 1f /* Loongson-3A1000 */ + bgt s0, 0x7, 1f /* Loongson-3A2000/3A3000 */ + dins t0, t2, 14, 2 /* Loongson-3B1000/3B1500 need bit 15~14 */ +1: li t9, 0x100 /* wait for init loop */ +2: addiu t9, -1 /* limit mailbox access */ + bnez t9, 2b + ld s1, 0x20(t0) /* get PC via mailbox */ + beqz s1, 1b + ld sp, 0x28(t0) /* get SP via mailbox */ + ld gp, 0x30(t0) /* get GP via mailbox */ + ld a1, 0x38(t0) + jr s1 /* jump to initial PC */ +#endif + j s1 END(kexec_smp_wait) #endif
arch/mips/loongson64/common/env.c +7 -0
@@ -149,6 +149,13 @@ void __init prom_init_env(void) loongson_sysconf.nr_cpus = ecpu->nr_cpus; loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id; loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask; +#ifdef CONFIG_KEXEC + loongson_sysconf.boot_cpu_id =get_ebase_cpunum (); + loongson_sysconf.reserved_cpus_mask |= + (1 << loongson_sysconf.boot_cpu_id) -1 ; +pr_info ("Boot CPU ID is being fixed from %d to %d\n" , + ecpu->cpu_startup_core_id, loongson_sysconf.boot_cpu_id); +#endif if (ecpu->nr_cpus >NR_CPUS || ecpu->nr_cpus ==0 ) loongson_sysconf.nr_cpus =NR_CPUS ; loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
arch/mips/loongson64/common/reset.c +95 -0
116 lines not on this page · raw message
arch/mips/loongson64/loongson-3/smp.c +5 -0
@@ -388,6 +388,11 @@ static void __init loongson3_smp_setup(void)ipi_status0_regs_init ();ipi_en0_regs_init ();ipi_mailbox_buf_init (); + +/* BIOS clear the mailbox, but KEXEC bypass BIOS so clear here */ +for (i =0 ; i < loongson_sysconf.nr_cpus; i++) +loongson3_ipi_write64 (0 , (void *)(ipi_mailbox_buf[i]+0x0 )); +cpu_set_core (&cpu_data[0 ],cpu_logical_map (0 ) % loongson_sysconf.cores_per_package); cpu_data[0 ].package =cpu_logical_map (0 ) / loongson_sysconf.cores_per_package;
Signature · 1 line
2.7.0
PATCH v5 8/8 MIPS: Loongson: Introduce and use WAR_LLSC_MB
In reply to Huacai ChenOn the Loongson-2G/2H/3A/3B there is a hardware flaw that ll/sc and lld/scd is very weak ordering. We should add sync instructions before each ll/lld and after the last sc/scd to workaround. Otherwise, this flaw will cause deadlock occationally (e.g. when doing heavy load test with LTP).
This patch is not a minimal change (it is very difficult to make a minimal change), but it is a safest change.
Why disable fix-loongson3-llsc in compiler?
Because compiler fix will cause problems in kernel's .fixup section.
--- arch/mips/include/asm/atomic.h | 36 ++++++++++++++++++++++++++++-------- arch/mips/include/asm/barrier.h | 6 ++++++ arch/mips/include/asm/bitops.h | 15 +++++++++++++++ arch/mips/include/asm/cmpxchg.h | 9 +++++++-- arch/mips/include/asm/edac.h | 5 ++++- arch/mips/include/asm/futex.h | 18 ++++++++++++------ arch/mips/include/asm/local.h | 10 ++++++++-- arch/mips/include/asm/pgtable.h | 5 ++++- arch/mips/kernel/syscall.c | 2 ++ arch/mips/loongson64/Platform | 3 +++ arch/mips/mm/tlbex.c | 11 +++++++++++ 11 files changed, 100 insertions(+), 20 deletions(-)
arch/mips/include/asm/atomic.h +28 -8
@@ -61,13 +61,16 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %0, %1 # atomic_" #op " \n" \ + "1: # atomic_" #op " \n" \ + __WAR_LLSC_MB \ + " ll %0, %1 \n" \ " " #asm_op " %0, %2 \n" \ " sc %0, %1 \n" \ "\t" __scbeqz " %0, 1b \n" \ " .set pop \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ } else { \ unsigned long flags; \ \
@@ -88,7 +91,9 @@ static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %1, %2 # atomic_" #op "_return \n" \ + "1: # atomic_" #op "_return \n" \ + __WAR_LLSC_MB \ + " ll %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \
@@ -121,7 +126,9 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %1, %2 # atomic_fetch_" #op " \n" \ + "1: # atomic_fetch_" #op " \n" \ + __WAR_LLSC_MB \ + " ll %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \
@@ -130,6 +137,7 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ }else { \unsigned long flags; \ \
@@ -193,7 +201,9 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_LEVEL " \n" -"1: ll %1, %2 # atomic_sub_if_positive\n" +"1: # atomic_sub_if_positive\n" + __WAR_LLSC_MB +" ll %1, %2 \n" " .set pop \n" " subu %0, %1, %3 \n" " move %1, %0 \n"
@@ -259,13 +269,16 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %0, %1 # atomic64_" #op " \n" \ + "1: # atomic64_" #op " \n" \ + __WAR_LLSC_MB \ + " lld %0, %1 \n" \ " " #asm_op " %0, %2 \n" \ " scd %0, %1 \n" \ "\t" __scbeqz " %0, 1b \n" \ " .set pop \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ } else { \ unsigned long flags; \ \
@@ -286,7 +299,9 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %1, %2 # atomic64_" #op "_return\n" \ + "1: # atomic64_" #op "_return\n" \ + __WAR_LLSC_MB \ + " lld %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \
@@ -319,7 +334,9 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %1, %2 # atomic64_fetch_" #op "\n" \ + "1: # atomic64_fetch_" #op "\n" \ + __WAR_LLSC_MB \ + " lld %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \
@@ -328,6 +345,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ }else { \unsigned long flags; \ \
@@ -392,7 +410,9 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_LEVEL " \n" -"1: lld %1, %2 # atomic64_sub_if_positive\n" +"1: # atomic64_sub_if_positive\n" + __WAR_LLSC_MB +" lld %1, %2 \n" " dsubu %0, %1, %3 \n" " move %1, %0 \n" " bltz %0, 1f \n"
arch/mips/include/asm/barrier.h +6 -0
@@ -203,6 +203,12 @@#define __WEAK_LLSC_MB " \n"#endif +#if defined(CONFIG_LOONGSON3 ) && defined(CONFIG_SMP )/* Loongson-3's LLSC workaround */ +#define __WAR_LLSC_MB " sync \n" +#else +#define __WAR_LLSC_MB " \n" +#endif +#define smp_llsc_mb () __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")#ifdef CONFIG_CPU_CAVIUM_OCTEON
arch/mips/include/asm/bitops.h +15 -0
@@ -71,18 +71,21 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) {do { __asm__ __volatile__( + __WAR_LLSC_MB" " __LL"%0, %1 # set_bit \n" " " __INS"%0, %3, %2, 1 \n" " " __SC"%0, %1 \n" : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) :"ir" (bit),"r" (~0 )); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory");#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ }else if (kernel_uses_llsc) { do { __asm__ __volatile__( " .set push \n" " .set "MIPS_ISA_ARCH_LEVEL" \n" + __WAR_LLSC_MB " " __LL "%0, %1 # set_bit \n" " or %0, %2 \n" " " __SC "%0, %1 \n"
@@ -90,6 +93,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (1UL << bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_set_bit (nr, addr); }
@@ -125,18 +129,21 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) {do { __asm__ __volatile__( + __WAR_LLSC_MB" " __LL"%0, %1 # clear_bit \n" " " __INS"%0, $0, %2, 1 \n" " " __SC"%0, %1 \n" : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) :"ir" (bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory");#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ }else if (kernel_uses_llsc) { do { __asm__ __volatile__( " .set push \n" " .set "MIPS_ISA_ARCH_LEVEL" \n" + __WAR_LLSC_MB " " __LL "%0, %1 # clear_bit \n" " and %0, %2 \n" " " __SC "%0, %1 \n"
@@ -144,6 +151,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (~(1UL << bit))); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_clear_bit (nr, addr); }
@@ -197,6 +205,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # change_bit \n" " xor %0, %2 \n" " " __SC "%0, %1 \n"
@@ -204,6 +213,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (1UL << bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_change_bit (nr, addr); }
@@ -248,6 +258,7 @@ static inline int test_and_set_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_set_bit \n" " or %2, %0, %3 \n" " " __SC "%2, %1 \n"
@@ -304,6 +315,7 @@ static inline int test_and_set_bit_lock(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_set_bit \n" " or %2, %0, %3 \n" " " __SC "%2, %1 \n"
@@ -361,6 +373,7 @@ static inline int test_and_clear_bit(unsigned long nr, do { __asm__ __volatile__( + __WAR_LLSC_MB " " __LL "%0, %1 # test_and_clear_bit \n" " " __EXT "%2, %0, %3, 1 \n" " " __INS "%0, $0, %3, 1 \n"
@@ -378,6 +391,7 @@ static inline int test_and_clear_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_clear_bit \n" " or %2, %0, %3 \n" " xor %2, %3 \n"
@@ -437,6 +451,7 @@ static inline int test_and_change_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_change_bit \n" " xor %2, %0, %3 \n" " " __SC "\t%2, %1 \n"
arch/mips/include/asm/cmpxchg.h +7 -2
@@ -49,7 +49,9 @@ extern unsigned long __xchg_called_with_bad_pointer(void)" .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ -"1: " ld" %0, %2 # __xchg_asm \n" \ +"1: # __xchg_asm \n" \ + __WAR_LLSC_MB \ +" " ld" %0, %2 \n" \" .set pop \n" \" move $1, %z3 \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \
@@ -120,7 +122,9 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x," .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ -"1: " ld" %0, %2 # __cmpxchg_asm \n" \ +"1: # __cmpxchg_asm \n" \ + __WAR_LLSC_MB \ +" " ld" %0, %2 \n" \" bne %0, %z3, 2f \n" \" .set pop \n" \" move $1, %z4 \n" \
@@ -129,6 +133,7 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,"\t" __scbeqz" $1, 1b \n" \" .set pop \n" \"2: \n" \ + __WAR_LLSC_MB \ : "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m) \: GCC_OFF_SMALL_ASM() (*m), " Jr" (old), " Jr" (new) \ : "memory"); \
arch/mips/include/asm/edac.h +4 -1
@@ -23,13 +23,16 @@ static inline void edac_atomic_scrub(void *va, u32 size) __asm__ __volatile__ (" .set push \n" " .set mips2 \n" -"1: ll %0, %1 # edac_atomic_scrub \n" +"1: # edac_atomic_scrub \n" + __WAR_LLSC_MB +" ll %0, %1 \n" " addu %0, $0 \n" " sc %0, %1 \n" " beqz %0, 1b \n" " .set pop \n" : "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*virt_addr) : GCC_OFF_SMALL_ASM() (*virt_addr)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); virt_addr++; }
arch/mips/include/asm/futex.h +12 -6
@@ -55,7 +55,9 @@" .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ - "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \ +"1: # __futex_atomic_op\n" \ + __WAR_LLSC_MB \ + " "user_ll("%1", "%4")" \n" \" .set pop \n" \" " insn" \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \
@@ -70,8 +72,9 @@" j 3b \n" \" .previous \n" \" .section __ex_table,\"a\" \n" \ -" " __UA_ADDR"\t1b, 4b \n" \ -" " __UA_ADDR"\t2b, 4b \n" \ +" " __UA_ADDR"\t(1b + 0), 4b \n" \ +" " __UA_ADDR"\t(1b + 4), 4b \n" \ +" " __UA_ADDR"\t(2b + 0), 4b \n" \" .previous \n" \ : "=r" (ret), "=&r" (oldval), \"=" GCC_OFF_SMALL_ASM () (*uaddr) \
@@ -169,7 +172,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr," .set noat \n" " .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" - "1: "user_ll("%1", "%3")" \n" +"1: \n" + __WAR_LLSC_MB + " "user_ll("%1", "%3")" \n"" bne %1, %z4, 3f \n" " .set pop \n" " move $1, %z5 \n"
@@ -185,8 +190,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr," j 3b \n" " .previous \n" " .section __ex_table,\"a\" \n" -" " __UA_ADDR"\t1b, 4b \n" -" " __UA_ADDR"\t2b, 4b \n" +" " __UA_ADDR"\t(1b + 0), 4b \n" +" " __UA_ADDR"\t(1b + 4), 4b \n" +" " __UA_ADDR"\t(2b + 0), 4b \n" " .previous \n" : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
arch/mips/include/asm/local.h +8 -2
@@ -52,7 +52,9 @@ static __inline__ long local_add_return(long i, local_t * l) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" -"1:" __LL"%1, %2 # local_add_return \n" +"1: # local_add_return \n" + __WAR_LLSC_MB + __LL"%1, %2 \n" " addu %0, %1, %3 \n" __SC"%0, %2 \n" " beqz %0, 1b \n"
@@ -61,6 +63,7 @@ static __inline__ long local_add_return(long i, local_t * l) : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) : "Ir" (i), "m" (l->a.counter) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else {unsigned long flags;
@@ -99,7 +102,9 @@ static __inline__ long local_sub_return(long i, local_t * l) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" -"1:" __LL"%1, %2 # local_sub_return \n" +"1: # local_sub_return \n" + __WAR_LLSC_MB + __LL"%1, %2 \n" " subu %0, %1, %3 \n" __SC"%0, %2 \n" " beqz %0, 1b \n"
@@ -108,6 +113,7 @@ static __inline__ long local_sub_return(long i, local_t * l) : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) : "Ir" (i), "m" (l->a.counter) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else {unsigned long flags;
arch/mips/include/asm/pgtable.h +4 -1
@@ -232,7 +232,9 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" " .set noreorder \n" -"1:" __LL"%[tmp], %[buddy] \n" +"1: \n" + __WAR_LLSC_MB + __LL"%[tmp], %[buddy] \n" " bnez %[tmp], 2f \n" " or %[tmp], %[tmp], %[global] \n" __SC"%[tmp], %[buddy] \n"
@@ -242,6 +244,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)" .set pop \n" : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) : [global] "r" (page_global)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }#else /* !CONFIG_SMP */ if (pte_none (*buddy))
arch/mips/kernel/syscall.c +2 -0
@@ -137,6 +137,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)" .set " MIPS_ISA_ARCH_LEVEL " \n" " li %[err], 0 \n" "1: \n" + __WAR_LLSC_MB user_ll("%[old]", "(%[addr])")" move %[tmp], %[new] \n" "2: \n"
@@ -160,6 +161,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) [new] "r" (new), [efault] "i" (-EFAULT) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else { do { preempt_disable();
arch/mips/loongson64/Platform +3 -0
@@ -23,6 +23,9 @@ ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS endif cflags-$(CONFIG_CPU_LOONGSON3) += -Wa,--trap +ifneq ($(call as-option,-Wa$(comma)-mfix-loongson3-llsc,),) + cflags-$(CONFIG_CPU_LOONGSON3) += -Wa$(comma)-mno-fix-loongson3-llsc +endif # # binutils from v2.25 on and gcc starting from v4.9.0 treat -march=loongson3a # as MIPS64 R2; older versions as just R1. This leaves the possibility open
arch/mips/mm/tlbex.c +11 -0
@@ -931,6 +931,8 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,* to mimic that here by taking a load/istream page * fault. */ +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (p,0 );UASM_i_LA (p, ptr, (unsigned long )tlb_do_page_fault_0);uasm_i_jr (p, ptr);
@@ -1555,6 +1557,7 @@ static void build_loongson3_tlb_refill_handler(void)if (check_for_high_segbits) {uasm_l_large_segbits_fault (&l, p); +uasm_i_sync (&p,0 );UASM_i_LA (&p,K1 , (unsigned long )tlb_do_page_fault_0);uasm_i_jr (&p,K1 );uasm_i_nop (&p);
@@ -1645,6 +1648,8 @@ static void iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) {#ifdef CONFIG_SMP +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (p,0 );# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits)uasm_i_lld (p, pte,0 , ptr);
@@ -2258,6 +2263,8 @@ static void build_r4000_tlb_load_handler(void)#endif uasm_l_nopage_tlbl (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_0 &1 ) {
@@ -2312,6 +2319,8 @@ static void build_r4000_tlb_store_handler(void)#endif uasm_l_nopage_tlbs (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_1 &1 ) {
@@ -2367,6 +2376,8 @@ static void build_r4000_tlb_modify_handler(void)#endif uasm_l_nopage_tlbm (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_1 &1 ) {
Signature · 1 line
2.7.0
Re: [PATCH V5 8/8] MIPS: Loongson: Introduce and use WAR_LLSC_MB
Quoted 492 lines · 在 2018年11月15日,下午3:53,Huacai Chen <[email protected]> 写道:
On the Loongson-2G/2H/3A/3B there is a hardware flaw that ll/sc and lld/scd is very weak ordering. We should add sync instructions before each ll/lld and after the last sc/scd to workaround. Otherwise, this flaw will cause deadlock occationally (e.g. when doing heavy load test with LTP).
This patch is not a minimal change (it is very difficult to make a minimal change), but it is a safest change.
Why disable fix-loongson3-llsc in compiler?
Because compiler fix will cause problems in kernel's .fixup section.Signed-off-by Huacai Chen <[email protected]>---
arch/mips/include/asm/atomic.h | 36 ++++++++++++++++++++++++++++-------- arch/mips/include/asm/barrier.h | 6 ++++++ arch/mips/include/asm/bitops.h | 15 +++++++++++++++ arch/mips/include/asm/cmpxchg.h | 9 +++++++-- arch/mips/include/asm/edac.h | 5 ++++- arch/mips/include/asm/futex.h | 18 ++++++++++++------ arch/mips/include/asm/local.h | 10 ++++++++-- arch/mips/include/asm/pgtable.h | 5 ++++- arch/mips/kernel/syscall.c | 2 ++ arch/mips/loongson64/Platform | 3 +++ arch/mips/mm/tlbex.c | 11 +++++++++++ 11 files changed, 100 insertions(+), 20 deletions(-)arch/mips/include/asm/atomic.h +28
-8@@ -61,13 +61,16 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %0, %1 # atomic_" #op " \n" \ + "1: # atomic_" #op " \n" \ + __WAR_LLSC_MB \ + " ll %0, %1 \n" \ " " #asm_op " %0, %2 \n" \ " sc %0, %1 \n" \ "\t" __scbeqz " %0, 1b \n" \ " .set pop \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ } else { \ unsigned long flags; \ \@@ -88,7 +91,9 @@ static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %1, %2 # atomic_" #op "_return \n" \ + "1: # atomic_" #op "_return \n" \ + __WAR_LLSC_MB \ + " ll %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \@@ -121,7 +126,9 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: ll %1, %2 # atomic_fetch_" #op " \n" \ + "1: # atomic_fetch_" #op " \n" \ + __WAR_LLSC_MB \ + " ll %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \@@ -130,6 +137,7 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ }else { \unsigned long flags; \ \@@ -193,7 +201,9 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_LEVEL " \n" -"1: ll %1, %2 # atomic_sub_if_positive\n" +"1: # atomic_sub_if_positive\n" + __WAR_LLSC_MB +" ll %1, %2 \n" " .set pop \n" " subu %0, %1, %3 \n" " move %1, %0 \n"@@ -259,13 +269,16 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %0, %1 # atomic64_" #op " \n" \ + "1: # atomic64_" #op " \n" \ + __WAR_LLSC_MB \ + " lld %0, %1 \n" \ " " #asm_op " %0, %2 \n" \ " scd %0, %1 \n" \ "\t" __scbeqz " %0, 1b \n" \ " .set pop \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ } else { \ unsigned long flags; \ \@@ -286,7 +299,9 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %1, %2 # atomic64_" #op "_return\n" \ + "1: # atomic64_" #op "_return\n" \ + __WAR_LLSC_MB \ + " lld %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \@@ -319,7 +334,9 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ __asm__ __volatile__( \ " .set push \n" \ " .set "MIPS_ISA_LEVEL" \n" \ - "1: lld %1, %2 # atomic64_fetch_" #op "\n" \ + "1: # atomic64_fetch_" #op "\n" \ + __WAR_LLSC_MB \ + " lld %1, %2 \n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ "\t" __scbeqz " %0, 1b \n" \@@ -328,6 +345,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); \ }else { \unsigned long flags; \ \@@ -392,7 +410,9 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_LEVEL " \n" -"1: lld %1, %2 # atomic64_sub_if_positive\n" +"1: # atomic64_sub_if_positive\n" + __WAR_LLSC_MB +" lld %1, %2 \n" " dsubu %0, %1, %3 \n" " move %1, %0 \n" " bltz %0, 1f \n"arch/mips/include/asm/barrier.h +6
-0@@ -203,6 +203,12 @@#define __WEAK_LLSC_MB " \n"#endif +#if defined(CONFIG_LOONGSON3 ) && defined(CONFIG_SMP )/* Loongson-3's LLSC workaround */ +#define __WAR_LLSC_MB " sync \n" +#else +#define __WAR_LLSC_MB " \n" +#endif +#define smp_llsc_mb () __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")#ifdef CONFIG_CPU_CAVIUM_OCTEON arch/mips/include/asm/bitops.h +15
-0@@ -71,18 +71,21 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) {do { __asm__ __volatile__( + __WAR_LLSC_MB" " __LL"%0, %1 # set_bit \n" " " __INS"%0, %3, %2, 1 \n" " " __SC"%0, %1 \n" : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) :"ir" (bit),"r" (~0 )); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory");#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ }else if (kernel_uses_llsc) { do { __asm__ __volatile__( " .set push \n" " .set "MIPS_ISA_ARCH_LEVEL" \n" + __WAR_LLSC_MB " " __LL "%0, %1 # set_bit \n" " or %0, %2 \n" " " __SC "%0, %1 \n"@@ -90,6 +93,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (1UL << bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_set_bit (nr, addr); }@@ -125,18 +129,21 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) {do { __asm__ __volatile__( + __WAR_LLSC_MB" " __LL"%0, %1 # clear_bit \n" " " __INS"%0, $0, %2, 1 \n" " " __SC"%0, %1 \n" : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) :"ir" (bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory");#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ }else if (kernel_uses_llsc) { do { __asm__ __volatile__( " .set push \n" " .set "MIPS_ISA_ARCH_LEVEL" \n" + __WAR_LLSC_MB " " __LL "%0, %1 # clear_bit \n" " and %0, %2 \n" " " __SC "%0, %1 \n"@@ -144,6 +151,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (~(1UL << bit))); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_clear_bit (nr, addr); }@@ -197,6 +205,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # change_bit \n" " xor %0, %2 \n" " " __SC "%0, %1 \n"@@ -204,6 +213,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m) : "ir" (1UL << bit)); }while (unlikely (!temp)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else __mips_change_bit (nr, addr); }@@ -248,6 +258,7 @@ static inline int test_and_set_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_set_bit \n" " or %2, %0, %3 \n" " " __SC "%2, %1 \n"@@ -304,6 +315,7 @@ static inline int test_and_set_bit_lock(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_set_bit \n" " or %2, %0, %3 \n" " " __SC "%2, %1 \n"@@ -361,6 +373,7 @@ static inline int test_and_clear_bit(unsigned long nr, do { __asm__ __volatile__( + __WAR_LLSC_MB " " __LL "%0, %1 # test_and_clear_bit \n" " " __EXT "%2, %0, %3, 1 \n" " " __INS "%0, $0, %3, 1 \n"@@ -378,6 +391,7 @@ static inline int test_and_clear_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_clear_bit \n" " or %2, %0, %3 \n" " xor %2, %3 \n"@@ -437,6 +451,7 @@ static inline int test_and_change_bit(unsigned long nr, __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" + __WAR_LLSC_MB" " __LL"%0, %1 # test_and_change_bit \n" " xor %2, %0, %3 \n" " " __SC "\t%2, %1 \n"arch/mips/include/asm/cmpxchg.h +7
-2@@ -49,7 +49,9 @@ extern unsigned long __xchg_called_with_bad_pointer(void)" .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ -"1: " ld" %0, %2 # __xchg_asm \n" \ +"1: # __xchg_asm \n" \ + __WAR_LLSC_MB \ +" " ld" %0, %2 \n" \" .set pop \n" \" move $1, %z3 \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \@@ -120,7 +122,9 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x," .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ -"1: " ld" %0, %2 # __cmpxchg_asm \n" \ +"1: # __cmpxchg_asm \n" \ + __WAR_LLSC_MB \ +" " ld" %0, %2 \n" \" bne %0, %z3, 2f \n" \" .set pop \n" \" move $1, %z4 \n" \@@ -129,6 +133,7 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,"\t" __scbeqz" $1, 1b \n" \" .set pop \n" \"2: \n" \ + __WAR_LLSC_MB \ : "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m) \: GCC_OFF_SMALL_ASM() (*m), " Jr" (old), " Jr" (new) \ : "memory"); \arch/mips/include/asm/edac.h +4
-1@@ -23,13 +23,16 @@ static inline void edac_atomic_scrub(void *va, u32 size) __asm__ __volatile__ (" .set push \n" " .set mips2 \n" -"1: ll %0, %1 # edac_atomic_scrub \n" +"1: # edac_atomic_scrub \n" + __WAR_LLSC_MB +" ll %0, %1 \n" " addu %0, $0 \n" " sc %0, %1 \n" " beqz %0, 1b \n" " .set pop \n" : "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*virt_addr) : GCC_OFF_SMALL_ASM() (*virt_addr)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); virt_addr++; }arch/mips/include/asm/futex.h +12
-6@@ -55,7 +55,9 @@" .set noat \n" \" .set push \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \ - "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \ +"1: # __futex_atomic_op\n" \ + __WAR_LLSC_MB \ + " "user_ll("%1", "%4")" \n" \" .set pop \n" \" " insn" \n" \" .set " MIPS_ISA_ARCH_LEVEL " \n" \@@ -70,8 +72,9 @@" j 3b \n" \" .previous \n" \" .section __ex_table,\"a\" \n" \ -" " __UA_ADDR"\t1b, 4b \n" \ -" " __UA_ADDR"\t2b, 4b \n" \ +" " __UA_ADDR"\t(1b + 0), 4b \n" \ +" " __UA_ADDR"\t(1b + 4), 4b \n" \ +" " __UA_ADDR"\t(2b + 0), 4b \n" \" .previous \n" \ : "=r" (ret), "=&r" (oldval), \"=" GCC_OFF_SMALL_ASM () (*uaddr) \@@ -169,7 +172,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr," .set noat \n" " .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" - "1: "user_ll("%1", "%3")" \n" +"1: \n" + __WAR_LLSC_MB + " "user_ll("%1", "%3")" \n"" bne %1, %z4, 3f \n" " .set pop \n" " move $1, %z5 \n" @@ -185,8 +190,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr," j 3b \n" " .previous \n" " .section __ex_table,\"a\" \n" -" " __UA_ADDR"\t1b, 4b \n" -" " __UA_ADDR"\t2b, 4b \n" +" " __UA_ADDR"\t(1b + 0), 4b \n" +" " __UA_ADDR"\t(1b + 4), 4b \n" +" " __UA_ADDR"\t(2b + 0), 4b \n" " .previous \n" : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),arch/mips/include/asm/local.h +8
-2@@ -52,7 +52,9 @@ static __inline__ long local_add_return(long i, local_t * l) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" -"1:" __LL"%1, %2 # local_add_return \n" +"1: # local_add_return \n" + __WAR_LLSC_MB + __LL"%1, %2 \n" " addu %0, %1, %3 \n" __SC"%0, %2 \n" " beqz %0, 1b \n"@@ -61,6 +63,7 @@ static __inline__ long local_add_return(long i, local_t * l) : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) : "Ir" (i), "m" (l->a.counter) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else {unsigned long flags;@@ -99,7 +102,9 @@ static __inline__ long local_sub_return(long i, local_t * l) __asm__ __volatile__(" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" -"1:" __LL"%1, %2 # local_sub_return \n" +"1: # local_sub_return \n" + __WAR_LLSC_MB + __LL"%1, %2 \n" " subu %0, %1, %3 \n" __SC"%0, %2 \n" " beqz %0, 1b \n"@@ -108,6 +113,7 @@ static __inline__ long local_sub_return(long i, local_t * l) : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) : "Ir" (i), "m" (l->a.counter) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else {unsigned long flags;arch/mips/include/asm/pgtable.h +4
-1@@ -232,7 +232,9 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)" .set push \n" " .set " MIPS_ISA_ARCH_LEVEL " \n" " .set noreorder \n" -"1:" __LL"%[tmp], %[buddy] \n" +"1: \n" + __WAR_LLSC_MB + __LL"%[tmp], %[buddy] \n" " bnez %[tmp], 2f \n" " or %[tmp], %[tmp], %[global] \n" __SC"%[tmp], %[buddy] \n" @@ -242,6 +244,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)" .set pop \n" : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) : [global] "r" (page_global)); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }#else /* !CONFIG_SMP */ if (pte_none (*buddy))arch/mips/kernel/syscall.c +2
-0@@ -137,6 +137,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)" .set " MIPS_ISA_ARCH_LEVEL " \n" " li %[err], 0 \n" "1: \n" + __WAR_LLSC_MB user_ll("%[old]", "(%[addr])")" move %[tmp], %[new] \n" "2: \n" @@ -160,6 +161,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) [new] "r" (new), [efault] "i" (-EFAULT) : "memory"); + __asm__ __volatile__(__WAR_LLSC_MB : : :"memory"); }else { do { preempt_disable();arch/mips/loongson64/Platform +0
-0@@ -23,6 +23,9 @@ ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDSendif
cflags-$(CONFIG_CPU_LOONGSON3) += -Wa,--trap
arch/mips/loongson64/Platform +3
-0+ifneq ($(call as-option,-Wa$(comma)-mfix-loongson3-llsc,),) + cflags-$(CONFIG_CPU_LOONGSON3) += -Wa$(comma)-mno-fix-loongson3-llsc +endif
Quoted 1 line
#
fix-loongson3-llsc is not in upstream yet.
And why this option generates .fixup section?
Quoted 24 lines
# binutils from v2.25 on and gcc starting from v4.9.0 treat -march=loongson3a # as MIPS64 R2; older versions as just R1. This leaves the possibility openarch/mips/mm/tlbex.c +3
-0@@ -931,6 +931,8 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,* to mimic that here by taking a load/istream page * fault. */ +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (p,0 );UASM_i_LA (p, ptr, (unsigned long )tlb_do_page_fault_0);uasm_i_jr (p, ptr);@@ -1555,6 +1557,7 @@ static void build_loongson3_tlb_refill_handler(void)if (check_for_high_segbits) {uasm_l_large_segbits_fault (&l, p); +uasm_i_sync (&p,0 );UASM_i_LA (&p,K1 , (unsigned long )tlb_do_page_fault_0);uasm_i_jr (&p,K1 );uasm_i_nop (&p);
arch/mips/mm/tlbex.c static void · line 1652
Quoted 5 lines
arch/mips/mm/tlbex.c +2
-0@@ -1645,6 +1648,8 @@ static void iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) {#ifdef CONFIG_SMP +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (p,0 );
@huacai, I guess we should set these 2 line a macro? #ifdef CONFIG_CPU_LOONGSON3
#define LS_UASM_I_SYNC_PTR uasm_i_sync(&p, 0) #else
#define LS_UASM_I_SYNC_PTR
#endif
Quoted 30 lines
arch/mips/mm/tlbex.c +6
-0# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits)uasm_i_lld (p, pte,0 , ptr);@@ -2258,6 +2263,8 @@ static void build_r4000_tlb_load_handler(void)#endif uasm_l_nopage_tlbl (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_0 &1 ) {@@ -2312,6 +2319,8 @@ static void build_r4000_tlb_store_handler(void)#endif uasm_l_nopage_tlbs (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_1 &1 ) {@@ -2367,6 +2376,8 @@ static void build_r4000_tlb_modify_handler(void)#endif uasm_l_nopage_tlbm (&l, p); +if (current_cpu_type () ==CPU_LOONGSON3 ) +uasm_i_sync (&p,0 );build_restore_work_registers (&p);#ifdef CONFIG_CPU_MICROMIPS if ((unsigned long )tlb_do_page_fault_1 &1 ) {
A message that is not in the archive (sent off-list or not yet received): MWHPR2201MB126144067773D533638F1759DED10@MWHPR2201MB1261.namprd22.prod.outlook.com
Re: [PATCH V5 8/8] MIPS: Loongson: Introduce and use WAR_LLSC_MB
Hi Yunqiang,
Please send only plain text mail to the linux-mips mailing list, and don't top-post.
Quoted 8 lines · Yunqiang Su
Quoted 8 lines · 在 2018年11月15日,下午3:53,Huacai Chen <[email protected]> 写道:
On the Loongson-2G/2H/3A/3B there is a hardware flaw that ll/sc and lld/scd is very weak ordering. We should add sync instructions before each ll/lld and after the last sc/scd to workaround. Otherwise, this flaw will cause deadlock occationally (e.g. when doing heavy load test with LTP).
Quoted 8 lines
Quoted 5 lines
This patch is not a minimal change (it is very difficult to make a minimal change), but it is a safest change.
Why disable fix-loongson3-llsc in compiler?
Because compiler fix will cause problems in kernel's .fixup section.@Paul Burton Loongson 3A/B 3000 have a bug of ll/sc, which is not in 3A/3B 1000 even.
Do you have any details? Are you saying that the problem Huacai's patch addresses only applies to those models, or that there's a separate problem?
Thanks,
Paul
Re: [PATCH V5 8/8] MIPS: Loongson: Introduce and use WAR_LLSC_MB
Quoted 24 lines · 在 2018年11月29日,上午3:14,Paul Burton <[email protected]> 写道:
Hi Yunqiang,
Please send only plain text mail to the linux-mips mailing list, and don't top-post.
Quoted 14 lines · Yunqiang Su
Quoted 13 lines · 在 2018年11月15日,下午3:53,Huacai Chen <[email protected]> 写道:
On the Loongson-2G/2H/3A/3B there is a hardware flaw that ll/sc and lld/scd is very weak ordering. We should add sync instructions before each ll/lld and after the last sc/scd to workaround. Otherwise, this flaw will cause deadlock occationally (e.g. when doing heavy load test with LTP).
This patch is not a minimal change (it is very difficult to make a minimal change), but it is a safest change.
Why disable fix-loongson3-llsc in compiler?
Because compiler fix will cause problems in kernel's .fixup section.
Quoted 6 lines
Quoted 2 lines
@Paul Burton Loongson 3A/B 3000 have a bug of ll/sc, which is not in 3A/3B 1000 even.
Do you have any details? Are you saying that the problem Huacai's patch addresses only applies to those models, or that there's a separate problem?
Yes. 3000 introduces some new bugs, this is one of them. 1000 doesn’t have this problem.
Without this patch, 3A 3000 is quite unstable when heavy load, as an personal experience, building kernel, with -j5 works well, while -j9 always makes the machine hangs.
3A 1000 has itself bugs, not the same with 3A 3000, and some of 1000’s bug is fixed in 3000.
Quoted 3 lines
Thanks,
Paul