Blame view
drivers/edac/fsl_ddr_edac.c
15.4 KB
ea2eb9a8b EDAC, fsl-ddr: Se... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * Freescale Memory Controller kernel module * * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and * ARM-based Layerscape SoCs including LS2xxx. Originally split * out from mpc85xx_edac EDAC driver. * * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. * * Author: Dave Jiang <djiang@mvista.com> * * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. |
ea2eb9a8b EDAC, fsl-ddr: Se... |
16 17 18 19 20 21 22 23 24 25 26 27 28 |
*/ #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/ctype.h> #include <linux/io.h> #include <linux/mod_devicetable.h> #include <linux/edac.h> #include <linux/smp.h> #include <linux/gfp.h> #include <linux/of_platform.h> #include <linux/of_device.h> |
eeb3d68b6 EDAC, layerscape:... |
29 |
#include <linux/of_address.h> |
ea2eb9a8b EDAC, fsl-ddr: Se... |
30 |
#include "edac_module.h" |
ea2eb9a8b EDAC, fsl-ddr: Se... |
31 32 33 34 35 36 37 38 |
#include "fsl_ddr_edac.h" #define EDAC_MOD_STR "fsl_ddr_edac" static int edac_mc_idx; static u32 orig_ddr_err_disable; static u32 orig_ddr_err_sbe; |
339fdff14 EDAC, fsl_ddr: Ad... |
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
static bool little_endian; static inline u32 ddr_in32(void __iomem *addr) { return little_endian ? ioread32(addr) : ioread32be(addr); } static inline void ddr_out32(void __iomem *addr, u32 value) { if (little_endian) iowrite32(value, addr); else iowrite32be(value, addr); } |
ea2eb9a8b EDAC, fsl-ddr: Se... |
53 54 55 56 |
/************************ MC SYSFS parts ***********************************/ #define to_mci(k) container_of(k, struct mem_ctl_info, dev) |
d43a9fb20 EDAC, fsl_ddr: Re... |
57 58 59 |
static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, struct device_attribute *mattr, char *data) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
60 61 |
{ struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
62 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
63 |
return sprintf(data, "0x%08x", |
339fdff14 EDAC, fsl_ddr: Ad... |
64 |
ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI)); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
65 |
} |
d43a9fb20 EDAC, fsl_ddr: Re... |
66 67 |
static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, struct device_attribute *mattr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
68 69 70 |
char *data) { struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
71 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
72 |
return sprintf(data, "0x%08x", |
339fdff14 EDAC, fsl_ddr: Ad... |
73 |
ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO)); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
74 |
} |
d43a9fb20 EDAC, fsl_ddr: Re... |
75 76 |
static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, struct device_attribute *mattr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
77 78 79 |
char *data) { struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
80 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
81 |
return sprintf(data, "0x%08x", |
339fdff14 EDAC, fsl_ddr: Ad... |
82 |
ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
83 |
} |
d43a9fb20 EDAC, fsl_ddr: Re... |
84 85 |
static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, struct device_attribute *mattr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
86 87 88 |
const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
89 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
f47ae798d EDAC, fsl_ddr: Re... |
90 91 |
unsigned long val; int rc; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
92 |
if (isdigit(*data)) { |
f47ae798d EDAC, fsl_ddr: Re... |
93 94 95 96 97 |
rc = kstrtoul(data, 0, &val); if (rc) return rc; ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, val); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
98 99 100 101 |
return count; } return 0; } |
d43a9fb20 EDAC, fsl_ddr: Re... |
102 103 |
static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, struct device_attribute *mattr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
104 105 106 |
const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
107 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
f47ae798d EDAC, fsl_ddr: Re... |
108 109 |
unsigned long val; int rc; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
110 |
if (isdigit(*data)) { |
f47ae798d EDAC, fsl_ddr: Re... |
111 112 113 114 115 |
rc = kstrtoul(data, 0, &val); if (rc) return rc; ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, val); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
116 117 118 119 |
return count; } return 0; } |
d43a9fb20 EDAC, fsl_ddr: Re... |
120 121 |
static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, struct device_attribute *mattr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
122 123 124 |
const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
125 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
f47ae798d EDAC, fsl_ddr: Re... |
126 127 |
unsigned long val; int rc; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
128 |
if (isdigit(*data)) { |
f47ae798d EDAC, fsl_ddr: Re... |
129 130 131 132 133 |
rc = kstrtoul(data, 0, &val); if (rc) return rc; ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, val); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
134 135 136 137 |
return count; } return 0; } |
279fa5803 EDAC, fsl_ddr: Ma... |
138 139 140 141 142 143 |
static DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, fsl_mc_inject_data_hi_show, fsl_mc_inject_data_hi_store); static DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); static DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
144 |
|
d43a9fb20 EDAC, fsl_ddr: Re... |
145 |
static struct attribute *fsl_ddr_dev_attrs[] = { |
ea2eb9a8b EDAC, fsl-ddr: Se... |
146 147 148 149 150 |
&dev_attr_inject_data_hi.attr, &dev_attr_inject_data_lo.attr, &dev_attr_inject_ctrl.attr, NULL }; |
d43a9fb20 EDAC, fsl_ddr: Re... |
151 |
ATTRIBUTE_GROUPS(fsl_ddr_dev); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
/**************************** MC Err device ***************************/ /* * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the * MPC8572 User's Manual. Each line represents a syndrome bit column as a * 64-bit value, but split into an upper and lower 32-bit chunk. The labels * below correspond to Freescale's manuals. */ static unsigned int ecc_table[16] = { /* MSB LSB */ /* [0:31] [32:63] */ 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ 0x00ff00ff, 0x00fff0ff, 0x0f0f0f0f, 0x0f0fff00, 0x11113333, 0x7777000f, 0x22224444, 0x8888222f, 0x44448888, 0xffff4441, 0x8888ffff, 0x11118882, 0xffff1111, 0x22221114, /* Syndrome bit 0 */ }; /* * Calculate the correct ECC value for a 64-bit value specified by high:low */ static u8 calculate_ecc(u32 high, u32 low) { u32 mask_low; u32 mask_high; int bit_cnt; u8 ecc = 0; int i; int j; for (i = 0; i < 8; i++) { mask_high = ecc_table[i * 2]; mask_low = ecc_table[i * 2 + 1]; bit_cnt = 0; for (j = 0; j < 32; j++) { if ((mask_high >> j) & 1) bit_cnt ^= (high >> j) & 1; if ((mask_low >> j) & 1) bit_cnt ^= (low >> j) & 1; } ecc |= bit_cnt << i; } return ecc; } /* * Create the syndrome code which is generated if the data line specified by * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 * User's Manual and 9-61 in the MPC8572 User's Manual. */ static u8 syndrome_from_bit(unsigned int bit) { int i; u8 syndrome = 0; /* * Cycle through the upper or lower 32-bit portion of each value in * ecc_table depending on if 'bit' is in the upper or lower half of * 64-bit data. */ for (i = bit < 32; i < 16; i += 2) syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); return syndrome; } /* * Decode data and ecc syndrome to determine what went wrong * Note: This can only decode single-bit errors */ static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, int *bad_data_bit, int *bad_ecc_bit) { int i; u8 syndrome; *bad_data_bit = -1; *bad_ecc_bit = -1; /* * Calculate the ECC of the captured data and XOR it with the captured * ECC to find an ECC syndrome value we can search for */ syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; /* Check if a data line is stuck... */ for (i = 0; i < 64; i++) { if (syndrome == syndrome_from_bit(i)) { *bad_data_bit = i; return; } } /* If data is correct, check ECC bits for errors... */ for (i = 0; i < 8; i++) { if ((syndrome >> i) & 0x1) { *bad_ecc_bit = i; return; } } } #define make64(high, low) (((u64)(high) << 32) | (low)) |
d43a9fb20 EDAC, fsl_ddr: Re... |
261 |
static void fsl_mc_check(struct mem_ctl_info *mci) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
262 |
{ |
d43a9fb20 EDAC, fsl_ddr: Re... |
263 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
264 265 266 267 268 269 270 271 272 273 274 |
struct csrow_info *csrow; u32 bus_width; u32 err_detect; u32 syndrome; u64 err_addr; u32 pfn; int row_index; u32 cap_high; u32 cap_low; int bad_data_bit; int bad_ecc_bit; |
339fdff14 EDAC, fsl_ddr: Ad... |
275 |
err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
276 277 |
if (!err_detect) return; |
d43a9fb20 EDAC, fsl_ddr: Re... |
278 279 280 |
fsl_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x ", err_detect); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
281 282 283 |
/* no more processing if not ECC bit errors */ if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { |
339fdff14 EDAC, fsl_ddr: Ad... |
284 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
285 286 |
return; } |
339fdff14 EDAC, fsl_ddr: Ad... |
287 |
syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
288 289 |
/* Mask off appropriate bits of syndrome based on bus width */ |
339fdff14 EDAC, fsl_ddr: Ad... |
290 291 |
bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & DSC_DBW_MASK) ? 32 : 64; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
292 293 294 295 296 297 |
if (bus_width == 64) syndrome &= 0xff; else syndrome &= 0xffff; err_addr = make64( |
339fdff14 EDAC, fsl_ddr: Ad... |
298 299 |
ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
300 301 302 303 304 305 306 |
pfn = err_addr >> PAGE_SHIFT; for (row_index = 0; row_index < mci->nr_csrows; row_index++) { csrow = mci->csrows[row_index]; if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) break; } |
339fdff14 EDAC, fsl_ddr: Ad... |
307 308 |
cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
309 310 311 312 313 314 315 316 317 318 |
/* * Analyze single-bit errors on 64-bit wide buses * TODO: Add support for 32-bit wide buses */ if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { sbe_ecc_decode(cap_high, cap_low, syndrome, &bad_data_bit, &bad_ecc_bit); if (bad_data_bit != -1) |
d43a9fb20 EDAC, fsl_ddr: Re... |
319 |
fsl_mc_printk(mci, KERN_ERR, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
320 321 322 |
"Faulty Data bit: %d ", bad_data_bit); if (bad_ecc_bit != -1) |
d43a9fb20 EDAC, fsl_ddr: Re... |
323 |
fsl_mc_printk(mci, KERN_ERR, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
324 325 |
"Faulty ECC bit: %d ", bad_ecc_bit); |
d43a9fb20 EDAC, fsl_ddr: Re... |
326 |
fsl_mc_printk(mci, KERN_ERR, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
327 328 329 330 331 332 |
"Expected Data / ECC:\t%#8.8x_%08x / %#2.2x ", cap_high ^ (1 << (bad_data_bit - 32)), cap_low ^ (1 << bad_data_bit), syndrome ^ (1 << bad_ecc_bit)); } |
d43a9fb20 EDAC, fsl_ddr: Re... |
333 |
fsl_mc_printk(mci, KERN_ERR, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
334 335 336 |
"Captured Data / ECC:\t%#8.8x_%08x / %#2.2x ", cap_high, cap_low, syndrome); |
d43a9fb20 EDAC, fsl_ddr: Re... |
337 338 339 340 |
fsl_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx ", err_addr); fsl_mc_printk(mci, KERN_ERR, "PFN: %#8.8x ", pfn); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
341 342 343 |
/* we are out of range */ if (row_index == mci->nr_csrows) |
d43a9fb20 EDAC, fsl_ddr: Re... |
344 345 |
fsl_mc_printk(mci, KERN_ERR, "PFN out of range! "); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
346 347 348 349 350 351 352 353 354 355 356 357 |
if (err_detect & DDR_EDE_SBE) edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, pfn, err_addr & ~PAGE_MASK, syndrome, row_index, 0, -1, mci->ctl_name, ""); if (err_detect & DDR_EDE_MBE) edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, pfn, err_addr & ~PAGE_MASK, syndrome, row_index, 0, -1, mci->ctl_name, ""); |
339fdff14 EDAC, fsl_ddr: Ad... |
358 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
359 |
} |
d43a9fb20 EDAC, fsl_ddr: Re... |
360 |
static irqreturn_t fsl_mc_isr(int irq, void *dev_id) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
361 362 |
{ struct mem_ctl_info *mci = dev_id; |
d43a9fb20 EDAC, fsl_ddr: Re... |
363 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
364 |
u32 err_detect; |
339fdff14 EDAC, fsl_ddr: Ad... |
365 |
err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
366 367 |
if (!err_detect) return IRQ_NONE; |
d43a9fb20 EDAC, fsl_ddr: Re... |
368 |
fsl_mc_check(mci); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
369 370 371 |
return IRQ_HANDLED; } |
d43a9fb20 EDAC, fsl_ddr: Re... |
372 |
static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
373 |
{ |
d43a9fb20 EDAC, fsl_ddr: Re... |
374 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
375 376 377 378 379 380 381 |
struct csrow_info *csrow; struct dimm_info *dimm; u32 sdram_ctl; u32 sdtype; enum mem_type mtype; u32 cs_bnds; int index; |
339fdff14 EDAC, fsl_ddr: Ad... |
382 |
sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
383 384 385 386 |
sdtype = sdram_ctl & DSC_SDTYPE_MASK; if (sdram_ctl & DSC_RD_EN) { switch (sdtype) { |
4e2c3252d EDAC, fsl_ddr: Ad... |
387 |
case 0x02000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
388 389 |
mtype = MEM_RDDR; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
390 |
case 0x03000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
391 392 |
mtype = MEM_RDDR2; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
393 |
case 0x07000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
394 395 |
mtype = MEM_RDDR3; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
396 397 398 |
case 0x05000000: mtype = MEM_RDDR4; break; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
399 400 401 402 403 404 |
default: mtype = MEM_UNKNOWN; break; } } else { switch (sdtype) { |
4e2c3252d EDAC, fsl_ddr: Ad... |
405 |
case 0x02000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
406 407 |
mtype = MEM_DDR; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
408 |
case 0x03000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
409 410 |
mtype = MEM_DDR2; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
411 |
case 0x07000000: |
ea2eb9a8b EDAC, fsl-ddr: Se... |
412 413 |
mtype = MEM_DDR3; break; |
4e2c3252d EDAC, fsl_ddr: Ad... |
414 415 416 |
case 0x05000000: mtype = MEM_DDR4; break; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
417 418 419 420 421 422 423 424 425 426 427 428 |
default: mtype = MEM_UNKNOWN; break; } } for (index = 0; index < mci->nr_csrows; index++) { u32 start; u32 end; csrow = mci->csrows[index]; dimm = csrow->channels[0]->dimm; |
339fdff14 EDAC, fsl_ddr: Ad... |
429 430 |
cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + (index * FSL_MC_CS_BNDS_OFS)); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
start = (cs_bnds & 0xffff0000) >> 16; end = (cs_bnds & 0x0000ffff); if (start == end) continue; /* not populated */ start <<= (24 - PAGE_SHIFT); end <<= (24 - PAGE_SHIFT); end |= (1 << (24 - PAGE_SHIFT)) - 1; csrow->first_page = start; csrow->last_page = end; dimm->nr_pages = end + 1 - start; dimm->grain = 8; dimm->mtype = mtype; dimm->dtype = DEV_UNKNOWN; if (sdram_ctl & DSC_X32_EN) dimm->dtype = DEV_X32; dimm->edac_mode = EDAC_SECDED; } } |
d43a9fb20 EDAC, fsl_ddr: Re... |
454 |
int fsl_mc_err_probe(struct platform_device *op) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
455 456 457 |
{ struct mem_ctl_info *mci; struct edac_mc_layer layers[2]; |
d43a9fb20 EDAC, fsl_ddr: Re... |
458 |
struct fsl_mc_pdata *pdata; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
459 460 461 |
struct resource r; u32 sdram_ctl; int res; |
d43a9fb20 EDAC, fsl_ddr: Re... |
462 |
if (!devres_open_group(&op->dev, fsl_mc_err_probe, GFP_KERNEL)) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
463 464 465 466 467 468 469 470 471 472 473 |
return -ENOMEM; layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; layers[0].size = 4; layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = 1; layers[1].is_virt_csrow = false; mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, sizeof(*pdata)); if (!mci) { |
d43a9fb20 EDAC, fsl_ddr: Re... |
474 |
devres_release_group(&op->dev, fsl_mc_err_probe); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
475 476 477 478 |
return -ENOMEM; } pdata = mci->pvt_info; |
d43a9fb20 EDAC, fsl_ddr: Re... |
479 |
pdata->name = "fsl_mc_err"; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
480 481 482 483 484 |
mci->pdev = &op->dev; pdata->edac_idx = edac_mc_idx++; dev_set_drvdata(mci->pdev, mci); mci->ctl_name = pdata->name; mci->dev_name = pdata->name; |
339fdff14 EDAC, fsl_ddr: Ad... |
485 486 487 488 489 |
/* * Get the endianness of DDR controller registers. * Default is big endian. */ little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { pr_err("%s: Unable to get resource for MC err regs ", __func__); goto err; } if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), pdata->name)) { pr_err("%s: Error while requesting mem region ", __func__); res = -EBUSY; goto err; } pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->mc_vbase) { pr_err("%s: Unable to setup MC err regs ", __func__); res = -ENOMEM; goto err; } |
339fdff14 EDAC, fsl_ddr: Ad... |
514 |
sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
515 516 517 518 519 520 521 522 523 524 |
if (!(sdram_ctl & DSC_ECC_EN)) { /* no ECC */ pr_warn("%s: No ECC DIMMs discovered ", __func__); res = -ENODEV; goto err; } edac_dbg(3, "init mci "); |
4e2c3252d EDAC, fsl_ddr: Ad... |
525 526 527 528 |
mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR | MEM_FLAG_DDR2 | MEM_FLAG_RDDR2 | MEM_FLAG_DDR3 | MEM_FLAG_RDDR3 | MEM_FLAG_DDR4 | MEM_FLAG_RDDR4; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
529 530 531 532 533 |
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; mci->edac_cap = EDAC_FLAG_SECDED; mci->mod_name = EDAC_MOD_STR; if (edac_op_state == EDAC_OPSTATE_POLL) |
d43a9fb20 EDAC, fsl_ddr: Re... |
534 |
mci->edac_check = fsl_mc_check; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
535 536 537 538 |
mci->ctl_page_to_phys = NULL; mci->scrub_mode = SCRUB_SW_SRC; |
d43a9fb20 EDAC, fsl_ddr: Re... |
539 |
fsl_ddr_init_csrows(mci); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
540 541 |
/* store the original error disable bits */ |
339fdff14 EDAC, fsl_ddr: Ad... |
542 543 |
orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
544 545 |
/* clear all error bits */ |
339fdff14 EDAC, fsl_ddr: Ad... |
546 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
547 |
|
43fa9ba63 EDAC, fsl_ddr: Fi... |
548 549 |
res = edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups); if (res) { |
ea2eb9a8b EDAC, fsl-ddr: Se... |
550 551 552 553 554 555 |
edac_dbg(3, "failed edac_mc_add_mc() "); goto err; } if (edac_op_state == EDAC_OPSTATE_INT) { |
339fdff14 EDAC, fsl_ddr: Ad... |
556 557 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, DDR_EIE_MBEE | DDR_EIE_SBEE); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
558 559 |
/* store the original error management threshold */ |
339fdff14 EDAC, fsl_ddr: Ad... |
560 561 |
orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_SBE) & 0xff0000; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
562 563 |
/* set threshold to 1 error per interrupt */ |
339fdff14 EDAC, fsl_ddr: Ad... |
564 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
565 566 |
/* register interrupts */ |
55764ed37 EDAC, fsl_ddr: Fi... |
567 |
pdata->irq = platform_get_irq(op, 0); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
568 |
res = devm_request_irq(&op->dev, pdata->irq, |
d43a9fb20 EDAC, fsl_ddr: Re... |
569 |
fsl_mc_isr, |
ea2eb9a8b EDAC, fsl-ddr: Se... |
570 571 572 |
IRQF_SHARED, "[EDAC] MC err", mci); if (res < 0) { |
d43a9fb20 EDAC, fsl_ddr: Re... |
573 574 |
pr_err("%s: Unable to request irq %d for FSL DDR DRAM ERR ", |
ea2eb9a8b EDAC, fsl-ddr: Se... |
575 |
__func__, pdata->irq); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
576 577 578 579 580 581 582 583 |
res = -ENODEV; goto err2; } pr_info(EDAC_MOD_STR " acquired irq %d for MC ", pdata->irq); } |
d43a9fb20 EDAC, fsl_ddr: Re... |
584 |
devres_remove_group(&op->dev, fsl_mc_err_probe); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
585 586 587 588 589 590 591 592 593 594 |
edac_dbg(3, "success "); pr_info(EDAC_MOD_STR " MC err registered "); return 0; err2: edac_mc_del_mc(&op->dev); err: |
d43a9fb20 EDAC, fsl_ddr: Re... |
595 |
devres_release_group(&op->dev, fsl_mc_err_probe); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
596 597 598 |
edac_mc_free(mci); return res; } |
d43a9fb20 EDAC, fsl_ddr: Re... |
599 |
int fsl_mc_err_remove(struct platform_device *op) |
ea2eb9a8b EDAC, fsl-ddr: Se... |
600 601 |
{ struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); |
d43a9fb20 EDAC, fsl_ddr: Re... |
602 |
struct fsl_mc_pdata *pdata = mci->pvt_info; |
ea2eb9a8b EDAC, fsl-ddr: Se... |
603 604 605 606 607 |
edac_dbg(0, " "); if (edac_op_state == EDAC_OPSTATE_INT) { |
339fdff14 EDAC, fsl_ddr: Ad... |
608 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
609 |
} |
339fdff14 EDAC, fsl_ddr: Ad... |
610 611 612 |
ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, orig_ddr_err_disable); ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); |
ea2eb9a8b EDAC, fsl-ddr: Se... |
613 614 615 616 617 |
edac_mc_del_mc(&op->dev); edac_mc_free(mci); return 0; } |