1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * CoreNet Coherency Fabric error reporting 4 * 5 * Copyright 2014 Freescale Semiconductor Inc. 6 */ 7 8 #include <linux/interrupt.h> 9 #include <linux/io.h> 10 #include <linux/irq.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/of_address.h> 14 #include <linux/of_device.h> 15 #include <linux/of_irq.h> 16 #include <linux/platform_device.h> 17 18 enum ccf_version { 19 CCF1, 20 CCF2, 21 }; 22 23 struct ccf_info { 24 enum ccf_version version; 25 int err_reg_offs; 26 bool has_brr; 27 }; 28 29 static const struct ccf_info ccf1_info = { 30 .version = CCF1, 31 .err_reg_offs = 0xa00, 32 .has_brr = false, 33 }; 34 35 static const struct ccf_info ccf2_info = { 36 .version = CCF2, 37 .err_reg_offs = 0xe40, 38 .has_brr = true, 39 }; 40 41 /* 42 * This register is present but not documented, with different values for 43 * IP_ID, on other chips with fsl,corenet2-cf such as t4240 and b4860. 44 */ 45 #define CCF_BRR 0xbf8 46 #define CCF_BRR_IPID 0xffff0000 47 #define CCF_BRR_IPID_T1040 0x09310000 48 49 static const struct of_device_id ccf_matches[] = { 50 { 51 .compatible = "fsl,corenet1-cf", 52 .data = &ccf1_info, 53 }, 54 { 55 .compatible = "fsl,corenet2-cf", 56 .data = &ccf2_info, 57 }, 58 {} 59 }; 60 MODULE_DEVICE_TABLE(of, ccf_matches); 61 62 struct ccf_err_regs { 63 u32 errdet; /* 0x00 Error Detect Register */ 64 /* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */ 65 u32 errdis; 66 /* 0x08 Error Interrupt Enable Register (ccf2 only) */ 67 u32 errinten; 68 u32 cecar; /* 0x0c Error Capture Attribute Register */ 69 u32 cecaddrh; /* 0x10 Error Capture Address High */ 70 u32 cecaddrl; /* 0x14 Error Capture Address Low */ 71 u32 cecar2; /* 0x18 Error Capture Attribute Register 2 */ 72 }; 73 74 /* LAE/CV also valid for errdis and errinten */ 75 #define ERRDET_LAE (1 << 0) /* Local Access Error */ 76 #define ERRDET_CV (1 << 1) /* Coherency Violation */ 77 #define ERRDET_UTID (1 << 2) /* Unavailable Target ID (t1040) */ 78 #define ERRDET_MCST (1 << 3) /* Multicast Stash (t1040) */ 79 #define ERRDET_CTYPE_SHIFT 26 /* Capture Type (ccf2 only) */ 80 #define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT) 81 #define ERRDET_CAP (1 << 31) /* Capture Valid (ccf2 only) */ 82 83 #define CECAR_VAL (1 << 0) /* Valid (ccf1 only) */ 84 #define CECAR_UVT (1 << 15) /* Unavailable target ID (ccf1) */ 85 #define CECAR_SRCID_SHIFT_CCF1 24 86 #define CECAR_SRCID_MASK_CCF1 (0xff << CECAR_SRCID_SHIFT_CCF1) 87 #define CECAR_SRCID_SHIFT_CCF2 18 88 #define CECAR_SRCID_MASK_CCF2 (0xff << CECAR_SRCID_SHIFT_CCF2) 89 90 #define CECADDRH_ADDRH 0xff 91 92 struct ccf_private { 93 const struct ccf_info *info; 94 struct device *dev; 95 void __iomem *regs; 96 struct ccf_err_regs __iomem *err_regs; 97 bool t1040; 98 }; 99 100 static irqreturn_t ccf_irq(int irq, void *dev_id) 101 { 102 struct ccf_private *ccf = dev_id; 103 static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL, 104 DEFAULT_RATELIMIT_BURST); 105 u32 errdet, cecar, cecar2; 106 u64 addr; 107 u32 src_id; 108 bool uvt = false; 109 bool cap_valid = false; 110 111 errdet = ioread32be(&ccf->err_regs->errdet); 112 cecar = ioread32be(&ccf->err_regs->cecar); 113 cecar2 = ioread32be(&ccf->err_regs->cecar2); 114 addr = ioread32be(&ccf->err_regs->cecaddrl); 115 addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) & 116 CECADDRH_ADDRH)) << 32; 117 118 if (!__ratelimit(&ratelimit)) 119 goto out; 120 121 switch (ccf->info->version) { 122 case CCF1: 123 if (cecar & CECAR_VAL) { 124 if (cecar & CECAR_UVT) 125 uvt = true; 126 127 src_id = (cecar & CECAR_SRCID_MASK_CCF1) >> 128 CECAR_SRCID_SHIFT_CCF1; 129 cap_valid = true; 130 } 131 132 break; 133 case CCF2: 134 if (errdet & ERRDET_CAP) { 135 src_id = (cecar & CECAR_SRCID_MASK_CCF2) >> 136 CECAR_SRCID_SHIFT_CCF2; 137 cap_valid = true; 138 } 139 140 break; 141 } 142 143 dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n", 144 errdet, cecar, cecar2); 145 146 if (errdet & ERRDET_LAE) { 147 if (uvt) 148 dev_crit(ccf->dev, "LAW Unavailable Target ID\n"); 149 else 150 dev_crit(ccf->dev, "Local Access Window Error\n"); 151 } 152 153 if (errdet & ERRDET_CV) 154 dev_crit(ccf->dev, "Coherency Violation\n"); 155 156 if (errdet & ERRDET_UTID) 157 dev_crit(ccf->dev, "Unavailable Target ID\n"); 158 159 if (errdet & ERRDET_MCST) 160 dev_crit(ccf->dev, "Multicast Stash\n"); 161 162 if (cap_valid) { 163 dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n", 164 addr, src_id); 165 } 166 167 out: 168 iowrite32be(errdet, &ccf->err_regs->errdet); 169 return errdet ? IRQ_HANDLED : IRQ_NONE; 170 } 171 172 static int ccf_probe(struct platform_device *pdev) 173 { 174 struct ccf_private *ccf; 175 struct resource *r; 176 const struct of_device_id *match; 177 u32 errinten; 178 int ret, irq; 179 180 match = of_match_device(ccf_matches, &pdev->dev); 181 if (WARN_ON(!match)) 182 return -ENODEV; 183 184 ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL); 185 if (!ccf) 186 return -ENOMEM; 187 188 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 if (!r) { 190 dev_err(&pdev->dev, "%s: no mem resource\n", __func__); 191 return -ENXIO; 192 } 193 194 ccf->regs = devm_ioremap_resource(&pdev->dev, r); 195 if (IS_ERR(ccf->regs)) { 196 dev_err(&pdev->dev, "%s: can't map mem resource\n", __func__); 197 return PTR_ERR(ccf->regs); 198 } 199 200 ccf->dev = &pdev->dev; 201 ccf->info = match->data; 202 ccf->err_regs = ccf->regs + ccf->info->err_reg_offs; 203 204 if (ccf->info->has_brr) { 205 u32 brr = ioread32be(ccf->regs + CCF_BRR); 206 207 if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040) 208 ccf->t1040 = true; 209 } 210 211 dev_set_drvdata(&pdev->dev, ccf); 212 213 irq = platform_get_irq(pdev, 0); 214 if (irq < 0) 215 return irq; 216 217 ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf); 218 if (ret) { 219 dev_err(&pdev->dev, "%s: can't request irq\n", __func__); 220 return ret; 221 } 222 223 errinten = ERRDET_LAE | ERRDET_CV; 224 if (ccf->t1040) 225 errinten |= ERRDET_UTID | ERRDET_MCST; 226 227 switch (ccf->info->version) { 228 case CCF1: 229 /* On CCF1 this register enables rather than disables. */ 230 iowrite32be(errinten, &ccf->err_regs->errdis); 231 break; 232 233 case CCF2: 234 iowrite32be(0, &ccf->err_regs->errdis); 235 iowrite32be(errinten, &ccf->err_regs->errinten); 236 break; 237 } 238 239 return 0; 240 } 241 242 static int ccf_remove(struct platform_device *pdev) 243 { 244 struct ccf_private *ccf = dev_get_drvdata(&pdev->dev); 245 246 switch (ccf->info->version) { 247 case CCF1: 248 iowrite32be(0, &ccf->err_regs->errdis); 249 break; 250 251 case CCF2: 252 /* 253 * We clear errdis on ccf1 because that's the only way to 254 * disable interrupts, but on ccf2 there's no need to disable 255 * detection. 256 */ 257 iowrite32be(0, &ccf->err_regs->errinten); 258 break; 259 } 260 261 return 0; 262 } 263 264 static struct platform_driver ccf_driver = { 265 .driver = { 266 .name = KBUILD_MODNAME, 267 .of_match_table = ccf_matches, 268 }, 269 .probe = ccf_probe, 270 .remove = ccf_remove, 271 }; 272 273 module_platform_driver(ccf_driver); 274 275 MODULE_LICENSE("GPL"); 276 MODULE_AUTHOR("Freescale Semiconductor"); 277 MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting"); 278