diff options
author | Scott Wood <scottwood@freescale.com> | 2015-12-10 14:07:12 -0500 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2015-12-11 10:56:16 -0500 |
commit | 666db563d3d9fffcfc019e3d1a980dac47601a71 (patch) | |
tree | 5494f13ab4f6be3e060b8bd29ca8b8e2c2002852 | |
parent | d0cdf9003140e9b40d2488aaee2838babe7e212c (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.c | 28 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.h | 9 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 38 | ||||
-rw-r--r-- | include/linux/fsl/edac.h | 8 |
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 | ||
1260 | static 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 | |||
1258 | static int fsl_pci_probe(struct platform_device *pdev) | 1279 | static 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); | |||
130 | static inline void fsl_pci_assign_primary(void) {} | 130 | static inline void fsl_pci_assign_primary(void) {} |
131 | #endif | 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 | #ifdef CONFIG_FSL_PCI | 133 | #ifdef CONFIG_FSL_PCI |
143 | extern int fsl_pci_mcheck_exception(struct pt_regs *); | 134 | extern 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 | ||
241 | int mpc85xx_pci_err_probe(struct platform_device *op) | 242 | static 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 | } |
389 | EXPORT_SYMBOL(mpc85xx_pci_err_probe); | ||
390 | 400 | ||
401 | static const struct platform_device_id mpc85xx_pci_err_match[] = { | ||
402 | { | ||
403 | .name = "mpc85xx-pci-edac" | ||
404 | }, | ||
405 | {} | ||
406 | }; | ||
407 | |||
408 | static 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) | |||
1211 | static struct platform_driver * const drivers[] = { | 1236 | static 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 | ||
1216 | static int __init mpc85xx_mc_init(void) | 1244 | static 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 | |||
4 | struct mpc85xx_edac_pci_plat_data { | ||
5 | struct device_node *of_node; | ||
6 | }; | ||
7 | |||
8 | #endif | ||