root/drivers/edac/sifive_edac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ecc_err_event
  2. ecc_register
  3. ecc_unregister
  4. sifive_edac_init
  5. sifive_edac_exit

   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 <asm/sifive_l2_cache.h>
  14 
  15 #define DRVNAME "sifive_edac"
  16 
  17 struct 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  */
  27 static
  28 int 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 
  43 static 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 
  74 err:
  75         edac_device_free_ctl_info(p->dci);
  76 
  77         return -ENXIO;
  78 }
  79 
  80 static 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 
  91 static struct platform_device *sifive_pdev;
  92 
  93 static 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 
 108 static void __exit sifive_edac_exit(void)
 109 {
 110         ecc_unregister(sifive_pdev);
 111         platform_device_unregister(sifive_pdev);
 112 }
 113 
 114 module_init(sifive_edac_init);
 115 module_exit(sifive_edac_exit);
 116 
 117 MODULE_AUTHOR("SiFive Inc.");
 118 MODULE_DESCRIPTION("SiFive platform EDAC driver");
 119 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */