linux/drivers/edac/tile_edac.c
<<
>>
Prefs
   1/*
   2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 * Tilera-specific EDAC driver.
  14 *
  15 * This source code is derived from the following driver:
  16 *
  17 * Cell MIC driver for ECC counting
  18 *
  19 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
  20 *                <benh@kernel.crashing.org>
  21 *
  22 */
  23
  24#include <linux/module.h>
  25#include <linux/init.h>
  26#include <linux/platform_device.h>
  27#include <linux/io.h>
  28#include <linux/uaccess.h>
  29#include <linux/edac.h>
  30#include <hv/hypervisor.h>
  31#include <hv/drv_mshim_intf.h>
  32
  33#include "edac_core.h"
  34
  35#define DRV_NAME        "tile-edac"
  36
  37/* Number of cs_rows needed per memory controller on TILEPro. */
  38#define TILE_EDAC_NR_CSROWS     1
  39
  40/* Number of channels per memory controller on TILEPro. */
  41#define TILE_EDAC_NR_CHANS      1
  42
  43/* Granularity of reported error in bytes on TILEPro. */
  44#define TILE_EDAC_ERROR_GRAIN   8
  45
  46/* TILE processor has multiple independent memory controllers. */
  47struct platform_device *mshim_pdev[TILE_MAX_MSHIMS];
  48
  49struct tile_edac_priv {
  50        int             hv_devhdl;      /* Hypervisor device handle. */
  51        int             node;           /* Memory controller instance #. */
  52        unsigned int    ce_count;       /*
  53                                         * Correctable-error counter
  54                                         * kept by the driver.
  55                                         */
  56};
  57
  58static void tile_edac_check(struct mem_ctl_info *mci)
  59{
  60        struct tile_edac_priv   *priv = mci->pvt_info;
  61        struct mshim_mem_error  mem_error;
  62
  63        if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_error,
  64                sizeof(struct mshim_mem_error), MSHIM_MEM_ERROR_OFF) !=
  65                sizeof(struct mshim_mem_error)) {
  66                pr_err(DRV_NAME ": MSHIM_MEM_ERROR_OFF pread failure.\n");
  67                return;
  68        }
  69
  70        /* Check if the current error count is different from the saved one. */
  71        if (mem_error.sbe_count != priv->ce_count) {
  72                dev_dbg(mci->pdev, "ECC CE err on node %d\n", priv->node);
  73                priv->ce_count = mem_error.sbe_count;
  74                edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
  75                                     0, 0, 0,
  76                                     0, 0, -1,
  77                                     mci->ctl_name, "");
  78        }
  79}
  80
  81/*
  82 * Initialize the 'csrows' table within the mci control structure with the
  83 * addressing of memory.
  84 */
  85static int tile_edac_init_csrows(struct mem_ctl_info *mci)
  86{
  87        struct csrow_info       *csrow = mci->csrows[0];
  88        struct tile_edac_priv   *priv = mci->pvt_info;
  89        struct mshim_mem_info   mem_info;
  90        struct dimm_info *dimm = csrow->channels[0]->dimm;
  91
  92        if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
  93                sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
  94                sizeof(struct mshim_mem_info)) {
  95                pr_err(DRV_NAME ": MSHIM_MEM_INFO_OFF pread failure.\n");
  96                return -1;
  97        }
  98
  99        if (mem_info.mem_ecc)
 100                dimm->edac_mode = EDAC_SECDED;
 101        else
 102                dimm->edac_mode = EDAC_NONE;
 103        switch (mem_info.mem_type) {
 104        case DDR2:
 105                dimm->mtype = MEM_DDR2;
 106                break;
 107
 108        case DDR3:
 109                dimm->mtype = MEM_DDR3;
 110                break;
 111
 112        default:
 113                return -1;
 114        }
 115
 116        dimm->nr_pages = mem_info.mem_size >> PAGE_SHIFT;
 117        dimm->grain = TILE_EDAC_ERROR_GRAIN;
 118        dimm->dtype = DEV_UNKNOWN;
 119
 120        return 0;
 121}
 122
 123static int tile_edac_mc_probe(struct platform_device *pdev)
 124{
 125        char                    hv_file[32];
 126        int                     hv_devhdl;
 127        struct mem_ctl_info     *mci;
 128        struct edac_mc_layer    layers[2];
 129        struct tile_edac_priv   *priv;
 130        int                     rc;
 131
 132        sprintf(hv_file, "mshim/%d", pdev->id);
 133        hv_devhdl = hv_dev_open((HV_VirtAddr)hv_file, 0);
 134        if (hv_devhdl < 0)
 135                return -EINVAL;
 136
 137        /* A TILE MC has a single channel and one chip-select row. */
 138        layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
 139        layers[0].size = TILE_EDAC_NR_CSROWS;
 140        layers[0].is_virt_csrow = true;
 141        layers[1].type = EDAC_MC_LAYER_CHANNEL;
 142        layers[1].size = TILE_EDAC_NR_CHANS;
 143        layers[1].is_virt_csrow = false;
 144        mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers,
 145                            sizeof(struct tile_edac_priv));
 146        if (mci == NULL)
 147                return -ENOMEM;
 148        priv = mci->pvt_info;
 149        priv->node = pdev->id;
 150        priv->hv_devhdl = hv_devhdl;
 151
 152        mci->pdev = &pdev->dev;
 153        mci->mtype_cap = MEM_FLAG_DDR2;
 154        mci->edac_ctl_cap = EDAC_FLAG_SECDED;
 155
 156        mci->mod_name = DRV_NAME;
 157#ifdef __tilegx__
 158        mci->ctl_name = "TILEGx_Memory_Controller";
 159#else
 160        mci->ctl_name = "TILEPro_Memory_Controller";
 161#endif
 162        mci->dev_name = dev_name(&pdev->dev);
 163        mci->edac_check = tile_edac_check;
 164
 165        /*
 166         * Initialize the MC control structure 'csrows' table
 167         * with the mapping and control information.
 168         */
 169        if (tile_edac_init_csrows(mci)) {
 170                /* No csrows found. */
 171                mci->edac_cap = EDAC_FLAG_NONE;
 172        } else {
 173                mci->edac_cap = EDAC_FLAG_SECDED;
 174        }
 175
 176        platform_set_drvdata(pdev, mci);
 177
 178        /* Register with EDAC core */
 179        rc = edac_mc_add_mc(mci);
 180        if (rc) {
 181                dev_err(&pdev->dev, "failed to register with EDAC core\n");
 182                edac_mc_free(mci);
 183                return rc;
 184        }
 185
 186        return 0;
 187}
 188
 189static int tile_edac_mc_remove(struct platform_device *pdev)
 190{
 191        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
 192
 193        edac_mc_del_mc(&pdev->dev);
 194        if (mci)
 195                edac_mc_free(mci);
 196        return 0;
 197}
 198
 199static struct platform_driver tile_edac_mc_driver = {
 200        .driver         = {
 201                .name   = DRV_NAME,
 202                .owner  = THIS_MODULE,
 203        },
 204        .probe          = tile_edac_mc_probe,
 205        .remove         = tile_edac_mc_remove,
 206};
 207
 208/*
 209 * Driver init routine.
 210 */
 211static int __init tile_edac_init(void)
 212{
 213        char    hv_file[32];
 214        struct platform_device *pdev;
 215        int i, err, num = 0;
 216
 217        /* Only support POLL mode. */
 218        edac_op_state = EDAC_OPSTATE_POLL;
 219
 220        err = platform_driver_register(&tile_edac_mc_driver);
 221        if (err)
 222                return err;
 223
 224        for (i = 0; i < TILE_MAX_MSHIMS; i++) {
 225                /*
 226                 * Not all memory controllers are configured such as in the
 227                 * case of a simulator. So we register only those mshims
 228                 * that are configured by the hypervisor.
 229                 */
 230                sprintf(hv_file, "mshim/%d", i);
 231                if (hv_dev_open((HV_VirtAddr)hv_file, 0) < 0)
 232                        continue;
 233
 234                pdev = platform_device_register_simple(DRV_NAME, i, NULL, 0);
 235                if (IS_ERR(pdev))
 236                        continue;
 237                mshim_pdev[i] = pdev;
 238                num++;
 239        }
 240
 241        if (num == 0) {
 242                platform_driver_unregister(&tile_edac_mc_driver);
 243                return -ENODEV;
 244        }
 245        return 0;
 246}
 247
 248/*
 249 * Driver cleanup routine.
 250 */
 251static void __exit tile_edac_exit(void)
 252{
 253        int i;
 254
 255        for (i = 0; i < TILE_MAX_MSHIMS; i++) {
 256                struct platform_device *pdev = mshim_pdev[i];
 257                if (!pdev)
 258                        continue;
 259
 260                platform_set_drvdata(pdev, NULL);
 261                platform_device_unregister(pdev);
 262        }
 263        platform_driver_unregister(&tile_edac_mc_driver);
 264}
 265
 266module_init(tile_edac_init);
 267module_exit(tile_edac_exit);
 268
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.