diff options
-rw-r--r-- | drivers/edac/amd64_edac.c | 59 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 14 |
2 files changed, 49 insertions, 24 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9efa88a9fdf5..9bc0299e8c74 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -18,6 +18,7 @@ static struct msr __percpu *msrs; | |||
18 | /* Per-node driver instances */ | 18 | /* Per-node driver instances */ |
19 | static struct mem_ctl_info **mcis; | 19 | static struct mem_ctl_info **mcis; |
20 | static struct amd64_pvt **pvts; | 20 | static struct amd64_pvt **pvts; |
21 | static struct ecc_settings **ecc_stngs; | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and | 24 | * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and |
@@ -2293,7 +2294,7 @@ out: | |||
2293 | return ret; | 2294 | return ret; |
2294 | } | 2295 | } |
2295 | 2296 | ||
2296 | static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) | 2297 | static int amd64_toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on) |
2297 | { | 2298 | { |
2298 | cpumask_var_t cmask; | 2299 | cpumask_var_t cmask; |
2299 | int cpu; | 2300 | int cpu; |
@@ -2303,7 +2304,7 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) | |||
2303 | return false; | 2304 | return false; |
2304 | } | 2305 | } |
2305 | 2306 | ||
2306 | get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id); | 2307 | get_cpus_on_this_dct_cpumask(cmask, nid); |
2307 | 2308 | ||
2308 | rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); | 2309 | rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); |
2309 | 2310 | ||
@@ -2313,14 +2314,14 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) | |||
2313 | 2314 | ||
2314 | if (on) { | 2315 | if (on) { |
2315 | if (reg->l & K8_MSR_MCGCTL_NBE) | 2316 | if (reg->l & K8_MSR_MCGCTL_NBE) |
2316 | pvt->flags.nb_mce_enable = 1; | 2317 | s->flags.nb_mce_enable = 1; |
2317 | 2318 | ||
2318 | reg->l |= K8_MSR_MCGCTL_NBE; | 2319 | reg->l |= K8_MSR_MCGCTL_NBE; |
2319 | } else { | 2320 | } else { |
2320 | /* | 2321 | /* |
2321 | * Turn off NB MCE reporting only when it was off before | 2322 | * Turn off NB MCE reporting only when it was off before |
2322 | */ | 2323 | */ |
2323 | if (!pvt->flags.nb_mce_enable) | 2324 | if (!s->flags.nb_mce_enable) |
2324 | reg->l &= ~K8_MSR_MCGCTL_NBE; | 2325 | reg->l &= ~K8_MSR_MCGCTL_NBE; |
2325 | } | 2326 | } |
2326 | } | 2327 | } |
@@ -2334,18 +2335,20 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) | |||
2334 | static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | 2335 | static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) |
2335 | { | 2336 | { |
2336 | struct amd64_pvt *pvt = mci->pvt_info; | 2337 | struct amd64_pvt *pvt = mci->pvt_info; |
2338 | u8 nid = pvt->mc_node_id; | ||
2339 | struct ecc_settings *s = ecc_stngs[nid]; | ||
2337 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; | 2340 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; |
2338 | 2341 | ||
2339 | amd64_read_pci_cfg(pvt->F3, K8_NBCTL, &value); | 2342 | amd64_read_pci_cfg(pvt->F3, K8_NBCTL, &value); |
2340 | 2343 | ||
2341 | /* turn on UECCn and CECCEn bits */ | 2344 | /* turn on UECCEn and CECCEn bits */ |
2342 | pvt->old_nbctl = value & mask; | 2345 | s->old_nbctl = value & mask; |
2343 | pvt->nbctl_mcgctl_saved = 1; | 2346 | s->nbctl_valid = true; |
2344 | 2347 | ||
2345 | value |= mask; | 2348 | value |= mask; |
2346 | pci_write_config_dword(pvt->F3, K8_NBCTL, value); | 2349 | pci_write_config_dword(pvt->F3, K8_NBCTL, value); |
2347 | 2350 | ||
2348 | if (amd64_toggle_ecc_err_reporting(pvt, ON)) | 2351 | if (amd64_toggle_ecc_err_reporting(s, nid, ON)) |
2349 | amd64_warn("Error enabling ECC reporting over MCGCTL!\n"); | 2352 | amd64_warn("Error enabling ECC reporting over MCGCTL!\n"); |
2350 | 2353 | ||
2351 | amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &value); | 2354 | amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &value); |
@@ -2357,7 +2360,7 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | |||
2357 | if (!(value & K8_NBCFG_ECC_ENABLE)) { | 2360 | if (!(value & K8_NBCFG_ECC_ENABLE)) { |
2358 | amd64_warn("DRAM ECC disabled on this node, enabling...\n"); | 2361 | amd64_warn("DRAM ECC disabled on this node, enabling...\n"); |
2359 | 2362 | ||
2360 | pvt->flags.nb_ecc_prev = 0; | 2363 | s->flags.nb_ecc_prev = 0; |
2361 | 2364 | ||
2362 | /* Attempt to turn on DRAM ECC Enable */ | 2365 | /* Attempt to turn on DRAM ECC Enable */ |
2363 | value |= K8_NBCFG_ECC_ENABLE; | 2366 | value |= K8_NBCFG_ECC_ENABLE; |
@@ -2372,7 +2375,7 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | |||
2372 | amd64_info("Hardware accepted DRAM ECC Enable\n"); | 2375 | amd64_info("Hardware accepted DRAM ECC Enable\n"); |
2373 | } | 2376 | } |
2374 | } else { | 2377 | } else { |
2375 | pvt->flags.nb_ecc_prev = 1; | 2378 | s->flags.nb_ecc_prev = 1; |
2376 | } | 2379 | } |
2377 | 2380 | ||
2378 | debugf0("NBCFG(2)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value, | 2381 | debugf0("NBCFG(2)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value, |
@@ -2384,26 +2387,28 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | |||
2384 | 2387 | ||
2385 | static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) | 2388 | static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) |
2386 | { | 2389 | { |
2390 | u8 nid = pvt->mc_node_id; | ||
2391 | struct ecc_settings *s = ecc_stngs[nid]; | ||
2387 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; | 2392 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; |
2388 | 2393 | ||
2389 | if (!pvt->nbctl_mcgctl_saved) | 2394 | if (!s->nbctl_valid) |
2390 | return; | 2395 | return; |
2391 | 2396 | ||
2392 | amd64_read_pci_cfg(pvt->F3, K8_NBCTL, &value); | 2397 | amd64_read_pci_cfg(pvt->F3, K8_NBCTL, &value); |
2393 | value &= ~mask; | 2398 | value &= ~mask; |
2394 | value |= pvt->old_nbctl; | 2399 | value |= s->old_nbctl; |
2395 | 2400 | ||
2396 | pci_write_config_dword(pvt->F3, K8_NBCTL, value); | 2401 | pci_write_config_dword(pvt->F3, K8_NBCTL, value); |
2397 | 2402 | ||
2398 | /* restore previous BIOS DRAM ECC "off" setting which we force-enabled */ | 2403 | /* restore previous BIOS DRAM ECC "off" setting we force-enabled */ |
2399 | if (!pvt->flags.nb_ecc_prev) { | 2404 | if (!s->flags.nb_ecc_prev) { |
2400 | amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &value); | 2405 | amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &value); |
2401 | value &= ~K8_NBCFG_ECC_ENABLE; | 2406 | value &= ~K8_NBCFG_ECC_ENABLE; |
2402 | pci_write_config_dword(pvt->F3, K8_NBCFG, value); | 2407 | pci_write_config_dword(pvt->F3, K8_NBCFG, value); |
2403 | } | 2408 | } |
2404 | 2409 | ||
2405 | /* restore the NB Enable MCGCTL bit */ | 2410 | /* restore the NB Enable MCGCTL bit */ |
2406 | if (amd64_toggle_ecc_err_reporting(pvt, OFF)) | 2411 | if (amd64_toggle_ecc_err_reporting(s, nid, OFF)) |
2407 | amd64_warn("Error restoring NB MCGCTL settings!\n"); | 2412 | amd64_warn("Error restoring NB MCGCTL settings!\n"); |
2408 | } | 2413 | } |
2409 | 2414 | ||
@@ -2654,6 +2659,8 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev, | |||
2654 | const struct pci_device_id *mc_type) | 2659 | const struct pci_device_id *mc_type) |
2655 | { | 2660 | { |
2656 | int ret = 0; | 2661 | int ret = 0; |
2662 | u8 nid = get_node_id(pdev); | ||
2663 | struct ecc_settings *s; | ||
2657 | 2664 | ||
2658 | ret = pci_enable_device(pdev); | 2665 | ret = pci_enable_device(pdev); |
2659 | if (ret < 0) { | 2666 | if (ret < 0) { |
@@ -2661,9 +2668,16 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev, | |||
2661 | return -EIO; | 2668 | return -EIO; |
2662 | } | 2669 | } |
2663 | 2670 | ||
2671 | ret = -ENOMEM; | ||
2672 | s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL); | ||
2673 | if (!s) | ||
2674 | return ret; | ||
2675 | |||
2676 | ecc_stngs[nid] = s; | ||
2677 | |||
2664 | ret = amd64_probe_one_instance(pdev); | 2678 | ret = amd64_probe_one_instance(pdev); |
2665 | if (ret < 0) | 2679 | if (ret < 0) |
2666 | amd64_err("Error probing instance: %d\n", get_node_id(pdev)); | 2680 | amd64_err("Error probing instance: %d\n", nid); |
2667 | 2681 | ||
2668 | return ret; | 2682 | return ret; |
2669 | } | 2683 | } |
@@ -2688,6 +2702,9 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev) | |||
2688 | amd_report_gart_errors(false); | 2702 | amd_report_gart_errors(false); |
2689 | amd_unregister_ecc_decoder(amd64_decode_bus_error); | 2703 | amd_unregister_ecc_decoder(amd64_decode_bus_error); |
2690 | 2704 | ||
2705 | kfree(ecc_stngs[pvt->mc_node_id]); | ||
2706 | ecc_stngs[pvt->mc_node_id] = NULL; | ||
2707 | |||
2691 | /* Free the EDAC CORE resources */ | 2708 | /* Free the EDAC CORE resources */ |
2692 | mci->pvt_info = NULL; | 2709 | mci->pvt_info = NULL; |
2693 | mcis[pvt->mc_node_id] = NULL; | 2710 | mcis[pvt->mc_node_id] = NULL; |
@@ -2767,9 +2784,10 @@ static int __init amd64_edac_init(void) | |||
2767 | goto err_ret; | 2784 | goto err_ret; |
2768 | 2785 | ||
2769 | err = -ENOMEM; | 2786 | err = -ENOMEM; |
2770 | pvts = kzalloc(amd_nb_num() * sizeof(pvts[0]), GFP_KERNEL); | 2787 | pvts = kzalloc(amd_nb_num() * sizeof(pvts[0]), GFP_KERNEL); |
2771 | mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); | 2788 | mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); |
2772 | if (!(pvts && mcis)) | 2789 | ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); |
2790 | if (!(pvts && mcis && ecc_stngs)) | ||
2773 | goto err_ret; | 2791 | goto err_ret; |
2774 | 2792 | ||
2775 | msrs = msrs_alloc(); | 2793 | msrs = msrs_alloc(); |
@@ -2820,6 +2838,9 @@ static void __exit amd64_edac_exit(void) | |||
2820 | 2838 | ||
2821 | pci_unregister_driver(&amd64_pci_driver); | 2839 | pci_unregister_driver(&amd64_pci_driver); |
2822 | 2840 | ||
2841 | kfree(ecc_stngs); | ||
2842 | ecc_stngs = NULL; | ||
2843 | |||
2823 | kfree(mcis); | 2844 | kfree(mcis); |
2824 | mcis = NULL; | 2845 | mcis = NULL; |
2825 | 2846 | ||
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 4bc6f183d97c..b76dce96e8e6 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -461,17 +461,21 @@ struct amd64_pvt { | |||
461 | /* place to store error injection parameters prior to issue */ | 461 | /* place to store error injection parameters prior to issue */ |
462 | struct error_injection injection; | 462 | struct error_injection injection; |
463 | 463 | ||
464 | /* Save old hw registers' values before we modified them */ | ||
465 | u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */ | ||
466 | u32 old_nbctl; | ||
467 | |||
468 | /* DCT per-family scrubrate setting */ | 464 | /* DCT per-family scrubrate setting */ |
469 | u32 min_scrubrate; | 465 | u32 min_scrubrate; |
470 | 466 | ||
471 | /* family name this instance is running on */ | 467 | /* family name this instance is running on */ |
472 | const char *ctl_name; | 468 | const char *ctl_name; |
473 | 469 | ||
474 | /* misc settings */ | 470 | }; |
471 | |||
472 | /* | ||
473 | * per-node ECC settings descriptor | ||
474 | */ | ||
475 | struct ecc_settings { | ||
476 | u32 old_nbctl; | ||
477 | bool nbctl_valid; | ||
478 | |||
475 | struct flags { | 479 | struct flags { |
476 | unsigned long nb_mce_enable:1; | 480 | unsigned long nb_mce_enable:1; |
477 | unsigned long nb_ecc_prev:1; | 481 | unsigned long nb_ecc_prev:1; |