xref: /linux/drivers/edac/highbank_l2_edac.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
269154d06SRob Herring /*
369154d06SRob Herring  * Copyright 2011-2012 Calxeda, Inc.
469154d06SRob Herring  */
569154d06SRob Herring #include <linux/types.h>
669154d06SRob Herring #include <linux/kernel.h>
769154d06SRob Herring #include <linux/ctype.h>
869154d06SRob Herring #include <linux/edac.h>
969154d06SRob Herring #include <linux/interrupt.h>
10408d8088SRob Herring #include <linux/of.h>
11408d8088SRob Herring #include <linux/of_device.h>
1269154d06SRob Herring #include <linux/platform_device.h>
1369154d06SRob Herring 
1469154d06SRob Herring #include "edac_module.h"
1569154d06SRob Herring 
1669154d06SRob Herring #define SR_CLR_SB_ECC_INTR	0x0
1769154d06SRob Herring #define SR_CLR_DB_ECC_INTR	0x4
1869154d06SRob Herring 
1969154d06SRob Herring struct hb_l2_drvdata {
2069154d06SRob Herring 	void __iomem *base;
2169154d06SRob Herring 	int sb_irq;
2269154d06SRob Herring 	int db_irq;
2369154d06SRob Herring };
2469154d06SRob Herring 
highbank_l2_err_handler(int irq,void * dev_id)2569154d06SRob Herring static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)
2669154d06SRob Herring {
2769154d06SRob Herring 	struct edac_device_ctl_info *dci = dev_id;
2869154d06SRob Herring 	struct hb_l2_drvdata *drvdata = dci->pvt_info;
2969154d06SRob Herring 
3069154d06SRob Herring 	if (irq == drvdata->sb_irq) {
3169154d06SRob Herring 		writel(1, drvdata->base + SR_CLR_SB_ECC_INTR);
3269154d06SRob Herring 		edac_device_handle_ce(dci, 0, 0, dci->ctl_name);
3369154d06SRob Herring 	}
3469154d06SRob Herring 	if (irq == drvdata->db_irq) {
3569154d06SRob Herring 		writel(1, drvdata->base + SR_CLR_DB_ECC_INTR);
3669154d06SRob Herring 		edac_device_handle_ue(dci, 0, 0, dci->ctl_name);
3769154d06SRob Herring 	}
3869154d06SRob Herring 
3969154d06SRob Herring 	return IRQ_HANDLED;
4069154d06SRob Herring }
4169154d06SRob Herring 
4241ec0e8dSRobert Richter static const struct of_device_id hb_l2_err_of_match[] = {
4341ec0e8dSRobert Richter 	{ .compatible = "calxeda,hb-sregs-l2-ecc", },
4441ec0e8dSRobert Richter 	{},
4541ec0e8dSRobert Richter };
4641ec0e8dSRobert Richter MODULE_DEVICE_TABLE(of, hb_l2_err_of_match);
4741ec0e8dSRobert Richter 
highbank_l2_err_probe(struct platform_device * pdev)489b3c6e85SGreg Kroah-Hartman static int highbank_l2_err_probe(struct platform_device *pdev)
4969154d06SRob Herring {
5041ec0e8dSRobert Richter 	const struct of_device_id *id;
5169154d06SRob Herring 	struct edac_device_ctl_info *dci;
5269154d06SRob Herring 	struct hb_l2_drvdata *drvdata;
5369154d06SRob Herring 	struct resource *r;
5469154d06SRob Herring 	int res = 0;
5569154d06SRob Herring 
5669154d06SRob Herring 	dci = edac_device_alloc_ctl_info(sizeof(*drvdata), "cpu",
57*48bc8869SJiri Slaby (SUSE) 					 1, "L", 1, 2, 0);
5869154d06SRob Herring 	if (!dci)
5969154d06SRob Herring 		return -ENOMEM;
6069154d06SRob Herring 
6169154d06SRob Herring 	drvdata = dci->pvt_info;
6269154d06SRob Herring 	dci->dev = &pdev->dev;
6369154d06SRob Herring 	platform_set_drvdata(pdev, dci);
6469154d06SRob Herring 
6569154d06SRob Herring 	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
6669154d06SRob Herring 		return -ENOMEM;
6769154d06SRob Herring 
6869154d06SRob Herring 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6969154d06SRob Herring 	if (!r) {
7069154d06SRob Herring 		dev_err(&pdev->dev, "Unable to get mem resource\n");
7169154d06SRob Herring 		res = -ENODEV;
7269154d06SRob Herring 		goto err;
7369154d06SRob Herring 	}
7469154d06SRob Herring 
7569154d06SRob Herring 	if (!devm_request_mem_region(&pdev->dev, r->start,
7669154d06SRob Herring 				     resource_size(r), dev_name(&pdev->dev))) {
7769154d06SRob Herring 		dev_err(&pdev->dev, "Error while requesting mem region\n");
7869154d06SRob Herring 		res = -EBUSY;
7969154d06SRob Herring 		goto err;
8069154d06SRob Herring 	}
8169154d06SRob Herring 
8269154d06SRob Herring 	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
8369154d06SRob Herring 	if (!drvdata->base) {
8469154d06SRob Herring 		dev_err(&pdev->dev, "Unable to map regs\n");
8569154d06SRob Herring 		res = -ENOMEM;
8669154d06SRob Herring 		goto err;
8769154d06SRob Herring 	}
8869154d06SRob Herring 
8941ec0e8dSRobert Richter 	id = of_match_device(hb_l2_err_of_match, &pdev->dev);
9041ec0e8dSRobert Richter 	dci->mod_name = pdev->dev.driver->name;
9141ec0e8dSRobert Richter 	dci->ctl_name = id ? id->compatible : "unknown";
9269154d06SRob Herring 	dci->dev_name = dev_name(&pdev->dev);
9369154d06SRob Herring 
9469154d06SRob Herring 	if (edac_device_add_device(dci))
9569154d06SRob Herring 		goto err;
9669154d06SRob Herring 
97a72b8859SRobert Richter 	drvdata->db_irq = platform_get_irq(pdev, 0);
98a72b8859SRobert Richter 	res = devm_request_irq(&pdev->dev, drvdata->db_irq,
99a72b8859SRobert Richter 			       highbank_l2_err_handler,
100a72b8859SRobert Richter 			       0, dev_name(&pdev->dev), dci);
101a72b8859SRobert Richter 	if (res < 0)
102a72b8859SRobert Richter 		goto err2;
103a72b8859SRobert Richter 
104a72b8859SRobert Richter 	drvdata->sb_irq = platform_get_irq(pdev, 1);
105a72b8859SRobert Richter 	res = devm_request_irq(&pdev->dev, drvdata->sb_irq,
106a72b8859SRobert Richter 			       highbank_l2_err_handler,
107a72b8859SRobert Richter 			       0, dev_name(&pdev->dev), dci);
108a72b8859SRobert Richter 	if (res < 0)
109a72b8859SRobert Richter 		goto err2;
110a72b8859SRobert Richter 
11169154d06SRob Herring 	devres_close_group(&pdev->dev, NULL);
11269154d06SRob Herring 	return 0;
113a72b8859SRobert Richter err2:
114a72b8859SRobert Richter 	edac_device_del_device(&pdev->dev);
11569154d06SRob Herring err:
11669154d06SRob Herring 	devres_release_group(&pdev->dev, NULL);
11769154d06SRob Herring 	edac_device_free_ctl_info(dci);
11869154d06SRob Herring 	return res;
11969154d06SRob Herring }
12069154d06SRob Herring 
highbank_l2_err_remove(struct platform_device * pdev)1217aca2e9bSUwe Kleine-König static void highbank_l2_err_remove(struct platform_device *pdev)
12269154d06SRob Herring {
12369154d06SRob Herring 	struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
12469154d06SRob Herring 
12569154d06SRob Herring 	edac_device_del_device(&pdev->dev);
12669154d06SRob Herring 	edac_device_free_ctl_info(dci);
12769154d06SRob Herring }
12869154d06SRob Herring 
12969154d06SRob Herring static struct platform_driver highbank_l2_edac_driver = {
13069154d06SRob Herring 	.probe = highbank_l2_err_probe,
1317aca2e9bSUwe Kleine-König 	.remove_new = highbank_l2_err_remove,
13269154d06SRob Herring 	.driver = {
13369154d06SRob Herring 		.name = "hb_l2_edac",
13469154d06SRob Herring 		.of_match_table = hb_l2_err_of_match,
13569154d06SRob Herring 	},
13669154d06SRob Herring };
13769154d06SRob Herring 
13869154d06SRob Herring module_platform_driver(highbank_l2_edac_driver);
13969154d06SRob Herring 
14069154d06SRob Herring MODULE_LICENSE("GPL v2");
14169154d06SRob Herring MODULE_AUTHOR("Calxeda, Inc.");
14269154d06SRob Herring MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank L2 Cache");
143