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 | |
| 117 | static char *cm2_causes[32] = { |
| 118 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", |
| 119 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", |
| 120 | "0x08", "0x09", "0x0a", "0x0b", |
| 121 | "0x0c", "0x0d", "0x0e", "0x0f", |
| 122 | "0x10", "0x11", "0x12", "0x13", |
| 123 | "0x14", "0x15", "0x16", "INTVN_WR_ERR", |
| 124 | "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", |
| 125 | "0x1c", "0x1d", "0x1e", "0x1f" |
| 126 | }; |
| 127 | |
| 128 | static char *cm3_causes[32] = { |
| 129 | "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", |
| 130 | "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", |
| 131 | "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", |
| 132 | "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", |
| 133 | "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", |
| 134 | "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" |
| 135 | }; |
| 136 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 137 | static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); |
| 138 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); |
| 139 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 140 | phys_addr_t __mips_cm_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 141 | { |
| 142 | u32 config3 = read_c0_config3(); |
Markos Chandras | 038b0f5 | 2015-07-09 10:40:45 +0100 | [diff] [blame] | 143 | unsigned long cmgcr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 144 | |
| 145 | /* Check the CMGCRBase register is implemented */ |
| 146 | if (!(config3 & MIPS_CONF3_CMGCR)) |
| 147 | return 0; |
| 148 | |
| 149 | /* Read the address from CMGCRBase */ |
| 150 | cmgcr = read_c0_cmgcrbase(); |
| 151 | return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); |
| 152 | } |
| 153 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 154 | phys_addr_t mips_cm_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 155 | __attribute__((weak, alias("__mips_cm_phys_base"))); |
| 156 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 157 | phys_addr_t __mips_cm_l2sync_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 158 | { |
| 159 | u32 base_reg; |
| 160 | |
| 161 | /* |
| 162 | * If the L2-only sync region is already enabled then leave it at it's |
| 163 | * current location. |
| 164 | */ |
| 165 | base_reg = read_gcr_l2_only_sync_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 166 | if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN) |
| 167 | return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 168 | |
| 169 | /* Default to following the CM */ |
| 170 | return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; |
| 171 | } |
| 172 | |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 173 | phys_addr_t mips_cm_l2sync_phys_base(void) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 174 | __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); |
| 175 | |
| 176 | static void mips_cm_probe_l2sync(void) |
| 177 | { |
| 178 | unsigned major_rev; |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 179 | phys_addr_t addr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 180 | |
| 181 | /* L2-only sync was introduced with CM major revision 6 */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 182 | major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR) >> |
| 183 | __ffs(CM_GCR_REV_MAJOR); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 184 | if (major_rev < 6) |
| 185 | return; |
| 186 | |
| 187 | /* Find a location for the L2 sync region */ |
| 188 | addr = mips_cm_l2sync_phys_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 189 | BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE) != addr); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 190 | if (!addr) |
| 191 | return; |
| 192 | |
| 193 | /* Set the region base address & enable it */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 194 | 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] | 195 | |
| 196 | /* Map the region */ |
| 197 | mips_cm_l2sync_base = ioremap_nocache(addr, MIPS_CM_L2SYNC_SIZE); |
| 198 | } |
| 199 | |
| 200 | int mips_cm_probe(void) |
| 201 | { |
Ralf Baechle | 15d45cc | 2014-11-22 00:22:09 +0100 | [diff] [blame] | 202 | phys_addr_t addr; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 203 | u32 base_reg; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 204 | unsigned cpu; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 205 | |
Markos Chandras | c014d16 | 2015-07-09 10:40:43 +0100 | [diff] [blame] | 206 | /* |
| 207 | * No need to probe again if we have already been |
| 208 | * here before. |
| 209 | */ |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 210 | if (mips_gcr_base) |
Markos Chandras | c014d16 | 2015-07-09 10:40:43 +0100 | [diff] [blame] | 211 | return 0; |
| 212 | |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 213 | addr = mips_cm_phys_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 214 | BUG_ON((addr & CM_GCR_BASE_GCRBASE) != addr); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 215 | if (!addr) |
| 216 | return -ENODEV; |
| 217 | |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 218 | mips_gcr_base = ioremap_nocache(addr, MIPS_CM_GCR_SIZE); |
| 219 | if (!mips_gcr_base) |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 220 | return -ENXIO; |
| 221 | |
| 222 | /* sanity check that we're looking at a CM */ |
| 223 | base_reg = read_gcr_base(); |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 224 | if ((base_reg & CM_GCR_BASE_GCRBASE) != addr) { |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 225 | pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n", |
| 226 | (unsigned long)addr); |
Paul Burton | abe852e | 2017-08-12 19:49:25 -0700 | [diff] [blame] | 227 | mips_gcr_base = NULL; |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 228 | return -ENODEV; |
| 229 | } |
| 230 | |
| 231 | /* set default target to memory */ |
Paul Burton | 846e191 | 2017-08-12 19:49:31 -0700 | [diff] [blame] | 232 | change_gcr_base(CM_GCR_BASE_CMDEFTGT, CM_GCR_BASE_CMDEFTGT_MEM); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 233 | |
| 234 | /* disable CM regions */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 235 | write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR); |
| 236 | write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 237 | write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR); |
| 238 | write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 239 | write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR); |
| 240 | write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK); |
| 241 | write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR); |
| 242 | write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK); |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 243 | |
| 244 | /* probe for an L2-only sync region */ |
| 245 | mips_cm_probe_l2sync(); |
| 246 | |
Markos Chandras | c0b584a | 2015-07-14 09:14:12 +0100 | [diff] [blame] | 247 | /* determine register width for this CM */ |
Masahiro Yamada | 97f2645 | 2016-08-03 13:45:50 -0700 | [diff] [blame] | 248 | 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] | 249 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 250 | for_each_possible_cpu(cpu) |
| 251 | spin_lock_init(&per_cpu(cm_core_lock, cpu)); |
| 252 | |
Paul Burton | 9f98f3d | 2014-01-15 10:31:51 +0000 | [diff] [blame] | 253 | return 0; |
| 254 | } |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 255 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 256 | void mips_cm_lock_other(unsigned int cluster, unsigned int core, |
| 257 | unsigned int vp, unsigned int block) |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 258 | { |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 259 | unsigned int curr_core, cm_rev; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 260 | u32 val; |
| 261 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 262 | cm_rev = mips_cm_revision(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 263 | preempt_disable(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 264 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 265 | if (cm_rev >= CM_REV_CM3) { |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 266 | val = core << __ffs(CM3_GCR_Cx_OTHER_CORE); |
| 267 | val |= vp << __ffs(CM3_GCR_Cx_OTHER_VP); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 268 | |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 269 | if (cm_rev >= CM_REV_CM3_5) { |
| 270 | val |= CM_GCR_Cx_OTHER_CLUSTER_EN; |
| 271 | val |= cluster << __ffs(CM_GCR_Cx_OTHER_CLUSTER); |
| 272 | val |= block << __ffs(CM_GCR_Cx_OTHER_BLOCK); |
| 273 | } else { |
| 274 | WARN_ON(cluster != 0); |
| 275 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
| 276 | } |
| 277 | |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 278 | /* |
| 279 | * We need to disable interrupts in SMP systems in order to |
| 280 | * ensure that we don't interrupt the caller with code which |
| 281 | * may modify the redirect register. We do so here in a |
| 282 | * slightly obscure way by using a spin lock, since this has |
| 283 | * the neat property of also catching any nested uses of |
| 284 | * mips_cm_lock_other() leading to a deadlock or a nice warning |
| 285 | * with lockdep enabled. |
| 286 | */ |
| 287 | spin_lock_irqsave(this_cpu_ptr(&cm_core_lock), |
| 288 | *this_cpu_ptr(&cm_core_lock_flags)); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 289 | } else { |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 290 | WARN_ON(cluster != 0); |
Paul Burton | 68923cd | 2017-08-12 19:49:39 -0700 | [diff] [blame] | 291 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 292 | |
| 293 | /* |
| 294 | * We only have a GCR_CL_OTHER per core in systems with |
| 295 | * CM 2.5 & older, so have to ensure other VP(E)s don't |
| 296 | * race with us. |
| 297 | */ |
Paul Burton | f875a832 | 2017-08-12 19:49:35 -0700 | [diff] [blame] | 298 | curr_core = cpu_core(¤t_cpu_data); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 299 | spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), |
| 300 | per_cpu(cm_core_lock_flags, curr_core)); |
| 301 | |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 302 | val = core << __ffs(CM_GCR_Cx_OTHER_CORENUM); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 303 | } |
| 304 | |
| 305 | write_gcr_cl_other(val); |
Paul Burton | 78a54c4 | 2015-09-22 11:12:18 -0700 | [diff] [blame] | 306 | |
| 307 | /* |
| 308 | * Ensure the core-other region reflects the appropriate core & |
| 309 | * VP before any accesses to it occur. |
| 310 | */ |
| 311 | mb(); |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | void mips_cm_unlock_other(void) |
| 315 | { |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 316 | unsigned int curr_core; |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 317 | |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 318 | if (mips_cm_revision() < CM_REV_CM3) { |
Paul Burton | f875a832 | 2017-08-12 19:49:35 -0700 | [diff] [blame] | 319 | curr_core = cpu_core(¤t_cpu_data); |
Paul Burton | 516db1c | 2017-06-02 14:48:50 -0700 | [diff] [blame] | 320 | spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), |
| 321 | per_cpu(cm_core_lock_flags, curr_core)); |
| 322 | } else { |
| 323 | spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock), |
| 324 | *this_cpu_ptr(&cm_core_lock_flags)); |
| 325 | } |
| 326 | |
Paul Burton | 23d5de8 | 2015-09-22 11:12:16 -0700 | [diff] [blame] | 327 | preempt_enable(); |
| 328 | } |
| 329 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 330 | void mips_cm_error_report(void) |
| 331 | { |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 332 | u64 cm_error, cm_addr, cm_other; |
| 333 | unsigned long revision; |
| 334 | int ocause, cause; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 335 | char buf[256]; |
| 336 | |
| 337 | if (!mips_cm_present()) |
| 338 | return; |
| 339 | |
Paul Burton | 03b1b85 | 2015-09-22 10:26:38 -0700 | [diff] [blame] | 340 | revision = mips_cm_revision(); |
Paul Burton | b025d51 | 2017-08-12 19:49:26 -0700 | [diff] [blame] | 341 | cm_error = read_gcr_error_cause(); |
| 342 | cm_addr = read_gcr_error_addr(); |
| 343 | cm_other = read_gcr_error_mult(); |
Paul Burton | 03b1b85 | 2015-09-22 10:26:38 -0700 | [diff] [blame] | 344 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 345 | if (revision < CM_REV_CM3) { /* CM2 */ |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 346 | cause = cm_error >> __ffs(CM_GCR_ERROR_CAUSE_ERRTYPE); |
| 347 | ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 348 | |
| 349 | if (!cause) |
| 350 | return; |
| 351 | |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 352 | if (cause < 16) { |
| 353 | unsigned long cca_bits = (cm_error >> 15) & 7; |
| 354 | unsigned long tr_bits = (cm_error >> 12) & 7; |
| 355 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; |
| 356 | unsigned long stag_bits = (cm_error >> 3) & 15; |
| 357 | unsigned long sport_bits = (cm_error >> 0) & 7; |
| 358 | |
| 359 | snprintf(buf, sizeof(buf), |
| 360 | "CCA=%lu TR=%s MCmd=%s STag=%lu " |
| 361 | "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], |
| 362 | cm2_cmd[cmd_bits], stag_bits, sport_bits); |
| 363 | } else { |
| 364 | /* glob state & sresp together */ |
| 365 | unsigned long c3_bits = (cm_error >> 18) & 7; |
| 366 | unsigned long c2_bits = (cm_error >> 15) & 7; |
| 367 | unsigned long c1_bits = (cm_error >> 12) & 7; |
| 368 | unsigned long c0_bits = (cm_error >> 9) & 7; |
| 369 | unsigned long sc_bit = (cm_error >> 8) & 1; |
| 370 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; |
| 371 | unsigned long sport_bits = (cm_error >> 0) & 7; |
| 372 | |
| 373 | snprintf(buf, sizeof(buf), |
| 374 | "C3=%s C2=%s C1=%s C0=%s SC=%s " |
| 375 | "MCmd=%s SPort=%lu\n", |
| 376 | cm2_core[c3_bits], cm2_core[c2_bits], |
| 377 | cm2_core[c1_bits], cm2_core[c0_bits], |
| 378 | sc_bit ? "True" : "False", |
| 379 | cm2_cmd[cmd_bits], sport_bits); |
| 380 | } |
Paul Burton | 462fb81 | 2019-02-15 14:22:44 -0800 | [diff] [blame] | 381 | pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, |
| 382 | cm2_causes[cause], buf); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 383 | pr_err("CM_ADDR =%08llx\n", cm_addr); |
| 384 | pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 385 | } else { /* CM3 */ |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 386 | ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits; |
| 387 | ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit; |
| 388 | |
Paul Burton | 93c5bba5 | 2017-08-12 19:49:27 -0700 | [diff] [blame] | 389 | cause = cm_error >> __ffs64(CM3_GCR_ERROR_CAUSE_ERRTYPE); |
| 390 | ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 391 | |
| 392 | if (!cause) |
| 393 | return; |
| 394 | |
| 395 | /* Used by cause == {1,2,3} */ |
| 396 | core_id_bits = (cm_error >> 22) & 0xf; |
| 397 | vp_id_bits = (cm_error >> 18) & 0xf; |
| 398 | cmd_bits = (cm_error >> 14) & 0xf; |
| 399 | cmd_group_bits = (cm_error >> 11) & 0xf; |
| 400 | cm3_cca_bits = (cm_error >> 8) & 7; |
| 401 | mcp_bits = (cm_error >> 5) & 0xf; |
| 402 | cm3_tr_bits = (cm_error >> 1) & 0xf; |
| 403 | sched_bit = cm_error & 0x1; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 404 | |
| 405 | if (cause == 1 || cause == 3) { /* Tag ECC */ |
| 406 | unsigned long tag_ecc = (cm_error >> 57) & 0x1; |
| 407 | unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; |
| 408 | unsigned long dword_bits = (cm_error >> 49) & 0xff; |
| 409 | unsigned long data_way_bits = (cm_error >> 45) & 0xf; |
| 410 | unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; |
| 411 | unsigned long bank_bit = (cm_error >> 28) & 0x1; |
| 412 | snprintf(buf, sizeof(buf), |
| 413 | "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" |
| 414 | "Bank=%lu CoreID=%lu VPID=%lu Command=%s" |
| 415 | "Command Group=%s CCA=%lu MCP=%d" |
| 416 | "Transaction type=%s Scheduler=%lu\n", |
| 417 | tag_ecc ? "TAG" : "DATA", |
| 418 | tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : |
| 419 | data_way_bits, bank_bit, dword_bits, |
| 420 | data_sets_bits, |
| 421 | core_id_bits, vp_id_bits, |
| 422 | cm3_cmd[cmd_bits], |
| 423 | cm3_cmd_group[cmd_group_bits], |
| 424 | cm3_cca_bits, 1 << mcp_bits, |
| 425 | cm3_tr[cm3_tr_bits], sched_bit); |
| 426 | } else if (cause == 2) { |
| 427 | unsigned long data_error_type = (cm_error >> 41) & 0xfff; |
| 428 | unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; |
| 429 | unsigned long data_decode_group = (cm_error >> 34) & 0x7; |
| 430 | unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; |
| 431 | |
| 432 | snprintf(buf, sizeof(buf), |
| 433 | "Decode Request Error: Type=%lu, Command=%lu" |
| 434 | "Command Group=%lu Destination ID=%lu" |
| 435 | "CoreID=%lu VPID=%lu Command=%s" |
| 436 | "Command Group=%s CCA=%lu MCP=%d" |
| 437 | "Transaction type=%s Scheduler=%lu\n", |
| 438 | data_error_type, data_decode_cmd, |
| 439 | data_decode_group, data_decode_destination_id, |
| 440 | core_id_bits, vp_id_bits, |
| 441 | cm3_cmd[cmd_bits], |
| 442 | cm3_cmd_group[cmd_group_bits], |
| 443 | cm3_cca_bits, 1 << mcp_bits, |
| 444 | cm3_tr[cm3_tr_bits], sched_bit); |
Paul Burton | f88e632 | 2015-09-22 10:26:39 -0700 | [diff] [blame] | 445 | } else { |
| 446 | buf[0] = 0; |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 447 | } |
| 448 | |
| 449 | pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, |
| 450 | cm3_causes[cause], buf); |
Paul Burton | 47b26a4 | 2015-09-22 10:26:41 -0700 | [diff] [blame] | 451 | pr_err("CM_ADDR =%llx\n", cm_addr); |
| 452 | pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 453 | } |
| 454 | |
| 455 | /* reprime cause register */ |
Vladimir Kondratiev | 05dc600 | 2019-02-06 13:46:17 +0200 | [diff] [blame] | 456 | write_gcr_error_cause(cm_error); |
Markos Chandras | 3885c2b | 2015-07-09 10:40:47 +0100 | [diff] [blame] | 457 | } |