Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS/EDAC: Improve OCTEON EDAC support.

Some initialization errors are reported with the existing OCTEON EDAC
support patch. Also some parts have more than one memory controller.

Fix the errors and add multiple controllers if present.

Signed-off-by: David Daney <david.daney@cavium.com>

authored by

David Daney and committed by
Ralf Baechle
e1ced097 abe105a4

+408 -337
+26 -4
arch/mips/cavium-octeon/setup.c
··· 1112 1112 unflatten_device_tree(); 1113 1113 } 1114 1114 1115 + static int __initdata disable_octeon_edac_p; 1116 + 1117 + static int __init disable_octeon_edac(char *str) 1118 + { 1119 + disable_octeon_edac_p = 1; 1120 + return 0; 1121 + } 1122 + early_param("disable_octeon_edac", disable_octeon_edac); 1123 + 1115 1124 static char *edac_device_names[] = { 1116 - "co_l2c_edac", 1117 - "co_lmc_edac", 1118 - "co_pc_edac", 1125 + "octeon_l2c_edac", 1126 + "octeon_pc_edac", 1119 1127 }; 1120 1128 1121 1129 static int __init edac_devinit(void) 1122 1130 { 1123 1131 struct platform_device *dev; 1124 1132 int i, err = 0; 1133 + int num_lmc; 1125 1134 char *name; 1135 + 1136 + if (disable_octeon_edac_p) 1137 + return 0; 1126 1138 1127 1139 for (i = 0; i < ARRAY_SIZE(edac_device_names); i++) { 1128 1140 name = edac_device_names[i]; ··· 1145 1133 } 1146 1134 } 1147 1135 1136 + num_lmc = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 1137 + (OCTEON_IS_MODEL(OCTEON_CN56XX) ? 2 : 1); 1138 + for (i = 0; i < num_lmc; i++) { 1139 + dev = platform_device_register_simple("octeon_lmc_edac", 1140 + i, NULL, 0); 1141 + if (IS_ERR(dev)) { 1142 + pr_err("Registation of octeon_lmc_edac %d failed!\n", i); 1143 + err = PTR_ERR(dev); 1144 + } 1145 + } 1146 + 1148 1147 return err; 1149 1148 } 1150 - 1151 1149 device_initcall(edac_devinit);
+30 -9
arch/mips/mm/c-octeon.c
··· 286 286 board_cache_error_setup = octeon_cache_error_setup; 287 287 } 288 288 289 - /** 289 + /* 290 290 * Handle a cache error exception 291 291 */ 292 - 293 292 static RAW_NOTIFIER_HEAD(co_cache_error_chain); 294 293 295 294 int register_co_cache_error_notifier(struct notifier_block *nb) ··· 303 304 } 304 305 EXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier); 305 306 306 - static inline int co_cache_error_call_notifiers(unsigned long val) 307 + static void co_cache_error_call_notifiers(unsigned long val) 307 308 { 308 - return raw_notifier_call_chain(&co_cache_error_chain, val, NULL); 309 + int rv = raw_notifier_call_chain(&co_cache_error_chain, val, NULL); 310 + if ((rv & ~NOTIFY_STOP_MASK) != NOTIFY_OK) { 311 + u64 dcache_err; 312 + unsigned long coreid = cvmx_get_core_num(); 313 + u64 icache_err = read_octeon_c0_icacheerr(); 314 + 315 + if (val) { 316 + dcache_err = cache_err_dcache[coreid]; 317 + cache_err_dcache[coreid] = 0; 318 + } else { 319 + dcache_err = read_octeon_c0_dcacheerr(); 320 + } 321 + 322 + pr_err("Core%lu: Cache error exception:\n", coreid); 323 + pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); 324 + if (icache_err & 1) { 325 + pr_err("CacheErr (Icache) == %llx\n", 326 + (unsigned long long)icache_err); 327 + write_octeon_c0_icacheerr(0); 328 + } 329 + if (dcache_err & 1) { 330 + pr_err("CacheErr (Dcache) == %llx\n", 331 + (unsigned long long)dcache_err); 332 + } 333 + } 309 334 } 310 335 311 - /** 336 + /* 312 337 * Called when the the exception is recoverable 313 338 */ 339 + 314 340 asmlinkage void cache_parity_error_octeon_recoverable(void) 315 341 { 316 342 co_cache_error_call_notifiers(0); ··· 343 319 344 320 /** 345 321 * Called when the the exception is not recoverable 346 - * 347 - * The issue not that the cache error exception itself was non-recoverable 348 - * but that due to nesting of exception may have lost some state so can't 349 - * continue. 350 322 */ 323 + 351 324 asmlinkage void cache_parity_error_octeon_non_recoverable(void) 352 325 { 353 326 co_cache_error_call_notifiers(1);
+2 -1
arch/mips/pci/pci-octeon.c
··· 705 705 */ 706 706 cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1); 707 707 708 - if (IS_ERR(platform_device_register_simple("co_pci_edac", 0, NULL, 0))) 708 + if (IS_ERR(platform_device_register_simple("octeon_pci_edac", 709 + -1, NULL, 0))) 709 710 pr_err("Registation of co_pci_edac failed!\n"); 710 711 711 712 octeon_pci_dma_init();
+134 -44
drivers/edac/octeon_edac-l2c.c
··· 3 3 * License. See the file "COPYING" in the main directory of this archive 4 4 * for more details. 5 5 * 6 + * Copyright (C) 2012 Cavium, Inc. 7 + * 6 8 * Copyright (C) 2009 Wind River Systems, 7 9 * written by Ralf Baechle <ralf@linux-mips.org> 8 10 */ ··· 21 19 22 20 #define EDAC_MOD_STR "octeon-l2c" 23 21 24 - static void co_l2c_poll(struct edac_device_ctl_info *l2c) 22 + static void octeon_l2c_poll_oct1(struct edac_device_ctl_info *l2c) 25 23 { 26 - union cvmx_l2t_err l2t_err; 24 + union cvmx_l2t_err l2t_err, l2t_err_reset; 25 + union cvmx_l2d_err l2d_err, l2d_err_reset; 27 26 27 + l2t_err_reset.u64 = 0; 28 28 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 29 29 if (l2t_err.s.sec_err) { 30 30 edac_device_handle_ce(l2c, 0, 0, 31 - "Single bit error (corrected)"); 32 - l2t_err.s.sec_err = 1; /* Reset */ 33 - cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 31 + "Tag Single bit error (corrected)"); 32 + l2t_err_reset.s.sec_err = 1; 34 33 } 35 34 if (l2t_err.s.ded_err) { 36 35 edac_device_handle_ue(l2c, 0, 0, 37 - "Double bit error (corrected)"); 38 - l2t_err.s.ded_err = 1; /* Reset */ 39 - cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 36 + "Tag Double bit error (detected)"); 37 + l2t_err_reset.s.ded_err = 1; 40 38 } 39 + if (l2t_err_reset.u64) 40 + cvmx_write_csr(CVMX_L2T_ERR, l2t_err_reset.u64); 41 + 42 + l2d_err_reset.u64 = 0; 43 + l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR); 44 + if (l2d_err.s.sec_err) { 45 + edac_device_handle_ce(l2c, 0, 1, 46 + "Data Single bit error (corrected)"); 47 + l2d_err_reset.s.sec_err = 1; 48 + } 49 + if (l2d_err.s.ded_err) { 50 + edac_device_handle_ue(l2c, 0, 1, 51 + "Data Double bit error (detected)"); 52 + l2d_err_reset.s.ded_err = 1; 53 + } 54 + if (l2d_err_reset.u64) 55 + cvmx_write_csr(CVMX_L2D_ERR, l2d_err_reset.u64); 56 + 41 57 } 42 58 43 - static int __devinit co_l2c_probe(struct platform_device *pdev) 59 + static void _octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c, int tad) 60 + { 61 + union cvmx_l2c_err_tdtx err_tdtx, err_tdtx_reset; 62 + union cvmx_l2c_err_ttgx err_ttgx, err_ttgx_reset; 63 + char buf1[64]; 64 + char buf2[80]; 65 + 66 + err_tdtx_reset.u64 = 0; 67 + err_tdtx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TDTX(tad)); 68 + if (err_tdtx.s.dbe || err_tdtx.s.sbe || 69 + err_tdtx.s.vdbe || err_tdtx.s.vsbe) 70 + snprintf(buf1, sizeof(buf1), 71 + "type:%d, syn:0x%x, way:%d", 72 + err_tdtx.s.type, err_tdtx.s.syn, err_tdtx.s.wayidx); 73 + 74 + if (err_tdtx.s.dbe) { 75 + snprintf(buf2, sizeof(buf2), 76 + "L2D Double bit error (detected):%s", buf1); 77 + err_tdtx_reset.s.dbe = 1; 78 + edac_device_handle_ue(l2c, tad, 1, buf2); 79 + } 80 + if (err_tdtx.s.sbe) { 81 + snprintf(buf2, sizeof(buf2), 82 + "L2D Single bit error (corrected):%s", buf1); 83 + err_tdtx_reset.s.sbe = 1; 84 + edac_device_handle_ce(l2c, tad, 1, buf2); 85 + } 86 + if (err_tdtx.s.vdbe) { 87 + snprintf(buf2, sizeof(buf2), 88 + "VBF Double bit error (detected):%s", buf1); 89 + err_tdtx_reset.s.vdbe = 1; 90 + edac_device_handle_ue(l2c, tad, 1, buf2); 91 + } 92 + if (err_tdtx.s.vsbe) { 93 + snprintf(buf2, sizeof(buf2), 94 + "VBF Single bit error (corrected):%s", buf1); 95 + err_tdtx_reset.s.vsbe = 1; 96 + edac_device_handle_ce(l2c, tad, 1, buf2); 97 + } 98 + if (err_tdtx_reset.u64) 99 + cvmx_write_csr(CVMX_L2C_ERR_TDTX(tad), err_tdtx_reset.u64); 100 + 101 + err_ttgx_reset.u64 = 0; 102 + err_ttgx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TTGX(tad)); 103 + 104 + if (err_ttgx.s.dbe || err_ttgx.s.sbe) 105 + snprintf(buf1, sizeof(buf1), 106 + "type:%d, syn:0x%x, way:%d", 107 + err_ttgx.s.type, err_ttgx.s.syn, err_ttgx.s.wayidx); 108 + 109 + if (err_ttgx.s.dbe) { 110 + snprintf(buf2, sizeof(buf2), 111 + "Tag Double bit error (detected):%s", buf1); 112 + err_ttgx_reset.s.dbe = 1; 113 + edac_device_handle_ue(l2c, tad, 0, buf2); 114 + } 115 + if (err_ttgx.s.sbe) { 116 + snprintf(buf2, sizeof(buf2), 117 + "Tag Single bit error (corrected):%s", buf1); 118 + err_ttgx_reset.s.sbe = 1; 119 + edac_device_handle_ce(l2c, tad, 0, buf2); 120 + } 121 + if (err_ttgx_reset.u64) 122 + cvmx_write_csr(CVMX_L2C_ERR_TTGX(tad), err_ttgx_reset.u64); 123 + } 124 + 125 + static void octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c) 126 + { 127 + int i; 128 + for (i = 0; i < l2c->nr_instances; i++) 129 + _octeon_l2c_poll_oct2(l2c, i); 130 + } 131 + 132 + static int __devinit octeon_l2c_probe(struct platform_device *pdev) 44 133 { 45 134 struct edac_device_ctl_info *l2c; 46 - union cvmx_l2t_err l2t_err; 47 - int res = 0; 48 135 49 - l2c = edac_device_alloc_ctl_info(0, "l2c", 1, NULL, 0, 0, 136 + int num_tads = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 1; 137 + 138 + /* 'Tags' are block 0, 'Data' is block 1*/ 139 + l2c = edac_device_alloc_ctl_info(0, "l2c", num_tads, "l2c", 2, 0, 50 140 NULL, 0, edac_device_alloc_index()); 51 141 if (!l2c) 52 142 return -ENOMEM; ··· 149 55 150 56 l2c->mod_name = "octeon-l2c"; 151 57 l2c->ctl_name = "octeon_l2c_err"; 152 - l2c->edac_check = co_l2c_poll; 58 + 59 + 60 + if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) { 61 + union cvmx_l2t_err l2t_err; 62 + union cvmx_l2d_err l2d_err; 63 + 64 + l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 65 + l2t_err.s.sec_intena = 0; /* We poll */ 66 + l2t_err.s.ded_intena = 0; 67 + cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 68 + 69 + l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR); 70 + l2d_err.s.sec_intena = 0; /* We poll */ 71 + l2d_err.s.ded_intena = 0; 72 + cvmx_write_csr(CVMX_L2T_ERR, l2d_err.u64); 73 + 74 + l2c->edac_check = octeon_l2c_poll_oct1; 75 + } else { 76 + /* OCTEON II */ 77 + l2c->edac_check = octeon_l2c_poll_oct2; 78 + } 153 79 154 80 if (edac_device_add_device(l2c) > 0) { 155 81 pr_err("%s: edac_device_add_device() failed\n", __func__); 156 82 goto err; 157 83 } 158 84 159 - l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 160 - l2t_err.s.sec_intena = 0; /* We poll */ 161 - l2t_err.s.ded_intena = 0; 162 - l2t_err.s.sec_err = 1; /* Clear, just in case */ 163 - l2t_err.s.ded_err = 1; 164 - cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 165 85 166 86 return 0; 167 87 168 88 err: 169 89 edac_device_free_ctl_info(l2c); 170 90 171 - return res; 91 + return -ENXIO; 172 92 } 173 93 174 - static int co_l2c_remove(struct platform_device *pdev) 94 + static int octeon_l2c_remove(struct platform_device *pdev) 175 95 { 176 96 struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev); 177 97 ··· 195 87 return 0; 196 88 } 197 89 198 - static struct platform_driver co_l2c_driver = { 199 - .probe = co_l2c_probe, 200 - .remove = co_l2c_remove, 90 + static struct platform_driver octeon_l2c_driver = { 91 + .probe = octeon_l2c_probe, 92 + .remove = octeon_l2c_remove, 201 93 .driver = { 202 - .name = "co_l2c_edac", 94 + .name = "octeon_l2c_edac", 203 95 } 204 96 }; 205 - 206 - static int __init co_edac_init(void) 207 - { 208 - int ret; 209 - 210 - ret = platform_driver_register(&co_l2c_driver); 211 - if (ret) 212 - pr_warning(EDAC_MOD_STR " EDAC failed to register\n"); 213 - 214 - return ret; 215 - } 216 - 217 - static void __exit co_edac_exit(void) 218 - { 219 - platform_driver_unregister(&co_l2c_driver); 220 - } 221 - 222 - module_init(co_edac_init); 223 - module_exit(co_edac_exit); 97 + module_platform_driver(octeon_l2c_driver); 224 98 225 99 MODULE_LICENSE("GPL"); 226 100 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+133 -97
drivers/edac/octeon_edac-lmc.c
··· 12 12 #include <linux/io.h> 13 13 #include <linux/edac.h> 14 14 15 - #include <asm/octeon/cvmx.h> 15 + #include <asm/octeon/octeon.h> 16 + #include <asm/octeon/cvmx-lmcx-defs.h> 16 17 17 18 #include "edac_core.h" 18 19 #include "edac_module.h" 19 - #include "octeon_edac-lmc.h" 20 20 21 - #define EDAC_MOD_STR "octeon" 21 + #define OCTEON_MAX_MC 4 22 22 23 - static struct mem_ctl_info *mc_cavium; 24 - static void *lmc_base; 25 - 26 - static void co_lmc_poll(struct mem_ctl_info *mci) 23 + static void octeon_lmc_edac_poll(struct mem_ctl_info *mci) 27 24 { 28 - union lmc_mem_cfg0 cfg0; 29 - union lmc_fadr fadr; 25 + union cvmx_lmcx_mem_cfg0 cfg0; 26 + bool do_clear = false; 30 27 char msg[64]; 31 28 32 - fadr.u64 = readq(lmc_base + LMC_FADR); 33 - cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); 34 - snprintf(msg, sizeof(msg), "DIMM %d rank %d bank %d row %d col %d", 35 - fadr.fdimm, fadr.fbunk, fadr.fbank, fadr.frow, fadr.fcol); 36 - 37 - if (cfg0.sec_err) { 38 - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, 39 - msg, ""); 40 - 41 - cfg0.intr_sec_ena = -1; /* Done, re-arm */ 29 + cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mci->mc_idx)); 30 + if (cfg0.s.sec_err || cfg0.s.ded_err) { 31 + union cvmx_lmcx_fadr fadr; 32 + fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx)); 33 + snprintf(msg, sizeof(msg), 34 + "DIMM %d rank %d bank %d row %d col %d", 35 + fadr.cn30xx.fdimm, fadr.cn30xx.fbunk, 36 + fadr.cn30xx.fbank, fadr.cn30xx.frow, fadr.cn30xx.fcol); 42 37 } 43 38 44 - if (cfg0.ded_err) { 45 - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, 46 - msg, ""); 47 - cfg0.intr_ded_ena = -1; /* Done, re-arm */ 39 + if (cfg0.s.sec_err) { 40 + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, 41 + -1, -1, -1, msg, ""); 42 + cfg0.s.sec_err = -1; /* Done, re-arm */ 43 + do_clear = true; 48 44 } 49 45 50 - writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0); 46 + if (cfg0.s.ded_err) { 47 + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 48 + -1, -1, -1, msg, ""); 49 + cfg0.s.ded_err = -1; /* Done, re-arm */ 50 + do_clear = true; 51 + } 52 + if (do_clear) 53 + cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mci->mc_idx), cfg0.u64); 51 54 } 52 55 53 - static int __devinit co_lmc_probe(struct platform_device *pdev) 56 + static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci) 57 + { 58 + union cvmx_lmcx_int int_reg; 59 + bool do_clear = false; 60 + char msg[64]; 61 + 62 + int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); 63 + if (int_reg.s.sec_err || int_reg.s.ded_err) { 64 + union cvmx_lmcx_fadr fadr; 65 + fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx)); 66 + snprintf(msg, sizeof(msg), 67 + "DIMM %d rank %d bank %d row %d col %d", 68 + fadr.cn61xx.fdimm, fadr.cn61xx.fbunk, 69 + fadr.cn61xx.fbank, fadr.cn61xx.frow, fadr.cn61xx.fcol); 70 + } 71 + 72 + if (int_reg.s.sec_err) { 73 + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, 74 + -1, -1, -1, msg, ""); 75 + int_reg.s.sec_err = -1; /* Done, re-arm */ 76 + do_clear = true; 77 + } 78 + 79 + if (int_reg.s.ded_err) { 80 + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 81 + -1, -1, -1, msg, ""); 82 + int_reg.s.ded_err = -1; /* Done, re-arm */ 83 + do_clear = true; 84 + } 85 + if (do_clear) 86 + cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64); 87 + } 88 + 89 + static int __devinit octeon_lmc_edac_probe(struct platform_device *pdev) 54 90 { 55 91 struct mem_ctl_info *mci; 56 - union lmc_mem_cfg0 cfg0; 57 - int res = 0; 92 + struct edac_mc_layer layers[1]; 93 + int mc = pdev->id; 58 94 59 - mci = edac_mc_alloc(0, 0, 0, 0); 60 - if (!mci) 61 - return -ENOMEM; 95 + layers[0].type = EDAC_MC_LAYER_CHANNEL; 96 + layers[0].size = 1; 97 + layers[0].is_virt_csrow = false; 62 98 63 - mci->pdev = &pdev->dev; 64 - platform_set_drvdata(pdev, mci); 65 - mci->dev_name = dev_name(&pdev->dev); 99 + if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) { 100 + union cvmx_lmcx_mem_cfg0 cfg0; 66 101 67 - mci->mod_name = "octeon-lmc"; 68 - mci->ctl_name = "co_lmc_err"; 69 - mci->edac_check = co_lmc_poll; 102 + cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); 103 + if (!cfg0.s.ecc_ena) { 104 + dev_info(&pdev->dev, "Disabled (ECC not enabled)\n"); 105 + return 0; 106 + } 70 107 71 - if (edac_mc_add_mc(mci) > 0) { 72 - pr_err("%s: edac_mc_add_mc() failed\n", __func__); 73 - goto err; 108 + mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0); 109 + if (!mci) 110 + return -ENXIO; 111 + 112 + mci->pdev = &pdev->dev; 113 + mci->dev_name = dev_name(&pdev->dev); 114 + 115 + mci->mod_name = "octeon-lmc"; 116 + mci->ctl_name = "octeon-lmc-err"; 117 + mci->edac_check = octeon_lmc_edac_poll; 118 + 119 + if (edac_mc_add_mc(mci)) { 120 + dev_err(&pdev->dev, "edac_mc_add_mc() failed\n"); 121 + edac_mc_free(mci); 122 + return -ENXIO; 123 + } 124 + 125 + cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc)); 126 + cfg0.s.intr_ded_ena = 0; /* We poll */ 127 + cfg0.s.intr_sec_ena = 0; 128 + cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), cfg0.u64); 129 + } else { 130 + /* OCTEON II */ 131 + union cvmx_lmcx_int_en en; 132 + union cvmx_lmcx_config config; 133 + 134 + config.u64 = cvmx_read_csr(CVMX_LMCX_CONFIG(0)); 135 + if (!config.s.ecc_ena) { 136 + dev_info(&pdev->dev, "Disabled (ECC not enabled)\n"); 137 + return 0; 138 + } 139 + 140 + mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0); 141 + if (!mci) 142 + return -ENXIO; 143 + 144 + mci->pdev = &pdev->dev; 145 + mci->dev_name = dev_name(&pdev->dev); 146 + 147 + mci->mod_name = "octeon-lmc"; 148 + mci->ctl_name = "co_lmc_err"; 149 + mci->edac_check = octeon_lmc_edac_poll_o2; 150 + 151 + if (edac_mc_add_mc(mci)) { 152 + dev_err(&pdev->dev, "edac_mc_add_mc() failed\n"); 153 + edac_mc_free(mci); 154 + return -ENXIO; 155 + } 156 + 157 + en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc)); 158 + en.s.intr_ded_ena = 0; /* We poll */ 159 + en.s.intr_sec_ena = 0; 160 + cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), en.u64); 74 161 } 75 - 76 - cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); /* We poll */ 77 - cfg0.intr_ded_ena = 0; 78 - cfg0.intr_sec_ena = 0; 79 - writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0); 80 - 81 - mc_cavium = mci; 162 + platform_set_drvdata(pdev, mci); 82 163 83 164 return 0; 84 - 85 - err: 86 - edac_mc_free(mci); 87 - 88 - return res; 89 165 } 90 166 91 - static int co_lmc_remove(struct platform_device *pdev) 167 + static int octeon_lmc_edac_remove(struct platform_device *pdev) 92 168 { 93 169 struct mem_ctl_info *mci = platform_get_drvdata(pdev); 94 170 95 - mc_cavium = NULL; 96 171 edac_mc_del_mc(&pdev->dev); 97 172 edac_mc_free(mci); 98 - 99 173 return 0; 100 174 } 101 175 102 - static struct platform_driver co_lmc_driver = { 103 - .probe = co_lmc_probe, 104 - .remove = co_lmc_remove, 176 + static struct platform_driver octeon_lmc_edac_driver = { 177 + .probe = octeon_lmc_edac_probe, 178 + .remove = octeon_lmc_edac_remove, 105 179 .driver = { 106 - .name = "co_lmc_edac", 180 + .name = "octeon_lmc_edac", 107 181 } 108 182 }; 109 - 110 - static int __init co_edac_init(void) 111 - { 112 - union lmc_mem_cfg0 cfg0; 113 - int ret; 114 - 115 - lmc_base = ioremap_nocache(LMC_BASE, LMC_SIZE); 116 - if (!lmc_base) 117 - return -ENOMEM; 118 - 119 - cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); 120 - if (!cfg0.ecc_ena) { 121 - pr_info(EDAC_MOD_STR " LMC EDAC: ECC disabled, good bye\n"); 122 - ret = -ENODEV; 123 - goto out; 124 - } 125 - 126 - ret = platform_driver_register(&co_lmc_driver); 127 - if (ret) { 128 - pr_warning(EDAC_MOD_STR " LMC EDAC failed to register\n"); 129 - goto out; 130 - } 131 - 132 - return ret; 133 - 134 - out: 135 - iounmap(lmc_base); 136 - 137 - return ret; 138 - } 139 - 140 - static void __exit co_edac_exit(void) 141 - { 142 - platform_driver_unregister(&co_lmc_driver); 143 - iounmap(lmc_base); 144 - } 145 - 146 - module_init(co_edac_init); 147 - module_exit(co_edac_exit); 183 + module_platform_driver(octeon_lmc_edac_driver); 148 184 149 185 MODULE_LICENSE("GPL"); 150 186 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
-78
drivers/edac/octeon_edac-lmc.h
··· 1 - /* 2 - * LMC Registers, see chapter 2.5 3 - * 4 - * These are RSL Type registers and are accessed indirectly across the 5 - * I/O bus, so accesses are slowish. Not that it matters. Any size load is 6 - * ok but stores must be 64-bit. 7 - */ 8 - #define LMC_BASE 0x0001180088000000 9 - #define LMC_SIZE 0xb8 10 - 11 - #define LMC_MEM_CFG0 0x0000000000000000 12 - #define LMC_MEM_CFG1 0x0000000000000008 13 - #define LMC_CTL 0x0000000000000010 14 - #define LMC_DDR2_CTL 0x0000000000000018 15 - #define LMC_FADR 0x0000000000000020 16 - #define LMC_FADR_FDIMM 17 - #define LMC_FADR_FBUNK 18 - #define LMC_FADR_FBANK 19 - #define LMC_FADR_FROW 20 - #define LMC_FADR_FCOL 21 - #define LMC_COMP_CTL 0x0000000000000028 22 - #define LMC_WODT_CTL 0x0000000000000030 23 - #define LMC_ECC_SYND 0x0000000000000038 24 - #define LMC_IFB_CNT_LO 0x0000000000000048 25 - #define LMC_IFB_CNT_HI 0x0000000000000050 26 - #define LMC_OPS_CNT_LO 0x0000000000000058 27 - #define LMC_OPS_CNT_HI 0x0000000000000060 28 - #define LMC_DCLK_CNT_LO 0x0000000000000068 29 - #define LMC_DCLK_CNT_HI 0x0000000000000070 30 - #define LMC_DELAY_CFG 0x0000000000000088 31 - #define LMC_CTL1 0x0000000000000090 32 - #define LMC_DUAL_MEM_CONFIG 0x0000000000000098 33 - #define LMC_RODT_COMP_CTL 0x00000000000000A0 34 - #define LMC_PLL_CTL 0x00000000000000A8 35 - #define LMC_PLL_STATUS 0x00000000000000B0 36 - 37 - union lmc_mem_cfg0 { 38 - uint64_t u64; 39 - struct { 40 - uint64_t reserved_32_63:32; 41 - uint64_t reset:1; 42 - uint64_t silo_qc:1; 43 - uint64_t bunk_ena:1; 44 - uint64_t ded_err:4; 45 - uint64_t sec_err:4; 46 - uint64_t intr_ded_ena:1; 47 - uint64_t intr_sec_ena:1; 48 - uint64_t reserved_15_18:4; 49 - uint64_t ref_int:5; 50 - uint64_t pbank_lsb:4; 51 - uint64_t row_lsb:3; 52 - uint64_t ecc_ena:1; 53 - uint64_t init_start:1; 54 - }; 55 - }; 56 - 57 - union lmc_fadr { 58 - uint64_t u64; 59 - struct { 60 - uint64_t reserved_32_63:32; 61 - uint64_t fdimm:2; 62 - uint64_t fbunk:1; 63 - uint64_t fbank:3; 64 - uint64_t frow:14; 65 - uint64_t fcol:12; 66 - }; 67 - }; 68 - 69 - union lmc_ecc_synd { 70 - uint64_t u64; 71 - struct { 72 - uint64_t reserved_32_63:32; 73 - uint64_t mrdsyn3:8; 74 - uint64_t mrdsyn2:8; 75 - uint64_t mrdsyn1:8; 76 - uint64_t mrdsyn0:8; 77 - }; 78 - };
+73 -70
drivers/edac/octeon_edac-pc.c
··· 3 3 * License. See the file "COPYING" in the main directory of this archive 4 4 * for more details. 5 5 * 6 + * Copyright (C) 2012 Cavium, Inc. 7 + * 6 8 * Copyright (C) 2009 Wind River Systems, 7 9 * written by Ralf Baechle <ralf@linux-mips.org> 8 10 */ ··· 21 19 #include <asm/octeon/cvmx.h> 22 20 #include <asm/mipsregs.h> 23 21 24 - #define EDAC_MOD_STR "octeon" 25 - 26 22 extern int register_co_cache_error_notifier(struct notifier_block *nb); 27 23 extern int unregister_co_cache_error_notifier(struct notifier_block *nb); 28 24 29 25 extern unsigned long long cache_err_dcache[NR_CPUS]; 30 26 31 - static struct edac_device_ctl_info *ed_cavium; 27 + struct co_cache_error { 28 + struct notifier_block notifier; 29 + struct edac_device_ctl_info *ed; 30 + }; 32 31 33 - /* 32 + /** 34 33 * EDAC CPU cache error callback 35 34 * 35 + * @event: non-zero if unrecoverable. 36 36 */ 37 - 38 37 static int co_cache_error_event(struct notifier_block *this, 39 38 unsigned long event, void *ptr) 40 39 { 40 + struct co_cache_error *p = container_of(this, struct co_cache_error, 41 + notifier); 42 + 41 43 unsigned int core = cvmx_get_core_num(); 42 44 unsigned int cpu = smp_processor_id(); 43 - uint64_t icache_err = read_octeon_c0_icacheerr(); 44 - struct edac_device_ctl_info *ed = ed_cavium; 45 + u64 icache_err = read_octeon_c0_icacheerr(); 46 + u64 dcache_err; 45 47 46 - edac_device_printk(ed, KERN_ERR, 47 - "Cache error exception on core %d / processor %d:\n", 48 - core, cpu); 49 - edac_device_printk(ed, KERN_ERR, 50 - "cp0_errorepc == %lx\n", read_c0_errorepc()); 51 - if (icache_err & 1) { 52 - edac_device_printk(ed, KERN_ERR, "CacheErr (Icache) == %llx\n", 53 - (unsigned long long)icache_err); 54 - write_octeon_c0_icacheerr(0); 55 - edac_device_handle_ce(ed, 0, 0, ed->ctl_name); 56 - } 57 - if (cache_err_dcache[core] & 1) { 58 - edac_device_printk(ed, KERN_ERR, "CacheErr (Dcache) == %llx\n", 59 - (unsigned long long)cache_err_dcache[core]); 48 + if (event) { 49 + dcache_err = cache_err_dcache[core]; 60 50 cache_err_dcache[core] = 0; 61 - edac_device_handle_ue(ed, 0, 0, ed->ctl_name); 51 + } else { 52 + dcache_err = read_octeon_c0_dcacheerr(); 62 53 } 63 54 64 - return NOTIFY_DONE; 65 - } 55 + if (icache_err & 1) { 56 + edac_device_printk(p->ed, KERN_ERR, 57 + "CacheErr (Icache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n", 58 + (unsigned long long)icache_err, core, cpu, 59 + read_c0_errorepc()); 60 + write_octeon_c0_icacheerr(0); 61 + edac_device_handle_ce(p->ed, cpu, 1, "icache"); 62 + } 63 + if (dcache_err & 1) { 64 + edac_device_printk(p->ed, KERN_ERR, 65 + "CacheErr (Dcache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n", 66 + (unsigned long long)dcache_err, core, cpu, 67 + read_c0_errorepc()); 68 + if (event) 69 + edac_device_handle_ue(p->ed, cpu, 0, "dcache"); 70 + else 71 + edac_device_handle_ce(p->ed, cpu, 0, "dcache"); 66 72 67 - static struct notifier_block co_cache_error_notifier = { 68 - .notifier_call = co_cache_error_event, 69 - }; 73 + /* Clear the error indication */ 74 + if (OCTEON_IS_MODEL(OCTEON_FAM_2)) 75 + write_octeon_c0_dcacheerr(1); 76 + else 77 + write_octeon_c0_dcacheerr(0); 78 + } 79 + 80 + return NOTIFY_STOP; 81 + } 70 82 71 83 static int __devinit co_cache_error_probe(struct platform_device *pdev) 72 84 { 73 - struct edac_device_ctl_info *ed; 74 - int res = 0; 85 + struct co_cache_error *p = devm_kzalloc(&pdev->dev, sizeof(*p), 86 + GFP_KERNEL); 87 + if (!p) 88 + return -ENOMEM; 75 89 76 - ed = edac_device_alloc_ctl_info(0, "cpu", 1, NULL, 0, 0, NULL, 0, 77 - edac_device_alloc_index()); 90 + p->notifier.notifier_call = co_cache_error_event; 91 + platform_set_drvdata(pdev, p); 78 92 79 - ed->dev = &pdev->dev; 80 - platform_set_drvdata(pdev, ed); 81 - ed->dev_name = dev_name(&pdev->dev); 82 - 83 - ed->mod_name = "octeon-cpu"; 84 - ed->ctl_name = "co_cpu_err"; 85 - 86 - if (edac_device_add_device(ed) > 0) { 87 - pr_err("%s: edac_device_add_device() failed\n", __func__); 93 + p->ed = edac_device_alloc_ctl_info(0, "cpu", num_possible_cpus(), 94 + "cache", 2, 0, NULL, 0, 95 + edac_device_alloc_index()); 96 + if (!p->ed) 88 97 goto err; 98 + 99 + p->ed->dev = &pdev->dev; 100 + 101 + p->ed->dev_name = dev_name(&pdev->dev); 102 + 103 + p->ed->mod_name = "octeon-cpu"; 104 + p->ed->ctl_name = "cache"; 105 + 106 + if (edac_device_add_device(p->ed)) { 107 + pr_err("%s: edac_device_add_device() failed\n", __func__); 108 + goto err1; 89 109 } 90 110 91 - register_co_cache_error_notifier(&co_cache_error_notifier); 92 - ed_cavium = ed; 111 + register_co_cache_error_notifier(&p->notifier); 93 112 94 113 return 0; 95 114 115 + err1: 116 + edac_device_free_ctl_info(p->ed); 96 117 err: 97 - edac_device_free_ctl_info(ed); 98 - 99 - return res; 118 + return -ENXIO; 100 119 } 101 120 102 121 static int co_cache_error_remove(struct platform_device *pdev) 103 122 { 104 - struct edac_device_ctl_info *ed = platform_get_drvdata(pdev); 123 + struct co_cache_error *p = platform_get_drvdata(pdev); 105 124 106 - unregister_co_cache_error_notifier(&co_cache_error_notifier); 107 - ed_cavium = NULL; 125 + unregister_co_cache_error_notifier(&p->notifier); 108 126 edac_device_del_device(&pdev->dev); 109 - edac_device_free_ctl_info(ed); 110 - 127 + edac_device_free_ctl_info(p->ed); 111 128 return 0; 112 129 } 113 130 ··· 134 113 .probe = co_cache_error_probe, 135 114 .remove = co_cache_error_remove, 136 115 .driver = { 137 - .name = "co_pc_edac", 116 + .name = "octeon_pc_edac", 138 117 } 139 118 }; 140 - 141 - static int __init co_edac_init(void) 142 - { 143 - int ret; 144 - 145 - ret = platform_driver_register(&co_cache_error_driver); 146 - if (ret) 147 - pr_warning(EDAC_MOD_STR "CPU err failed to register\n"); 148 - 149 - return ret; 150 - } 151 - 152 - static void __exit co_edac_exit(void) 153 - { 154 - platform_driver_unregister(&co_cache_error_driver); 155 - } 156 - 157 - module_init(co_edac_init); 158 - module_exit(co_edac_exit); 119 + module_platform_driver(co_cache_error_driver); 159 120 160 121 MODULE_LICENSE("GPL"); 161 122 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+10 -34
drivers/edac/octeon_edac-pci.c
··· 3 3 * License. See the file "COPYING" in the main directory of this archive 4 4 * for more details. 5 5 * 6 + * Copyright (C) 2012 Cavium, Inc. 6 7 * Copyright (C) 2009 Wind River Systems, 7 8 * written by Ralf Baechle <ralf@linux-mips.org> 8 9 */ ··· 21 20 #include "edac_core.h" 22 21 #include "edac_module.h" 23 22 24 - #define EDAC_MOD_STR "octeon" 25 - 26 - static void co_pci_poll(struct edac_pci_ctl_info *pci) 23 + static void octeon_pci_poll(struct edac_pci_ctl_info *pci) 27 24 { 28 25 union cvmx_pci_cfg01 cfg01; 29 26 ··· 56 57 cfg01.s.mdpe = 1; /* Reset */ 57 58 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 58 59 } 59 - if (cfg01.s.mdpe) { 60 - edac_pci_handle_npe(pci, "Master Data Parity Error"); 61 - cfg01.s.mdpe = 1; /* Reset */ 62 - octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 63 - } 64 60 } 65 61 66 - static int __devinit co_pci_probe(struct platform_device *pdev) 62 + static int __devinit octeon_pci_probe(struct platform_device *pdev) 67 63 { 68 64 struct edac_pci_ctl_info *pci; 69 65 int res = 0; ··· 73 79 74 80 pci->mod_name = "octeon-pci"; 75 81 pci->ctl_name = "octeon_pci_err"; 76 - pci->edac_check = co_pci_poll; 82 + pci->edac_check = octeon_pci_poll; 77 83 78 84 if (edac_pci_add_device(pci, 0) > 0) { 79 85 pr_err("%s: edac_pci_add_device() failed\n", __func__); ··· 88 94 return res; 89 95 } 90 96 91 - static int co_pci_remove(struct platform_device *pdev) 97 + static int octeon_pci_remove(struct platform_device *pdev) 92 98 { 93 99 struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); 94 100 ··· 98 104 return 0; 99 105 } 100 106 101 - static struct platform_driver co_pci_driver = { 102 - .probe = co_pci_probe, 103 - .remove = co_pci_remove, 107 + static struct platform_driver octeon_pci_driver = { 108 + .probe = octeon_pci_probe, 109 + .remove = octeon_pci_remove, 104 110 .driver = { 105 - .name = "co_pci_edac", 111 + .name = "octeon_pci_edac", 106 112 } 107 113 }; 108 - 109 - static int __init co_edac_init(void) 110 - { 111 - int ret; 112 - 113 - ret = platform_driver_register(&co_pci_driver); 114 - if (ret) 115 - pr_warning(EDAC_MOD_STR " PCI EDAC failed to register\n"); 116 - 117 - return ret; 118 - } 119 - 120 - static void __exit co_edac_exit(void) 121 - { 122 - platform_driver_unregister(&co_pci_driver); 123 - } 124 - 125 - module_init(co_edac_init); 126 - module_exit(co_edac_exit); 114 + module_platform_driver(octeon_pci_driver); 127 115 128 116 MODULE_LICENSE("GPL"); 129 117 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");