I've verified this patch can apply for galak/powerpc.git 'next' branch with no change.
Best Regards, Shaohui Xie >-----Original Message----- >From: Xie Shaohui-B21989 >Sent: Thursday, July 21, 2011 6:33 PM >To: linuxppc-dev@lists.ozlabs.org >Cc: Gala Kumar-B11780; mm-comm...@vger.kernel.org; avoront...@mvista.com; >da...@davemloft.net; grant.lik...@secretlab.ca; a...@linux-foundation.org; >Jiang Kai-B18973; Kumar Gala; Xie Shaohui-B21989 >Subject: [PATCH 4/4] edac/85xx: PCI/PCIE error interrupt edac support. > >From: Kai.Jiang <kai.ji...@freescale.com> > >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.ji...@freescale.com> >Signed-off-by: Kumar Gala <ga...@kernel.crashing.org> >Signed-off-by: Shaohui Xie <shaohui....@freescale.com> >--- > drivers/edac/mpc85xx_edac.c | 239 ++++++++++++++++++++++++++++++++------ >---- > drivers/edac/mpc85xx_edac.h | 17 +-- > 2 files changed, 188 insertions(+), 68 deletions(-) > >diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c >index b048a5f..dde156f 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) 2011 Freescale Semiconductor, Inc. > * > * Author: Dave Jiang <dji...@mvista.com> > * >@@ -21,6 +22,8 @@ > > #include <linux/of_platform.h> > #include <linux/of_device.h> >+#include <include/asm/pci.h> >+#include <sysdev/fsl_pci.h> > #include "edac_module.h" > #include "edac_core.h" > #include "mpc85xx_edac.h" >@@ -34,14 +37,6 @@ static int edac_mc_idx; static u32 >orig_ddr_err_disable; 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]; >@@ -151,37 +146,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 >+200,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,11 +210,99 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void >*dev_id) > return IRQ_HANDLED; > } > >+#define MPC85XX_MPIC_EIMR0 0x3910 >+/* >+ * 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 device *op) { >+ u32 *int_cell = NULL; >+ struct device_node *np = NULL; >+ void __iomem *mpic_base = NULL; >+ u32 reg_tmp = 0; >+ u32 int_len = 0; >+ struct resource r; >+ int res = 0; >+ >+ if (!op->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->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) { > struct edac_pci_ctl_info *pci; > struct mpc85xx_pci_pdata *pdata; > struct resource r; >+ struct ccsr_pci *reg = NULL; > int res = 0; > > if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL)) >@@ -217,6 +315,10 @@ 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; >@@ -235,37 +337,40 @@ 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", >- __func__); >+ printk(KERN_ERR >+ "%s:Error while requesting mem region\n", __func__); > res = -EBUSY; > 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->dev) < 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__); @@ >-275,7 +380,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 >@@ -290,6 +395,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"); @@ -311,10 >+427,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); > >@@ -333,6 +452,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); diff --git >a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index >932016f..d0e7b11 100644 >--- a/drivers/edac/mpc85xx_edac.h >+++ b/drivers/edac/mpc85xx_edac.h >@@ -131,16 +131,8 @@ > #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 >+#define PCI_ERR_CAP_DR_DIS_MST 0x40 >+#define PCI_ERR_EN_DIS_MST (~0x40) > > struct mpc85xx_mc_pdata { > char *name; >@@ -159,8 +151,11 @@ struct mpc85xx_l2_pdata { struct mpc85xx_pci_pdata { > char *name; > int edac_idx; >- void __iomem *pci_vbase; > int irq; >+ struct ccsr_pci *pci_reg; >+ u8 pcie_flag; >+ u32 orig_pci_err_dr; >+ u32 orig_pci_err_en; > }; > > #endif >-- >1.6.4 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev