xref: /linux/arch/powerpc/kernel/cputable.c (revision de5a7fedf5061bdf6823eb509353bd7c128e34b5)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
4  *
5  *  Modifications for ppc64:
6  *      Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
7  */
8 
9 #include <linux/string.h>
10 #include <linux/sched.h>
11 #include <linux/threads.h>
12 #include <linux/init.h>
13 #include <linux/export.h>
14 #include <linux/jump_label.h>
15 #include <linux/of.h>
16 
17 #include <asm/cputable.h>
18 #include <asm/mce.h>
19 #include <asm/mmu.h>
20 #include <asm/setup.h>
21 #include <asm/cpu_setup.h>
22 
23 static struct cpu_spec the_cpu_spec __ro_after_init;
24 
25 struct cpu_spec *cur_cpu_spec __ro_after_init = NULL;
26 EXPORT_SYMBOL(cur_cpu_spec);
27 
28 /* The platform string corresponding to the real PVR */
29 const char *powerpc_base_platform;
30 
31 #include "cpu_specs.h"
32 
33 void __init set_cur_cpu_spec(struct cpu_spec *s)
34 {
35 	struct cpu_spec *t = &the_cpu_spec;
36 
37 	t = PTRRELOC(t);
38 	*t = *s;
39 	*PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
40 }
41 
42 static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
43 					       struct cpu_spec *s)
44 {
45 	struct cpu_spec *t = &the_cpu_spec;
46 	struct cpu_spec old;
47 
48 	t = PTRRELOC(t);
49 	old = *t;
50 
51 	/* Copy everything, then do fixups. */
52 	*t = *s;
53 
54 	/*
55 	 * If we are overriding a previous value derived from the real
56 	 * PVR with a new value obtained using a logical PVR value,
57 	 * don't modify the performance monitor fields.
58 	 */
59 	if (old.num_pmcs && !s->num_pmcs) {
60 		t->num_pmcs = old.num_pmcs;
61 		t->pmc_type = old.pmc_type;
62 
63 		/*
64 		 * Let's ensure that the
65 		 * fix for the PMAO bug is enabled on compatibility mode.
66 		 */
67 		t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG;
68 	}
69 
70 	/* Set kuap ON at startup, will be disabled later if cmdline has 'nosmap' */
71 	if (IS_ENABLED(CONFIG_PPC_KUAP) && IS_ENABLED(CONFIG_PPC32))
72 		t->mmu_features |= MMU_FTR_KUAP;
73 
74 	*PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
75 
76 	/*
77 	 * Set the base platform string once; assumes
78 	 * we're called with real pvr first.
79 	 */
80 	if (*PTRRELOC(&powerpc_base_platform) == NULL)
81 		*PTRRELOC(&powerpc_base_platform) = t->platform;
82 
83 #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE)
84 	/* ppc64 and booke expect identify_cpu to also call setup_cpu for
85 	 * that processor. I will consolidate that at a later time, for now,
86 	 * just use #ifdef. We also don't need to PTRRELOC the function
87 	 * pointer on ppc64 and booke as we are running at 0 in real mode
88 	 * on ppc64 and reloc_offset is always 0 on booke.
89 	 */
90 	if (t->cpu_setup) {
91 		t->cpu_setup(offset, t);
92 	}
93 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
94 
95 	return t;
96 }
97 
98 struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
99 {
100 	struct cpu_spec *s = cpu_specs;
101 	int i;
102 
103 	BUILD_BUG_ON(!ARRAY_SIZE(cpu_specs));
104 
105 	s = PTRRELOC(s);
106 
107 	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
108 		if ((pvr & s->pvr_mask) == s->pvr_value)
109 			return setup_cpu_spec(offset, s);
110 	}
111 
112 	BUG();
113 
114 	return NULL;
115 }
116 
117 /*
118  * Used by cpufeatures to get the name for CPUs with a PVR table.
119  * If they don't hae a PVR table, cpufeatures gets the name from
120  * cpu device-tree node.
121  */
122 void __init identify_cpu_name(unsigned int pvr)
123 {
124 	struct cpu_spec *s = cpu_specs;
125 	struct cpu_spec *t = &the_cpu_spec;
126 	int i;
127 
128 	s = PTRRELOC(s);
129 	t = PTRRELOC(t);
130 
131 	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
132 		if ((pvr & s->pvr_mask) == s->pvr_value) {
133 			t->cpu_name = s->cpu_name;
134 			return;
135 		}
136 	}
137 }
138 
139 
140 #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
141 struct static_key_true cpu_feature_keys[NUM_CPU_FTR_KEYS] = {
142 			[0 ... NUM_CPU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
143 };
144 EXPORT_SYMBOL_GPL(cpu_feature_keys);
145 
146 void __init cpu_feature_keys_init(void)
147 {
148 	int i;
149 
150 	for (i = 0; i < NUM_CPU_FTR_KEYS; i++) {
151 		unsigned long f = 1ul << i;
152 
153 		if (!(cur_cpu_spec->cpu_features & f))
154 			static_branch_disable(&cpu_feature_keys[i]);
155 	}
156 }
157 
158 struct static_key_true mmu_feature_keys[NUM_MMU_FTR_KEYS] = {
159 			[0 ... NUM_MMU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
160 };
161 EXPORT_SYMBOL(mmu_feature_keys);
162 
163 void __init mmu_feature_keys_init(void)
164 {
165 	int i;
166 
167 	for (i = 0; i < NUM_MMU_FTR_KEYS; i++) {
168 		unsigned long f = 1ul << i;
169 
170 		if (!(cur_cpu_spec->mmu_features & f))
171 			static_branch_disable(&mmu_feature_keys[i]);
172 	}
173 }
174 #endif
175