File Index
Files and directories
Sign in
FILE

sifive_edac.c

File preview with syntax highlighting.

linux-6.19.14/drivers/edac/sifive_edac.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * SiFive Platform EDAC Driver
  4 *
  5 * Copyright (C) 2018-2022 SiFive, Inc.
  6 *
  7 * This driver is partially based on octeon_edac-pc.c
  8 *
  9 */
 10#include <linux/edac.h>
 11#include <linux/platform_device.h>
 12#include "edac_module.h"
 13#include <soc/sifive/sifive_ccache.h>
 14
 15#define DRVNAME "sifive_edac"
 16
 17struct sifive_edac_priv {
 18	struct notifier_block notifier;
 19	struct edac_device_ctl_info *dci;
 20};
 21
 22/*
 23 * EDAC error callback
 24 *
 25 * @event: non-zero if unrecoverable.
 26 */
 27static
 28int ecc_err_event(struct notifier_block *this, unsigned long event, void *ptr)
 29{
 30	const char *msg = (char *)ptr;
 31	struct sifive_edac_priv *p;
 32
 33	p = container_of(this, struct sifive_edac_priv, notifier);
 34
 35	if (event == SIFIVE_CCACHE_ERR_TYPE_UE)
 36		edac_device_handle_ue(p->dci, 0, 0, msg);
 37	else if (event == SIFIVE_CCACHE_ERR_TYPE_CE)
 38		edac_device_handle_ce(p->dci, 0, 0, msg);
 39
 40	return NOTIFY_OK;
 41}
 42
 43static int ecc_register(struct platform_device *pdev)
 44{
 45	struct sifive_edac_priv *p;
 46
 47	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
 48	if (!p)
 49		return -ENOMEM;
 50
 51	p->notifier.notifier_call = ecc_err_event;
 52	platform_set_drvdata(pdev, p);
 53
 54	p->dci = edac_device_alloc_ctl_info(0, "sifive_ecc", 1, "sifive_ecc",
 55					    1, 1, edac_device_alloc_index());
 56	if (!p->dci)
 57		return -ENOMEM;
 58
 59	p->dci->dev = &pdev->dev;
 60	p->dci->mod_name = "Sifive ECC Manager";
 61	p->dci->ctl_name = dev_name(&pdev->dev);
 62	p->dci->dev_name = dev_name(&pdev->dev);
 63
 64	if (edac_device_add_device(p->dci)) {
 65		dev_err(p->dci->dev, "failed to register with EDAC core\n");
 66		goto err;
 67	}
 68
 69	register_sifive_ccache_error_notifier(&p->notifier);
 70
 71	return 0;
 72
 73err:
 74	edac_device_free_ctl_info(p->dci);
 75
 76	return -ENXIO;
 77}
 78
 79static int ecc_unregister(struct platform_device *pdev)
 80{
 81	struct sifive_edac_priv *p = platform_get_drvdata(pdev);
 82
 83	unregister_sifive_ccache_error_notifier(&p->notifier);
 84	edac_device_del_device(&pdev->dev);
 85	edac_device_free_ctl_info(p->dci);
 86
 87	return 0;
 88}
 89
 90static struct platform_device *sifive_pdev;
 91
 92static int __init sifive_edac_init(void)
 93{
 94	int ret;
 95
 96	sifive_pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0);
 97	if (IS_ERR(sifive_pdev))
 98		return PTR_ERR(sifive_pdev);
 99
100	ret = ecc_register(sifive_pdev);
101	if (ret)
102		platform_device_unregister(sifive_pdev);
103
104	return ret;
105}
106
107static void __exit sifive_edac_exit(void)
108{
109	ecc_unregister(sifive_pdev);
110	platform_device_unregister(sifive_pdev);
111}
112
113module_init(sifive_edac_init);
114module_exit(sifive_edac_exit);
115
116MODULE_AUTHOR("SiFive Inc.");
117MODULE_DESCRIPTION("SiFive platform EDAC driver");
118MODULE_LICENSE("GPL v2");
~/ Read-only file preview.