Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: disable MMID when not supported by the hardware

It is possible that MMID is supported at the CPU level, but its
integration in a SoC prevents its usage. For instance, if the
System-level Interconnect (also known as Network on Chip) does not
support global invalidation, then the MMID feature is not usable. The
current implementation of MMID relies on the GINV* instructions.

This patch allows the disabling of MMID based on a device tree
property, as this issue cannot be detected at runtime.

MMID is set up very early during the boot process, even before device
tree data can be accessed. Therefore, when we determine whether MMID
needs to be disabled, some MMID setup has already been performed for
the boot CPU. Consequently, we must revert the MMID setup on the first
CPU before disabling the feature for the subsequent CPUs that will be
initialized later.

Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

authored by

Gregory CLEMENT and committed by
Thomas Bogendoerfer
07f8888e ca943354

+46 -2
+1
arch/mips/include/asm/cpu-info.h
··· 123 123 124 124 extern void cpu_probe(void); 125 125 extern void cpu_report(void); 126 + extern void cpu_disable_mmid(void); 126 127 127 128 extern const char *__cpu_name[]; 128 129 #define cpu_name_string() __cpu_name[raw_smp_processor_id()]
+40 -2
arch/mips/kernel/cpu-probe.c
··· 9 9 */ 10 10 #include <linux/init.h> 11 11 #include <linux/kernel.h> 12 + #include <linux/mmu_context.h> 12 13 #include <linux/ptrace.h> 13 14 #include <linux/smp.h> 14 15 #include <linux/stddef.h> ··· 37 36 /* Hardware capabilities */ 38 37 unsigned int elf_hwcap __read_mostly; 39 38 EXPORT_SYMBOL_GPL(elf_hwcap); 39 + 40 + static bool mmid_disabled_quirk; 40 41 41 42 static inline unsigned long cpu_get_msa_id(void) 42 43 { ··· 648 645 config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); 649 646 650 647 if (cpu_has_mips_r6) { 651 - if (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid) 648 + if (!mmid_disabled_quirk && (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid)) 652 649 config5 |= MIPS_CONF5_MI; 653 650 else 654 651 config5 &= ~MIPS_CONF5_MI; ··· 711 708 max_mmid_width); 712 709 asid_mask = GENMASK(max_mmid_width - 1, 0); 713 710 } 714 - 715 711 set_cpu_asid_mask(c, asid_mask); 716 712 } 717 713 } ··· 2047 2045 2048 2046 cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_VP; 2049 2047 cpuinfo->globalnumber |= vpe << MIPS_GLOBALNUMBER_VP_SHF; 2048 + } 2049 + 2050 + void cpu_disable_mmid(void) 2051 + { 2052 + int i; 2053 + unsigned long asid_mask; 2054 + unsigned int cpu = smp_processor_id(); 2055 + struct cpuinfo_mips *c = &current_cpu_data; 2056 + unsigned int config4 = read_c0_config4(); 2057 + unsigned int config5 = read_c0_config5(); 2058 + 2059 + /* Setup the initial ASID mask based on config4 */ 2060 + asid_mask = MIPS_ENTRYHI_ASID; 2061 + if (config4 & MIPS_CONF4_AE) 2062 + asid_mask |= MIPS_ENTRYHI_ASIDX; 2063 + set_cpu_asid_mask(c, asid_mask); 2064 + 2065 + /* Disable MMID in the C0 and update cpuinfo_mips accordingly */ 2066 + config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); 2067 + config5 &= ~MIPS_CONF5_MI; 2068 + write_c0_config5(config5); 2069 + /* Ensure the write to config5 above takes effect */ 2070 + back_to_back_c0_hazard(); 2071 + c->options &= ~MIPS_CPU_MMID; 2072 + 2073 + /* Setup asid cache value cleared in per_cpu_trap_init() */ 2074 + cpu_data[cpu].asid_cache = asid_first_version(cpu); 2075 + 2076 + /* Reinit context for each CPU */ 2077 + for_each_possible_cpu(i) 2078 + set_cpu_context(i, &init_mm, 0); 2079 + 2080 + /* Ensure that now MMID will be seen as disable */ 2081 + mmid_disabled_quirk = true; 2082 + 2083 + pr_info("MMID support disabled due to hardware support issue\n"); 2050 2084 }
+5
arch/mips/kernel/mips-cm.c
··· 248 248 return; 249 249 pr_info("HCI (Hardware Cache Init for the L2 cache) in GCR_L2_RAM_CONFIG from the CM3 is broken"); 250 250 mips_cm_is_l2_hci_broken = true; 251 + 252 + /* Disable MMID only if it was configured */ 253 + if (cpu_has_mmid) 254 + cpu_disable_mmid(); 255 + 251 256 of_node_put(cm_node); 252 257 } 253 258