Commit f0f3680e50352c57b6cfc5b0d44d63bb0aa20f80
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac
Pull EDAC fixes from Mauro Carvalho Chehab: "A series of EDAC driver fixes. It also has one core fix at the documentation, and a rename patch, fixing the name of the struct that contains the rank information." * 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac: edac: rename channel_info to rank_info i5400_edac: Avoid calling pci_put_device() twice edac: i5100 ack error detection register after each read edac: i5100 fix erroneous define for M1Err edac: sb_edac: Fix a wrong value setting for the previous value edac: sb_edac: Fix a INTERLEAVE_MODE() misuse edac: sb_edac: Let the driver depend on PCI_MMCONFIG edac: Improve the comments to better describe the memory concepts edac/ppc4xx_edac: Fix compilation Fix sb_edac compilation with 32 bits kernels
Showing 7 changed files Side-by-side Diff
drivers/edac/Kconfig
... | ... | @@ -215,7 +215,7 @@ |
215 | 215 | config EDAC_SBRIDGE |
216 | 216 | tristate "Intel Sandy-Bridge Integrated MC" |
217 | 217 | depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL |
218 | - depends on EXPERIMENTAL | |
218 | + depends on PCI_MMCONFIG && EXPERIMENTAL | |
219 | 219 | help |
220 | 220 | Support for error detection and correction the Intel |
221 | 221 | Sandy Bridge Integrated Memory Controller. |
drivers/edac/edac_mc.c
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | |
40 | 40 | #ifdef CONFIG_EDAC_DEBUG |
41 | 41 | |
42 | -static void edac_mc_dump_channel(struct channel_info *chan) | |
42 | +static void edac_mc_dump_channel(struct rank_info *chan) | |
43 | 43 | { |
44 | 44 | debugf4("\tchannel = %p\n", chan); |
45 | 45 | debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); |
... | ... | @@ -156,7 +156,7 @@ |
156 | 156 | { |
157 | 157 | struct mem_ctl_info *mci; |
158 | 158 | struct csrow_info *csi, *csrow; |
159 | - struct channel_info *chi, *chp, *chan; | |
159 | + struct rank_info *chi, *chp, *chan; | |
160 | 160 | void *pvt; |
161 | 161 | unsigned size; |
162 | 162 | int row, chn; |
... | ... | @@ -181,7 +181,7 @@ |
181 | 181 | * rather than an imaginary chunk of memory located at address 0. |
182 | 182 | */ |
183 | 183 | csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); |
184 | - chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi)); | |
184 | + chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi)); | |
185 | 185 | pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; |
186 | 186 | |
187 | 187 | /* setup index and various internal pointers */ |
drivers/edac/i5100_edac.c
... | ... | @@ -49,7 +49,7 @@ |
49 | 49 | #define I5100_FERR_NF_MEM_M6ERR_MASK (1 << 6) |
50 | 50 | #define I5100_FERR_NF_MEM_M5ERR_MASK (1 << 5) |
51 | 51 | #define I5100_FERR_NF_MEM_M4ERR_MASK (1 << 4) |
52 | -#define I5100_FERR_NF_MEM_M1ERR_MASK 1 | |
52 | +#define I5100_FERR_NF_MEM_M1ERR_MASK (1 << 1) | |
53 | 53 | #define I5100_FERR_NF_MEM_ANY_MASK \ |
54 | 54 | (I5100_FERR_NF_MEM_M16ERR_MASK | \ |
55 | 55 | I5100_FERR_NF_MEM_M15ERR_MASK | \ |
56 | 56 | |
57 | 57 | |
58 | 58 | |
59 | 59 | |
60 | 60 | |
... | ... | @@ -535,23 +535,20 @@ |
535 | 535 | static void i5100_check_error(struct mem_ctl_info *mci) |
536 | 536 | { |
537 | 537 | struct i5100_priv *priv = mci->pvt_info; |
538 | - u32 dw; | |
538 | + u32 dw, dw2; | |
539 | 539 | |
540 | - | |
541 | 540 | pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw); |
542 | 541 | if (i5100_ferr_nf_mem_any(dw)) { |
543 | - u32 dw2; | |
544 | 542 | |
545 | 543 | pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2); |
546 | - if (dw2) | |
547 | - pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, | |
548 | - dw2); | |
549 | - pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw); | |
550 | 544 | |
551 | 545 | i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw), |
552 | 546 | i5100_ferr_nf_mem_any(dw), |
553 | 547 | i5100_nerr_nf_mem_any(dw2)); |
548 | + | |
549 | + pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2); | |
554 | 550 | } |
551 | + pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw); | |
555 | 552 | } |
556 | 553 | |
557 | 554 | /* The i5100 chipset will scrub the entire memory once, then |
drivers/edac/i5400_edac.c
... | ... | @@ -735,7 +735,7 @@ |
735 | 735 | |
736 | 736 | /* Attempt to 'get' the MCH register we want */ |
737 | 737 | pdev = NULL; |
738 | - while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) { | |
738 | + while (1) { | |
739 | 739 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
740 | 740 | PCI_DEVICE_ID_INTEL_5400_ERR, pdev); |
741 | 741 | if (!pdev) { |
742 | 742 | |
743 | 743 | |
744 | 744 | |
745 | 745 | |
746 | 746 | |
... | ... | @@ -743,23 +743,42 @@ |
743 | 743 | i5400_printk(KERN_ERR, |
744 | 744 | "'system address,Process Bus' " |
745 | 745 | "device not found:" |
746 | - "vendor 0x%x device 0x%x ERR funcs " | |
746 | + "vendor 0x%x device 0x%x ERR func 1 " | |
747 | 747 | "(broken BIOS?)\n", |
748 | 748 | PCI_VENDOR_ID_INTEL, |
749 | 749 | PCI_DEVICE_ID_INTEL_5400_ERR); |
750 | - goto error; | |
750 | + return -ENODEV; | |
751 | 751 | } |
752 | 752 | |
753 | - /* Store device 16 funcs 1 and 2 */ | |
754 | - switch (PCI_FUNC(pdev->devfn)) { | |
755 | - case 1: | |
756 | - pvt->branchmap_werrors = pdev; | |
753 | + /* Store device 16 func 1 */ | |
754 | + if (PCI_FUNC(pdev->devfn) == 1) | |
757 | 755 | break; |
758 | - case 2: | |
759 | - pvt->fsb_error_regs = pdev; | |
760 | - break; | |
756 | + } | |
757 | + pvt->branchmap_werrors = pdev; | |
758 | + | |
759 | + pdev = NULL; | |
760 | + while (1) { | |
761 | + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | |
762 | + PCI_DEVICE_ID_INTEL_5400_ERR, pdev); | |
763 | + if (!pdev) { | |
764 | + /* End of list, leave */ | |
765 | + i5400_printk(KERN_ERR, | |
766 | + "'system address,Process Bus' " | |
767 | + "device not found:" | |
768 | + "vendor 0x%x device 0x%x ERR func 2 " | |
769 | + "(broken BIOS?)\n", | |
770 | + PCI_VENDOR_ID_INTEL, | |
771 | + PCI_DEVICE_ID_INTEL_5400_ERR); | |
772 | + | |
773 | + pci_dev_put(pvt->branchmap_werrors); | |
774 | + return -ENODEV; | |
761 | 775 | } |
776 | + | |
777 | + /* Store device 16 func 2 */ | |
778 | + if (PCI_FUNC(pdev->devfn) == 2) | |
779 | + break; | |
762 | 780 | } |
781 | + pvt->fsb_error_regs = pdev; | |
763 | 782 | |
764 | 783 | debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", |
765 | 784 | pci_name(pvt->system_address), |
... | ... | @@ -778,7 +797,10 @@ |
778 | 797 | "MC: 'BRANCH 0' device not found:" |
779 | 798 | "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", |
780 | 799 | PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0); |
781 | - goto error; | |
800 | + | |
801 | + pci_dev_put(pvt->fsb_error_regs); | |
802 | + pci_dev_put(pvt->branchmap_werrors); | |
803 | + return -ENODEV; | |
782 | 804 | } |
783 | 805 | |
784 | 806 | /* If this device claims to have more than 2 channels then |
785 | 807 | |
... | ... | @@ -796,14 +818,14 @@ |
796 | 818 | "(broken BIOS?)\n", |
797 | 819 | PCI_VENDOR_ID_INTEL, |
798 | 820 | PCI_DEVICE_ID_INTEL_5400_FBD1); |
799 | - goto error; | |
821 | + | |
822 | + pci_dev_put(pvt->branch_0); | |
823 | + pci_dev_put(pvt->fsb_error_regs); | |
824 | + pci_dev_put(pvt->branchmap_werrors); | |
825 | + return -ENODEV; | |
800 | 826 | } |
801 | 827 | |
802 | 828 | return 0; |
803 | - | |
804 | -error: | |
805 | - i5400_put_devices(mci); | |
806 | - return -ENODEV; | |
807 | 829 | } |
808 | 830 | |
809 | 831 | /* |
drivers/edac/ppc4xx_edac.c
... | ... | @@ -184,7 +184,7 @@ |
184 | 184 | |
185 | 185 | /* Function Prototypes */ |
186 | 186 | |
187 | -static int ppc4xx_edac_probe(struct platform_device *device) | |
187 | +static int ppc4xx_edac_probe(struct platform_device *device); | |
188 | 188 | static int ppc4xx_edac_remove(struct platform_device *device); |
189 | 189 | |
190 | 190 | /* Global Variables */ |
... | ... | @@ -1068,7 +1068,7 @@ |
1068 | 1068 | |
1069 | 1069 | mci->mod_name = PPC4XX_EDAC_MODULE_NAME; |
1070 | 1070 | mci->mod_ver = PPC4XX_EDAC_MODULE_REVISION; |
1071 | - mci->ctl_name = match->compatible, | |
1071 | + mci->ctl_name = ppc4xx_edac_match->compatible, | |
1072 | 1072 | mci->dev_name = np->full_name; |
1073 | 1073 | |
1074 | 1074 | /* Initialize callbacks */ |
drivers/edac/sb_edac.c
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | #include <linux/mmzone.h> |
21 | 21 | #include <linux/smp.h> |
22 | 22 | #include <linux/bitmap.h> |
23 | +#include <linux/math64.h> | |
23 | 24 | #include <asm/processor.h> |
24 | 25 | #include <asm/mce.h> |
25 | 26 | |
... | ... | @@ -670,6 +671,7 @@ |
670 | 671 | u32 reg; |
671 | 672 | u64 limit, prv = 0; |
672 | 673 | u64 tmp_mb; |
674 | + u32 mb, kb; | |
673 | 675 | u32 rir_way; |
674 | 676 | |
675 | 677 | /* |
... | ... | @@ -682,8 +684,9 @@ |
682 | 684 | pvt->tolm = GET_TOLM(reg); |
683 | 685 | tmp_mb = (1 + pvt->tolm) >> 20; |
684 | 686 | |
685 | - debugf0("TOLM: %Lu.%03Lu GB (0x%016Lx)\n", | |
686 | - tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tolm); | |
687 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
688 | + debugf0("TOLM: %u.%03u GB (0x%016Lx)\n", | |
689 | + mb, kb, (u64)pvt->tolm); | |
687 | 690 | |
688 | 691 | /* Address range is already 45:25 */ |
689 | 692 | pci_read_config_dword(pvt->pci_sad1, TOHM, |
... | ... | @@ -691,8 +694,9 @@ |
691 | 694 | pvt->tohm = GET_TOHM(reg); |
692 | 695 | tmp_mb = (1 + pvt->tohm) >> 20; |
693 | 696 | |
694 | - debugf0("TOHM: %Lu.%03Lu GB (0x%016Lx)", | |
695 | - tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tohm); | |
697 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
698 | + debugf0("TOHM: %u.%03u GB (0x%016Lx)", | |
699 | + mb, kb, (u64)pvt->tohm); | |
696 | 700 | |
697 | 701 | /* |
698 | 702 | * Step 2) Get SAD range and SAD Interleave list |
699 | 703 | |
... | ... | @@ -714,10 +718,11 @@ |
714 | 718 | break; |
715 | 719 | |
716 | 720 | tmp_mb = (limit + 1) >> 20; |
717 | - debugf0("SAD#%d %s up to %Lu.%03Lu GB (0x%016Lx) %s reg=0x%08x\n", | |
721 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
722 | + debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n", | |
718 | 723 | n_sads, |
719 | 724 | get_dram_attr(reg), |
720 | - tmp_mb / 1000, tmp_mb % 1000, | |
725 | + mb, kb, | |
721 | 726 | ((u64)tmp_mb) << 20L, |
722 | 727 | INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]", |
723 | 728 | reg); |
... | ... | @@ -747,8 +752,9 @@ |
747 | 752 | break; |
748 | 753 | tmp_mb = (limit + 1) >> 20; |
749 | 754 | |
750 | - debugf0("TAD#%d: up to %Lu.%03Lu GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", | |
751 | - n_tads, tmp_mb / 1000, tmp_mb % 1000, | |
755 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
756 | + debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", | |
757 | + n_tads, mb, kb, | |
752 | 758 | ((u64)tmp_mb) << 20L, |
753 | 759 | (u32)TAD_SOCK(reg), |
754 | 760 | (u32)TAD_CH(reg), |
... | ... | @@ -757,7 +763,7 @@ |
757 | 763 | (u32)TAD_TGT2(reg), |
758 | 764 | (u32)TAD_TGT3(reg), |
759 | 765 | reg); |
760 | - prv = tmp_mb; | |
766 | + prv = limit; | |
761 | 767 | } |
762 | 768 | |
763 | 769 | /* |
764 | 770 | |
... | ... | @@ -771,9 +777,10 @@ |
771 | 777 | tad_ch_nilv_offset[j], |
772 | 778 | ®); |
773 | 779 | tmp_mb = TAD_OFFSET(reg) >> 20; |
774 | - debugf0("TAD CH#%d, offset #%d: %Lu.%03Lu GB (0x%016Lx), reg=0x%08x\n", | |
780 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
781 | + debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n", | |
775 | 782 | i, j, |
776 | - tmp_mb / 1000, tmp_mb % 1000, | |
783 | + mb, kb, | |
777 | 784 | ((u64)tmp_mb) << 20L, |
778 | 785 | reg); |
779 | 786 | } |
780 | 787 | |
... | ... | @@ -795,9 +802,10 @@ |
795 | 802 | |
796 | 803 | tmp_mb = RIR_LIMIT(reg) >> 20; |
797 | 804 | rir_way = 1 << RIR_WAY(reg); |
798 | - debugf0("CH#%d RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d, reg=0x%08x\n", | |
805 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
806 | + debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", | |
799 | 807 | i, j, |
800 | - tmp_mb / 1000, tmp_mb % 1000, | |
808 | + mb, kb, | |
801 | 809 | ((u64)tmp_mb) << 20L, |
802 | 810 | rir_way, |
803 | 811 | reg); |
804 | 812 | |
... | ... | @@ -808,9 +816,10 @@ |
808 | 816 | ®); |
809 | 817 | tmp_mb = RIR_OFFSET(reg) << 6; |
810 | 818 | |
811 | - debugf0("CH#%d RIR#%d INTL#%d, offset %Lu.%03Lu GB (0x%016Lx), tgt: %d, reg=0x%08x\n", | |
819 | + mb = div_u64_rem(tmp_mb, 1000, &kb); | |
820 | + debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", | |
812 | 821 | i, j, k, |
813 | - tmp_mb / 1000, tmp_mb % 1000, | |
822 | + mb, kb, | |
814 | 823 | ((u64)tmp_mb) << 20L, |
815 | 824 | (u32)RIR_RNK_TGT(reg), |
816 | 825 | reg); |
... | ... | @@ -848,6 +857,7 @@ |
848 | 857 | u8 ch_way,sck_way; |
849 | 858 | u32 tad_offset; |
850 | 859 | u32 rir_way; |
860 | + u32 mb, kb; | |
851 | 861 | u64 ch_addr, offset, limit, prv = 0; |
852 | 862 | |
853 | 863 | |
... | ... | @@ -858,7 +868,7 @@ |
858 | 868 | * range (e. g. VGA addresses). It is unlikely, however, that the |
859 | 869 | * memory controller would generate an error on that range. |
860 | 870 | */ |
861 | - if ((addr > (u64) pvt->tolm) && (addr < (1L << 32))) { | |
871 | + if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) { | |
862 | 872 | sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr); |
863 | 873 | edac_mc_handle_ce_no_info(mci, msg); |
864 | 874 | return -EINVAL; |
... | ... | @@ -913,7 +923,7 @@ |
913 | 923 | addr, |
914 | 924 | limit, |
915 | 925 | sad_way + 7, |
916 | - INTERLEAVE_MODE(reg) ? "" : "XOR[18:16]"); | |
926 | + interleave_mode ? "" : "XOR[18:16]"); | |
917 | 927 | if (interleave_mode) |
918 | 928 | idx = ((addr >> 6) ^ (addr >> 16)) & 7; |
919 | 929 | else |
... | ... | @@ -1053,7 +1063,7 @@ |
1053 | 1063 | ch_addr = addr & 0x7f; |
1054 | 1064 | /* Remove socket wayness and remove 6 bits */ |
1055 | 1065 | addr >>= 6; |
1056 | - addr /= sck_xch; | |
1066 | + addr = div_u64(addr, sck_xch); | |
1057 | 1067 | #if 0 |
1058 | 1068 | /* Divide by channel way */ |
1059 | 1069 | addr = addr / ch_way; |
1060 | 1070 | |
... | ... | @@ -1073,10 +1083,10 @@ |
1073 | 1083 | continue; |
1074 | 1084 | |
1075 | 1085 | limit = RIR_LIMIT(reg); |
1076 | - | |
1077 | - debugf0("RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d\n", | |
1086 | + mb = div_u64_rem(limit >> 20, 1000, &kb); | |
1087 | + debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", | |
1078 | 1088 | n_rir, |
1079 | - (limit >> 20) / 1000, (limit >> 20) % 1000, | |
1089 | + mb, kb, | |
1080 | 1090 | limit, |
1081 | 1091 | 1 << RIR_WAY(reg)); |
1082 | 1092 | if (ch_addr <= limit) |
include/linux/edac.h
... | ... | @@ -70,25 +70,64 @@ |
70 | 70 | #define DEV_FLAG_X32 BIT(DEV_X32) |
71 | 71 | #define DEV_FLAG_X64 BIT(DEV_X64) |
72 | 72 | |
73 | -/* memory types */ | |
73 | +/** | |
74 | + * enum mem_type - memory types. For a more detailed reference, please see | |
75 | + * http://en.wikipedia.org/wiki/DRAM | |
76 | + * | |
77 | + * @MEM_EMPTY Empty csrow | |
78 | + * @MEM_RESERVED: Reserved csrow type | |
79 | + * @MEM_UNKNOWN: Unknown csrow type | |
80 | + * @MEM_FPM: FPM - Fast Page Mode, used on systems up to 1995. | |
81 | + * @MEM_EDO: EDO - Extended data out, used on systems up to 1998. | |
82 | + * @MEM_BEDO: BEDO - Burst Extended data out, an EDO variant. | |
83 | + * @MEM_SDR: SDR - Single data rate SDRAM | |
84 | + * http://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory | |
85 | + * They use 3 pins for chip select: Pins 0 and 2 are | |
86 | + * for rank 0; pins 1 and 3 are for rank 1, if the memory | |
87 | + * is dual-rank. | |
88 | + * @MEM_RDR: Registered SDR SDRAM | |
89 | + * @MEM_DDR: Double data rate SDRAM | |
90 | + * http://en.wikipedia.org/wiki/DDR_SDRAM | |
91 | + * @MEM_RDDR: Registered Double data rate SDRAM | |
92 | + * This is a variant of the DDR memories. | |
93 | + * A registered memory has a buffer inside it, hiding | |
94 | + * part of the memory details to the memory controller. | |
95 | + * @MEM_RMBS: Rambus DRAM, used on a few Pentium III/IV controllers. | |
96 | + * @MEM_DDR2: DDR2 RAM, as described at JEDEC JESD79-2F. | |
97 | + * Those memories are labed as "PC2-" instead of "PC" to | |
98 | + * differenciate from DDR. | |
99 | + * @MEM_FB_DDR2: Fully-Buffered DDR2, as described at JEDEC Std No. 205 | |
100 | + * and JESD206. | |
101 | + * Those memories are accessed per DIMM slot, and not by | |
102 | + * a chip select signal. | |
103 | + * @MEM_RDDR2: Registered DDR2 RAM | |
104 | + * This is a variant of the DDR2 memories. | |
105 | + * @MEM_XDR: Rambus XDR | |
106 | + * It is an evolution of the original RAMBUS memories, | |
107 | + * created to compete with DDR2. Weren't used on any | |
108 | + * x86 arch, but cell_edac PPC memory controller uses it. | |
109 | + * @MEM_DDR3: DDR3 RAM | |
110 | + * @MEM_RDDR3: Registered DDR3 RAM | |
111 | + * This is a variant of the DDR3 memories. | |
112 | + */ | |
74 | 113 | enum mem_type { |
75 | - MEM_EMPTY = 0, /* Empty csrow */ | |
76 | - MEM_RESERVED, /* Reserved csrow type */ | |
77 | - MEM_UNKNOWN, /* Unknown csrow type */ | |
78 | - MEM_FPM, /* Fast page mode */ | |
79 | - MEM_EDO, /* Extended data out */ | |
80 | - MEM_BEDO, /* Burst Extended data out */ | |
81 | - MEM_SDR, /* Single data rate SDRAM */ | |
82 | - MEM_RDR, /* Registered single data rate SDRAM */ | |
83 | - MEM_DDR, /* Double data rate SDRAM */ | |
84 | - MEM_RDDR, /* Registered Double data rate SDRAM */ | |
85 | - MEM_RMBS, /* Rambus DRAM */ | |
86 | - MEM_DDR2, /* DDR2 RAM */ | |
87 | - MEM_FB_DDR2, /* fully buffered DDR2 */ | |
88 | - MEM_RDDR2, /* Registered DDR2 RAM */ | |
89 | - MEM_XDR, /* Rambus XDR */ | |
90 | - MEM_DDR3, /* DDR3 RAM */ | |
91 | - MEM_RDDR3, /* Registered DDR3 RAM */ | |
114 | + MEM_EMPTY = 0, | |
115 | + MEM_RESERVED, | |
116 | + MEM_UNKNOWN, | |
117 | + MEM_FPM, | |
118 | + MEM_EDO, | |
119 | + MEM_BEDO, | |
120 | + MEM_SDR, | |
121 | + MEM_RDR, | |
122 | + MEM_DDR, | |
123 | + MEM_RDDR, | |
124 | + MEM_RMBS, | |
125 | + MEM_DDR2, | |
126 | + MEM_FB_DDR2, | |
127 | + MEM_RDDR2, | |
128 | + MEM_XDR, | |
129 | + MEM_DDR3, | |
130 | + MEM_RDDR3, | |
92 | 131 | }; |
93 | 132 | |
94 | 133 | #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) |
95 | 134 | |
... | ... | @@ -166,9 +205,10 @@ |
166 | 205 | #define OP_OFFLINE 0x300 |
167 | 206 | |
168 | 207 | /* |
208 | + * Concepts used at the EDAC subsystem | |
209 | + * | |
169 | 210 | * There are several things to be aware of that aren't at all obvious: |
170 | 211 | * |
171 | - * | |
172 | 212 | * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc.. |
173 | 213 | * |
174 | 214 | * These are some of the many terms that are thrown about that don't always |
175 | 215 | |
176 | 216 | |
177 | 217 | |
178 | 218 | |
179 | 219 | |
... | ... | @@ -176,37 +216,62 @@ |
176 | 216 | * creating a common ground for discussion, terms and their definitions |
177 | 217 | * will be established. |
178 | 218 | * |
179 | - * Memory devices: The individual chip on a memory stick. These devices | |
180 | - * commonly output 4 and 8 bits each. Grouping several | |
181 | - * of these in parallel provides 64 bits which is common | |
182 | - * for a memory stick. | |
219 | + * Memory devices: The individual DRAM chips on a memory stick. These | |
220 | + * devices commonly output 4 and 8 bits each (x4, x8). | |
221 | + * Grouping several of these in parallel provides the | |
222 | + * number of bits that the memory controller expects: | |
223 | + * typically 72 bits, in order to provide 64 bits + | |
224 | + * 8 bits of ECC data. | |
183 | 225 | * |
184 | 226 | * Memory Stick: A printed circuit board that aggregates multiple |
185 | - * memory devices in parallel. This is the atomic | |
186 | - * memory component that is purchaseable by Joe consumer | |
187 | - * and loaded into a memory socket. | |
227 | + * memory devices in parallel. In general, this is the | |
228 | + * Field Replaceable Unit (FRU) which gets replaced, in | |
229 | + * the case of excessive errors. Most often it is also | |
230 | + * called DIMM (Dual Inline Memory Module). | |
188 | 231 | * |
189 | - * Socket: A physical connector on the motherboard that accepts | |
190 | - * a single memory stick. | |
232 | + * Memory Socket: A physical connector on the motherboard that accepts | |
233 | + * a single memory stick. Also called as "slot" on several | |
234 | + * datasheets. | |
191 | 235 | * |
192 | - * Channel: Set of memory devices on a memory stick that must be | |
193 | - * grouped in parallel with one or more additional | |
194 | - * channels from other memory sticks. This parallel | |
195 | - * grouping of the output from multiple channels are | |
196 | - * necessary for the smallest granularity of memory access. | |
197 | - * Some memory controllers are capable of single channel - | |
198 | - * which means that memory sticks can be loaded | |
199 | - * individually. Other memory controllers are only | |
200 | - * capable of dual channel - which means that memory | |
201 | - * sticks must be loaded as pairs (see "socket set"). | |
236 | + * Channel: A memory controller channel, responsible to communicate | |
237 | + * with a group of DIMMs. Each channel has its own | |
238 | + * independent control (command) and data bus, and can | |
239 | + * be used independently or grouped with other channels. | |
202 | 240 | * |
203 | - * Chip-select row: All of the memory devices that are selected together. | |
204 | - * for a single, minimum grain of memory access. | |
205 | - * This selects all of the parallel memory devices across | |
206 | - * all of the parallel channels. Common chip-select rows | |
207 | - * for single channel are 64 bits, for dual channel 128 | |
208 | - * bits. | |
241 | + * Branch: It is typically the highest hierarchy on a | |
242 | + * Fully-Buffered DIMM memory controller. | |
243 | + * Typically, it contains two channels. | |
244 | + * Two channels at the same branch can be used in single | |
245 | + * mode or in lockstep mode. | |
246 | + * When lockstep is enabled, the cacheline is doubled, | |
247 | + * but it generally brings some performance penalty. | |
248 | + * Also, it is generally not possible to point to just one | |
249 | + * memory stick when an error occurs, as the error | |
250 | + * correction code is calculated using two DIMMs instead | |
251 | + * of one. Due to that, it is capable of correcting more | |
252 | + * errors than on single mode. | |
209 | 253 | * |
254 | + * Single-channel: The data accessed by the memory controller is contained | |
255 | + * into one dimm only. E. g. if the data is 64 bits-wide, | |
256 | + * the data flows to the CPU using one 64 bits parallel | |
257 | + * access. | |
258 | + * Typically used with SDR, DDR, DDR2 and DDR3 memories. | |
259 | + * FB-DIMM and RAMBUS use a different concept for channel, | |
260 | + * so this concept doesn't apply there. | |
261 | + * | |
262 | + * Double-channel: The data size accessed by the memory controller is | |
263 | + * interlaced into two dimms, accessed at the same time. | |
264 | + * E. g. if the DIMM is 64 bits-wide (72 bits with ECC), | |
265 | + * the data flows to the CPU using a 128 bits parallel | |
266 | + * access. | |
267 | + * | |
268 | + * Chip-select row: This is the name of the DRAM signal used to select the | |
269 | + * DRAM ranks to be accessed. Common chip-select rows for | |
270 | + * single channel are 64 bits, for dual channel 128 bits. | |
271 | + * It may not be visible by the memory controller, as some | |
272 | + * DIMM types have a memory buffer that can hide direct | |
273 | + * access to it from the Memory Controller. | |
274 | + * | |
210 | 275 | * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory. |
211 | 276 | * Motherboards commonly drive two chip-select pins to |
212 | 277 | * a memory stick. A single-ranked stick, will occupy |
... | ... | @@ -218,8 +283,8 @@ |
218 | 283 | * |
219 | 284 | * Double-sided stick: DEPRECATED TERM, see Double-Ranked stick. |
220 | 285 | * A double-sided stick has two chip-select rows which |
221 | - * access different sets of memory devices. The two | |
222 | - * rows cannot be accessed concurrently. "Double-sided" | |
286 | + * access different sets of memory devices. The two | |
287 | + * rows cannot be accessed concurrently. "Double-sided" | |
223 | 288 | * is irrespective of the memory devices being mounted |
224 | 289 | * on both sides of the memory stick. |
225 | 290 | * |
... | ... | @@ -247,10 +312,22 @@ |
247 | 312 | * PS - I enjoyed writing all that about as much as you enjoyed reading it. |
248 | 313 | */ |
249 | 314 | |
250 | -struct channel_info { | |
251 | - int chan_idx; /* channel index */ | |
252 | - u32 ce_count; /* Correctable Errors for this CHANNEL */ | |
253 | - char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ | |
315 | +/** | |
316 | + * struct rank_info - contains the information for one DIMM rank | |
317 | + * | |
318 | + * @chan_idx: channel number where the rank is (typically, 0 or 1) | |
319 | + * @ce_count: number of correctable errors for this rank | |
320 | + * @label: DIMM label. Different ranks for the same DIMM should be | |
321 | + * filled, on userspace, with the same label. | |
322 | + * FIXME: The core currently won't enforce it. | |
323 | + * @csrow: A pointer to the chip select row structure (the parent | |
324 | + * structure). The location of the rank is given by | |
325 | + * the (csrow->csrow_idx, chan_idx) vector. | |
326 | + */ | |
327 | +struct rank_info { | |
328 | + int chan_idx; | |
329 | + u32 ce_count; | |
330 | + char label[EDAC_MC_LABEL_LEN + 1]; | |
254 | 331 | struct csrow_info *csrow; /* the parent */ |
255 | 332 | }; |
256 | 333 | |
... | ... | @@ -274,7 +351,7 @@ |
274 | 351 | |
275 | 352 | /* channel information for this csrow */ |
276 | 353 | u32 nr_channels; |
277 | - struct channel_info *channels; | |
354 | + struct rank_info *channels; | |
278 | 355 | }; |
279 | 356 | |
280 | 357 | struct mcidev_sysfs_group { |