xref: /openbmc/linux/arch/powerpc/kernel/cputable.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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 __read_mostly;
24  
25  struct cpu_spec* cur_cpu_spec __read_mostly = 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  
set_cur_cpu_spec(struct cpu_spec * s)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  	/*
39  	 * use memcpy() instead of *t = *s so that GCC replaces it
40  	 * by __memcpy() when KASAN is active
41  	 */
42  	memcpy(t, s, sizeof(*t));
43  
44  	*PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
45  }
46  
setup_cpu_spec(unsigned long offset,struct cpu_spec * s)47  static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
48  					       struct cpu_spec *s)
49  {
50  	struct cpu_spec *t = &the_cpu_spec;
51  	struct cpu_spec old;
52  
53  	t = PTRRELOC(t);
54  	old = *t;
55  
56  	/*
57  	 * Copy everything, then do fixups. Use memcpy() instead of *t = *s
58  	 * so that GCC replaces it by __memcpy() when KASAN is active
59  	 */
60  	memcpy(t, s, sizeof(*t));
61  
62  	/*
63  	 * If we are overriding a previous value derived from the real
64  	 * PVR with a new value obtained using a logical PVR value,
65  	 * don't modify the performance monitor fields.
66  	 */
67  	if (old.num_pmcs && !s->num_pmcs) {
68  		t->num_pmcs = old.num_pmcs;
69  		t->pmc_type = old.pmc_type;
70  
71  		/*
72  		 * Let's ensure that the
73  		 * fix for the PMAO bug is enabled on compatibility mode.
74  		 */
75  		t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG;
76  	}
77  
78  	/* Set kuap ON at startup, will be disabled later if cmdline has 'nosmap' */
79  	if (IS_ENABLED(CONFIG_PPC_KUAP) && IS_ENABLED(CONFIG_PPC32))
80  		t->mmu_features |= MMU_FTR_KUAP;
81  
82  	*PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
83  
84  	/*
85  	 * Set the base platform string once; assumes
86  	 * we're called with real pvr first.
87  	 */
88  	if (*PTRRELOC(&powerpc_base_platform) == NULL)
89  		*PTRRELOC(&powerpc_base_platform) = t->platform;
90  
91  #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE)
92  	/* ppc64 and booke expect identify_cpu to also call setup_cpu for
93  	 * that processor. I will consolidate that at a later time, for now,
94  	 * just use #ifdef. We also don't need to PTRRELOC the function
95  	 * pointer on ppc64 and booke as we are running at 0 in real mode
96  	 * on ppc64 and reloc_offset is always 0 on booke.
97  	 */
98  	if (t->cpu_setup) {
99  		t->cpu_setup(offset, t);
100  	}
101  #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
102  
103  	return t;
104  }
105  
identify_cpu(unsigned long offset,unsigned int pvr)106  struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
107  {
108  	struct cpu_spec *s = cpu_specs;
109  	int i;
110  
111  	BUILD_BUG_ON(!ARRAY_SIZE(cpu_specs));
112  
113  	s = PTRRELOC(s);
114  
115  	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
116  		if ((pvr & s->pvr_mask) == s->pvr_value)
117  			return setup_cpu_spec(offset, s);
118  	}
119  
120  	BUG();
121  
122  	return NULL;
123  }
124  
125  /*
126   * Used by cpufeatures to get the name for CPUs with a PVR table.
127   * If they don't hae a PVR table, cpufeatures gets the name from
128   * cpu device-tree node.
129   */
identify_cpu_name(unsigned int pvr)130  void __init identify_cpu_name(unsigned int pvr)
131  {
132  	struct cpu_spec *s = cpu_specs;
133  	struct cpu_spec *t = &the_cpu_spec;
134  	int i;
135  
136  	s = PTRRELOC(s);
137  	t = PTRRELOC(t);
138  
139  	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
140  		if ((pvr & s->pvr_mask) == s->pvr_value) {
141  			t->cpu_name = s->cpu_name;
142  			return;
143  		}
144  	}
145  }
146  
147  
148  #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
149  struct static_key_true cpu_feature_keys[NUM_CPU_FTR_KEYS] = {
150  			[0 ... NUM_CPU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
151  };
152  EXPORT_SYMBOL_GPL(cpu_feature_keys);
153  
cpu_feature_keys_init(void)154  void __init cpu_feature_keys_init(void)
155  {
156  	int i;
157  
158  	for (i = 0; i < NUM_CPU_FTR_KEYS; i++) {
159  		unsigned long f = 1ul << i;
160  
161  		if (!(cur_cpu_spec->cpu_features & f))
162  			static_branch_disable(&cpu_feature_keys[i]);
163  	}
164  }
165  
166  struct static_key_true mmu_feature_keys[NUM_MMU_FTR_KEYS] = {
167  			[0 ... NUM_MMU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
168  };
169  EXPORT_SYMBOL(mmu_feature_keys);
170  
mmu_feature_keys_init(void)171  void __init mmu_feature_keys_init(void)
172  {
173  	int i;
174  
175  	for (i = 0; i < NUM_MMU_FTR_KEYS; i++) {
176  		unsigned long f = 1ul << i;
177  
178  		if (!(cur_cpu_spec->mmu_features & f))
179  			static_branch_disable(&mmu_feature_keys[i]);
180  	}
181  }
182  #endif
183