aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2015-12-10 14:07:12 -0500
committerBorislav Petkov <bp@suse.de>2015-12-11 10:56:16 -0500
commit666db563d3d9fffcfc019e3d1a980dac47601a71 (patch)
tree5494f13ab4f6be3e060b8bd29ca8b8e2c2002852
parentd0cdf9003140e9b40d2488aaee2838babe7e212c (diff)
EDAC, mpc85xx: Make mpc85xx-pci-edac a platform device
Originally the mpc85xx-pci-edac driver bound directly to the PCI controller node. Commit 905e75c46dba ("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: Michael Ellerman <mpe@ellerman.id.au> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Scott 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.com Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c28
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h9
-rw-r--r--drivers/edac/mpc85xx_edac.c38
-rw-r--r--include/linux/fsl/edac.h8
4 files changed, 68 insertions, 15 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 610f472f91d1..a1ac80b3041a 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -21,10 +21,12 @@
21#include <linux/pci.h> 21#include <linux/pci.h>
22#include <linux/delay.h> 22#include <linux/delay.h>
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/fsl/edac.h>
24#include <linux/init.h> 25#include <linux/init.h>
25#include <linux/interrupt.h> 26#include <linux/interrupt.h>
26#include <linux/memblock.h> 27#include <linux/memblock.h>
27#include <linux/log2.h> 28#include <linux/log2.h>
29#include <linux/platform_device.h>
28#include <linux/slab.h> 30#include <linux/slab.h>
29#include <linux/suspend.h> 31#include <linux/suspend.h>
30#include <linux/syscore_ops.h> 32#include <linux/syscore_ops.h>
@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
1255#endif 1257#endif
1256} 1258}
1257 1259
1260static int add_err_dev(struct platform_device *pdev)
1261{
1262 struct platform_device *errdev;
1263 struct mpc85xx_edac_pci_plat_data pd = {
1264 .of_node = pdev->dev.of_node
1265 };
1266
1267 errdev = platform_device_register_resndata(&pdev->dev,
1268 "mpc85xx-pci-edac",
1269 PLATFORM_DEVID_AUTO,
1270 pdev->resource,
1271 pdev->num_resources,
1272 &pd, sizeof(pd));
1273 if (IS_ERR(errdev))
1274 return PTR_ERR(errdev);
1275
1276 return 0;
1277}
1278
1258static int fsl_pci_probe(struct platform_device *pdev) 1279static int fsl_pci_probe(struct platform_device *pdev)
1259{ 1280{
1260 struct device_node *node; 1281 struct device_node *node;
@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
1262 1283
1263 node = pdev->dev.of_node; 1284 node = pdev->dev.of_node;
1264 ret = fsl_add_bridge(pdev, fsl_pci_primary == node); 1285 ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
1286 if (ret)
1287 return ret;
1265 1288
1266 mpc85xx_pci_err_probe(pdev); 1289 ret = add_err_dev(pdev);
1290 if (ret)
1291 dev_err(&pdev->dev, "couldn't register error device: %d\n",
1292 ret);
1267 1293
1268 return 0; 1294 return 0;
1269} 1295}
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index c1cec771d5ea..151588530b06 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
130static inline void fsl_pci_assign_primary(void) {} 130static inline void fsl_pci_assign_primary(void) {}
131#endif 131#endif
132 132
133#ifdef CONFIG_EDAC_MPC85XX
134int mpc85xx_pci_err_probe(struct platform_device *op);
135#else
136static inline int mpc85xx_pci_err_probe(struct platform_device *op)
137{
138 return -ENOTSUPP;
139}
140#endif
141
142#ifdef CONFIG_FSL_PCI 133#ifdef CONFIG_FSL_PCI
143extern int fsl_pci_mcheck_exception(struct pt_regs *); 134extern int fsl_pci_mcheck_exception(struct pt_regs *);
144#else 135#else
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 3eab06351089..b7139c160baf 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -20,6 +20,7 @@
20#include <linux/edac.h> 20#include <linux/edac.h>
21#include <linux/smp.h> 21#include <linux/smp.h>
22#include <linux/gfp.h> 22#include <linux/gfp.h>
23#include <linux/fsl/edac.h>
23 24
24#include <linux/of_platform.h> 25#include <linux/of_platform.h>
25#include <linux/of_device.h> 26#include <linux/of_device.h>
@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
238 return IRQ_HANDLED; 239 return IRQ_HANDLED;
239} 240}
240 241
241int mpc85xx_pci_err_probe(struct platform_device *op) 242static int mpc85xx_pci_err_probe(struct platform_device *op)
242{ 243{
243 struct edac_pci_ctl_info *pci; 244 struct edac_pci_ctl_info *pci;
244 struct mpc85xx_pci_pdata *pdata; 245 struct mpc85xx_pci_pdata *pdata;
246 struct mpc85xx_edac_pci_plat_data *plat_data;
247 struct device_node *of_node;
245 struct resource r; 248 struct resource r;
246 int res = 0; 249 int res = 0;
247 250
@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
266 pdata->name = "mpc85xx_pci_err"; 269 pdata->name = "mpc85xx_pci_err";
267 pdata->irq = NO_IRQ; 270 pdata->irq = NO_IRQ;
268 271
269 if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0) 272 plat_data = op->dev.platform_data;
273 if (!plat_data) {
274 dev_err(&op->dev, "no platform data");
275 res = -ENXIO;
276 goto err;
277 }
278 of_node = plat_data->of_node;
279
280 if (mpc85xx_pcie_find_capability(of_node) > 0)
270 pdata->is_pcie = true; 281 pdata->is_pcie = true;
271 282
272 dev_set_drvdata(&op->dev, pci); 283 dev_set_drvdata(&op->dev, pci);
@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
284 295
285 pdata->edac_idx = edac_pci_idx++; 296 pdata->edac_idx = edac_pci_idx++;
286 297
287 res = of_address_to_resource(op->dev.of_node, 0, &r); 298 res = of_address_to_resource(of_node, 0, &r);
288 if (res) { 299 if (res) {
289 printk(KERN_ERR "%s: Unable to get resource for " 300 printk(KERN_ERR "%s: Unable to get resource for "
290 "PCI err regs\n", __func__); 301 "PCI err regs\n", __func__);
@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
339 } 350 }
340 351
341 if (edac_op_state == EDAC_OPSTATE_INT) { 352 if (edac_op_state == EDAC_OPSTATE_INT) {
342 pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); 353 pdata->irq = irq_of_parse_and_map(of_node, 0);
343 res = devm_request_irq(&op->dev, pdata->irq, 354 res = devm_request_irq(&op->dev, pdata->irq,
344 mpc85xx_pci_isr, 355 mpc85xx_pci_isr,
345 IRQF_SHARED, 356 IRQF_SHARED,
@@ -386,8 +397,22 @@ err:
386 devres_release_group(&op->dev, mpc85xx_pci_err_probe); 397 devres_release_group(&op->dev, mpc85xx_pci_err_probe);
387 return res; 398 return res;
388} 399}
389EXPORT_SYMBOL(mpc85xx_pci_err_probe);
390 400
401static const struct platform_device_id mpc85xx_pci_err_match[] = {
402 {
403 .name = "mpc85xx-pci-edac"
404 },
405 {}
406};
407
408static struct platform_driver mpc85xx_pci_err_driver = {
409 .probe = mpc85xx_pci_err_probe,
410 .id_table = mpc85xx_pci_err_match,
411 .driver = {
412 .name = "mpc85xx_pci_err",
413 .suppress_bind_attrs = true,
414 },
415};
391#endif /* CONFIG_PCI */ 416#endif /* CONFIG_PCI */
392 417
393/**************************** L2 Err device ***************************/ 418/**************************** L2 Err device ***************************/
@@ -1211,6 +1236,9 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
1211static struct platform_driver * const drivers[] = { 1236static struct platform_driver * const drivers[] = {
1212 &mpc85xx_mc_err_driver, 1237 &mpc85xx_mc_err_driver,
1213 &mpc85xx_l2_err_driver, 1238 &mpc85xx_l2_err_driver,
1239#ifdef CONFIG_PCI
1240 &mpc85xx_pci_err_driver,
1241#endif
1214}; 1242};
1215 1243
1216static int __init mpc85xx_mc_init(void) 1244static int __init mpc85xx_mc_init(void)
diff --git a/include/linux/fsl/edac.h b/include/linux/fsl/edac.h
new file mode 100644
index 000000000000..90d64d4ec1a9
--- /dev/null
+++ b/include/linux/fsl/edac.h
@@ -0,0 +1,8 @@
1#ifndef FSL_EDAC_H
2#define FSL_EDAC_H
3
4struct mpc85xx_edac_pci_plat_data {
5 struct device_node *of_node;
6};
7
8#endif