diff mbox series

[3/5] LoongArch: cpu-probe: Move IOCSR probing out of cpu_probe_common

Message ID 20240907-iocsr-v1-3-0c99b3334444@flygoat.com (mailing list archive)
State New
Headers show
Series LoongArch, MIPS: Unify Loongson IOCSR handling | expand

Commit Message

Jiaxun Yang Sept. 7, 2024, 10:17 a.m. UTC
IOCSR register definition appears to be a platform specific
spec instead of architecture spec, even for Loongson CPUs
there is no guarantee that IOCSR will always present.

Thus it's dangerous to perform IOCSR probing without checking
CPU type and instruction availability.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 arch/loongarch/kernel/cpu-probe.c | 63 ++++++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 24 deletions(-)

Comments

Huacai Chen Sept. 8, 2024, 2:47 a.m. UTC | #1
Hi, Jiaxun,

On Sat, Sep 7, 2024 at 6:17 PM Jiaxun Yang <jiaxun.yang@flygoat.com> wrote:
>
> IOCSR register definition appears to be a platform specific
> spec instead of architecture spec, even for Loongson CPUs
> there is no guarantee that IOCSR will always present.
>
> Thus it's dangerous to perform IOCSR probing without checking
> CPU type and instruction availability.
I don't think this is necessary. Loongson's Chip engineers confirm
that IOCSR is always present in Loongson processors. If other
LoongArch (not Loongson) processors have no IOCSR, they should
implement their own cpu_probe_abc() instead of cpu_probe_loongson().

Huacai

>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---
>  arch/loongarch/kernel/cpu-probe.c | 63 ++++++++++++++++++++++++---------------
>  1 file changed, 39 insertions(+), 24 deletions(-)
>
> diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
> index 6a82ceb6e321..968b5a35a0d2 100644
> --- a/arch/loongarch/kernel/cpu-probe.c
> +++ b/arch/loongarch/kernel/cpu-probe.c
> @@ -173,22 +173,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
>         if (config & CPUCFG6_PMP)
>                 c->options |= LOONGARCH_CPU_PMP;
>
> -       config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
> -       if (config & IOCSRF_CSRIPI)
> -               c->options |= LOONGARCH_CPU_CSRIPI;
> -       if (config & IOCSRF_EXTIOI)
> -               c->options |= LOONGARCH_CPU_EXTIOI;
> -       if (config & IOCSRF_FREQSCALE)
> -               c->options |= LOONGARCH_CPU_SCALEFREQ;
> -       if (config & IOCSRF_FLATMODE)
> -               c->options |= LOONGARCH_CPU_FLATMODE;
> -       if (config & IOCSRF_EIODECODE)
> -               c->options |= LOONGARCH_CPU_EIODECODE;
> -       if (config & IOCSRF_AVEC)
> -               c->options |= LOONGARCH_CPU_AVECINT;
> -       if (config & IOCSRF_VM)
> -               c->options |= LOONGARCH_CPU_HYPERVISOR;
> -
>         config = csr_read32(LOONGARCH_CSR_ASID);
>         config = (config & CSR_ASID_BIT) >> CSR_ASID_BIT_SHIFT;
>         asid_mask = GENMASK(config - 1, 0);
> @@ -231,16 +215,8 @@ static char cpu_full_name[MAX_NAME_LEN] = "        -        ";
>
>  static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
>  {
> -       uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
> -       uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
>         const char *core_name = "Unknown";
>
> -       if (!__cpu_full_name[cpu])
> -               __cpu_full_name[cpu] = cpu_full_name;
> -
> -       *vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
> -       *cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
> -
>         switch (c->processor_id & PRID_SERIES_MASK) {
>         case PRID_SERIES_LA132:
>                 c->cputype = CPU_LOONGSON32;
> @@ -283,6 +259,36 @@ static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int
>         pr_info("%s Processor probed (%s Core)\n", __cpu_family[cpu], core_name);
>  }
>
> +static inline void iocsr_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
> +{
> +       uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
> +       uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
> +       unsigned int config;
> +
> +       *vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
> +       *cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
> +
> +       if (!__cpu_full_name[cpu])
> +               __cpu_full_name[cpu] = cpu_full_name;
> +
> +       config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
> +       if (config & IOCSRF_CSRIPI)
> +               c->options |= LOONGARCH_CPU_CSRIPI;
> +       if (config & IOCSRF_EXTIOI)
> +               c->options |= LOONGARCH_CPU_EXTIOI;
> +       if (config & IOCSRF_FREQSCALE)
> +               c->options |= LOONGARCH_CPU_SCALEFREQ;
> +       if (config & IOCSRF_FLATMODE)
> +               c->options |= LOONGARCH_CPU_FLATMODE;
> +       if (config & IOCSRF_EIODECODE)
> +               c->options |= LOONGARCH_CPU_EIODECODE;
> +       if (config & IOCSRF_AVEC)
> +               c->options |= LOONGARCH_CPU_AVECINT;
> +       if (config & IOCSRF_VM)
> +               c->options |= LOONGARCH_CPU_HYPERVISOR;
> +
> +}
> +
>  #ifdef CONFIG_64BIT
>  /* For use by uaccess.h */
>  u64 __ua_limit;
> @@ -331,6 +337,15 @@ void cpu_probe(void)
>                 break;
>         }
>
> +       if (c->options & LOONGARCH_CPU_IOCSR) {
> +               switch (c->cputype) {
> +               case CPU_LOONGSON32:
> +               case CPU_LOONGSON64:
> +                       iocsr_probe_loongson(c, cpu);
> +                       break;
> +               }
> +       }
> +
>         BUG_ON(!__cpu_family[cpu]);
>         BUG_ON(c->cputype == CPU_UNKNOWN);
>
>
> --
> 2.46.0
>
Jiaxun Yang Sept. 8, 2024, 10 a.m. UTC | #2
在2024年9月8日九月 上午3:47,Huacai Chen写道:
> Hi, Jiaxun,
>
> On Sat, Sep 7, 2024 at 6:17 PM Jiaxun Yang <jiaxun.yang@flygoat.com> wrote:
>>
>> IOCSR register definition appears to be a platform specific
>> spec instead of architecture spec, even for Loongson CPUs
>> there is no guarantee that IOCSR will always present.
>>
>> Thus it's dangerous to perform IOCSR probing without checking
>> CPU type and instruction availability.
> I don't think this is necessary. Loongson's Chip engineers confirm
> that IOCSR is always present in Loongson processors. If other
> LoongArch (not Loongson) processors have no IOCSR, they should
> implement their own cpu_probe_abc() instead of cpu_probe_loongson().

