]> Git Repo - J-linux.git/blob - arch/mips/include/asm/mips-cps.h
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / arch / mips / include / asm / mips-cps.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (C) 2017 Imagination Technologies
4  * Author: Paul Burton <[email protected]>
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__ */
This page took 0.042768 seconds and 4 git commands to generate.