Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c92132f5 authored by Chunhe Lan's avatar Chunhe Lan Committed by Borislav Petkov
Browse files

edac/85xx: Add PCIe error interrupt edac support



Add pcie error interrupt edac support for mpc85xx, p3041, p4080, and
p5020. The mpc85xx uses the legacy interrupt report mechanism - the
error interrupts are reported directly to mpic. While the p3041/
p4080/p5020 attaches the most of error interrupts to interrupt zero. And
report error interrupts to mpic via interrupt 0.

This patch can handle both of them.

Signed-off-by: default avatarChunhe Lan <Chunhe.Lan@freescale.com>
Link: http://lkml.kernel.org/r/1384712714-8826-3-git-send-email-morbidrsa@gmail.com


Cc: Doug Thompson <dougthompson@xmission.com>
Cc: Dave Jiang <dave.jiang@gmail.com>
Signed-off-by: default avatarJohannes Thumshirn <johannes.thumshirn@men.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
parent 6ce4eac1
Loading
Loading
Loading
Loading
+87 −11
Original line number Original line Diff line number Diff line
/*
/*
 * Freescale MPC85xx Memory Controller kenel module
 * Freescale MPC85xx Memory Controller kenel module
 *
 *
 * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
 *
 * Author: Dave Jiang <djiang@mvista.com>
 * Author: Dave Jiang <djiang@mvista.com>
 *
 *
 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
@@ -196,6 +198,42 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
		edac_pci_handle_npe(pci, pci->ctl_name);
		edac_pci_handle_npe(pci, pci->ctl_name);
}
}


static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci)
{
	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
	u32 err_detect;

	err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);

	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(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR));
	pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n",
			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0));
	pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n",
			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1));
	pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n",
			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2));
	pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n",
			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3));

	/* clear error bits */
	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
}

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);
}

static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
{
{
	struct edac_pci_ctl_info *pci = dev_id;
	struct edac_pci_ctl_info *pci = dev_id;
@@ -207,6 +245,9 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
	if (!err_detect)
	if (!err_detect)
		return IRQ_NONE;
		return IRQ_NONE;


	if (pdata->is_pcie)
		mpc85xx_pcie_check(pci);
	else
		mpc85xx_pci_check(pci);
		mpc85xx_pci_check(pci);


	return IRQ_HANDLED;
	return IRQ_HANDLED;
@@ -239,14 +280,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
	pdata = pci->pvt_info;
	pdata = pci->pvt_info;
	pdata->name = "mpc85xx_pci_err";
	pdata->name = "mpc85xx_pci_err";
	pdata->irq = NO_IRQ;
	pdata->irq = NO_IRQ;

	if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
		pdata->is_pcie = true;

	dev_set_drvdata(&op->dev, pci);
	dev_set_drvdata(&op->dev, pci);
	pci->dev = &op->dev;
	pci->dev = &op->dev;
	pci->mod_name = EDAC_MOD_STR;
	pci->mod_name = EDAC_MOD_STR;
	pci->ctl_name = pdata->name;
	pci->ctl_name = pdata->name;
	pci->dev_name = dev_name(&op->dev);
	pci->dev_name = dev_name(&op->dev);


	if (edac_op_state == EDAC_OPSTATE_POLL)
	if (edac_op_state == EDAC_OPSTATE_POLL) {
		if (pdata->is_pcie)
			pci->edac_check = mpc85xx_pcie_check;
		else
			pci->edac_check = mpc85xx_pci_check;
			pci->edac_check = mpc85xx_pci_check;
	}


	pdata->edac_idx = edac_pci_idx++;
	pdata->edac_idx = edac_pci_idx++;


@@ -275,16 +324,26 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
		goto err;
		goto err;
	}
	}


	if (pdata->is_pcie) {
		orig_pci_err_cap_dr =
		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR);
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0);
		orig_pci_err_en =
		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0);
	} else {
		orig_pci_err_cap_dr =
		orig_pci_err_cap_dr =
		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);


		/* PCI master abort is expected during config cycles */
		/* PCI master abort is expected during config cycles */
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);


	orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
		orig_pci_err_en =
		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);


		/* disable master abort reporting */
		/* disable master abort reporting */
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
	}


	/* clear error bits */
	/* clear error bits */
	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
