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 }, 203 .probe = tile_edac_mc_probe, 204 .remove = tile_edac_mc_remove, 205}; 206 207/* 208 * Driver init routine. 209 */ 210static int __init tile_edac_init(void) 211{ 212 char hv_file[32]; 213 struct platform_device *pdev; 214 int i, err, num = 0; 215 216 /* Only support POLL mode. */ 217 edac_op_state = EDAC_OPSTATE_POLL; 218 219 err = platform_driver_register(&tile_edac_mc_driver); 220 if (err) 221 return err; 222 223 for (i = 0; i < TILE_MAX_MSHIMS; i++) { 224 /* 225 * Not all memory controllers are configured such as in the 226 * case of a simulator. So we register only those mshims 227 * that are configured by the hypervisor. 228 */ 229 sprintf(hv_file, "mshim/%d", i); 230 if (hv_dev_open((HV_VirtAddr)hv_file, 0) < 0) 231 continue; 232 233 pdev = platform_device_register_simple(DRV_NAME, i, NULL, 0); 234 if (IS_ERR(pdev)) 235 continue; 236 mshim_pdev[i] = pdev; 237 num++; 238 } 239 240 if (num == 0) { 241 platform_driver_unregister(&tile_edac_mc_driver); 242 return -ENODEV; 243 } 244 return 0; 245} 246 247/* 248 * Driver cleanup routine. 249 */ 250static void __exit tile_edac_exit(void) 251{ 252 int i; 253 254 for (i = 0; i < TILE_MAX_MSHIMS; i++) { 255 struct platform_device *pdev = mshim_pdev[i]; 256 if (!pdev) 257 continue; 258 259 platform_device_unregister(pdev); 260 } 261 platform_driver_unregister(&tile_edac_mc_driver); 262} 263 264module_init(tile_edac_init); 265module_exit(tile_edac_exit); 266