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