Hi Huacai,

IOCSR_FEATURE probing process is now in cpu_probe_common, which is shared
among all PRIDs, that's why it needs to be moved out.

It also prepares for different IOCSR definitions, as you said before IOCSR
definitions are not guaranteed to be compatible, so if an incompatible
implementation arise, you can just introduce a new CPU_TYPE for it and
create a new iocsr_probe function.

Thanks
- Jiaxun

>
> Huacai
>
>>
>> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
diff mbox series

Patch

diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
index 6a82ceb6e321..968b5a35a0d2 100644
--- a/arch/loongarch/kernel/cpu-probe.c
+++ b/arch/loongarch/kernel/cpu-probe.c
@@ -173,22 +173,6 @@  static void cpu_probe_common(struct cpuinfo_loongarch *c)
 	if (config & CPUCFG6_PMP)
 		c->options |= LOONGARCH_CPU_PMP;
 
-	config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
-	if (config & IOCSRF_CSRIPI)
-		c->options |= LOONGARCH_CPU_CSRIPI;
-	if (config & IOCSRF_EXTIOI)
-		c->options |= LOONGARCH_CPU_EXTIOI;
-	if (config & IOCSRF_FREQSCALE)
-		c->options |= LOONGARCH_CPU_SCALEFREQ;
-	if (config & IOCSRF_FLATMODE)
-		c->options |= LOONGARCH_CPU_FLATMODE;
-	if (config & IOCSRF_EIODECODE)
-		c->options |= LOONGARCH_CPU_EIODECODE;
-	if (config & IOCSRF_AVEC)
-		c->options |= LOONGARCH_CPU_AVECINT;
-	if (config & IOCSRF_VM)
-		c->options |= LOONGARCH_CPU_HYPERVISOR;
-
 	config = csr_read32(LOONGARCH_CSR_ASID);
 	config = (config & CSR_ASID_BIT) >> CSR_ASID_BIT_SHIFT;
 	asid_mask = GENMASK(config - 1, 0);
@@ -231,16 +215,8 @@  static char cpu_full_name[MAX_NAME_LEN] = "        -        ";
 
 static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
 {
-	uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
-	uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
 	const char *core_name = "Unknown";
 
-	if (!__cpu_full_name[cpu])
-		__cpu_full_name[cpu] = cpu_full_name;
-
-	*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
-	*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
-
 	switch (c->processor_id & PRID_SERIES_MASK) {
 	case PRID_SERIES_LA132:
 		c->cputype = CPU_LOONGSON32;
@@ -283,6 +259,36 @@  static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int
 	pr_info("%s Processor probed (%s Core)\n", __cpu_family[cpu], core_name);
 }
 
+static inline void iocsr_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
+{
+	uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
+	uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
+	unsigned int config;
+
+	*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
+	*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
+
+	if (!__cpu_full_name[cpu])
+		__cpu_full_name[cpu] = cpu_full_name;
+
+	config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
+	if (config & IOCSRF_CSRIPI)
+		c->options |= LOONGARCH_CPU_CSRIPI;
+	if (config & IOCSRF_EXTIOI)
+		c->options |= LOONGARCH_CPU_EXTIOI;
+	if (config & IOCSRF_FREQSCALE)
+		c->options |= LOONGARCH_CPU_SCALEFREQ;
+	if (config & IOCSRF_FLATMODE)
+		c->options |= LOONGARCH_CPU_FLATMODE;
+	if (config & IOCSRF_EIODECODE)
+		c->options |= LOONGARCH_CPU_EIODECODE;
+	if (config & IOCSRF_AVEC)
+		c->options |= LOONGARCH_CPU_AVECINT;
+	if (config & IOCSRF_VM)
+		c->options |= LOONGARCH_CPU_HYPERVISOR;
+
+}
+
 #ifdef CONFIG_64BIT
 /* For use by uaccess.h */
 u64 __ua_limit;
@@ -331,6 +337,15 @@  void cpu_probe(void)
 		break;
 	}
 
+	if (c->options & LOONGARCH_CPU_IOCSR) {
+		switch (c->cputype) {
+		case CPU_LOONGSON32:
+		case CPU_LOONGSON64:
+			iocsr_probe_loongson(c, cpu);
+			break;
+		}
+	}
+
 	BUG_ON(!__cpu_family[cpu]);
 	BUG_ON(c->cputype == CPU_UNKNOWN);