* [PATCH 2/3] edac/85xx: PCI/PCIE error interrupt edac support
@ 2010-11-05 5:27 Lan Chunhe
0 siblings, 0 replies; 3+ messages in thread
From: Lan Chunhe @ 2010-11-05 5:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Lan Chunhe, akpm, Kai.Jiang, dougthompson
Add pcie error interrupt edac support for mpc85xx and p4080.
mpc85xx uses the legacy interrupt report mechanism - the error
interrupts are reported directly to mpic. While, p4080 attaches
most of error interrupts to interrupt 0. And report error interrupt
to mpic via interrupt 0. This patch can handle both of them.
Due to the error management register offset and definition difference
between pci and pcie, use ccsr_pci structure to merge pci and pcie
edac code into one.
Signed-off-by: Kai.Jiang <Kai.Jiang@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Lan Chunhe <b25806@freescale.com>
---
drivers/edac/mpc85xx_edac.c | 243 +++++++++++++++++++++++++++++++++----------
drivers/edac/mpc85xx_edac.h | 9 ++-
2 files changed, 194 insertions(+), 58 deletions(-)
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index b123bb3..c878527 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1,5 +1,6 @@
/*
* Freescale MPC85xx Memory Controller kenel module
+ * Copyright (c) 2010 Freescale Semiconductor, Inc.
*
* Author: Dave Jiang <djiang@mvista.com>
*
@@ -21,6 +22,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
+#include <sysdev/fsl_pci.h>
#include "edac_module.h"
#include "edac_core.h"
#include "mpc85xx_edac.h"
@@ -37,13 +39,8 @@ static u32 orig_ddr_err_sbe;
/*
* PCI Err defines
*/
-#ifdef CONFIG_PCI
-static u32 orig_pci_err_cap_dr;
-static u32 orig_pci_err_en;
-#endif
-
static u32 orig_l2_err_disable;
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static u32 orig_hid1[2];
#endif
@@ -151,37 +148,52 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
{
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
+ struct ccsr_pci *reg = pdata->pci_reg;
+
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
+
+ if (pdata->pcie_flag) {
+ printk(KERN_ERR "PCIE error(s) detected\n");
+ printk(KERN_ERR "PCIE ERR_DR register: 0x%08x\n", err_detect);
+ printk(KERN_ERR "PCIE ERR_CAP_STAT register: 0x%08x\n",
+ in_be32(®->pex_err_cap_stat));
+ printk(KERN_ERR "PCIE ERR_CAP_R0 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r0));
+ printk(KERN_ERR "PCIE ERR_CAP_R1 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r1));
+ printk(KERN_ERR "PCIE ERR_CAP_R2 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r2));
+ printk(KERN_ERR "PCIE ERR_CAP_R3 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r3));
+ } else {
+ /* master aborts can happen during PCI config cycles */
+ if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
+ out_be32(®->pex_err_dr, err_detect);
+ return;
+ }
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
-
- /* master aborts can happen during PCI config cycles */
- if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
- return;
+ printk(KERN_ERR "PCI error(s) detected\n");
+ printk(KERN_ERR "PCI/X ERR_DR register: 0x%08x\n", err_detect);
+ printk(KERN_ERR "PCI/X ERR_ATTRIB register: 0x%08x\n",
+ in_be32(®->pex_err_attrib));
+ printk(KERN_ERR "PCI/X ERR_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_disr));
+ printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_ext_addr));
+ printk(KERN_ERR "PCI/X ERR_DL register: 0x%08x\n",
+ in_be32(®->pex_err_dl));
+ printk(KERN_ERR "PCI/X ERR_DH register: 0x%08x\n",
+ in_be32(®->pex_err_dh));
+
+ if (err_detect & PCI_EDE_PERR_MASK)
+ edac_pci_handle_pe(pci, pci->ctl_name);
+
+ if (err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_PERR_MASK))
+ edac_pci_handle_npe(pci, pci->ctl_name);
}
- printk(KERN_ERR "PCI error(s) detected\n");
- printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect);
-
- printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));
- printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));
- printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));
- printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));
- printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));
-
/* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
-
- if (err_detect & PCI_EDE_PERR_MASK)
- edac_pci_handle_pe(pci, pci->ctl_name);
-
- if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)
- edac_pci_handle_npe(pci, pci->ctl_name);
+ out_be32(®->pex_err_dr, err_detect);
}
static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
@@ -190,7 +202,7 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
if (!err_detect)
return IRQ_NONE;
@@ -200,12 +212,103 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * This function is for error interrupt ORed mechanism.
+ * This mechanism attaches most functions' error interrupts to interrupt 0.
+ * And report error interrupt to mpic via interrupt 0.
+ * EIMR0 - Error Interrupt Mask Register 0.
+ *
+ * This function check whether the device support error interrupt ORed
+ * mechanism via device tree. If supported, umask pcie error interrupt
+ * bit in EIMR0.
+ */
+static int mpc85xx_err_int_en(struct platform_device *op)
+{
+ u32 *int_cell;
+ struct device_node *np;
+ void __iomem *mpic_base;
+ u32 reg_tmp;
+ u32 int_len;
+ struct resource r;
+ int res;
+
+ if (!op->dev.of_node)
+ return -EINVAL;
+
+ /*
+ * Unmask pcie error interrupt bit in EIMR0.
+ * Extend interrupt specifier has 4 cells.
+ * For the 3rd cell:
+ * 0 -- normal interrupt;
+ * 1 -- error interrupt.
+ */
+ int_cell = (u32 *)of_get_property(op->dev.of_node, "interrupts",
+ &int_len);
+ if ((int_len/sizeof(u32)) == 4) {
+ /* soc has error interrupt integration handling mechanism */
+ if (*(int_cell + 2) == 1) {
+ np = of_find_node_by_type(NULL, "open-pic");
+
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "%s: Failed to map mpic regs\n",
+ __func__);
+ of_node_put(np);
+ res = -ENOMEM;
+ goto err;
+ }
+
+ if (!request_mem_region(r.start, r.end - r.start + 1,
+ "mpic")) {
+ printk(KERN_ERR "%s: Error while requesting "
+ "mem region\n", __func__);
+ res = -EBUSY;
+ goto err;
+ }
+
+ mpic_base = ioremap(r.start, r.end - r.start + 1);
+ if (!mpic_base) {
+ printk(KERN_ERR "%s: Unable to map mpic regs\n",
+ __func__);
+ res = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ reg_tmp = in_be32(mpic_base + MPC85XX_MPIC_EIMR0);
+ out_be32(mpic_base + MPC85XX_MPIC_EIMR0,
+ reg_tmp & ~(1 << (31 - *(int_cell + 3))));
+ iounmap(mpic_base);
+ release_mem_region(r.start, r.end - r.start + 1);
+ of_node_put(np);
+ }
+ }
+
+ return 0;
+
+err_ioremap:
+ release_mem_region(r.start, r.end - r.start + 1);
+err:
+ return res;
+}
+
+static int mpc85xx_pcie_find_capability(struct device_node *np)
+{
+ struct pci_controller *hose;
+
+ if (!np)
+ return -EINVAL;
+
+ hose = pci_find_hose_for_OF_device(np);
+ return early_find_capability(hose, hose->bus->number, 0,
+ PCI_CAP_ID_EXP);
+}
+
static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata;
struct resource r;
+ struct ccsr_pci *reg;
int res = 0;
if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
@@ -218,6 +321,9 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
pdata = pci->pvt_info;
pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ;
+ if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
+ pdata->pcie_flag = 1;
+
dev_set_drvdata(&op->dev, pci);
pci->dev = &op->dev;
pci->mod_name = EDAC_MOD_STR;
@@ -236,9 +342,6 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
goto err;
}
- /* we only need the error registers */
- r.start += 0xe00;
-
if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
@@ -247,26 +350,32 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
goto err;
}
- pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
- if (!pdata->pci_vbase) {
+ pdata->pci_reg = devm_ioremap(&op->dev, r.start, resource_size(&r));
+ if (!pdata->pci_reg) {
printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
res = -ENOMEM;
goto err;
}
- orig_pci_err_cap_dr =
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
-
- /* PCI master abort is expected during config cycles */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
+ if (mpc85xx_err_int_en(op) < 0)
+ goto err;
- orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
+ reg = pdata->pci_reg;
+ /* disable pci/pcie error detect */
+ if (pdata->pcie_flag) {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_disr);
+ out_be32(®->pex_err_disr, ~0);
+ } else {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_cap_dr);
+ out_be32(®->pex_err_cap_dr, ~0);
+ }
- /* disable master abort reporting */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
+ /* disable all pcie error interrupt */
+ pdata->orig_pci_err_en = in_be32(®->pex_err_en);
+ out_be32(®->pex_err_en, 0);
- /* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
+ /* clear all error bits */
+ out_be32(®->pex_err_dr, ~0);
if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
debugf3("%s(): failed edac_pci_add_device()\n", __func__);
@@ -276,7 +385,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_pci_isr, IRQF_DISABLED,
+ mpc85xx_pci_isr, IRQF_SHARED,
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
@@ -291,6 +400,17 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
pdata->irq);
}
+ if (pdata->pcie_flag) {
+ /* enable all pcie error interrupt & error detect */
+ out_be32(®->pex_err_en, ~0);
+ out_be32(®->pex_err_disr, 0);
+ } else {
+ /* PCI master abort is expected during config cycles */
+ out_be32(®->pex_err_cap_dr, PCI_ERR_CAP_DR_DIS_MST);
+ /* disable master abort reporting */
+ out_be32(®->pex_err_en, PCI_ERR_EN_DIS_MST);
+ }
+
devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
debugf3("%s(): success\n", __func__);
printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
@@ -312,10 +432,13 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
debugf0("%s()\n", __func__);
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
- orig_pci_err_cap_dr);
+ if (pdata->pcie_flag)
+ out_be32(&pdata->pci_reg->pex_err_disr, pdata->orig_pci_err_dr);
+ else
+ out_be32(&pdata->pci_reg->pex_err_cap_dr,
+ pdata->orig_pci_err_dr);
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
+ out_be32(&pdata->pci_reg->pex_err_en, pdata->orig_pci_err_en);
edac_pci_del_device(pci->dev);
@@ -334,6 +457,12 @@ static struct of_device_id mpc85xx_pci_err_of_match[] = {
{
.compatible = "fsl,mpc8540-pci",
},
+ {
+ .compatible = "fsl,mpc8548-pcie",
+ },
+ {
+ .compatible = "fsl,p4080-pcie",
+ },
{},
};
MODULE_DEVICE_TABLE(of, mpc85xx_pci_err_of_match);
@@ -1146,7 +1275,7 @@ static struct of_platform_driver mpc85xx_mc_err_driver = {
},
};
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static void __init mpc85xx_mc_clear_rfxe(void *data)
{
orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1);
@@ -1185,7 +1314,7 @@ static int __init mpc85xx_mc_init(void)
printk(KERN_WARNING EDAC_MOD_STR "PCI fails to register\n");
#endif
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
/*
* need to clear HID1[RFXE] to disable machine check int
* so we can catch it
@@ -1199,7 +1328,7 @@ static int __init mpc85xx_mc_init(void)
module_init(mpc85xx_mc_init);
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static void __exit mpc85xx_mc_restore_hid1(void *data)
{
mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]);
@@ -1208,7 +1337,7 @@ static void __exit mpc85xx_mc_restore_hid1(void *data)
static void __exit mpc85xx_mc_exit(void)
{
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
#endif
#ifdef CONFIG_PCI
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 099581d..604f181 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -133,6 +133,10 @@
#define PCI_EDE_PERR_MASK (PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
PCI_EDE_ADDR_PERR)
+#define PCI_ERR_CAP_DR_DIS_MST 0x40
+#define PCI_ERR_EN_DIS_MST (~PCI_ERR_CAP_DR_DIS_MST)
+#define MPC85XX_MPIC_EIMR0 0x3910
+
struct mpc85xx_mc_pdata {
char *name;
int edac_idx;
@@ -149,8 +153,11 @@ struct mpc85xx_l2_pdata {
struct mpc85xx_pci_pdata {
char *name;
+ u8 pcie_flag;
int edac_idx;
- void __iomem *pci_vbase;
+ struct ccsr_pci *pci_reg;
+ u32 orig_pci_err_dr;
+ u32 orig_pci_err_en;
int irq;
};
--
1.5.4.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 1/3] edac: Use ccsr_pci structure instead of hardcoded define
@ 2012-09-27 19:02 Chunhe Lan
2012-09-27 19:02 ` [PATCH 2/3] edac/85xx: PCI/PCIe error interrupt edac support Chunhe Lan
0 siblings, 1 reply; 3+ messages in thread
From: Chunhe Lan @ 2012-09-27 19:02 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kumar.gala, Chunhe Lan
There are some differences of register offset and definition between
pci and pcie error management registers. While, some other pci/pcie
error management registers are nearly the same.
To merge pci and pcie edac code into one, it is easier to use ccsr_pci
structure than the hardcoded define. So remove the hardcoded define and
add pci/pcie error management register in ccsr_pci structure.
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
---
arch/powerpc/sysdev/fsl_pci.h | 46 +++++++++++++++++++++++++++++++++-------
drivers/edac/mpc85xx_edac.h | 12 +---------
2 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index d078537..796fe55 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -1,7 +1,7 @@
/*
* MPC85xx/86xx PCI Express structure define
*
- * Copyright 2007,2011 Freescale Semiconductor, Inc
+ * Copyright 2007,2011,2012 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
@@ -14,6 +14,8 @@
#ifndef __POWERPC_FSL_PCI_H
#define __POWERPC_FSL_PCI_H
+#include <asm/pci-bridge.h>
+
#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
#define PCIE_LTSSM_L0 0x16 /* L0 state */
#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */
@@ -77,13 +79,41 @@ struct ccsr_pci {
*/
struct pci_inbound_window_regs piw[4];
- __be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */
- u8 res21[4];
- __be32 pex_err_en; /* 0x.e08 - PCI/PCIE error interrupt enable register */
- u8 res22[4];
- __be32 pex_err_disr; /* 0x.e10 - PCI/PCIE error disable register */
- u8 res23[12];
- __be32 pex_err_cap_stat; /* 0x.e20 - PCI/PCIE error capture status register */
+/* Merge PCI Express/PCI error management registers */
+ __be32 pex_err_dr; /* 0x.e00
+ * - PCI/PCIE error detect register
+ */
+ __be32 pex_err_cap_dr; /* 0x.e04
+ * - PCI error capture disabled register
+ * - PCIE has no this register
+ */
+ __be32 pex_err_en; /* 0x.e08
+ * - PCI/PCIE error interrupt enable register
+ */
+ __be32 pex_err_attrib; /* 0x.e0c
+ * - PCI error attributes capture register
+ * - PCIE has no this register
+ */
+ __be32 pex_err_disr; /* 0x.e10
+ * - PCI error address capture register
+ * - PCIE error disable register
+ */
+ __be32 pex_err_ext_addr; /* 0x.e14
+ * - PCI error extended addr capture register
+ * - PCIE has no this register
+ */
+ __be32 pex_err_dl; /* 0x.e18
+ * - PCI error data low capture register
+ * - PCIE has no this register
+ */
+ __be32 pex_err_dh; /* 0x.e1c
+ * - PCI error data high capture register
+ * - PCIE has no this register
+ */
+ __be32 pex_err_cap_stat; /* 0x.e20
+ * - PCI gasket timer register
+ * - PCIE error capture status register
+ */
u8 res24[4];
__be32 pex_err_cap_r0; /* 0x.e28 - PCIE error capture register 0 */
__be32 pex_err_cap_r1; /* 0x.e2c - PCIE error capture register 0 */
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 932016f..192c8f5 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -1,5 +1,7 @@
/*
* Freescale MPC85xx Memory Controller kenel module
+ * Copyright (c) 2012 Freescale Semiconductor, Inc.
+ *
* Author: Dave Jiang <djiang@mvista.com>
*
* 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
@@ -131,16 +133,6 @@
#define PCI_EDE_PERR_MASK (PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
PCI_EDE_ADDR_PERR)
-#define MPC85XX_PCI_ERR_DR 0x0000
-#define MPC85XX_PCI_ERR_CAP_DR 0x0004
-#define MPC85XX_PCI_ERR_EN 0x0008
-#define MPC85XX_PCI_ERR_ATTRIB 0x000c
-#define MPC85XX_PCI_ERR_ADDR 0x0010
-#define MPC85XX_PCI_ERR_EXT_ADDR 0x0014
-#define MPC85XX_PCI_ERR_DL 0x0018
-#define MPC85XX_PCI_ERR_DH 0x001c
-#define MPC85XX_PCI_GAS_TIMR 0x0020
-#define MPC85XX_PCI_PCIX_TIMR 0x0024
struct mpc85xx_mc_pdata {
char *name;
--
1.7.6.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/3] edac/85xx: PCI/PCIe error interrupt edac support
2012-09-27 19:02 [PATCH 1/3] edac: Use ccsr_pci structure instead of hardcoded define Chunhe Lan
@ 2012-09-27 19:02 ` Chunhe Lan
0 siblings, 0 replies; 3+ messages in thread
From: Chunhe Lan @ 2012-09-27 19:02 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kumar.gala, Chunhe Lan
Adding pcie error interrupt edac support for mpc85xx and p4080.
mpc85xx uses the legacy interrupt report mechanism - the error
interrupts are reported directly to mpic. While, p4080 attaches
the most of error interrupts to interrupt 0. And report error
interrupts to mpic via interrupt 0. This patch can handle both
of them.
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
---
drivers/edac/mpc85xx_edac.c | 228 +++++++++++++++++++++++++++++++++----------
drivers/edac/mpc85xx_edac.h | 8 ++-
2 files changed, 182 insertions(+), 54 deletions(-)
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 4fe66fa..05ef1f2 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1,5 +1,6 @@
/*
* Freescale MPC85xx Memory Controller kenel module
+ * Copyright (c) 2012 Freescale Semiconductor, Inc.
*
* Author: Dave Jiang <djiang@mvista.com>
*
@@ -21,6 +22,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
+#include <sysdev/fsl_pci.h>
#include "edac_module.h"
#include "edac_core.h"
#include "mpc85xx_edac.h"
@@ -37,11 +39,6 @@ static u32 orig_ddr_err_sbe;
/*
* PCI Err defines
*/
-#ifdef CONFIG_PCI
-static u32 orig_pci_err_cap_dr;
-static u32 orig_pci_err_en;
-#endif
-
static u32 orig_l2_err_disable;
#ifdef CONFIG_FSL_SOC_BOOKE
static u32 orig_hid1[2];
@@ -163,37 +160,52 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
{
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
+ struct ccsr_pci *reg = pdata->pci_reg;
+
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
+
+ if (pdata->pcie_flag) {
+ pr_err("PCIE error(s) detected\n");
+ pr_err("PCIE ERR_DR register: 0x%08x\n", err_detect);
+ pr_err("PCIE ERR_CAP_STAT register: 0x%08x\n",
+ in_be32(®->pex_err_cap_stat));
+ pr_err("PCIE ERR_CAP_R0 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r0));
+ pr_err("PCIE ERR_CAP_R1 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r1));
+ pr_err("PCIE ERR_CAP_R2 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r2));
+ pr_err("PCIE ERR_CAP_R3 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r3));
+ } else {
+ /* master aborts can happen during PCI config cycles */
+ if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
+ out_be32(®->pex_err_dr, err_detect);
+ return;
+ }
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
-
- /* master aborts can happen during PCI config cycles */
- if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
- return;
+ pr_err("PCI error(s) detected\n");
+ pr_err("PCI/X ERR_DR register: 0x%08x\n", err_detect);
+ pr_err("PCI/X ERR_ATTRIB register: 0x%08x\n",
+ in_be32(®->pex_err_attrib));
+ pr_err("PCI/X ERR_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_disr));
+ pr_err("PCI/X ERR_EXT_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_ext_addr));
+ pr_err("PCI/X ERR_DL register: 0x%08x\n",
+ in_be32(®->pex_err_dl));
+ pr_err("PCI/X ERR_DH register: 0x%08x\n",
+ in_be32(®->pex_err_dh));
+
+ if (err_detect & PCI_EDE_PERR_MASK)
+ edac_pci_handle_pe(pci, pci->ctl_name);
+
+ if (err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_PERR_MASK))
+ edac_pci_handle_npe(pci, pci->ctl_name);
}
- printk(KERN_ERR "PCI error(s) detected\n");
- printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect);
-
- printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));
- printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));
- printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));
- printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));
- printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));
-
/* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
-
- if (err_detect & PCI_EDE_PERR_MASK)
- edac_pci_handle_pe(pci, pci->ctl_name);
-
- if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)
- edac_pci_handle_npe(pci, pci->ctl_name);
+ out_be32(®->pex_err_dr, err_detect);
}
static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
@@ -202,7 +214,7 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
if (!err_detect)
return IRQ_NONE;
@@ -212,11 +224,102 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * This function is for error interrupt ORed mechanism.
+ * This mechanism attaches most functions' error interrupts to interrupt 0.
+ * And report error interrupt to mpic via interrupt 0.
+ * EIMR0 - Error Interrupt Mask Register 0.
+ *
+ * This function check whether the device support error interrupt ORed
+ * mechanism via device tree. If supported, umask pcie error interrupt
+ * bit in EIMR0.
+ */
+static int mpc85xx_err_int_en(struct platform_device *op)
+{
+ u32 *int_cell;
+ struct device_node *np;
+ void __iomem *mpic_base;
+ u32 reg_tmp;
+ u32 int_len;
+ struct resource r;
+ int res;
+
+ if (!op->dev.of_node)
+ return -EINVAL;
+
+ /*
+ * Unmask pcie error interrupt bit in EIMR0.
+ * Extend interrupt specifier has 4 cells.
+ * For the 3rd cell:
+ * 0 -- normal interrupt;
+ * 1 -- error interrupt.
+ */
+ int_cell = (u32 *)of_get_property(op->dev.of_node, "interrupts",
+ &int_len);
+ if ((int_len/sizeof(u32)) == 4) {
+ /* soc has error interrupt integration handling mechanism */
+ if (*(int_cell + 2) == 1) {
+ np = of_find_node_by_type(NULL, "open-pic");
+
+ if (of_address_to_resource(np, 0, &r)) {
+ pr_err("%s: Failed to map mpic regs\n",
+ __func__);
+ of_node_put(np);
+ res = -ENOMEM;
+ goto err;
+ }
+
+ if (!request_mem_region(r.start, r.end - r.start + 1,
+ "mpic")) {
+ pr_err("%s: Error when requesting mem region\n",
+ __func__);
+ res = -EBUSY;
+ goto err;
+ }
+
+ mpic_base = ioremap(r.start, r.end - r.start + 1);
+ if (!mpic_base) {
+ pr_err("%s: Unable to map mpic regs\n",
+ __func__);
+ res = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ reg_tmp = in_be32(mpic_base + MPC85XX_MPIC_EIMR0);
+ out_be32(mpic_base + MPC85XX_MPIC_EIMR0, reg_tmp &
+ ~(1 << (31 - *(int_cell + 3))));
+ iounmap(mpic_base);
+ release_mem_region(r.start, r.end - r.start + 1);
+ of_node_put(np);
+ }
+ }
+
+ return 0;
+
+err_ioremap:
+ release_mem_region(r.start, r.end - r.start + 1);
+err:
+ return res;
+}
+
+static int mpc85xx_pcie_find_capability(struct device_node *np)
+{
+ struct pci_controller *hose;
+
+ if (!np)
+ return -EINVAL;
+
+ hose = pci_find_hose_for_OF_device(np);
+
+ return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
+}
+
int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
{
struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata;
struct resource r;
+ struct ccsr_pci *reg;
int res = 0;
if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
@@ -245,6 +348,9 @@ int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
pci->ctl_name = pdata->name;
pci->dev_name = dev_name(&op->dev);
+ if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
+ pdata->pcie_flag = 1;
+
if (edac_op_state == EDAC_OPSTATE_POLL)
pci->edac_check = mpc85xx_pci_check;
@@ -256,10 +362,6 @@ int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
"PCI err regs\n", __func__);
goto err;
}
-
- /* we only need the error registers */
- r.start += 0xe00;
-
if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
@@ -268,26 +370,32 @@ int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
goto err;
}
- pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
- if (!pdata->pci_vbase) {
+ pdata->pci_reg = devm_ioremap(&op->dev, r.start, resource_size(&r));
+ if (!pdata->pci_reg) {
printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
res = -ENOMEM;
goto err;
}
- orig_pci_err_cap_dr =
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
-
- /* PCI master abort is expected during config cycles */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
+ if (mpc85xx_err_int_en(op) < 0)
+ goto err;
- orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
+ reg = pdata->pci_reg;
+ /* disable pci/pcie error detect */
+ if (pdata->pcie_flag) {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_disr);
+ out_be32(®->pex_err_disr, ~0);
+ } else {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_cap_dr);
+ out_be32(®->pex_err_cap_dr, ~0);
+ }
- /* disable master abort reporting */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
+ /* disable all pcie error interrupt */
+ pdata->orig_pci_err_en = in_be32(®->pex_err_en);
+ out_be32(®->pex_err_en, 0);
- /* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
+ /* clear all error bits */
+ out_be32(®->pex_err_dr, ~0);
if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
edac_dbg(3, "failed edac_pci_add_device()\n");
@@ -297,7 +405,7 @@ int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_pci_isr, IRQF_DISABLED,
+ mpc85xx_pci_isr, IRQF_SHARED,
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
@@ -312,6 +420,17 @@ int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
pdata->irq);
}
+ if (pdata->pcie_flag) {
+ /* enable all pcie error interrupt & error detect */
+ out_be32(®->pex_err_en, ~0);
+ out_be32(®->pex_err_disr, 0);
+ } else {
+ /* PCI master abort is expected during config cycles */
+ out_be32(®->pex_err_cap_dr, PCI_ERR_CAP_DR_DIS_MST);
+ /* disable master abort reporting */
+ out_be32(®->pex_err_en, PCI_ERR_EN_DIS_MST);
+ }
+
devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
edac_dbg(3, "success\n");
printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
@@ -334,10 +453,13 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
edac_dbg(0, "\n");
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
- orig_pci_err_cap_dr);
+ if (pdata->pcie_flag)
+ out_be32(&pdata->pci_reg->pex_err_disr, pdata->orig_pci_err_dr);
+ else
+ out_be32(&pdata->pci_reg->pex_err_cap_dr,
+ pdata->orig_pci_err_dr);
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
+ out_be32(&pdata->pci_reg->pex_err_en, pdata->orig_pci_err_en);
edac_pci_del_device(pci->dev);
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 192c8f5..262004d 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -133,6 +133,9 @@
#define PCI_EDE_PERR_MASK (PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
PCI_EDE_ADDR_PERR)
+#define PCI_ERR_CAP_DR_DIS_MST 0x40
+#define PCI_ERR_EN_DIS_MST (~PCI_ERR_CAP_DR_DIS_MST)
+#define MPC85XX_MPIC_EIMR0 0x3910
struct mpc85xx_mc_pdata {
char *name;
@@ -150,8 +153,11 @@ struct mpc85xx_l2_pdata {
struct mpc85xx_pci_pdata {
char *name;
+ u8 pcie_flag;
int edac_idx;
- void __iomem *pci_vbase;
+ struct ccsr_pci *pci_reg;
+ u32 orig_pci_err_dr;
+ u32 orig_pci_err_en;
int irq;
};
--
1.7.6.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/3] edac/85xx: PCI/PCIE error interrupt edac support
@ 2010-11-05 2:56 Lan Chunhe
0 siblings, 0 replies; 3+ messages in thread
From: Lan Chunhe @ 2010-11-05 2:56 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Lan Chunhe, akpm, Kai.Jiang, dougthompson
Add pcie error interrupt edac support for mpc85xx and p4080.
mpc85xx uses the legacy interrupt report mechanism - the error
interrupts are reported directly to mpic. While, p4080 attaches
most of error interrupts to interrupt 0. And report error interrupt
to mpic via interrupt 0. This patch can handle both of them.
Due to the error management register offset and definition difference
between pci and pcie, use ccsr_pci structure to merge pci and pcie
edac code into one.
Signed-off-by: Kai.Jiang <Kai.Jiang@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Lan Chunhe <b25806@freescale.com>
---
drivers/edac/mpc85xx_edac.c | 243 +++++++++++++++++++++++++++++++++----------
drivers/edac/mpc85xx_edac.h | 9 ++-
2 files changed, 194 insertions(+), 58 deletions(-)
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index b123bb3..c878527 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1,5 +1,6 @@
/*
* Freescale MPC85xx Memory Controller kenel module
+ * Copyright (c) 2010 Freescale Semiconductor, Inc.
*
* Author: Dave Jiang <djiang@mvista.com>
*
@@ -21,6 +22,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
+#include <sysdev/fsl_pci.h>
#include "edac_module.h"
#include "edac_core.h"
#include "mpc85xx_edac.h"
@@ -37,13 +39,8 @@ static u32 orig_ddr_err_sbe;
/*
* PCI Err defines
*/
-#ifdef CONFIG_PCI
-static u32 orig_pci_err_cap_dr;
-static u32 orig_pci_err_en;
-#endif
-
static u32 orig_l2_err_disable;
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static u32 orig_hid1[2];
#endif
@@ -151,37 +148,52 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
{
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
+ struct ccsr_pci *reg = pdata->pci_reg;
+
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
+
+ if (pdata->pcie_flag) {
+ printk(KERN_ERR "PCIE error(s) detected\n");
+ printk(KERN_ERR "PCIE ERR_DR register: 0x%08x\n", err_detect);
+ printk(KERN_ERR "PCIE ERR_CAP_STAT register: 0x%08x\n",
+ in_be32(®->pex_err_cap_stat));
+ printk(KERN_ERR "PCIE ERR_CAP_R0 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r0));
+ printk(KERN_ERR "PCIE ERR_CAP_R1 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r1));
+ printk(KERN_ERR "PCIE ERR_CAP_R2 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r2));
+ printk(KERN_ERR "PCIE ERR_CAP_R3 register: 0x%08x\n",
+ in_be32(®->pex_err_cap_r3));
+ } else {
+ /* master aborts can happen during PCI config cycles */
+ if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
+ out_be32(®->pex_err_dr, err_detect);
+ return;
+ }
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
-
- /* master aborts can happen during PCI config cycles */
- if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
- return;
+ printk(KERN_ERR "PCI error(s) detected\n");
+ printk(KERN_ERR "PCI/X ERR_DR register: 0x%08x\n", err_detect);
+ printk(KERN_ERR "PCI/X ERR_ATTRIB register: 0x%08x\n",
+ in_be32(®->pex_err_attrib));
+ printk(KERN_ERR "PCI/X ERR_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_disr));
+ printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: 0x%08x\n",
+ in_be32(®->pex_err_ext_addr));
+ printk(KERN_ERR "PCI/X ERR_DL register: 0x%08x\n",
+ in_be32(®->pex_err_dl));
+ printk(KERN_ERR "PCI/X ERR_DH register: 0x%08x\n",
+ in_be32(®->pex_err_dh));
+
+ if (err_detect & PCI_EDE_PERR_MASK)
+ edac_pci_handle_pe(pci, pci->ctl_name);
+
+ if (err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_PERR_MASK))
+ edac_pci_handle_npe(pci, pci->ctl_name);
}
- printk(KERN_ERR "PCI error(s) detected\n");
- printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect);
-
- printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));
- printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));
- printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));
- printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));
- printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n",
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));
-
/* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
-
- if (err_detect & PCI_EDE_PERR_MASK)
- edac_pci_handle_pe(pci, pci->ctl_name);
-
- if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)
- edac_pci_handle_npe(pci, pci->ctl_name);
+ out_be32(®->pex_err_dr, err_detect);
}
static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
@@ -190,7 +202,7 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
u32 err_detect;
- err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
+ err_detect = in_be32(&pdata->pci_reg->pex_err_dr);
if (!err_detect)
return IRQ_NONE;
@@ -200,12 +212,103 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * This function is for error interrupt ORed mechanism.
+ * This mechanism attaches most functions' error interrupts to interrupt 0.
+ * And report error interrupt to mpic via interrupt 0.
+ * EIMR0 - Error Interrupt Mask Register 0.
+ *
+ * This function check whether the device support error interrupt ORed
+ * mechanism via device tree. If supported, umask pcie error interrupt
+ * bit in EIMR0.
+ */
+static int mpc85xx_err_int_en(struct platform_device *op)
+{
+ u32 *int_cell;
+ struct device_node *np;
+ void __iomem *mpic_base;
+ u32 reg_tmp;
+ u32 int_len;
+ struct resource r;
+ int res;
+
+ if (!op->dev.of_node)
+ return -EINVAL;
+
+ /*
+ * Unmask pcie error interrupt bit in EIMR0.
+ * Extend interrupt specifier has 4 cells.
+ * For the 3rd cell:
+ * 0 -- normal interrupt;
+ * 1 -- error interrupt.
+ */
+ int_cell = (u32 *)of_get_property(op->dev.of_node, "interrupts",
+ &int_len);
+ if ((int_len/sizeof(u32)) == 4) {
+ /* soc has error interrupt integration handling mechanism */
+ if (*(int_cell + 2) == 1) {
+ np = of_find_node_by_type(NULL, "open-pic");
+
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "%s: Failed to map mpic regs\n",
+ __func__);
+ of_node_put(np);
+ res = -ENOMEM;
+ goto err;
+ }
+
+ if (!request_mem_region(r.start, r.end - r.start + 1,
+ "mpic")) {
+ printk(KERN_ERR "%s: Error while requesting "
+ "mem region\n", __func__);
+ res = -EBUSY;
+ goto err;
+ }
+
+ mpic_base = ioremap(r.start, r.end - r.start + 1);
+ if (!mpic_base) {
+ printk(KERN_ERR "%s: Unable to map mpic regs\n",
+ __func__);
+ res = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ reg_tmp = in_be32(mpic_base + MPC85XX_MPIC_EIMR0);
+ out_be32(mpic_base + MPC85XX_MPIC_EIMR0,
+ reg_tmp & ~(1 << (31 - *(int_cell + 3))));
+ iounmap(mpic_base);
+ release_mem_region(r.start, r.end - r.start + 1);
+ of_node_put(np);
+ }
+ }
+
+ return 0;
+
+err_ioremap:
+ release_mem_region(r.start, r.end - r.start + 1);
+err:
+ return res;
+}
+
+static int mpc85xx_pcie_find_capability(struct device_node *np)
+{
+ struct pci_controller *hose;
+
+ if (!np)
+ return -EINVAL;
+
+ hose = pci_find_hose_for_OF_device(np);
+ return early_find_capability(hose, hose->bus->number, 0,
+ PCI_CAP_ID_EXP);
+}
+
static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata;
struct resource r;
+ struct ccsr_pci *reg;
int res = 0;
if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
@@ -218,6 +321,9 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
pdata = pci->pvt_info;
pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ;
+ if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
+ pdata->pcie_flag = 1;
+
dev_set_drvdata(&op->dev, pci);
pci->dev = &op->dev;
pci->mod_name = EDAC_MOD_STR;
@@ -236,9 +342,6 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
goto err;
}
- /* we only need the error registers */
- r.start += 0xe00;
-
if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
@@ -247,26 +350,32 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
goto err;
}
- pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
- if (!pdata->pci_vbase) {
+ pdata->pci_reg = devm_ioremap(&op->dev, r.start, resource_size(&r));
+ if (!pdata->pci_reg) {
printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
res = -ENOMEM;
goto err;
}
- orig_pci_err_cap_dr =
- in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
-
- /* PCI master abort is expected during config cycles */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
+ if (mpc85xx_err_int_en(op) < 0)
+ goto err;
- orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
+ reg = pdata->pci_reg;
+ /* disable pci/pcie error detect */
+ if (pdata->pcie_flag) {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_disr);
+ out_be32(®->pex_err_disr, ~0);
+ } else {
+ pdata->orig_pci_err_dr = in_be32(®->pex_err_cap_dr);
+ out_be32(®->pex_err_cap_dr, ~0);
+ }
- /* disable master abort reporting */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
+ /* disable all pcie error interrupt */
+ pdata->orig_pci_err_en = in_be32(®->pex_err_en);
+ out_be32(®->pex_err_en, 0);
- /* clear error bits */
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
+ /* clear all error bits */
+ out_be32(®->pex_err_dr, ~0);
if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
debugf3("%s(): failed edac_pci_add_device()\n", __func__);
@@ -276,7 +385,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_pci_isr, IRQF_DISABLED,
+ mpc85xx_pci_isr, IRQF_SHARED,
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
@@ -291,6 +400,17 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
pdata->irq);
}
+ if (pdata->pcie_flag) {
+ /* enable all pcie error interrupt & error detect */
+ out_be32(®->pex_err_en, ~0);
+ out_be32(®->pex_err_disr, 0);
+ } else {
+ /* PCI master abort is expected during config cycles */
+ out_be32(®->pex_err_cap_dr, PCI_ERR_CAP_DR_DIS_MST);
+ /* disable master abort reporting */
+ out_be32(®->pex_err_en, PCI_ERR_EN_DIS_MST);
+ }
+
devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
debugf3("%s(): success\n", __func__);
printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
@@ -312,10 +432,13 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
debugf0("%s()\n", __func__);
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
- orig_pci_err_cap_dr);
+ if (pdata->pcie_flag)
+ out_be32(&pdata->pci_reg->pex_err_disr, pdata->orig_pci_err_dr);
+ else
+ out_be32(&pdata->pci_reg->pex_err_cap_dr,
+ pdata->orig_pci_err_dr);
- out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
+ out_be32(&pdata->pci_reg->pex_err_en, pdata->orig_pci_err_en);
edac_pci_del_device(pci->dev);
@@ -334,6 +457,12 @@ static struct of_device_id mpc85xx_pci_err_of_match[] = {
{
.compatible = "fsl,mpc8540-pci",
},
+ {
+ .compatible = "fsl,mpc8548-pcie",
+ },
+ {
+ .compatible = "fsl,p4080-pcie",
+ },
{},
};
MODULE_DEVICE_TABLE(of, mpc85xx_pci_err_of_match);
@@ -1146,7 +1275,7 @@ static struct of_platform_driver mpc85xx_mc_err_driver = {
},
};
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static void __init mpc85xx_mc_clear_rfxe(void *data)
{
orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1);
@@ -1185,7 +1314,7 @@ static int __init mpc85xx_mc_init(void)
printk(KERN_WARNING EDAC_MOD_STR "PCI fails to register\n");
#endif
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
/*
* need to clear HID1[RFXE] to disable machine check int
* so we can catch it
@@ -1199,7 +1328,7 @@ static int __init mpc85xx_mc_init(void)
module_init(mpc85xx_mc_init);
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
static void __exit mpc85xx_mc_restore_hid1(void *data)
{
mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]);
@@ -1208,7 +1337,7 @@ static void __exit mpc85xx_mc_restore_hid1(void *data)
static void __exit mpc85xx_mc_exit(void)
{
-#ifdef CONFIG_FSL_SOC_BOOKE
+#if defined(CONFIG_FSL_SOC_BOOKE) && !defined(CONFIG_PPC_E500MC)
on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
#endif
#ifdef CONFIG_PCI
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 099581d..604f181 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -133,6 +133,10 @@
#define PCI_EDE_PERR_MASK (PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
PCI_EDE_ADDR_PERR)
+#define PCI_ERR_CAP_DR_DIS_MST 0x40
+#define PCI_ERR_EN_DIS_MST (~PCI_ERR_CAP_DR_DIS_MST)
+#define MPC85XX_MPIC_EIMR0 0x3910
+
struct mpc85xx_mc_pdata {
char *name;
int edac_idx;
@@ -149,8 +153,11 @@ struct mpc85xx_l2_pdata {
struct mpc85xx_pci_pdata {
char *name;
+ u8 pcie_flag;
int edac_idx;
- void __iomem *pci_vbase;
+ struct ccsr_pci *pci_reg;
+ u32 orig_pci_err_dr;
+ u32 orig_pci_err_en;
int irq;
};
--
1.5.4.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-09-27 6:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-05 5:27 [PATCH 2/3] edac/85xx: PCI/PCIE error interrupt edac support Lan Chunhe
-- strict thread matches above, loose matches on Subject: below --
2012-09-27 19:02 [PATCH 1/3] edac: Use ccsr_pci structure instead of hardcoded define Chunhe Lan
2012-09-27 19:02 ` [PATCH 2/3] edac/85xx: PCI/PCIe error interrupt edac support Chunhe Lan
2010-11-05 2:56 [PATCH 2/3] edac/85xx: PCI/PCIE " Lan Chunhe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).