xref: /linux/arch/mips/include/asm/mips-cps.h (revision da5b2ad1c2f18834cb1ce429e2e5a5cf5cbdf21b)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (C) 2017 Imagination Technologies
4  * Author: Paul Burton <paul.burton@mips.com>
5  */
6 
7 #ifndef __MIPS_ASM_MIPS_CPS_H__
8 #define __MIPS_ASM_MIPS_CPS_H__
9 
10 #include <linux/bitfield.h>
11 #include <linux/cpumask.h>
12 #include <linux/io.h>
13 #include <linux/types.h>
14 
15 extern unsigned long __cps_access_bad_size(void)
16 	__compiletime_error("Bad size for CPS accessor");
17 
18 #define CPS_ACCESSOR_A(unit, off, name)					\
19 static inline void *addr_##unit##_##name(void)				\
20 {									\
21 	return mips_##unit##_base + (off);				\
22 }
23 
24 #define CPS_ACCESSOR_R(unit, sz, name)					\
25 static inline uint##sz##_t read_##unit##_##name(void)			\
26 {									\
27 	uint64_t val64;							\
28 									\
29 	switch (sz) {							\
30 	case 32:							\
31 		return __raw_readl(addr_##unit##_##name());		\
32 									\
33 	case 64:							\
34 		if (mips_cm_is64)					\
35 			return __raw_readq(addr_##unit##_##name());	\
36 									\
37 		val64 = __raw_readl(addr_##unit##_##name() + 4);	\
38 		val64 <<= 32;						\
39 		val64 |= __raw_readl(addr_##unit##_##name());		\
40 		return val64;						\
41 									\
42 	default:							\
43 		return __cps_access_bad_size();				\
44 	}								\
45 }
46 
47 #define CPS_ACCESSOR_W(unit, sz, name)					\
48 static inline void write_##unit##_##name(uint##sz##_t val)		\
49 {									\
50 	switch (sz) {							\
51 	case 32:							\
52 		__raw_writel(val, addr_##unit##_##name());		\
53 		break;							\
54 									\
55 	case 64:							\
56 		if (mips_cm_is64) {					\
57 			__raw_writeq(val, addr_##unit##_##name());	\
58 			break;						\
59 		}							\
60 									\
61 		__raw_writel((uint64_t)val >> 32,			\
62 			     addr_##unit##_##name() + 4);		\
63 		__raw_writel(val, addr_##unit##_##name());		\
64 		break;							\
65 									\
66 	default:							\
67 		__cps_access_bad_size();				\
68 		break;							\
69 	}								\
70 }
71 
72 #define CPS_ACCESSOR_M(unit, sz, name)					\
73 static inline void change_##unit##_##name(uint##sz##_t mask,		\
74 					  uint##sz##_t val)		\
75 {									\
76 	uint##sz##_t reg_val = read_##unit##_##name();			\
77 	reg_val &= ~mask;						\
78 	reg_val |= val;							\
79 	write_##unit##_##name(reg_val);					\
80 }									\
81 									\
82 static inline void set_##unit##_##name(uint##sz##_t val)		\
83 {									\
84 	change_##unit##_##name(val, val);				\
85 }									\
86 									\
87 static inline void clear_##unit##_##name(uint##sz##_t val)		\
88 {									\
89 	change_##unit##_##name(val, 0);					\
90 }
91 
92 #define CPS_ACCESSOR_RO(unit, sz, off, name)				\
93 	CPS_ACCESSOR_A(unit, off, name)					\
94 	CPS_ACCESSOR_R(unit, sz, name)
95 
96 #define CPS_ACCESSOR_WO(unit, sz, off, name)				\
97 	CPS_ACCESSOR_A(unit, off, name)					\
98 	CPS_ACCESSOR_W(unit, sz, name)
99 
100 #define CPS_ACCESSOR_RW(unit, sz, off, name)				\
101 	CPS_ACCESSOR_A(unit, off, name)					\
102 	CPS_ACCESSOR_R(unit, sz, name)					\
103 	CPS_ACCESSOR_W(unit, sz, name)					\
104 	CPS_ACCESSOR_M(unit, sz, name)
105 
106 #include <asm/mips-cm.h>
107 #include <asm/mips-cpc.h>
108 #include <asm/mips-gic.h>
109 
110 /**
111  * mips_cps_numclusters - return the number of clusters present in the system
112  *
113  * Returns the number of clusters in the system.
114  */
115 static inline unsigned int mips_cps_numclusters(void)
116 {
117 	if (mips_cm_revision() < CM_REV_CM3_5)
118 		return 1;
119 
120 	return FIELD_GET(CM_GCR_CONFIG_NUM_CLUSTERS, read_gcr_config());
121 }
122 
123 /**
124  * mips_cps_cluster_config - return (GCR|CPC)_CONFIG from a cluster
125  * @cluster: the ID of the cluster whose config we want
126  *
127  * Read the value of GCR_CONFIG (or its CPC_CONFIG mirror) from a @cluster.
128  *
129  * Returns the value of GCR_CONFIG.
130  */
131 static inline uint64_t mips_cps_cluster_config(unsigned int cluster)
132 {
133 	uint64_t config;
134 
135 	if (mips_cm_revision() < CM_REV_CM3_5) {
136 		/*
137 		 * Prior to CM 3.5 we don't have the notion of multiple
138 		 * clusters so we can trivially read the GCR_CONFIG register
139 		 * within this cluster.
140 		 */
141 		WARN_ON(cluster != 0);
142 		config = read_gcr_config();
143 	} else {
144 		/*
145 		 * From CM 3.5 onwards we read the CPC_CONFIG mirror of
146 		 * GCR_CONFIG via the redirect region, since the CPC is always
147 		 * powered up allowing us not to need to power up the CM.
148 		 */
149 		mips_cm_lock_other(cluster, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
150 		config = read_cpc_redir_config();
151 		mips_cm_unlock_other();
152 	}
153 
154 	return config;
155 }
156 
157 /**
158  * mips_cps_numcores - return the number of cores present in a cluster
159  * @cluster: the ID of the cluster whose core count we want
160  *
161  * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
162  * zero if no Coherence Manager is present.
163  */
164 static inline unsigned int mips_cps_numcores(unsigned int cluster)
165 {
166 	if (!mips_cm_present())
167 		return 0;
168 
169 	/* Add one before masking to handle 0xff indicating no cores */
170 	return FIELD_GET(CM_GCR_CONFIG_PCORES,
171 			 mips_cps_cluster_config(cluster) + 1);
172 }
173 
174 /**
175  * mips_cps_numiocu - return the number of IOCUs present in a cluster
176  * @cluster: the ID of the cluster whose IOCU count we want
177  *
178  * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
179  * if no Coherence Manager is present.
180  */
181 static inline unsigned int mips_cps_numiocu(unsigned int cluster)
182 {
183 	if (!mips_cm_present())
184 		return 0;
185 
186 	return FIELD_GET(CM_GCR_CONFIG_NUMIOCU,
187 			 mips_cps_cluster_config(cluster));
188 }
189 
190 /**
191  * mips_cps_numvps - return the number of VPs (threads) supported by a core
192  * @cluster: the ID of the cluster containing the core we want to examine
193  * @core: the ID of the core whose VP count we want
194  *
195  * Returns the number of Virtual Processors (VPs, ie. hardware threads) that
196  * are supported by the given @core in the given @cluster. If the core or the
197  * kernel do not support hardware mutlti-threading this returns 1.
198  */
199 static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int core)
200 {
201 	unsigned int cfg;
202 
203 	if (!mips_cm_present())
204 		return 1;
205 
206 	if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
207 		&& (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
208 		return 1;
209 
210 	mips_cm_lock_other(cluster, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
211 
212 	if (mips_cm_revision() < CM_REV_CM3_5) {
213 		/*
214 		 * Prior to CM 3.5 we can only have one cluster & don't have
215 		 * CPC_Cx_CONFIG, so we read GCR_Cx_CONFIG.
216 		 */
217 		cfg = read_gcr_co_config();
218 	} else {
219 		/*
220 		 * From CM 3.5 onwards we read CPC_Cx_CONFIG because the CPC is
221 		 * always powered, which allows us to not worry about powering
222 		 * up the cluster's CM here.
223 		 */
224 		cfg = read_cpc_co_config();
225 	}
226 
227 	mips_cm_unlock_other();
228 
229 	return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, cfg + 1);
230 }
231 
232 /**
233  * mips_cps_multicluster_cpus() - Detect whether CPUs are in multiple clusters
234  *
235  * Determine whether the system includes CPUs in multiple clusters - ie.
236  * whether we can treat the system as single or multi-cluster as far as CPUs
237  * are concerned. Note that this is slightly different to simply checking
238  * whether multiple clusters are present - it is possible for there to be
239  * clusters which contain no CPUs, which this function will effectively ignore.
240  *
241  * Returns true if CPUs are spread across multiple clusters, else false.
242  */
243 static inline bool mips_cps_multicluster_cpus(void)
244 {
245 	unsigned int first_cl, last_cl;
246 
247 	/*
248 	 * CPUs are numbered sequentially by cluster - ie. CPUs 0..X will be in
249 	 * cluster 0, CPUs X+1..Y in cluster 1, CPUs Y+1..Z in cluster 2 etc.
250 	 *
251 	 * Thus we can detect multiple clusters trivially by checking whether
252 	 * the first & last CPUs belong to the same cluster.
253 	 */
254 	first_cl = cpu_cluster(&boot_cpu_data);
255 	last_cl = cpu_cluster(&cpu_data[nr_cpu_ids - 1]);
256 	return first_cl != last_cl;
257 }
258 
259 /**
260  * mips_cps_first_online_in_cluster() - Detect if CPU is first online in cluster
261  *
262  * Determine whether the local CPU is the first to be brought online in its
263  * cluster - that is, whether there are any other online CPUs in the local
264  * cluster.
265  *
266  * Returns true if this CPU is first online, else false.
267  */
268 extern unsigned int mips_cps_first_online_in_cluster(void);
269 
270 #endif /* __MIPS_ASM_MIPS_CPS_H__ */
271