cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sifive_edac.c (2586B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * SiFive Platform EDAC Driver
      4 *
      5 * Copyright (C) 2018-2019 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_l2_cache.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_L2_ERR_TYPE_UE)
     36		edac_device_handle_ue(p->dci, 0, 0, msg);
     37	else if (event == SIFIVE_L2_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, NULL, 0,
     56					    edac_device_alloc_index());
     57	if (!p->dci)
     58		return -ENOMEM;
     59
     60	p->dci->dev = &pdev->dev;
     61	p->dci->mod_name = "Sifive ECC Manager";
     62	p->dci->ctl_name = dev_name(&pdev->dev);
     63	p->dci->dev_name = dev_name(&pdev->dev);
     64
     65	if (edac_device_add_device(p->dci)) {
     66		dev_err(p->dci->dev, "failed to register with EDAC core\n");
     67		goto err;
     68	}
     69
     70	register_sifive_l2_error_notifier(&p->notifier);
     71
     72	return 0;
     73
     74err:
     75	edac_device_free_ctl_info(p->dci);
     76
     77	return -ENXIO;
     78}
     79
     80static int ecc_unregister(struct platform_device *pdev)
     81{
     82	struct sifive_edac_priv *p = platform_get_drvdata(pdev);
     83
     84	unregister_sifive_l2_error_notifier(&p->notifier);
     85	edac_device_del_device(&pdev->dev);
     86	edac_device_free_ctl_info(p->dci);
     87
     88	return 0;
     89}
     90
     91static struct platform_device *sifive_pdev;
     92
     93static int __init sifive_edac_init(void)
     94{
     95	int ret;
     96
     97	sifive_pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0);
     98	if (IS_ERR(sifive_pdev))
     99		return PTR_ERR(sifive_pdev);
    100
    101	ret = ecc_register(sifive_pdev);
    102	if (ret)
    103		platform_device_unregister(sifive_pdev);
    104
    105	return ret;
    106}
    107
    108static void __exit sifive_edac_exit(void)
    109{
    110	ecc_unregister(sifive_pdev);
    111	platform_device_unregister(sifive_pdev);
    112}
    113
    114module_init(sifive_edac_init);
    115module_exit(sifive_edac_exit);
    116
    117MODULE_AUTHOR("SiFive Inc.");
    118MODULE_DESCRIPTION("SiFive platform EDAC driver");
    119MODULE_LICENSE("GPL v2");