Skip to content

Commit 34e3c45

Browse files
FlyGoatchenhuacai
authored andcommitted
LoongArch: Rework CPU feature probe from CPUCFG/IOCSR
Probe ISA level, TLB, IOCSR information from CPUCFG to improve kernel resilience to different core implementations. BTW, IOCSR register definition appears to be a platform-specific spec instead of an architecture spec, even for the 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 <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent d0bb0b6 commit 34e3c45

File tree

6 files changed

+100
-64
lines changed

6 files changed

+100
-64
lines changed

arch/loongarch/include/asm/cpu-features.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#define cpu_has_lbt_mips cpu_opt(LOONGARCH_CPU_LBT_MIPS)
5252
#define cpu_has_lbt (cpu_has_lbt_x86|cpu_has_lbt_arm|cpu_has_lbt_mips)
5353
#define cpu_has_csr cpu_opt(LOONGARCH_CPU_CSR)
54+
#define cpu_has_iocsr cpu_opt(LOONGARCH_CPU_IOCSR)
5455
#define cpu_has_tlb cpu_opt(LOONGARCH_CPU_TLB)
5556
#define cpu_has_watch cpu_opt(LOONGARCH_CPU_WATCH)
5657
#define cpu_has_vint cpu_opt(LOONGARCH_CPU_VINT)
@@ -65,6 +66,7 @@
6566
#define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID)
6667
#define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR)
6768
#define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW)
69+
#define cpu_has_lspw cpu_opt(LOONGARCH_CPU_LSPW)
6870
#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT)
6971

7072
#endif /* __ASM_CPU_FEATURES_H */

