Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * CoreNet Coherency Fabric error reporting
0004  *
0005  * Copyright 2014 Freescale Semiconductor Inc.
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  * This register is present but not documented, with different values for
0043  * IP_ID, on other chips with fsl,corenet2-cf such as t4240 and b4860.
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;     /* 0x00 Error Detect Register */
0064     /* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */
0065     u32 errdis;
0066     /* 0x08 Error Interrupt Enable Register (ccf2 only) */
0067     u32 errinten;
0068     u32 cecar;      /* 0x0c Error Capture Attribute Register */
0069     u32 cecaddrh;       /* 0x10 Error Capture Address High */
0070     u32 cecaddrl;       /* 0x14 Error Capture Address Low */
0071     u32 cecar2;     /* 0x18 Error Capture Attribute Register 2 */
0072 };
0073 
0074 /* LAE/CV also valid for errdis and errinten */
0075 #define ERRDET_LAE      (1 << 0)  /* Local Access Error */
0076 #define ERRDET_CV       (1 << 1)  /* Coherency Violation */
0077 #define ERRDET_UTID     (1 << 2)  /* Unavailable Target ID (t1040) */
0078 #define ERRDET_MCST     (1 << 3)  /* Multicast Stash (t1040) */
0079 #define ERRDET_CTYPE_SHIFT  26    /* Capture Type (ccf2 only) */
0080 #define ERRDET_CTYPE_MASK   (0x1f << ERRDET_CTYPE_SHIFT)
0081 #define ERRDET_CAP      (1 << 31) /* Capture Valid (ccf2 only) */
0082 
0083 #define CECAR_VAL       (1 << 0)  /* Valid (ccf1 only) */
0084 #define CECAR_UVT       (1 << 15) /* Unavailable target ID (ccf1) */
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         /* On CCF1 this register enables rather than disables. */
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          * We clear errdis on ccf1 because that's the only way to
0245          * disable interrupts, but on ccf2 there's no need to disable
0246          * detection.
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");