brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 282ca65 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2011-2012 Calxeda, Inc.4 */5#include <linux/types.h>6#include <linux/kernel.h>7#include <linux/ctype.h>8#include <linux/edac.h>9#include <linux/interrupt.h>10#include <linux/of.h>11#include <linux/of_device.h>12#include <linux/platform_device.h>13 14#include "edac_module.h"15 16#define SR_CLR_SB_ECC_INTR	0x017#define SR_CLR_DB_ECC_INTR	0x418 19struct hb_l2_drvdata {20	void __iomem *base;21	int sb_irq;22	int db_irq;23};24 25static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)26{27	struct edac_device_ctl_info *dci = dev_id;28	struct hb_l2_drvdata *drvdata = dci->pvt_info;29 30	if (irq == drvdata->sb_irq) {31		writel(1, drvdata->base + SR_CLR_SB_ECC_INTR);32		edac_device_handle_ce(dci, 0, 0, dci->ctl_name);33	}34	if (irq == drvdata->db_irq) {35		writel(1, drvdata->base + SR_CLR_DB_ECC_INTR);36		edac_device_handle_ue(dci, 0, 0, dci->ctl_name);37	}38 39	return IRQ_HANDLED;40}41 42static const struct of_device_id hb_l2_err_of_match[] = {43	{ .compatible = "calxeda,hb-sregs-l2-ecc", },44	{},45};46MODULE_DEVICE_TABLE(of, hb_l2_err_of_match);47 48static int highbank_l2_err_probe(struct platform_device *pdev)49{50	const struct of_device_id *id;51	struct edac_device_ctl_info *dci;52	struct hb_l2_drvdata *drvdata;53	struct resource *r;54	int res = 0;55 56	dci = edac_device_alloc_ctl_info(sizeof(*drvdata), "cpu",57					 1, "L", 1, 2, 0);58	if (!dci)59		return -ENOMEM;60 61	drvdata = dci->pvt_info;62	dci->dev = &pdev->dev;63	platform_set_drvdata(pdev, dci);64 65	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))66		return -ENOMEM;67 68	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);69	if (!r) {70		dev_err(&pdev->dev, "Unable to get mem resource\n");71		res = -ENODEV;72		goto err;73	}74 75	if (!devm_request_mem_region(&pdev->dev, r->start,76				     resource_size(r), dev_name(&pdev->dev))) {77		dev_err(&pdev->dev, "Error while requesting mem region\n");78		res = -EBUSY;79		goto err;80	}81 82	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));83	if (!drvdata->base) {84		dev_err(&pdev->dev, "Unable to map regs\n");85		res = -ENOMEM;86		goto err;87	}88 89	id = of_match_device(hb_l2_err_of_match, &pdev->dev);90	dci->mod_name = pdev->dev.driver->name;91	dci->ctl_name = id ? id->compatible : "unknown";92	dci->dev_name = dev_name(&pdev->dev);93 94	if (edac_device_add_device(dci))95		goto err;96 97	drvdata->db_irq = platform_get_irq(pdev, 0);98	res = devm_request_irq(&pdev->dev, drvdata->db_irq,99			       highbank_l2_err_handler,100			       0, dev_name(&pdev->dev), dci);101	if (res < 0)102		goto err2;103 104	drvdata->sb_irq = platform_get_irq(pdev, 1);105	res = devm_request_irq(&pdev->dev, drvdata->sb_irq,106			       highbank_l2_err_handler,107			       0, dev_name(&pdev->dev), dci);108	if (res < 0)109		goto err2;110 111	devres_close_group(&pdev->dev, NULL);112	return 0;113err2:114	edac_device_del_device(&pdev->dev);115err:116	devres_release_group(&pdev->dev, NULL);117	edac_device_free_ctl_info(dci);118	return res;119}120 121static void highbank_l2_err_remove(struct platform_device *pdev)122{123	struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);124 125	edac_device_del_device(&pdev->dev);126	edac_device_free_ctl_info(dci);127}128 129static struct platform_driver highbank_l2_edac_driver = {130	.probe = highbank_l2_err_probe,131	.remove_new = highbank_l2_err_remove,132	.driver = {133		.name = "hb_l2_edac",134		.of_match_table = hb_l2_err_of_match,135	},136};137 138module_platform_driver(highbank_l2_edac_driver);139 140MODULE_LICENSE("GPL v2");141MODULE_AUTHOR("Calxeda, Inc.");142MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank L2 Cache");143