Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Scott Wood and committed by
Borislav Petkov
666db563 d0cdf900

+68 -15
+27 -1
arch/powerpc/sysdev/fsl_pci.c
··· 21 21 #include <linux/pci.h> 22 22 #include <linux/delay.h> 23 23 #include <linux/string.h> 24 + #include <linux/fsl/edac.h> 24 25 #include <linux/init.h> 25 26 #include <linux/interrupt.h> 26 27 #include <linux/memblock.h> 27 28 #include <linux/log2.h> 29 + #include <linux/platform_device.h> 28 30 #include <linux/slab.h> 29 31 #include <linux/suspend.h> 30 32 #include <linux/syscore_ops.h> ··· 1257 1255 #endif 1258 1256 } 1259 1257 1258 + static int add_err_dev(struct platform_device *pdev) 1259 + { 1260 + struct platform_device *errdev; 1261 + struct mpc85xx_edac_pci_plat_data pd = { 1262 + .of_node = pdev->dev.of_node 1263 + }; 1264 + 1265 + errdev = platform_device_register_resndata(&pdev->dev, 1266 + "mpc85xx-pci-edac", 1267 + PLATFORM_DEVID_AUTO, 1268 + pdev->resource, 1269 + pdev->num_resources, 1270 + &pd, sizeof(pd)); 1271 + if (IS_ERR(errdev)) 1272 + return PTR_ERR(errdev); 1273 + 1274 + return 0; 1275 + } 1276 + 1260 1277 static int fsl_pci_probe(struct platform_device *pdev) 1261 1278 { 1262 1279 struct device_node *node; ··· 1283 1262 1284 1263 node = pdev->dev.of_node; 1285 1264 ret = fsl_add_bridge(pdev, fsl_pci_primary == node); 1265 + if (ret) 1266 + return ret; 1286 1267 1287 - mpc85xx_pci_err_probe(pdev); 1268 + ret = add_err_dev(pdev); 1269 + if (ret) 1270 + dev_err(&pdev->dev, "couldn't register error device: %d\n", 1271 + ret); 1288 1272 1289 1273 return 0; 1290 1274 }
-9
arch/powerpc/sysdev/fsl_pci.h
··· 130 130 static inline void fsl_pci_assign_primary(void) {} 131 131 #endif 132 132 133 - #ifdef CONFIG_EDAC_MPC85XX 134 - int mpc85xx_pci_err_probe(struct platform_device *op); 135 - #else 136 - static inline int mpc85xx_pci_err_probe(struct platform_device *op) 137 - { 138 - return -ENOTSUPP; 139 - } 140 - #endif 141 - 142 133 #ifdef CONFIG_FSL_PCI 143 134 extern int fsl_pci_mcheck_exception(struct pt_regs *); 144 135 #else
+33 -5
drivers/edac/mpc85xx_edac.c
··· 20 20 #include <linux/edac.h> 21 21 #include <linux/smp.h> 22 22 #include <linux/gfp.h> 23 + #include <linux/fsl/edac.h> 23 24 24 25 #include <linux/of_platform.h> 25 26 #include <linux/of_device.h> ··· 239 238 return IRQ_HANDLED; 240 239 } 241 240 242 - int mpc85xx_pci_err_probe(struct platform_device *op) 241 + static int mpc85xx_pci_err_probe(struct platform_device *op) 243 242 { 244 243 struct edac_pci_ctl_info *pci; 245 244 struct mpc85xx_pci_pdata *pdata; 245 + struct mpc85xx_edac_pci_plat_data *plat_data; 246 + struct device_node *of_node; 246 247 struct resource r; 247 248 int res = 0; 248 249 ··· 269 266 pdata->name = "mpc85xx_pci_err"; 270 267 pdata->irq = NO_IRQ; 271 268 272 - if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0) 269 + plat_data = op->dev.platform_data; 270 + if (!plat_data) { 271 + dev_err(&op->dev, "no platform data"); 272 + res = -ENXIO; 273 + goto err; 274 + } 275 + of_node = plat_data->of_node; 276 + 277 + if (mpc85xx_pcie_find_capability(of_node) > 0) 273 278 pdata->is_pcie = true; 274 279 275 280 dev_set_drvdata(&op->dev, pci); ··· 295 284 296 285 pdata->edac_idx = edac_pci_idx++; 297 286 298 - res = of_address_to_resource(op->dev.of_node, 0, &r); 287 + res = of_address_to_resource(of_node, 0, &r); 299 288 if (res) { 300 289 printk(KERN_ERR "%s: Unable to get resource for " 301 290 "PCI err regs\n", __func__); ··· 350 339 } 351 340 352 341 if (edac_op_state == EDAC_OPSTATE_INT) { 353 - pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); 342 + pdata->irq = irq_of_parse_and_map(of_node, 0); 354 343 res = devm_request_irq(&op->dev, pdata->irq, 355 344 mpc85xx_pci_isr, 356 345 IRQF_SHARED, ··· 397 386 devres_release_group(&op->dev, mpc85xx_pci_err_probe); 398 387 return res; 399 388 } 400 - EXPORT_SYMBOL(mpc85xx_pci_err_probe); 401 389 390 + static const struct platform_device_id mpc85xx_pci_err_match[] = { 391 + { 392 + .name = "mpc85xx-pci-edac" 393 + }, 394 + {} 395 + }; 396 + 397 + static struct platform_driver mpc85xx_pci_err_driver = { 398 + .probe = mpc85xx_pci_err_probe, 399 + .id_table = mpc85xx_pci_err_match, 400 + .driver = { 401 + .name = "mpc85xx_pci_err", 402 + .suppress_bind_attrs = true, 403 + }, 404 + }; 402 405 #endif /* CONFIG_PCI */ 403 406 404 407 /**************************** L2 Err device ***************************/ ··· 1236 1211 static struct platform_driver * const drivers[] = { 1237 1212 &mpc85xx_mc_err_driver, 1238 1213 &mpc85xx_l2_err_driver, 1214 + #ifdef CONFIG_PCI 1215 + &mpc85xx_pci_err_driver, 1216 + #endif 1239 1217 }; 1240 1218 1241 1219 static int __init mpc85xx_mc_init(void)
+8
include/linux/fsl/edac.h
··· 1 + #ifndef FSL_EDAC_H 2 + #define FSL_EDAC_H 3 + 4 + struct mpc85xx_edac_pci_plat_data { 5 + struct device_node *of_node; 6 + }; 7 + 8 + #endif