> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Thursday, July 03, 2014 5:22 AM
> To: linuxppc-...@lists.ozlabs.org
> Cc: linux-kernel@vger.kernel.org; Bhushan Bharat-R65777
> Subject: [PATCH v2] memory: Freescale CoreNet Coherency Fabric error reporting
> driver
> 
> The CoreNet Coherency Fabric is part of the memory subsystem on
> some Freescale QorIQ chips.  It can report coherency violations (e.g.
> due to misusing memory that is mapped noncoherent) as well as
> transactions that do not hit any local access window, or which hit a
> local access window with an invalid target ID.
> 
> Signed-off-by: Scott Wood <scottw...@freescale.com>

Reviewed-by: Bharat Bhushan <bharat.bhus...@freescale.com>


Regards
-Bharat

> ---
> v2:
>  - s/cecadr/cecaddr/ to consistently use ccf2 names
>  - fix ERRDET_CTYPE_MASK value
>  - use the ccf2 value for CECADDRH_ADDRH (harmless on ccf1)
>  - add comment explaining why we disable detection on remove for
>    ccf1 but not ccf2
> ---
>  arch/powerpc/configs/corenet32_smp_defconfig |   1 +
>  arch/powerpc/configs/corenet64_smp_defconfig |   1 +
>  drivers/memory/Kconfig                       |  10 ++
>  drivers/memory/Makefile                      |   1 +
>  drivers/memory/fsl-corenet-cf.c              | 251 
> +++++++++++++++++++++++++++
>  5 files changed, 264 insertions(+)
>  create mode 100644 drivers/memory/fsl-corenet-cf.c
> 
> diff --git a/arch/powerpc/configs/corenet32_smp_defconfig
> b/arch/powerpc/configs/corenet32_smp_defconfig
> index 7d0c837..6a3c58a 100644
> --- a/arch/powerpc/configs/corenet32_smp_defconfig
> +++ b/arch/powerpc/configs/corenet32_smp_defconfig
> @@ -180,3 +180,4 @@ CONFIG_CRYPTO_SHA512=y
>  CONFIG_CRYPTO_AES=y
>  # CONFIG_CRYPTO_ANSI_CPRNG is not set
>  CONFIG_CRYPTO_DEV_FSL_CAAM=y
> +CONFIG_FSL_CORENET_CF=y
> diff --git a/arch/powerpc/configs/corenet64_smp_defconfig
> b/arch/powerpc/configs/corenet64_smp_defconfig
> index 6ae07e1..4b07bad 100644
> --- a/arch/powerpc/configs/corenet64_smp_defconfig
> +++ b/arch/powerpc/configs/corenet64_smp_defconfig
> @@ -179,3 +179,4 @@ CONFIG_CRYPTO_SHA256=y
>  CONFIG_CRYPTO_SHA512=y
>  # CONFIG_CRYPTO_ANSI_CPRNG is not set
>  CONFIG_CRYPTO_DEV_FSL_CAAM=y
> +CONFIG_FSL_CORENET_CF=y
> diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
> index c59e9c9..fab81a1 100644
> --- a/drivers/memory/Kconfig
> +++ b/drivers/memory/Kconfig
> @@ -61,6 +61,16 @@ config TEGRA30_MC
>         analysis, especially for IOMMU/SMMU(System Memory Management
>         Unit) module.
> 
> +config FSL_CORENET_CF
> +     tristate "Freescale CoreNet Error Reporting"
> +     depends on FSL_SOC_BOOKE
> +     help
> +       Say Y for reporting of errors from the Freescale CoreNet
> +       Coherency Fabric.  Errors reported include accesses to
> +       physical addresses that mapped by no local access window
> +       (LAW) or an invalid LAW, as well as bad cache state that
> +       represents a coherency violation.
> +
>  config FSL_IFC
>       bool
>       depends on FSL_SOC
> diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
> index 71160a2..4055c47 100644
> --- a/drivers/memory/Makefile
> +++ b/drivers/memory/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_OF)              += of_memory.o
>  endif
>  obj-$(CONFIG_TI_AEMIF)               += ti-aemif.o
>  obj-$(CONFIG_TI_EMIF)                += emif.o
> +obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
>  obj-$(CONFIG_FSL_IFC)                += fsl_ifc.o
>  obj-$(CONFIG_MVEBU_DEVBUS)   += mvebu-devbus.o
>  obj-$(CONFIG_TEGRA20_MC)     += tegra20-mc.o
> diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c
> new file mode 100644
> index 0000000..c9443fc
> --- /dev/null
> +++ b/drivers/memory/fsl-corenet-cf.c
> @@ -0,0 +1,251 @@
> +/*
> + * CoreNet Coherency Fabric error reporting
> + *
> + * Copyright 2014 Freescale Semiconductor Inc.
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +
> +enum ccf_version {
> +     CCF1,
> +     CCF2,
> +};
> +
> +struct ccf_info {
> +     enum ccf_version version;
> +     int err_reg_offs;
> +};
> +
> +static const struct ccf_info ccf1_info = {
> +     .version = CCF1,
> +     .err_reg_offs = 0xa00,
> +};
> +
> +static const struct ccf_info ccf2_info = {
> +     .version = CCF2,
> +     .err_reg_offs = 0xe40,
> +};
> +
> +static const struct of_device_id ccf_matches[] = {
> +     {
> +             .compatible = "fsl,corenet1-cf",
> +             .data = &ccf1_info,
> +     },
> +     {
> +             .compatible = "fsl,corenet2-cf",
> +             .data = &ccf2_info,
> +     },
> +     {}
> +};
> +
> +struct ccf_err_regs {
> +     u32 errdet;             /* 0x00 Error Detect Register */
> +     /* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */
> +     u32 errdis;
> +     /* 0x08 Error Interrupt Enable Register (ccf2 only) */
> +     u32 errinten;
> +     u32 cecar;              /* 0x0c Error Capture Attribute Register */
> +     u32 cecaddrh;           /* 0x10 Error Capture Address High */
> +     u32 cecaddrl;           /* 0x14 Error Capture Address Low */
> +     u32 cecar2;             /* 0x18 Error Capture Attribute Register 2 */
> +};
> +
> +/* LAE/CV also valid for errdis and errinten */
> +#define ERRDET_LAE           (1 << 0)  /* Local Access Error */
> +#define ERRDET_CV            (1 << 1)  /* Coherency Violation */
> +#define ERRDET_CTYPE_SHIFT   26        /* Capture Type (ccf2 only) */
> +#define ERRDET_CTYPE_MASK    (0x1f << ERRDET_CTYPE_SHIFT)
> +#define ERRDET_CAP           (1 << 31) /* Capture Valid (ccf2 only) */
> +
> +#define CECAR_VAL            (1 << 0)  /* Valid (ccf1 only) */
> +#define CECAR_UVT            (1 << 15) /* Unavailable target ID (ccf1) */
> +#define CECAR_SRCID_SHIFT_CCF1       24
> +#define CECAR_SRCID_MASK_CCF1        (0xff << CECAR_SRCID_SHIFT_CCF1)
> +#define CECAR_SRCID_SHIFT_CCF2       18
> +#define CECAR_SRCID_MASK_CCF2        (0xff << CECAR_SRCID_SHIFT_CCF2)
> +
> +#define CECADDRH_ADDRH               0xff
> +
> +struct ccf_private {
> +     const struct ccf_info *info;
> +     struct device *dev;
> +     void __iomem *regs;
> +     struct ccf_err_regs __iomem *err_regs;
> +};
> +
> +static irqreturn_t ccf_irq(int irq, void *dev_id)
> +{
> +     struct ccf_private *ccf = dev_id;
> +     static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL,
> +                                   DEFAULT_RATELIMIT_BURST);
> +     u32 errdet, cecar, cecar2;
> +     u64 addr;
> +     u32 src_id;
> +     bool uvt = false;
> +     bool cap_valid = false;
> +
> +     errdet = ioread32be(&ccf->err_regs->errdet);
> +     cecar = ioread32be(&ccf->err_regs->cecar);
> +     cecar2 = ioread32be(&ccf->err_regs->cecar2);
> +     addr = ioread32be(&ccf->err_regs->cecaddrl);
> +     addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) &
> +                    CECADDRH_ADDRH)) << 32;
> +
> +     if (!__ratelimit(&ratelimit))
> +             goto out;
> +
> +     switch (ccf->info->version) {
> +     case CCF1:
> +             if (cecar & CECAR_VAL) {
> +                     if (cecar & CECAR_UVT)
> +                             uvt = true;
> +
> +                     src_id = (cecar & CECAR_SRCID_MASK_CCF1) >>
> +                              CECAR_SRCID_SHIFT_CCF1;
> +                     cap_valid = true;
> +             }
> +
> +             break;
> +     case CCF2:
> +             if (errdet & ERRDET_CAP) {
> +                     src_id = (cecar & CECAR_SRCID_MASK_CCF2) >>
> +                              CECAR_SRCID_SHIFT_CCF2;
> +                     cap_valid = true;
> +             }
> +
> +             break;
> +     }
> +
> +     dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n",
> +              errdet, cecar, cecar2);
> +
> +     if (errdet & ERRDET_LAE) {
> +             if (uvt)
> +                     dev_crit(ccf->dev, "LAW Unavailable Target ID\n");
> +             else
> +                     dev_crit(ccf->dev, "Local Access Window Error\n");
> +     }
> +
> +     if (errdet & ERRDET_CV)
> +             dev_crit(ccf->dev, "Coherency Violation\n");
> +
> +     if (cap_valid) {
> +             dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",
> +                      addr, src_id);
> +     }
> +
> +out:
> +     iowrite32be(errdet, &ccf->err_regs->errdet);
> +     return errdet ? IRQ_HANDLED : IRQ_NONE;
> +}
> +
> +static int ccf_probe(struct platform_device *pdev)
> +{
> +     struct ccf_private *ccf;
> +     struct resource *r;
> +     const struct of_device_id *match;
> +     int ret, irq;
> +
> +     match = of_match_device(ccf_matches, &pdev->dev);
> +     if (WARN_ON(!match))
> +             return -ENODEV;
> +
> +     ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);
> +     if (!ccf)
> +             return -ENOMEM;
> +
> +     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     if (!r) {
> +             dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
> +             return -ENXIO;
> +     }
> +
> +     ccf->regs = devm_ioremap_resource(&pdev->dev, r);
> +     if (IS_ERR(ccf->regs)) {
> +             dev_err(&pdev->dev, "%s: can't map mem resource\n", __func__);
> +             return PTR_ERR(ccf->regs);
> +     }
> +
> +     ccf->dev = &pdev->dev;
> +     ccf->info = match->data;
> +     ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
> +
> +     dev_set_drvdata(&pdev->dev, ccf);
> +
> +     irq = platform_get_irq(pdev, 0);
> +     if (!irq) {
> +             dev_err(&pdev->dev, "%s: no irq\n", __func__);
> +             return -ENXIO;
> +     }
> +
> +     ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
> +     if (ret) {
> +             dev_err(&pdev->dev, "%s: can't request irq\n", __func__);
> +             return ret;
> +     }
> +
> +     switch (ccf->info->version) {
> +     case CCF1:
> +             /* On CCF1 this register enables rather than disables. */
> +             iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errdis);
> +             break;
> +
> +     case CCF2:
> +             iowrite32be(0, &ccf->err_regs->errdis);
> +             iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errinten);
> +             break;
> +     }
> +
> +     return 0;
> +}
> +
> +static int ccf_remove(struct platform_device *pdev)
> +{
> +     struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
> +
> +     switch (ccf->info->version) {
> +     case CCF1:
> +             iowrite32be(0, &ccf->err_regs->errdis);
> +             break;
> +
> +     case CCF2:
> +             /*
> +              * We clear errdis on ccf1 because that's the only way to
> +              * disable interrupts, but on ccf2 there's no need to disable
> +              * detection.
> +              */
> +             iowrite32be(0, &ccf->err_regs->errinten);
> +             break;
> +     }
> +
> +     return 0;
> +}
> +
> +static struct platform_driver ccf_driver = {
> +     .driver = {
> +             .name = KBUILD_MODNAME,
> +             .owner = THIS_MODULE,
> +             .of_match_table = ccf_matches,
> +     },
> +     .probe = ccf_probe,
> +     .remove = ccf_remove,
> +};
> +
> +module_platform_driver(ccf_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Freescale Semiconductor");
> +MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");
> --
> 1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to