linux/drivers/edac/octeon_edac-l2c.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2012 Cavium, Inc.
   7 *
   8 * Copyright (C) 2009 Wind River Systems,
   9 *   written by Ralf Baechle <ralf@linux-mips.org>
  10 */
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/slab.h>
  14#include <linux/io.h>
  15#include <linux/edac.h>
  16
  17#include <asm/octeon/cvmx.h>
  18
  19#include "edac_core.h"
  20#include "edac_module.h"
  21
  22#define EDAC_MOD_STR "octeon-l2c"
  23
  24static void octeon_l2c_poll_oct1(struct edac_device_ctl_info *l2c)
  25{
  26        union cvmx_l2t_err l2t_err, l2t_err_reset;
  27        union cvmx_l2d_err l2d_err, l2d_err_reset;
  28
  29        l2t_err_reset.u64 = 0;
  30        l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
  31        if (l2t_err.s.sec_err) {
  32                edac_device_handle_ce(l2c, 0, 0,
  33                                      "Tag Single bit error (corrected)");
  34                l2t_err_reset.s.sec_err = 1;
  35        }
  36        if (l2t_err.s.ded_err) {
  37                edac_device_handle_ue(l2c, 0, 0,
  38                                      "Tag Double bit error (detected)");
  39                l2t_err_reset.s.ded_err = 1;
  40        }
  41        if (l2t_err_reset.u64)
  42                cvmx_write_csr(CVMX_L2T_ERR, l2t_err_reset.u64);
  43
  44        l2d_err_reset.u64 = 0;
  45        l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR);
  46        if (l2d_err.s.sec_err) {
  47                edac_device_handle_ce(l2c, 0, 1,
  48                                      "Data Single bit error (corrected)");
  49                l2d_err_reset.s.sec_err = 1;
  50        }
  51        if (l2d_err.s.ded_err) {
  52                edac_device_handle_ue(l2c, 0, 1,
  53                                      "Data Double bit error (detected)");
  54                l2d_err_reset.s.ded_err = 1;
  55        }
  56        if (l2d_err_reset.u64)
  57                cvmx_write_csr(CVMX_L2D_ERR, l2d_err_reset.u64);
  58
  59}
  60
  61static void _octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c, int tad)
  62{
  63        union cvmx_l2c_err_tdtx err_tdtx, err_tdtx_reset;
  64        union cvmx_l2c_err_ttgx err_ttgx, err_ttgx_reset;
  65        char buf1[64];
  66        char buf2[80];
  67
  68        err_tdtx_reset.u64 = 0;
  69        err_tdtx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TDTX(tad));
  70        if (err_tdtx.s.dbe || err_tdtx.s.sbe ||
  71            err_tdtx.s.vdbe || err_tdtx.s.vsbe)
  72                snprintf(buf1, sizeof(buf1),
  73                         "type:%d, syn:0x%x, way:%d",
  74                         err_tdtx.s.type, err_tdtx.s.syn, err_tdtx.s.wayidx);
  75
  76        if (err_tdtx.s.dbe) {
  77                snprintf(buf2, sizeof(buf2),
  78                         "L2D Double bit error (detected):%s", buf1);
  79                err_tdtx_reset.s.dbe = 1;
  80                edac_device_handle_ue(l2c, tad, 1, buf2);
  81        }
  82        if (err_tdtx.s.sbe) {
  83                snprintf(buf2, sizeof(buf2),
  84                         "L2D Single bit error (corrected):%s", buf1);
  85                err_tdtx_reset.s.sbe = 1;
  86                edac_device_handle_ce(l2c, tad, 1, buf2);
  87        }
  88        if (err_tdtx.s.vdbe) {
  89                snprintf(buf2, sizeof(buf2),
  90                         "VBF Double bit error (detected):%s", buf1);
  91                err_tdtx_reset.s.vdbe = 1;
  92                edac_device_handle_ue(l2c, tad, 1, buf2);
  93        }
  94        if (err_tdtx.s.vsbe) {
  95                snprintf(buf2, sizeof(buf2),
  96                         "VBF Single bit error (corrected):%s", buf1);
  97                err_tdtx_reset.s.vsbe = 1;
  98                edac_device_handle_ce(l2c, tad, 1, buf2);
  99        }
 100        if (err_tdtx_reset.u64)
 101                cvmx_write_csr(CVMX_L2C_ERR_TDTX(tad), err_tdtx_reset.u64);
 102
 103        err_ttgx_reset.u64 = 0;
 104        err_ttgx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TTGX(tad));
 105
 106        if (err_ttgx.s.dbe || err_ttgx.s.sbe)
 107                snprintf(buf1, sizeof(buf1),
 108                         "type:%d, syn:0x%x, way:%d",
 109                         err_ttgx.s.type, err_ttgx.s.syn, err_ttgx.s.wayidx);
 110
 111        if (err_ttgx.s.dbe) {
 112                snprintf(buf2, sizeof(buf2),
 113                         "Tag Double bit error (detected):%s", buf1);
 114                err_ttgx_reset.s.dbe = 1;
 115                edac_device_handle_ue(l2c, tad, 0, buf2);
 116        }
 117        if (err_ttgx.s.sbe) {
 118                snprintf(buf2, sizeof(buf2),
 119                         "Tag Single bit error (corrected):%s", buf1);
 120                err_ttgx_reset.s.sbe = 1;
 121                edac_device_handle_ce(l2c, tad, 0, buf2);
 122        }
 123        if (err_ttgx_reset.u64)
 124                cvmx_write_csr(CVMX_L2C_ERR_TTGX(tad), err_ttgx_reset.u64);
 125}
 126
 127static void octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c)
 128{
 129        int i;
 130        for (i = 0; i < l2c->nr_instances; i++)
 131                _octeon_l2c_poll_oct2(l2c, i);
 132}
 133
 134static int octeon_l2c_probe(struct platform_device *pdev)
 135{
 136        struct edac_device_ctl_info *l2c;
 137
 138        int num_tads = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 1;
 139
 140        /* 'Tags' are block 0, 'Data' is block 1*/
 141        l2c = edac_device_alloc_ctl_info(0, "l2c", num_tads, "l2c", 2, 0,
 142                                         NULL, 0, edac_device_alloc_index());
 143        if (!l2c)
 144                return -ENOMEM;
 145
 146        l2c->dev = &pdev->dev;
 147        platform_set_drvdata(pdev, l2c);
 148        l2c->dev_name = dev_name(&pdev->dev);
 149
 150        l2c->mod_name = "octeon-l2c";
 151        l2c->ctl_name = "octeon_l2c_err";
 152
 153
 154        if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) {
 155                union cvmx_l2t_err l2t_err;
 156                union cvmx_l2d_err l2d_err;
 157
 158                l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
 159                l2t_err.s.sec_intena = 0;       /* We poll */
 160                l2t_err.s.ded_intena = 0;
 161                cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
 162
 163                l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR);
 164                l2d_err.s.sec_intena = 0;       /* We poll */
 165                l2d_err.s.ded_intena = 0;
 166                cvmx_write_csr(CVMX_L2T_ERR, l2d_err.u64);
 167
 168                l2c->edac_check = octeon_l2c_poll_oct1;
 169        } else {
 170                /* OCTEON II */
 171                l2c->edac_check = octeon_l2c_poll_oct2;
 172        }
 173
 174        if (edac_device_add_device(l2c) > 0) {
 175                pr_err("%s: edac_device_add_device() failed\n", __func__);
 176                goto err;
 177        }
 178
 179
 180        return 0;
 181
 182err:
 183        edac_device_free_ctl_info(l2c);
 184
 185        return -ENXIO;
 186}
 187
 188static int octeon_l2c_remove(struct platform_device *pdev)
 189{
 190        struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev);
 191
 192        edac_device_del_device(&pdev->dev);
 193        edac_device_free_ctl_info(l2c);
 194
 195        return 0;
 196}
 197
 198static struct platform_driver octeon_l2c_driver = {
 199        .probe = octeon_l2c_probe,
 200        .remove = octeon_l2c_remove,
 201        .driver = {
 202                   .name = "octeon_l2c_edac",
 203        }
 204};
 205module_platform_driver(octeon_l2c_driver);
 206
 207MODULE_LICENSE("GPL");
 208MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
 209