Commit 666db563 authored by Scott Wood's avatar Scott Wood Committed by Borislav Petkov

EDAC, mpc85xx: Make mpc85xx-pci-edac a platform device

Originally the mpc85xx-pci-edac driver bound directly to the PCI
controller node.

Commit

  905e75c4 ("powerpc/fsl-pci: Unify pci/pcie initialization code")

turned the PCI controller code into a platform device. Since we can't
have two drivers binding to the same device, the EDAC code was changed
to be called into as a library-style submodule. However, this doesn't
work if the EDAC driver is built as a module.

Commit

  8d8fcba6d1ea ("EDAC: Rip out the edac_subsys reference counting")

exposed another problem with this approach -- mpc85xx_pci_err_probe()
was being called in the same early boot phase that the PCI controller
is initialized, rather than in the device_initcall phase that the EDAC
layer expects. This caused a crash on boot.

To fix this, the PCI controller code now creates a child platform device
specifically for EDAC, which the mpc85xx-pci-edac driver binds to.
Reported-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarScott Wood <scottwood@freescale.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Daniel Axtens <dja@axtens.net>
Cc: Doug Thompson <dougthompson@xmission.com>
Cc: Jia Hongtao <B38951@freescale.com>
Cc: Jiri Kosina <jkosina@suse.com>
Cc: Kim Phillips <kim.phillips@freescale.com>
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Masanari Iida <standby24x7@gmail.com>
Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Rob Herring <robh@kernel.org>
Link: http://lkml.kernel.org/r/1449774432-18593-1-git-send-email-scottwood@freescale.comSigned-off-by: default avatarBorislav Petkov <bp@suse.de>
parent d0cdf900
...@@ -21,10 +21,12 @@ ...@@ -21,10 +21,12 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/fsl/edac.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
...@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb) ...@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
#endif #endif
} }
static int add_err_dev(struct platform_device *pdev)
{
struct platform_device *errdev;
struct mpc85xx_edac_pci_plat_data pd = {
.of_node = pdev->dev.of_node
};
errdev = platform_device_register_resndata(&pdev->dev,
"mpc85xx-pci-edac",
PLATFORM_DEVID_AUTO,
pdev->resource,
pdev->num_resources,
&pd, sizeof(pd));
if (IS_ERR(errdev))
return PTR_ERR(errdev);
return 0;
}
static int fsl_pci_probe(struct platform_device *pdev) static int fsl_pci_probe(struct platform_device *pdev)
{ {
struct device_node *node; struct device_node *node;
...@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev) ...@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
node = pdev->dev.of_node; node = pdev->dev.of_node;
ret = fsl_add_bridge(pdev, fsl_pci_primary == node); ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
if (ret)
return ret;
mpc85xx_pci_err_probe(pdev); ret = add_err_dev(pdev);
if (ret)
dev_err(&pdev->dev, "couldn't register error device: %d\n",
ret);
return 0; return 0;
} }
......
...@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void); ...@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
static inline void fsl_pci_assign_primary(void) {} static inline void fsl_pci_assign_primary(void) {}
#endif #endif
#ifdef CONFIG_EDAC_MPC85XX
int mpc85xx_pci_err_probe(struct platform_device *op);
#else
static inline int mpc85xx_pci_err_probe(struct platform_device *op)
{
return -ENOTSUPP;
}
#endif
#ifdef CONFIG_FSL_PCI #ifdef CONFIG_FSL_PCI
extern int fsl_pci_mcheck_exception(struct pt_regs *); extern int fsl_pci_mcheck_exception(struct pt_regs *);
#else #else
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/edac.h> #include <linux/edac.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/fsl/edac.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) ...@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int mpc85xx_pci_err_probe(struct platform_device *op) static int mpc85xx_pci_err_probe(struct platform_device *op)
{ {
struct edac_pci_ctl_info *pci; struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata; struct mpc85xx_pci_pdata *pdata;
struct mpc85xx_edac_pci_plat_data *plat_data;
struct device_node *of_node;
struct resource r; struct resource r;
int res = 0; int res = 0;
...@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
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) plat_data = op->dev.platform_data;
if (!plat_data) {
dev_err(&op->dev, "no platform data");
res = -ENXIO;
goto err;
}
of_node = plat_data->of_node;
if (mpc85xx_pcie_find_capability(of_node) > 0)
pdata->is_pcie = true; pdata->is_pcie = true;
dev_set_drvdata(&op->dev, pci); dev_set_drvdata(&op->dev, pci);
...@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->edac_idx = edac_pci_idx++; pdata->edac_idx = edac_pci_idx++;
res = of_address_to_resource(op->dev.of_node, 0, &r); res = of_address_to_resource(of_node, 0, &r);
if (res) { if (res) {
printk(KERN_ERR "%s: Unable to get resource for " printk(KERN_ERR "%s: Unable to get resource for "
"PCI err regs\n", __func__); "PCI err regs\n", __func__);
...@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -339,7 +350,7 @@ 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(of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq, res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr, mpc85xx_pci_isr,
IRQF_SHARED, IRQF_SHARED,
...@@ -386,8 +397,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -386,8 +397,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
devres_release_group(&op->dev, mpc85xx_pci_err_probe); devres_release_group(&op->dev, mpc85xx_pci_err_probe);
return res; return res;
} }
EXPORT_SYMBOL(mpc85xx_pci_err_probe);
static const struct platform_device_id mpc85xx_pci_err_match[] = {
{
.name = "mpc85xx-pci-edac"
},
{}
};
static struct platform_driver mpc85xx_pci_err_driver = {
.probe = mpc85xx_pci_err_probe,
.id_table = mpc85xx_pci_err_match,
.driver = {
.name = "mpc85xx_pci_err",
.suppress_bind_attrs = true,
},
};
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/**************************** L2 Err device ***************************/ /**************************** L2 Err device ***************************/
...@@ -1211,6 +1236,9 @@ static void __init mpc85xx_mc_clear_rfxe(void *data) ...@@ -1211,6 +1236,9 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
static struct platform_driver * const drivers[] = { static struct platform_driver * const drivers[] = {
&mpc85xx_mc_err_driver, &mpc85xx_mc_err_driver,
&mpc85xx_l2_err_driver, &mpc85xx_l2_err_driver,
#ifdef CONFIG_PCI
&mpc85xx_pci_err_driver,
#endif
}; };
static int __init mpc85xx_mc_init(void) static int __init mpc85xx_mc_init(void)
......
#ifndef FSL_EDAC_H
#define FSL_EDAC_H
struct mpc85xx_edac_pci_plat_data {
struct device_node *of_node;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment