Thomas Gleixner | 2874c5f | 2019-05-27 08:55:01 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2013 Imagination Technologies |
Paul Burton | fb615d6 | 2017-10-25 17:04:33 -0700 | [diff] [blame] | 4 | * Author: Paul Burton <paul.burton@mips.com> |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 5 | */ |
| 6 | |
| 7 | #include <linux/errno.h> |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 8 | #include <linux/percpu.h> |
| 9 | #include <linux/spinlock.h> |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 10 | |
Paul Burton | e83f7e0 | 2017-08-12 19:49:41 -0700 | [diff] [blame] | 11 | #include <asm/mips-cps.h> |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 12 | #include <asm/mipsregs.h> |
| 13 | |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 14 | void __iomem *mips_gcr_base; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 15 | void __iomem *mips_cm_l2sync_base; |
Markos Chandras | c0b584a | 2015-07-14 09:14:12 +0100 | [diff] [blame] | 16 | int mips_cm_is64; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 17 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 18 | static char *cm2_tr[8] = { |
| 19 | "mem", "gcr", "gic", "mmio", |
| 20 | "0x04", "cpc", "0x06", "0x07" |
| 21 | }; |
| 22 | |
Adam Buchbinder | 92a76f6 | 2016-02-25 00:44:58 -0800 | [diff] [blame] | 23 | /* CM3 Tag ECC transaction type */ |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 24 | static char *cm3_tr[16] = { |
| 25 | [0x0] = "ReqNoData", |
| 26 | [0x1] = "0x1", |
| 27 | [0x2] = "ReqWData", |
| 28 | [0x3] = "0x3", |
| 29 | [0x4] = "IReqNoResp", |
| 30 | [0x5] = "IReqWResp", |
| 31 | [0x6] = "IReqNoRespDat", |
| 32 | [0x7] = "IReqWRespDat", |
| 33 | [0x8] = "RespNoData", |
| 34 | [0x9] = "RespDataFol", |
| 35 | [0xa] = "RespWData", |
| 36 | [0xb] = "RespDataOnly", |
| 37 | [0xc] = "IRespNoData", |
| 38 | [0xd] = "IRespDataFol", |
| 39 | [0xe] = "IRespWData", |
| 40 | [0xf] = "IRespDataOnly" |
| 41 | }; |
| 42 | |
| 43 | static char *cm2_cmd[32] = { |
| 44 | [0x00] = "0x00", |
| 45 | [0x01] = "Legacy Write", |
| 46 | [0x02] = "Legacy Read", |
| 47 | [0x03] = "0x03", |
| 48 | [0x04] = "0x04", |
| 49 | [0x05] = "0x05", |
| 50 | [0x06] = "0x06", |
| 51 | [0x07] = "0x07", |
| 52 | [0x08] = "Coherent Read Own", |
| 53 | [0x09] = "Coherent Read Share", |
| 54 | [0x0a] = "Coherent Read Discard", |
| 55 | [0x0b] = "Coherent Ready Share Always", |
| 56 | [0x0c] = "Coherent Upgrade", |
| 57 | [0x0d] = "Coherent Writeback", |
| 58 | [0x0e] = "0x0e", |
| 59 | [0x0f] = "0x0f", |
| 60 | [0x10] = "Coherent Copyback", |
| 61 | [0x11] = "Coherent Copyback Invalidate", |
| 62 | [0x12] = "Coherent Invalidate", |
| 63 | [0x13] = "Coherent Write Invalidate", |
| 64 | [0x14] = "Coherent Completion Sync", |
| 65 | [0x15] = "0x15", |
| 66 | [0x16] = "0x16", |
| 67 | [0x17] = "0x17", |
| 68 | [0x18] = "0x18", |
| 69 | [0x19] = "0x19", |
| 70 | [0x1a] = "0x1a", |
| 71 | [0x1b] = "0x1b", |
| 72 | [0x1c] = "0x1c", |
| 73 | [0x1d] = "0x1d", |
| 74 | [0x1e] = "0x1e", |
| 75 | [0x1f] = "0x1f" |
| 76 | }; |
| 77 | |
| 78 | /* CM3 Tag ECC command type */ |
| 79 | static char *cm3_cmd[16] = { |
| 80 | [0x0] = "Legacy Read", |
| 81 | [0x1] = "Legacy Write", |
| 82 | [0x2] = "Coherent Read Own", |
| 83 | [0x3] = "Coherent Read Share", |
| 84 | [0x4] = "Coherent Read Discard", |
| 85 | [0x5] = "Coherent Evicted", |
| 86 | [0x6] = "Coherent Upgrade", |
| 87 | [0x7] = "Coherent Upgrade for Store Conditional", |
| 88 | [0x8] = "Coherent Writeback", |
| 89 | [0x9] = "Coherent Write Invalidate", |
| 90 | [0xa] = "0xa", |
| 91 | [0xb] = "0xb", |
| 92 | [0xc] = "0xc", |
| 93 | [0xd] = "0xd", |
| 94 | [0xe] = "0xe", |
| 95 | [0xf] = "0xf" |
| 96 | }; |
| 97 | |
| 98 | /* CM3 Tag ECC command group */ |
| 99 | static char *cm3_cmd_group[8] = { |
| 100 | [0x0] = "Normal", |
| 101 | [0x1] = "Registers", |
| 102 | [0x2] = "TLB", |
| 103 | [0x3] = "0x3", |
| 104 | [0x4] = "L1I", |
| 105 | [0x5] = "L1D", |
| 106 | [0x6] = "L3", |
| 107 | [0x7] = "L2" |
| 108 | }; |
| 109 | |
| 110 | static char *cm2_core[8] = { |
| 111 | "Invalid/OK", "Invalid/Data", |
| 112 | "Shared/OK", "Shared/Data", |
| 113 | "Modified/OK", "Modified/Data", |
| 114 | "Exclusive/OK", "Exclusive/Data" |
| 115 | }; |
| 116 | |
Serge Semin | 109111b | 2020-05-06 20:42:23 +0300 | [diff] [blame] | 117 | static char *cm2_l2_type[4] = { |
| 118 | [0x0] = "None", |
| 119 | [0x1] = "Tag RAM single/double ECC error", |
| 120 | [0x2] = "Data RAM single/double ECC error", |
| 121 | [0x3] = "WS RAM uncorrectable dirty parity" |
| 122 | }; |
| 123 | |
| 124 | static char *cm2_l2_instr[32] = { |
| 125 | [0x00] = "L2_NOP", |
| 126 | [0x01] = "L2_ERR_CORR", |
| 127 | [0x02] = "L2_TAG_INV", |
| 128 | [0x03] = "L2_WS_CLEAN", |
| 129 | [0x04] = "L2_RD_MDYFY_WR", |
| 130 | [0x05] = "L2_WS_MRU", |
| 131 | [0x06] = "L2_EVICT_LN2", |
| 132 | [0x07] = "0x07", |
| 133 | [0x08] = "L2_EVICT", |
| 134 | [0x09] = "L2_REFL", |
| 135 | [0x0a] = "L2_RD", |
| 136 | [0x0b] = "L2_WR", |
| 137 | [0x0c] = "L2_EVICT_MRU", |
| 138 | [0x0d] = "L2_SYNC", |
| 139 | [0x0e] = "L2_REFL_ERR", |
| 140 | [0x0f] = "0x0f", |
| 141 | [0x10] = "L2_INDX_WB_INV", |
| 142 | [0x11] = "L2_INDX_LD_TAG", |
| 143 | [0x12] = "L2_INDX_ST_TAG", |
| 144 | [0x13] = "L2_INDX_ST_DATA", |
| 145 | [0x14] = "L2_INDX_ST_ECC", |
| 146 | [0x15] = "0x15", |
| 147 | [0x16] = "0x16", |
| 148 | [0x17] = "0x17", |
| 149 | [0x18] = "L2_FTCH_AND_LCK", |
| 150 | [0x19] = "L2_HIT_INV", |
| 151 | [0x1a] = "L2_HIT_WB_INV", |
| 152 | [0x1b] = "L2_HIT_WB", |
| 153 | [0x1c] = "0x1c", |
| 154 | [0x1d] = "0x1d", |
| 155 | [0x1e] = "0x1e", |
| 156 | [0x1f] = "0x1f" |
| 157 | }; |
| 158 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 159 | static char *cm2_causes[32] = { |
| 160 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", |
| 161 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", |
| 162 | "0x08", "0x09", "0x0a", "0x0b", |
| 163 | "0x0c", "0x0d", "0x0e", "0x0f", |
Serge Semin | 8a0efb8 | 2020-05-06 20:42:22 +0300 | [diff] [blame] | 164 | "0x10", "INTVN_WR_ERR", "INTVN_RD_ERR", "0x13", |
| 165 | "0x14", "0x15", "0x16", "0x17", |
Serge Semin | 109111b | 2020-05-06 20:42:23 +0300 | [diff] [blame] | 166 | "L2_RD_UNCORR", "L2_WR_UNCORR", "L2_CORR", "0x1b", |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 167 | "0x1c", "0x1d", "0x1e", "0x1f" |
| 168 | }; |
| 169 | |
| 170 | static char *cm3_causes[32] = { |
| 171 | "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", |
| 172 | "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", |
| 173 | "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", |
| 174 | "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", |
| 175 | "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", |
| 176 | "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" |
| 177 | }; |
| 178 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 179 | static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); |
| 180 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); |
| 181 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 182 | phys_addr_t __mips_cm_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 183 | { |
| 184 | u32 config3 = read_c0_config3(); |
Markos Chandras | 038b0f5 | 2015-07-09 10:40:45 +0100 | [diff] [blame] | 185 | unsigned long cmgcr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 186 | |
| 187 | /* Check the CMGCRBase register is implemented */ |
| 188 | if (!(config3 & MIPS_CONF3_CMGCR)) |
| 189 | return 0; |
| 190 | |
| 191 | /* Read the address from CMGCRBase */ |
| 192 | cmgcr = read_c0_cmgcrbase(); |
| 193 | return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); |
| 194 | } |
| 195 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 196 | phys_addr_t mips_cm_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 197 | __attribute__((weak, alias("__mips_cm_phys_base"))); |
| 198 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 199 | phys_addr_t __mips_cm_l2sync_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 200 | { |
| 201 | u32 base_reg; |
| 202 | |
| 203 | /* |
| 204 | * If the L2-only sync region is already enabled then leave it at it's |
| 205 | * current location. |
| 206 | */ |
| 207 | base_reg = read_gcr_l2_only_sync_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 208 | if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN) |
| 209 | return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 210 | |
| 211 | /* Default to following the CM */ |
| 212 | return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; |
| 213 | } |
| 214 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 215 | phys_addr_t mips_cm_l2sync_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 216 | __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); |
| 217 | |
| 218 | static void mips_cm_probe_l2sync(void) |
| 219 | { |
| 220 | unsigned major_rev; |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 221 | phys_addr_t addr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 222 | |
| 223 | /* L2-only sync was introduced with CM major revision 6 */ |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 224 | major_rev = FIELD_GET(CM_GCR_REV_MAJOR, read_gcr_rev()); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 225 | if (major_rev < 6) |
| 226 | return; |
| 227 | |
| 228 | /* Find a location for the L2 sync region */ |
| 229 | addr = mips_cm_l2sync_phys_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 230 | BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE) != addr); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 231 | if (!addr) |
| 232 | return; |
| 233 | |
| 234 | /* Set the region base address & enable it */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 235 | write_gcr_l2_only_sync_base(addr | CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 236 | |
| 237 | /* Map the region */ |
Christoph Hellwig | 4bdc0d6 | 2020-01-06 09:43:50 +0100 | [diff] [blame] | 238 | mips_cm_l2sync_base = ioremap(addr, MIPS_CM_L2SYNC_SIZE); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | int mips_cm_probe(void) |
| 242 | { |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 243 | phys_addr_t addr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 244 | u32 base_reg; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 245 | unsigned cpu; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 246 | |
Markos Chandras | c014d16 | 2015-07-09 10:40:43 +0100 | [diff] [blame] | 247 | /* |
| 248 | * No need to probe again if we have already been |
| 249 | * here before. |
| 250 | */ |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 251 | if (mips_gcr_base) |
Markos Chandras | c014d16 | 2015-07-09 10:40:43 +0100 | [diff] [blame] | 252 | return 0; |
| 253 | |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 254 | addr = mips_cm_phys_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 255 | BUG_ON((addr & CM_GCR_BASE_GCRBASE) != addr); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 256 | if (!addr) |
| 257 | return -ENODEV; |
| 258 | |
Christoph Hellwig | 4bdc0d6 | 2020-01-06 09:43:50 +0100 | [diff] [blame] | 259 | mips_gcr_base = ioremap(addr, MIPS_CM_GCR_SIZE); |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 260 | if (!mips_gcr_base) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 261 | return -ENXIO; |
| 262 | |
| 263 | /* sanity check that we're looking at a CM */ |
| 264 | base_reg = read_gcr_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 265 | if ((base_reg & CM_GCR_BASE_GCRBASE) != addr) { |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 266 | pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n", |
| 267 | (unsigned long)addr); |
Qinglang Miao | 2673ecf9 | 2020-10-28 17:15:46 +0800 | [diff] [blame] | 268 | iounmap(mips_gcr_base); |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 269 | mips_gcr_base = NULL; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 270 | return -ENODEV; |
| 271 | } |
| 272 | |
| 273 | /* set default target to memory */ |
Paul Burton | 846e191 | 2017-08-12 19:49:31 -0700 | [diff] [blame] | 274 | change_gcr_base(CM_GCR_BASE_CMDEFTGT, CM_GCR_BASE_CMDEFTGT_MEM); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 275 | |
| 276 | /* disable CM regions */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 277 | write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR); |
| 278 | write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 279 | write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR); |
| 280 | write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 281 | write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR); |
| 282 | write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 283 | write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR); |
| 284 | write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 285 | |
| 286 | /* probe for an L2-only sync region */ |
| 287 | mips_cm_probe_l2sync(); |
| 288 | |
Markos Chandras | c0b584a | 2015-07-14 09:14:12 +0100 | [diff] [blame] | 289 | /* determine register width for this CM */ |
Masahiro Yamada | 97f2645 | 2016-08-03 13:45:50 -0700 | [diff] [blame] | 290 | mips_cm_is64 = IS_ENABLED(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); |
Markos Chandras | c0b584a | 2015-07-14 09:14:12 +0100 | [diff] [blame] | 291 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 292 | for_each_possible_cpu(cpu) |
| 293 | spin_lock_init(&per_cpu(cm_core_lock, cpu)); |
| 294 | |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 295 | return 0; |
| 296 | } |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 297 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 298 | void mips_cm_lock_other(unsigned int cluster, unsigned int core, |
| 299 | unsigned int vp, unsigned int block) |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 300 | { |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 301 | unsigned int curr_core, cm_rev; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 302 | u32 val; |
| 303 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 304 | cm_rev = mips_cm_revision(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 305 | preempt_disable(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 306 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 307 | if (cm_rev >= CM_REV_CM3) { |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 308 | val = FIELD_PREP(CM3_GCR_Cx_OTHER_CORE, core) | |
| 309 | FIELD_PREP(CM3_GCR_Cx_OTHER_VP, vp); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 310 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 311 | if (cm_rev >= CM_REV_CM3_5) { |
| 312 | val |= CM_GCR_Cx_OTHER_CLUSTER_EN; |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 313 | val |= FIELD_PREP(CM_GCR_Cx_OTHER_CLUSTER, cluster); |
| 314 | val |= FIELD_PREP(CM_GCR_Cx_OTHER_BLOCK, block); |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 315 | } else { |
| 316 | WARN_ON(cluster != 0); |
| 317 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
| 318 | } |
| 319 | |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 320 | /* |
| 321 | * We need to disable interrupts in SMP systems in order to |
| 322 | * ensure that we don't interrupt the caller with code which |
| 323 | * may modify the redirect register. We do so here in a |
| 324 | * slightly obscure way by using a spin lock, since this has |
| 325 | * the neat property of also catching any nested uses of |
| 326 | * mips_cm_lock_other() leading to a deadlock or a nice warning |
| 327 | * with lockdep enabled. |
| 328 | */ |
| 329 | spin_lock_irqsave(this_cpu_ptr(&cm_core_lock), |
| 330 | *this_cpu_ptr(&cm_core_lock_flags)); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 331 | } else { |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 332 | WARN_ON(cluster != 0); |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 333 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 334 | |
| 335 | /* |
| 336 | * We only have a GCR_CL_OTHER per core in systems with |
| 337 | * CM 2.5 & older, so have to ensure other VP(E)s don't |
| 338 | * race with us. |
| 339 | */ |
Paul Burton | f875a832 | 2017-08-12 19:49:35 -0700 | [diff] [blame] | 340 | curr_core = cpu_core(¤t_cpu_data); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 341 | spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), |
| 342 | per_cpu(cm_core_lock_flags, curr_core)); |
| 343 | |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 344 | val = FIELD_PREP(CM_GCR_Cx_OTHER_CORENUM, core); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 345 | } |
| 346 | |
| 347 | write_gcr_cl_other(val); |
Paul Burton | 78a54c4 | 2015-09-22 11:12:18 -0700 | [diff] [blame] | 348 | |
| 349 | /* |
| 350 | * Ensure the core-other region reflects the appropriate core & |
| 351 | * VP before any accesses to it occur. |
| 352 | */ |
| 353 | mb(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | void mips_cm_unlock_other(void) |
| 357 | { |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 358 | unsigned int curr_core; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 359 | |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 360 | if (mips_cm_revision() < CM_REV_CM3) { |
Paul Burton | f875a832 | 2017-08-12 19:49:35 -0700 | [diff] [blame] | 361 | curr_core = cpu_core(¤t_cpu_data); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 362 | spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), |
| 363 | per_cpu(cm_core_lock_flags, curr_core)); |
| 364 | } else { |
| 365 | spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock), |
| 366 | *this_cpu_ptr(&cm_core_lock_flags)); |
| 367 | } |
| 368 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 369 | preempt_enable(); |
| 370 | } |
| 371 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 372 | void mips_cm_error_report(void) |
| 373 | { |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 374 | u64 cm_error, cm_addr, cm_other; |
| 375 | unsigned long revision; |
| 376 | int ocause, cause; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 377 | char buf[256]; |
| 378 | |
| 379 | if (!mips_cm_present()) |
| 380 | return; |
| 381 | |
Paul Burton | 03b1b85 | 2015-09-22 10:26:38 -0700 | [diff] [blame] | 382 | revision = mips_cm_revision(); |
Paul Burton | b025d51 | 2017-08-12 19:49:26 -0700 | [diff] [blame] | 383 | cm_error = read_gcr_error_cause(); |
| 384 | cm_addr = read_gcr_error_addr(); |
| 385 | cm_other = read_gcr_error_mult(); |
Paul Burton | 03b1b85 | 2015-09-22 10:26:38 -0700 | [diff] [blame] | 386 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 387 | if (revision < CM_REV_CM3) { /* CM2 */ |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 388 | cause = FIELD_GET(CM_GCR_ERROR_CAUSE_ERRTYPE, cm_error); |
| 389 | ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 390 | |
| 391 | if (!cause) |
| 392 | return; |
| 393 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 394 | if (cause < 16) { |
| 395 | unsigned long cca_bits = (cm_error >> 15) & 7; |
| 396 | unsigned long tr_bits = (cm_error >> 12) & 7; |
| 397 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; |
| 398 | unsigned long stag_bits = (cm_error >> 3) & 15; |
| 399 | unsigned long sport_bits = (cm_error >> 0) & 7; |
| 400 | |
| 401 | snprintf(buf, sizeof(buf), |
| 402 | "CCA=%lu TR=%s MCmd=%s STag=%lu " |
| 403 | "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], |
| 404 | cm2_cmd[cmd_bits], stag_bits, sport_bits); |
Serge Semin | 109111b | 2020-05-06 20:42:23 +0300 | [diff] [blame] | 405 | } else if (cause < 24) { |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 406 | /* glob state & sresp together */ |
| 407 | unsigned long c3_bits = (cm_error >> 18) & 7; |
| 408 | unsigned long c2_bits = (cm_error >> 15) & 7; |
| 409 | unsigned long c1_bits = (cm_error >> 12) & 7; |
| 410 | unsigned long c0_bits = (cm_error >> 9) & 7; |
| 411 | unsigned long sc_bit = (cm_error >> 8) & 1; |
| 412 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; |
| 413 | unsigned long sport_bits = (cm_error >> 0) & 7; |
| 414 | |
| 415 | snprintf(buf, sizeof(buf), |
| 416 | "C3=%s C2=%s C1=%s C0=%s SC=%s " |
| 417 | "MCmd=%s SPort=%lu\n", |
| 418 | cm2_core[c3_bits], cm2_core[c2_bits], |
| 419 | cm2_core[c1_bits], cm2_core[c0_bits], |
| 420 | sc_bit ? "True" : "False", |
| 421 | cm2_cmd[cmd_bits], sport_bits); |
Serge Semin | 109111b | 2020-05-06 20:42:23 +0300 | [diff] [blame] | 422 | } else { |
| 423 | unsigned long muc_bit = (cm_error >> 23) & 1; |
| 424 | unsigned long ins_bits = (cm_error >> 18) & 0x1f; |
| 425 | unsigned long arr_bits = (cm_error >> 16) & 3; |
| 426 | unsigned long dw_bits = (cm_error >> 12) & 15; |
| 427 | unsigned long way_bits = (cm_error >> 9) & 7; |
| 428 | unsigned long mway_bit = (cm_error >> 8) & 1; |
| 429 | unsigned long syn_bits = (cm_error >> 0) & 0xFF; |
| 430 | |
| 431 | snprintf(buf, sizeof(buf), |
| 432 | "Type=%s%s Instr=%s DW=%lu Way=%lu " |
| 433 | "MWay=%s Syndrome=0x%02lx", |
| 434 | muc_bit ? "Multi-UC " : "", |
| 435 | cm2_l2_type[arr_bits], |
| 436 | cm2_l2_instr[ins_bits], dw_bits, way_bits, |
| 437 | mway_bit ? "True" : "False", syn_bits); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 438 | } |
Paul Burton | 462fb81 | 2019-02-15 14:22:44 -0800 | [diff] [blame] | 439 | pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, |
| 440 | cm2_causes[cause], buf); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 441 | pr_err("CM_ADDR =%08llx\n", cm_addr); |
| 442 | pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 443 | } else { /* CM3 */ |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 444 | ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits; |
| 445 | ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit; |
| 446 | |
Geert Uytterhoeven | 18b8f5b | 2021-10-29 11:58:16 +0200 | [diff] [blame] | 447 | cause = FIELD_GET(CM3_GCR_ERROR_CAUSE_ERRTYPE, cm_error); |
| 448 | ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 449 | |
| 450 | if (!cause) |
| 451 | return; |
| 452 | |
| 453 | /* Used by cause == {1,2,3} */ |
| 454 | core_id_bits = (cm_error >> 22) & 0xf; |
| 455 | vp_id_bits = (cm_error >> 18) & 0xf; |
| 456 | cmd_bits = (cm_error >> 14) & 0xf; |
| 457 | cmd_group_bits = (cm_error >> 11) & 0xf; |
| 458 | cm3_cca_bits = (cm_error >> 8) & 7; |
| 459 | mcp_bits = (cm_error >> 5) & 0xf; |
| 460 | cm3_tr_bits = (cm_error >> 1) & 0xf; |
| 461 | sched_bit = cm_error & 0x1; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 462 | |
| 463 | if (cause == 1 || cause == 3) { /* Tag ECC */ |
| 464 | unsigned long tag_ecc = (cm_error >> 57) & 0x1; |
| 465 | unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; |
| 466 | unsigned long dword_bits = (cm_error >> 49) & 0xff; |
| 467 | unsigned long data_way_bits = (cm_error >> 45) & 0xf; |
| 468 | unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; |
| 469 | unsigned long bank_bit = (cm_error >> 28) & 0x1; |
| 470 | snprintf(buf, sizeof(buf), |
| 471 | "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" |
| 472 | "Bank=%lu CoreID=%lu VPID=%lu Command=%s" |
| 473 | "Command Group=%s CCA=%lu MCP=%d" |
| 474 | "Transaction type=%s Scheduler=%lu\n", |
| 475 | tag_ecc ? "TAG" : "DATA", |
| 476 | tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : |
| 477 | data_way_bits, bank_bit, dword_bits, |
| 478 | data_sets_bits, |
| 479 | core_id_bits, vp_id_bits, |
| 480 | cm3_cmd[cmd_bits], |
| 481 | cm3_cmd_group[cmd_group_bits], |
| 482 | cm3_cca_bits, 1 << mcp_bits, |
| 483 | cm3_tr[cm3_tr_bits], sched_bit); |
| 484 | } else if (cause == 2) { |
| 485 | unsigned long data_error_type = (cm_error >> 41) & 0xfff; |
| 486 | unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; |
| 487 | unsigned long data_decode_group = (cm_error >> 34) & 0x7; |
| 488 | unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; |
| 489 | |
| 490 | snprintf(buf, sizeof(buf), |
| 491 | "Decode Request Error: Type=%lu, Command=%lu" |
| 492 | "Command Group=%lu Destination ID=%lu" |
| 493 | "CoreID=%lu VPID=%lu Command=%s" |
| 494 | "Command Group=%s CCA=%lu MCP=%d" |
| 495 | "Transaction type=%s Scheduler=%lu\n", |
| 496 | data_error_type, data_decode_cmd, |
| 497 | data_decode_group, data_decode_destination_id, |
| 498 | core_id_bits, vp_id_bits, |
| 499 | cm3_cmd[cmd_bits], |
| 500 | cm3_cmd_group[cmd_group_bits], |
| 501 | cm3_cca_bits, 1 << mcp_bits, |
| 502 | cm3_tr[cm3_tr_bits], sched_bit); |
Paul Burton | f88e632 | 2015-09-22 10:26:39 -0700 | [diff] [blame] | 503 | } else { |
| 504 | buf[0] = 0; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 505 | } |
| 506 | |
| 507 | pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, |
| 508 | cm3_causes[cause], buf); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 509 | pr_err("CM_ADDR =%llx\n", cm_addr); |
| 510 | pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 511 | } |
| 512 | |
| 513 | /* reprime cause register */ |
Vladimir Kondratiev | 05dc600 | 2019-02-06 13:46:17 +0200 | [diff] [blame] | 514 | write_gcr_error_cause(cm_error); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 515 | } |