@@ -297,7 +356,8 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
	if (edac_op_state == EDAC_OPSTATE_INT) {
	if (edac_op_state == EDAC_OPSTATE_INT) {
		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
		res = devm_request_irq(&op->dev, pdata->irq,
		res = devm_request_irq(&op->dev, pdata->irq,
				       mpc85xx_pci_isr, IRQF_DISABLED,
				       mpc85xx_pci_isr,
				       IRQF_DISABLED | IRQF_SHARED,
				       "[EDAC] PCI err", pci);
				       "[EDAC] PCI err", pci);
		if (res < 0) {
		if (res < 0) {
			printk(KERN_ERR
			printk(KERN_ERR
@@ -312,6 +372,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
		       pdata->irq);
		       pdata->irq);
	}
	}


	if (pdata->is_pcie) {
		/*
		 * Enable all PCIe error interrupt & error detect except invalid
		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation
		 * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access
		 * detection enable bit. Because PCIe bus code to initialize and
		 * configure these PCIe devices on booting will use some invalid
		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much
		 * notice information. So disable this detect to fix ugly print.
		 */
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0
			 & ~PEX_ERR_ICCAIE_EN_BIT);
		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0
			 | PEX_ERR_ICCAD_DISR_BIT);
	}

	devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
	devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
	edac_dbg(3, "success\n");
	edac_dbg(3, "success\n");
	printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
	printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
+7 −0
Original line number Original line Diff line number Diff line
@@ -134,13 +134,19 @@
#define MPC85XX_PCI_ERR_DR		0x0000
#define MPC85XX_PCI_ERR_DR		0x0000
#define MPC85XX_PCI_ERR_CAP_DR		0x0004
#define MPC85XX_PCI_ERR_CAP_DR		0x0004
#define MPC85XX_PCI_ERR_EN		0x0008
#define MPC85XX_PCI_ERR_EN		0x0008
#define   PEX_ERR_ICCAIE_EN_BIT		0x00020000
#define MPC85XX_PCI_ERR_ATTRIB		0x000c
#define MPC85XX_PCI_ERR_ATTRIB		0x000c
#define MPC85XX_PCI_ERR_ADDR		0x0010
#define MPC85XX_PCI_ERR_ADDR		0x0010
#define   PEX_ERR_ICCAD_DISR_BIT	0x00020000
#define MPC85XX_PCI_ERR_EXT_ADDR	0x0014
#define MPC85XX_PCI_ERR_EXT_ADDR	0x0014
#define MPC85XX_PCI_ERR_DL		0x0018
#define MPC85XX_PCI_ERR_DL		0x0018
#define MPC85XX_PCI_ERR_DH		0x001c
#define MPC85XX_PCI_ERR_DH		0x001c
#define MPC85XX_PCI_GAS_TIMR		0x0020
#define MPC85XX_PCI_GAS_TIMR		0x0020
#define MPC85XX_PCI_PCIX_TIMR		0x0024
#define MPC85XX_PCI_PCIX_TIMR		0x0024
#define MPC85XX_PCIE_ERR_CAP_R0		0x0028
#define MPC85XX_PCIE_ERR_CAP_R1		0x002c
#define MPC85XX_PCIE_ERR_CAP_R2		0x0030
#define MPC85XX_PCIE_ERR_CAP_R3		0x0034


struct mpc85xx_mc_pdata {
struct mpc85xx_mc_pdata {
	char *name;
	char *name;
@@ -158,6 +164,7 @@ struct mpc85xx_l2_pdata {


struct mpc85xx_pci_pdata {
struct mpc85xx_pci_pdata {
	char *name;
	char *name;
	bool is_pcie;
	int edac_idx;
	int edac_idx;
	void __iomem *pci_vbase;
	void __iomem *pci_vbase;
	int irq;
	int irq;