0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/interrupt.h>
0009 #include <linux/io.h>
0010 #include <linux/irq.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_device.h>
0015 #include <linux/of_irq.h>
0016 #include <linux/platform_device.h>
0017
0018 enum ccf_version {
0019 CCF1,
0020 CCF2,
0021 };
0022
0023 struct ccf_info {
0024 enum ccf_version version;
0025 int err_reg_offs;
0026 bool has_brr;
0027 };
0028
0029 static const struct ccf_info ccf1_info = {
0030 .version = CCF1,
0031 .err_reg_offs = 0xa00,
0032 .has_brr = false,
0033 };
0034
0035 static const struct ccf_info ccf2_info = {
0036 .version = CCF2,
0037 .err_reg_offs = 0xe40,
0038 .has_brr = true,
0039 };
0040
0041
0042
0043
0044
0045 #define CCF_BRR 0xbf8
0046 #define CCF_BRR_IPID 0xffff0000
0047 #define CCF_BRR_IPID_T1040 0x09310000
0048
0049 static const struct of_device_id ccf_matches[] = {
0050 {
0051 .compatible = "fsl,corenet1-cf",
0052 .data = &ccf1_info,
0053 },
0054 {
0055 .compatible = "fsl,corenet2-cf",
0056 .data = &ccf2_info,
0057 },
0058 {}
0059 };
0060 MODULE_DEVICE_TABLE(of, ccf_matches);
0061
0062 struct ccf_err_regs {
0063 u32 errdet;
0064
0065 u32 errdis;
0066
0067 u32 errinten;
0068 u32 cecar;
0069 u32 cecaddrh;
0070 u32 cecaddrl;
0071 u32 cecar2;
0072 };
0073
0074
0075 #define ERRDET_LAE (1 << 0)
0076 #define ERRDET_CV (1 << 1)
0077 #define ERRDET_UTID (1 << 2)
0078 #define ERRDET_MCST (1 << 3)
0079 #define ERRDET_CTYPE_SHIFT 26
0080 #define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT)
0081 #define ERRDET_CAP (1 << 31)
0082
0083 #define CECAR_VAL (1 << 0)
0084 #define CECAR_UVT (1 << 15)
0085 #define CECAR_SRCID_SHIFT_CCF1 24
0086 #define CECAR_SRCID_MASK_CCF1 (0xff << CECAR_SRCID_SHIFT_CCF1)
0087 #define CECAR_SRCID_SHIFT_CCF2 18
0088 #define CECAR_SRCID_MASK_CCF2 (0xff << CECAR_SRCID_SHIFT_CCF2)
0089
0090 #define CECADDRH_ADDRH 0xff
0091
0092 struct ccf_private {
0093 const struct ccf_info *info;
0094 struct device *dev;
0095 void __iomem *regs;
0096 struct ccf_err_regs __iomem *err_regs;
0097 bool t1040;
0098 };
0099
0100 static irqreturn_t ccf_irq(int irq, void *dev_id)
0101 {
0102 struct ccf_private *ccf = dev_id;
0103 static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL,
0104 DEFAULT_RATELIMIT_BURST);
0105 u32 errdet, cecar, cecar2;
0106 u64 addr;
0107 u32 src_id;
0108 bool uvt = false;
0109 bool cap_valid = false;
0110
0111 errdet = ioread32be(&ccf->err_regs->errdet);
0112 cecar = ioread32be(&ccf->err_regs->cecar);
0113 cecar2 = ioread32be(&ccf->err_regs->cecar2);
0114 addr = ioread32be(&ccf->err_regs->cecaddrl);
0115 addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) &
0116 CECADDRH_ADDRH)) << 32;
0117
0118 if (!__ratelimit(&ratelimit))
0119 goto out;
0120
0121 switch (ccf->info->version) {
0122 case CCF1:
0123 if (cecar & CECAR_VAL) {
0124 if (cecar & CECAR_UVT)
0125 uvt = true;
0126
0127 src_id = (cecar & CECAR_SRCID_MASK_CCF1) >>
0128 CECAR_SRCID_SHIFT_CCF1;
0129 cap_valid = true;
0130 }
0131
0132 break;
0133 case CCF2:
0134 if (errdet & ERRDET_CAP) {
0135 src_id = (cecar & CECAR_SRCID_MASK_CCF2) >>
0136 CECAR_SRCID_SHIFT_CCF2;
0137 cap_valid = true;
0138 }
0139
0140 break;
0141 }
0142
0143 dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n",
0144 errdet, cecar, cecar2);
0145
0146 if (errdet & ERRDET_LAE) {
0147 if (uvt)
0148 dev_crit(ccf->dev, "LAW Unavailable Target ID\n");
0149 else
0150 dev_crit(ccf->dev, "Local Access Window Error\n");
0151 }
0152
0153 if (errdet & ERRDET_CV)
0154 dev_crit(ccf->dev, "Coherency Violation\n");
0155
0156 if (errdet & ERRDET_UTID)
0157 dev_crit(ccf->dev, "Unavailable Target ID\n");
0158
0159 if (errdet & ERRDET_MCST)
0160 dev_crit(ccf->dev, "Multicast Stash\n");
0161
0162 if (cap_valid) {
0163 dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",
0164 addr, src_id);
0165 }
0166
0167 out:
0168 iowrite32be(errdet, &ccf->err_regs->errdet);
0169 return errdet ? IRQ_HANDLED : IRQ_NONE;
0170 }
0171
0172 static int ccf_probe(struct platform_device *pdev)
0173 {
0174 struct ccf_private *ccf;
0175 const struct of_device_id *match;
0176 u32 errinten;
0177 int ret, irq;
0178
0179 match = of_match_device(ccf_matches, &pdev->dev);
0180 if (WARN_ON(!match))
0181 return -ENODEV;
0182
0183 ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);
0184 if (!ccf)
0185 return -ENOMEM;
0186
0187 ccf->regs = devm_platform_ioremap_resource(pdev, 0);
0188 if (IS_ERR(ccf->regs))
0189 return PTR_ERR(ccf->regs);
0190
0191 ccf->dev = &pdev->dev;
0192 ccf->info = match->data;
0193 ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
0194
0195 if (ccf->info->has_brr) {
0196 u32 brr = ioread32be(ccf->regs + CCF_BRR);
0197
0198 if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040)
0199 ccf->t1040 = true;
0200 }
0201
0202 dev_set_drvdata(&pdev->dev, ccf);
0203
0204 irq = platform_get_irq(pdev, 0);
0205 if (irq < 0)
0206 return irq;
0207
0208 ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
0209 if (ret) {
0210 dev_err(&pdev->dev, "%s: can't request irq\n", __func__);
0211 return ret;
0212 }
0213
0214 errinten = ERRDET_LAE | ERRDET_CV;
0215 if (ccf->t1040)
0216 errinten |= ERRDET_UTID | ERRDET_MCST;
0217
0218 switch (ccf->info->version) {
0219 case CCF1:
0220
0221 iowrite32be(errinten, &ccf->err_regs->errdis);
0222 break;
0223
0224 case CCF2:
0225 iowrite32be(0, &ccf->err_regs->errdis);
0226 iowrite32be(errinten, &ccf->err_regs->errinten);
0227 break;
0228 }
0229
0230 return 0;
0231 }
0232
0233 static int ccf_remove(struct platform_device *pdev)
0234 {
0235 struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
0236
0237 switch (ccf->info->version) {
0238 case CCF1:
0239 iowrite32be(0, &ccf->err_regs->errdis);
0240 break;
0241
0242 case CCF2:
0243
0244
0245
0246
0247
0248 iowrite32be(0, &ccf->err_regs->errinten);
0249 break;
0250 }
0251
0252 return 0;
0253 }
0254
0255 static struct platform_driver ccf_driver = {
0256 .driver = {
0257 .name = KBUILD_MODNAME,
0258 .of_match_table = ccf_matches,
0259 },
0260 .probe = ccf_probe,
0261 .remove = ccf_remove,
0262 };
0263
0264 module_platform_driver(ccf_driver);
0265
0266 MODULE_LICENSE("GPL");
0267 MODULE_AUTHOR("Freescale Semiconductor");
0268 MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");