fsl-corenet-cf.c (6366B)
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 18enum ccf_version { 19 CCF1, 20 CCF2, 21}; 22 23struct ccf_info { 24 enum ccf_version version; 25 int err_reg_offs; 26 bool has_brr; 27}; 28 29static const struct ccf_info ccf1_info = { 30 .version = CCF1, 31 .err_reg_offs = 0xa00, 32 .has_brr = false, 33}; 34 35static 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 49static 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}; 60MODULE_DEVICE_TABLE(of, ccf_matches); 61 62struct 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 92struct 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 100static 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 167out: 168 iowrite32be(errdet, &ccf->err_regs->errdet); 169 return errdet ? IRQ_HANDLED : IRQ_NONE; 170} 171 172static int ccf_probe(struct platform_device *pdev) 173{ 174 struct ccf_private *ccf; 175 const struct of_device_id *match; 176 u32 errinten; 177 int ret, irq; 178 179 match = of_match_device(ccf_matches, &pdev->dev); 180 if (WARN_ON(!match)) 181 return -ENODEV; 182 183 ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL); 184 if (!ccf) 185 return -ENOMEM; 186 187 ccf->regs = devm_platform_ioremap_resource(pdev, 0); 188 if (IS_ERR(ccf->regs)) 189 return PTR_ERR(ccf->regs); 190 191 ccf->dev = &pdev->dev; 192 ccf->info = match->data; 193 ccf->err_regs = ccf->regs + ccf->info->err_reg_offs; 194 195 if (ccf->info->has_brr) { 196 u32 brr = ioread32be(ccf->regs + CCF_BRR); 197 198 if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040) 199 ccf->t1040 = true; 200 } 201 202 dev_set_drvdata(&pdev->dev, ccf); 203 204 irq = platform_get_irq(pdev, 0); 205 if (irq < 0) 206 return irq; 207 208 ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf); 209 if (ret) { 210 dev_err(&pdev->dev, "%s: can't request irq\n", __func__); 211 return ret; 212 } 213 214 errinten = ERRDET_LAE | ERRDET_CV; 215 if (ccf->t1040) 216 errinten |= ERRDET_UTID | ERRDET_MCST; 217 218 switch (ccf->info->version) { 219 case CCF1: 220 /* On CCF1 this register enables rather than disables. */ 221 iowrite32be(errinten, &ccf->err_regs->errdis); 222 break; 223 224 case CCF2: 225 iowrite32be(0, &ccf->err_regs->errdis); 226 iowrite32be(errinten, &ccf->err_regs->errinten); 227 break; 228 } 229 230 return 0; 231} 232 233static int ccf_remove(struct platform_device *pdev) 234{ 235 struct ccf_private *ccf = dev_get_drvdata(&pdev->dev); 236 237 switch (ccf->info->version) { 238 case CCF1: 239 iowrite32be(0, &ccf->err_regs->errdis); 240 break; 241 242 case CCF2: 243 /* 244 * We clear errdis on ccf1 because that's the only way to 245 * disable interrupts, but on ccf2 there's no need to disable 246 * detection. 247 */ 248 iowrite32be(0, &ccf->err_regs->errinten); 249 break; 250 } 251 252 return 0; 253} 254 255static struct platform_driver ccf_driver = { 256 .driver = { 257 .name = KBUILD_MODNAME, 258 .of_match_table = ccf_matches, 259 }, 260 .probe = ccf_probe, 261 .remove = ccf_remove, 262}; 263 264module_platform_driver(ccf_driver); 265 266MODULE_LICENSE("GPL"); 267MODULE_AUTHOR("Freescale Semiconductor"); 268MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");