Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.14-rc4 266 lines 6.6 kB view raw
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_device_unregister(pdev); 261 } 262 platform_driver_unregister(&tile_edac_mc_driver); 263} 264 265module_init(tile_edac_init); 266module_exit(tile_edac_exit);