arch/loongarch/include/asm/cpu.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,21 @@ enum cpu_type_enum {
8787
#define CPU_FEATURE_LBT_MIPS 12 /* CPU has MIPS Binary Translation */
8888
#define CPU_FEATURE_TLB 13 /* CPU has TLB */
8989
#define CPU_FEATURE_CSR 14 /* CPU has CSR */
90-
#define CPU_FEATURE_WATCH 15 /* CPU has watchpoint registers */
91-
#define CPU_FEATURE_VINT 16 /* CPU has vectored interrupts */
92-
#define CPU_FEATURE_CSRIPI 17 /* CPU has CSR-IPI */
93-
#define CPU_FEATURE_EXTIOI 18 /* CPU has EXT-IOI */
94-
#define CPU_FEATURE_PREFETCH 19 /* CPU has prefetch instructions */
95-
#define CPU_FEATURE_PMP 20 /* CPU has perfermance counter */
96-
#define CPU_FEATURE_SCALEFREQ 21 /* CPU supports cpufreq scaling */
97-
#define CPU_FEATURE_FLATMODE 22 /* CPU has flat mode */
98-
#define CPU_FEATURE_EIODECODE 23 /* CPU has EXTIOI interrupt pin decode mode */
99-
#define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */
100-
#define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */
101-
#define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */
102-
#define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */
90+
#define CPU_FEATURE_IOCSR 15 /* CPU has IOCSR */
91+
#define CPU_FEATURE_WATCH 16 /* CPU has watchpoint registers */
92+
#define CPU_FEATURE_VINT 17 /* CPU has vectored interrupts */
93+
#define CPU_FEATURE_CSRIPI 18 /* CPU has CSR-IPI */
94+
#define CPU_FEATURE_EXTIOI 19 /* CPU has EXT-IOI */
95+
#define CPU_FEATURE_PREFETCH 20 /* CPU has prefetch instructions */
96+
#define CPU_FEATURE_PMP 21 /* CPU has perfermance counter */
97+
#define CPU_FEATURE_SCALEFREQ 22 /* CPU supports cpufreq scaling */
98+
#define CPU_FEATURE_FLATMODE 23 /* CPU has flat mode */
99+
#define CPU_FEATURE_EIODECODE 24 /* CPU has EXTIOI interrupt pin decode mode */
100+
#define CPU_FEATURE_GUESTID 25 /* CPU has GuestID feature */
101+
#define CPU_FEATURE_HYPERVISOR 26 /* CPU has hypervisor (running in VM) */
102+
#define CPU_FEATURE_PTW 27 /* CPU has hardware page table walker */
103+
#define CPU_FEATURE_LSPW 28 /* CPU has LSPW (lddir/ldpte instructions) */
104+
#define CPU_FEATURE_AVECINT 29 /* CPU has AVEC interrupt */
103105

104106
#define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG)
105107
#define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM)
@@ -115,6 +117,7 @@ enum cpu_type_enum {
115117
#define LOONGARCH_CPU_LBT_ARM BIT_ULL(CPU_FEATURE_LBT_ARM)
116118
#define LOONGARCH_CPU_LBT_MIPS BIT_ULL(CPU_FEATURE_LBT_MIPS)
117119
#define LOONGARCH_CPU_TLB BIT_ULL(CPU_FEATURE_TLB)
120+
#define LOONGARCH_CPU_IOCSR BIT_ULL(CPU_FEATURE_IOCSR)
118121
#define LOONGARCH_CPU_CSR BIT_ULL(CPU_FEATURE_CSR)
119122
#define LOONGARCH_CPU_WATCH BIT_ULL(CPU_FEATURE_WATCH)
120123
#define LOONGARCH_CPU_VINT BIT_ULL(CPU_FEATURE_VINT)
@@ -128,6 +131,7 @@ enum cpu_type_enum {
128131
#define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID)
129132
#define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR)
130133
#define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW)
134+
#define LOONGARCH_CPU_LSPW BIT_ULL(CPU_FEATURE_LSPW)
131135
#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT)
132136

133137
#endif /* _ASM_CPU_H */

arch/loongarch/include/asm/loongarch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#define LOONGARCH_CPUCFG1 0x1
6363
#define CPUCFG1_ISGR32 BIT(0)
6464
#define CPUCFG1_ISGR64 BIT(1)
65+
#define CPUCFG1_ISA GENMASK(1, 0)
6566
#define CPUCFG1_PAGING BIT(2)
6667
#define CPUCFG1_IOCSR BIT(3)
6768
#define CPUCFG1_PABITS GENMASK(11, 4)

arch/loongarch/include/uapi/asm/hwcap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
#define HWCAP_LOONGARCH_LBT_ARM (1 << 11)
1818
#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12)
1919
#define HWCAP_LOONGARCH_PTW (1 << 13)
20+
#define HWCAP_LOONGARCH_LSPW (1 << 14)
2021

2122
#endif /* _UAPI_ASM_HWCAP_H */

arch/loongarch/kernel/cpu-probe.c

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,30 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
9191
unsigned int config;
9292
unsigned long asid_mask;
9393

94-
c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR |
95-
LOONGARCH_CPU_TLB | LOONGARCH_CPU_VINT | LOONGARCH_CPU_WATCH;
94+
c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR | LOONGARCH_CPU_VINT;
9695

9796
elf_hwcap = HWCAP_LOONGARCH_CPUCFG;
9897

9998
config = read_cpucfg(LOONGARCH_CPUCFG1);
99+
100+
switch (config & CPUCFG1_ISA) {
101+
case 0:
102+
set_isa(c, LOONGARCH_CPU_ISA_LA32R);
103+
break;
104+
case 1:
105+
set_isa(c, LOONGARCH_CPU_ISA_LA32S);
106+
break;
107+
case 2:
108+
set_isa(c, LOONGARCH_CPU_ISA_LA64);
109+
break;
110+
default:
111+
pr_warn("Warning: unknown ISA level\n");
112+
}
113+
114+
if (config & CPUCFG1_PAGING)
115+
c->options |= LOONGARCH_CPU_TLB;
116+
if (config & CPUCFG1_IOCSR)
117+
c->options |= LOONGARCH_CPU_IOCSR;
100118
if (config & CPUCFG1_UAL) {
101119
c->options |= LOONGARCH_CPU_UAL;
102120
elf_hwcap |= HWCAP_LOONGARCH_UAL;
@@ -139,6 +157,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
139157
c->options |= LOONGARCH_CPU_PTW;
140158
elf_hwcap |= HWCAP_LOONGARCH_PTW;
141159
}
160+
if (config & CPUCFG2_LSPW) {
161+
c->options |= LOONGARCH_CPU_LSPW;
162+
elf_hwcap |= HWCAP_LOONGARCH_LSPW;
163+
}
142164
if (config & CPUCFG2_LVZP) {
143165
c->options |= LOONGARCH_CPU_LVZ;
144166
elf_hwcap |= HWCAP_LOONGARCH_LVZ;
@@ -162,22 +184,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
162184
if (config & CPUCFG6_PMP)
163185
c->options |= LOONGARCH_CPU_PMP;
164186

165-
config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
166-
if (config & IOCSRF_CSRIPI)
167-
c->options |= LOONGARCH_CPU_CSRIPI;
168-
if (config & IOCSRF_EXTIOI)
169-
c->options |= LOONGARCH_CPU_EXTIOI;
170-
if (config & IOCSRF_FREQSCALE)
171-
c->options |= LOONGARCH_CPU_SCALEFREQ;
172-
if (config & IOCSRF_FLATMODE)
173-
c->options |= LOONGARCH_CPU_FLATMODE;
174-
if (config & IOCSRF_EIODECODE)
175-
c->options |= LOONGARCH_CPU_EIODECODE;
176-
if (config & IOCSRF_AVEC)
177-
c->options |= LOONGARCH_CPU_AVECINT;
178-
if (config & IOCSRF_VM)
179-
c->options |= LOONGARCH_CPU_HYPERVISOR;
180-
181187
config = csr_read32(LOONGARCH_CSR_ASID);
182188
config = (config & CSR_ASID_BIT) >> CSR_ASID_BIT_SHIFT;
183189
asid_mask = GENMASK(config - 1, 0);
@@ -210,6 +216,9 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
210216
default:
211217
pr_warn("Warning: unknown TLB type\n");
212218
}
219+
220+
if (get_num_brps() + get_num_wrps())
221+
c->options |= LOONGARCH_CPU_WATCH;
213222
}
214223

215224
#define MAX_NAME_LEN 32
@@ -220,52 +229,67 @@ static char cpu_full_name[MAX_NAME_LEN] = " - ";
220229

221230
static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
222231
{
232+
uint32_t config;
223233
uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
224234
uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
235+
const char *core_name = "Unknown";
225236

226-
if (!__cpu_full_name[cpu])
227-
__cpu_full_name[cpu] = cpu_full_name;
228-
229-
*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
230-
*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
231-
232-
switch (c->processor_id & PRID_SERIES_MASK) {
233-
case PRID_SERIES_LA132:
237+
switch (BIT(fls(c->isa_level) - 1)) {
238+
case LOONGARCH_CPU_ISA_LA32R:
239+
case LOONGARCH_CPU_ISA_LA32S:
234240
c->cputype = CPU_LOONGSON32;
235-
set_isa(c, LOONGARCH_CPU_ISA_LA32S);
236241
__cpu_family[cpu] = "Loongson-32bit";
237-
pr_info("32-bit Loongson Processor probed (LA132 Core)\n");
238242
break;
239-
case PRID_SERIES_LA264:
243+
case LOONGARCH_CPU_ISA_LA64:
240244
c->cputype = CPU_LOONGSON64;
241-
set_isa(c, LOONGARCH_CPU_ISA_LA64);
242245
__cpu_family[cpu] = "Loongson-64bit";
243-
pr_info("64-bit Loongson Processor probed (LA264 Core)\n");
246+
break;
247+
}
248+
249+
switch (c->processor_id & PRID_SERIES_MASK) {
250+
case PRID_SERIES_LA132:
251+
core_name = "LA132";
252+
break;
253+
case PRID_SERIES_LA264:
254+
core_name = "LA264";
244255
break;
245256
case PRID_SERIES_LA364:
246-
c->cputype = CPU_LOONGSON64;
247-
set_isa(c, LOONGARCH_CPU_ISA_LA64);
248-
__cpu_family[cpu] = "Loongson-64bit";
249-
pr_info("64-bit Loongson Processor probed (LA364 Core)\n");
257+
core_name = "LA364";
250258
break;
251259
case PRID_SERIES_LA464:
252-
c->cputype = CPU_LOONGSON64;
253-
set_isa(c, LOONGARCH_CPU_ISA_LA64);
254-
__cpu_family[cpu] = "Loongson-64bit";
255-
pr_info("64-bit Loongson Processor probed (LA464 Core)\n");
260+
core_name = "LA464";
256261
break;
257262
case PRID_SERIES_LA664:
258-
c->cputype = CPU_LOONGSON64;
259-
set_isa(c, LOONGARCH_CPU_ISA_LA64);
260-
__cpu_family[cpu] = "Loongson-64bit";
261-
pr_info("64-bit Loongson Processor probed (LA664 Core)\n");
263+
core_name = "LA664";
262264
break;
263-
default: /* Default to 64 bit */
264-
c->cputype = CPU_LOONGSON64;
265-
set_isa(c, LOONGARCH_CPU_ISA_LA64);
266-
__cpu_family[cpu] = "Loongson-64bit";
267-
pr_info("64-bit Loongson Processor probed (Unknown Core)\n");
268265
}
266+
267+
pr_info("%s Processor probed (%s Core)\n", __cpu_family[cpu], core_name);
268+
269+
if (!cpu_has_iocsr)
270+
return;
271+
272+
if (!__cpu_full_name[cpu])
273+
__cpu_full_name[cpu] = cpu_full_name;
274+
275+
*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
276+
*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
277+
278+
config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
279+
if (config & IOCSRF_CSRIPI)
280+
c->options |= LOONGARCH_CPU_CSRIPI;
281+
if (config & IOCSRF_EXTIOI)
282+
c->options |= LOONGARCH_CPU_EXTIOI;
283+
if (config & IOCSRF_FREQSCALE)
284+
c->options |= LOONGARCH_CPU_SCALEFREQ;
285+
if (config & IOCSRF_FLATMODE)
286+
c->options |= LOONGARCH_CPU_FLATMODE;
287+
if (config & IOCSRF_EIODECODE)
288+
c->options |= LOONGARCH_CPU_EIODECODE;
289+
if (config & IOCSRF_AVEC)
290+
c->options |= LOONGARCH_CPU_AVECINT;
291+
if (config & IOCSRF_VM)
292+
c->options |= LOONGARCH_CPU_HYPERVISOR;
269293
}
270294

271295
#ifdef CONFIG_64BIT

arch/loongarch/kernel/proc.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v)
3131
static int show_cpuinfo(struct seq_file *m, void *v)
3232
{
3333
unsigned long n = (unsigned long) v - 1;
34+
unsigned int isa = cpu_data[n].isa_level;
3435
unsigned int version = cpu_data[n].processor_id & 0xff;
3536
unsigned int fp_version = cpu_data[n].fpu_vers;
3637
struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args;
@@ -64,9 +65,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
6465
cpu_pabits + 1, cpu_vabits + 1);
6566

6667
seq_printf(m, "ISA\t\t\t:");
67-
if (cpu_has_loongarch32)
68-
seq_printf(m, " loongarch32");
69-
if (cpu_has_loongarch64)
68+
if (isa & LOONGARCH_CPU_ISA_LA32R)
69+
seq_printf(m, " loongarch32r");
70+
if (isa & LOONGARCH_CPU_ISA_LA32S)
71+
seq_printf(m, " loongarch32s");
72+
if (isa & LOONGARCH_CPU_ISA_LA64)
7073
seq_printf(m, " loongarch64");
7174
seq_printf(m, "\n");
7275

@@ -81,6 +84,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
8184
if (cpu_has_complex) seq_printf(m, " complex");
8285
if (cpu_has_crypto) seq_printf(m, " crypto");
8386
if (cpu_has_ptw) seq_printf(m, " ptw");
87+
if (cpu_has_lspw) seq_printf(m, " lspw");
8488
if (cpu_has_lvz) seq_printf(m, " lvz");
8589
if (cpu_has_lbt_x86) seq_printf(m, " lbt_x86");
8690
if (cpu_has_lbt_arm) seq_printf(m, " lbt_arm");

0 commit comments

Comments
 (0)