diff options
author | Doug Thompson <norsk5@xmission.com> | 2006-06-30 04:56:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-30 14:25:39 -0400 |
commit | 1318952514d5651c453d89989595a9df3b37267b (patch) | |
tree | df793132fa7e24e53c68897d4302d964eb07b526 /drivers/edac/e752x_edac.c | |
parent | 2d7bbb91c8df26c60d223205a087507430024177 (diff) |
[PATCH] EDAC: probe1 cleanup 1-of-2
- Add lower-level functions that handle various parts of the initialization
done by the xxx_probe1() functions. Some of the xxx_probe1() functions are
much too long and complicated (see "Chapter 5: Functions" in
Documentation/CodingStyle).
- Cleanup of probe1() functions in EDAC
Signed-off-by: Doug Thompson <norsk5@xmission.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/edac/e752x_edac.c')
-rw-r--r-- | drivers/edac/e752x_edac.c | 322 |
1 files changed, 177 insertions, 145 deletions
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 5e773e382e8a..5351a76739e5 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c | |||
@@ -765,22 +765,174 @@ static void e752x_check(struct mem_ctl_info *mci) | |||
765 | e752x_process_error_info(mci, &info, 1); | 765 | e752x_process_error_info(mci, &info, 1); |
766 | } | 766 | } |
767 | 767 | ||
768 | static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | 768 | /* Return 1 if dual channel mode is active. Else return 0. */ |
769 | static inline int dual_channel_active(u16 ddrcsr) | ||
770 | { | ||
771 | return (((ddrcsr >> 12) & 3) == 3); | ||
772 | } | ||
773 | |||
774 | static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | ||
775 | u16 ddrcsr) | ||
776 | { | ||
777 | struct csrow_info *csrow; | ||
778 | unsigned long last_cumul_size; | ||
779 | int index, mem_dev, drc_chan; | ||
780 | int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ | ||
781 | int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ | ||
782 | u8 value; | ||
783 | u32 dra, drc, cumul_size; | ||
784 | |||
785 | pci_read_config_dword(pdev, E752X_DRA, &dra); | ||
786 | pci_read_config_dword(pdev, E752X_DRC, &drc); | ||
787 | drc_chan = dual_channel_active(ddrcsr); | ||
788 | drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ | ||
789 | drc_ddim = (drc >> 20) & 0x3; | ||
790 | |||
791 | /* The dram row boundary (DRB) reg values are boundary address for | ||
792 | * each DRAM row with a granularity of 64 or 128MB (single/dual | ||
793 | * channel operation). DRB regs are cumulative; therefore DRB7 will | ||
794 | * contain the total memory contained in all eight rows. | ||
795 | */ | ||
796 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | ||
797 | /* mem_dev 0=x8, 1=x4 */ | ||
798 | mem_dev = (dra >> (index * 4 + 2)) & 0x3; | ||
799 | csrow = &mci->csrows[index]; | ||
800 | |||
801 | mem_dev = (mem_dev == 2); | ||
802 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | ||
803 | /* convert a 128 or 64 MiB DRB to a page size. */ | ||
804 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); | ||
805 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, | ||
806 | cumul_size); | ||
807 | if (cumul_size == last_cumul_size) | ||
808 | continue; /* not populated */ | ||
809 | |||
810 | csrow->first_page = last_cumul_size; | ||
811 | csrow->last_page = cumul_size - 1; | ||
812 | csrow->nr_pages = cumul_size - last_cumul_size; | ||
813 | last_cumul_size = cumul_size; | ||
814 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | ||
815 | csrow->mtype = MEM_RDDR; /* only one type supported */ | ||
816 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; | ||
817 | |||
818 | /* | ||
819 | * if single channel or x8 devices then SECDED | ||
820 | * if dual channel and x4 then S4ECD4ED | ||
821 | */ | ||
822 | if (drc_ddim) { | ||
823 | if (drc_chan && mem_dev) { | ||
824 | csrow->edac_mode = EDAC_S4ECD4ED; | ||
825 | mci->edac_cap |= EDAC_FLAG_S4ECD4ED; | ||
826 | } else { | ||
827 | csrow->edac_mode = EDAC_SECDED; | ||
828 | mci->edac_cap |= EDAC_FLAG_SECDED; | ||
829 | } | ||
830 | } else | ||
831 | csrow->edac_mode = EDAC_NONE; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | static void e752x_init_mem_map_table(struct pci_dev *pdev, | ||
836 | struct e752x_pvt *pvt) | ||
769 | { | 837 | { |
770 | int rc = -ENODEV; | ||
771 | int index; | 838 | int index; |
839 | u8 value, last, row, stat8; | ||
840 | |||
841 | last = 0; | ||
842 | row = 0; | ||
843 | |||
844 | for (index = 0; index < 8; index += 2) { | ||
845 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | ||
846 | /* test if there is a dimm in this slot */ | ||
847 | if (value == last) { | ||
848 | /* no dimm in the slot, so flag it as empty */ | ||
849 | pvt->map[index] = 0xff; | ||
850 | pvt->map[index + 1] = 0xff; | ||
851 | } else { /* there is a dimm in the slot */ | ||
852 | pvt->map[index] = row; | ||
853 | row++; | ||
854 | last = value; | ||
855 | /* test the next value to see if the dimm is double | ||
856 | * sided | ||
857 | */ | ||
858 | pci_read_config_byte(pdev, E752X_DRB + index + 1, | ||
859 | &value); | ||
860 | pvt->map[index + 1] = (value == last) ? | ||
861 | 0xff : /* the dimm is single sided, | ||
862 | so flag as empty */ | ||
863 | row; /* this is a double sided dimm | ||
864 | to save the next row # */ | ||
865 | row++; | ||
866 | last = value; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | /* set the map type. 1 = normal, 0 = reversed */ | ||
871 | pci_read_config_byte(pdev, E752X_DRM, &stat8); | ||
872 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); | ||
873 | } | ||
874 | |||
875 | /* Return 0 on success or 1 on failure. */ | ||
876 | static int e752x_get_devs(struct pci_dev *pdev, int dev_idx, | ||
877 | struct e752x_pvt *pvt) | ||
878 | { | ||
879 | struct pci_dev *dev; | ||
880 | |||
881 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
882 | pvt->dev_info->err_dev, | ||
883 | pvt->bridge_ck); | ||
884 | |||
885 | if (pvt->bridge_ck == NULL) | ||
886 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, | ||
887 | PCI_DEVFN(0, 1)); | ||
888 | |||
889 | if (pvt->bridge_ck == NULL) { | ||
890 | e752x_printk(KERN_ERR, "error reporting device not found:" | ||
891 | "vendor %x device 0x%x (broken BIOS?)\n", | ||
892 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); | ||
893 | return 1; | ||
894 | } | ||
895 | |||
896 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, | ||
897 | NULL); | ||
898 | |||
899 | if (dev == NULL) | ||
900 | goto fail; | ||
901 | |||
902 | pvt->dev_d0f0 = dev; | ||
903 | pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); | ||
904 | |||
905 | return 0; | ||
906 | |||
907 | fail: | ||
908 | pci_dev_put(pvt->bridge_ck); | ||
909 | return 1; | ||
910 | } | ||
911 | |||
912 | static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) | ||
913 | { | ||
914 | struct pci_dev *dev; | ||
915 | |||
916 | dev = pvt->dev_d0f1; | ||
917 | /* Turn off error disable & SMI in case the BIOS turned it on */ | ||
918 | pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); | ||
919 | pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); | ||
920 | pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); | ||
921 | pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); | ||
922 | pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); | ||
923 | pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); | ||
924 | pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); | ||
925 | pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); | ||
926 | } | ||
927 | |||
928 | static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | ||
929 | { | ||
772 | u16 pci_data; | 930 | u16 pci_data; |
773 | u8 stat8; | 931 | u8 stat8; |
774 | struct mem_ctl_info *mci = NULL; | 932 | struct mem_ctl_info *mci; |
775 | struct e752x_pvt *pvt = NULL; | 933 | struct e752x_pvt *pvt; |
776 | u16 ddrcsr; | 934 | u16 ddrcsr; |
777 | u32 drc; | ||
778 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ | 935 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ |
779 | int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ | ||
780 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | ||
781 | u32 dra; | ||
782 | unsigned long last_cumul_size; | ||
783 | struct pci_dev *dev = NULL; | ||
784 | struct e752x_error_info discard; | 936 | struct e752x_error_info discard; |
785 | 937 | ||
786 | debugf0("%s(): mci\n", __func__); | 938 | debugf0("%s(): mci\n", __func__); |
@@ -794,25 +946,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
794 | if (!force_function_unhide && !(stat8 & (1 << 5))) { | 946 | if (!force_function_unhide && !(stat8 & (1 << 5))) { |
795 | printk(KERN_INFO "Contact your BIOS vendor to see if the " | 947 | printk(KERN_INFO "Contact your BIOS vendor to see if the " |
796 | "E752x error registers can be safely un-hidden\n"); | 948 | "E752x error registers can be safely un-hidden\n"); |
797 | goto fail; | 949 | return -ENOMEM; |
798 | } | 950 | } |
799 | stat8 |= (1 << 5); | 951 | stat8 |= (1 << 5); |
800 | pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); | 952 | pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); |
801 | 953 | ||
802 | /* need to find out the number of channels */ | ||
803 | pci_read_config_dword(pdev, E752X_DRC, &drc); | ||
804 | pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); | 954 | pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); |
805 | /* FIXME: should check >>12 or 0xf, true for all? */ | 955 | /* FIXME: should check >>12 or 0xf, true for all? */ |
806 | /* Dual channel = 1, Single channel = 0 */ | 956 | /* Dual channel = 1, Single channel = 0 */ |
807 | drc_chan = (((ddrcsr >> 12) & 3) == 3); | 957 | drc_chan = dual_channel_active(ddrcsr); |
808 | drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ | ||
809 | drc_ddim = (drc >> 20) & 0x3; | ||
810 | 958 | ||
811 | mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1); | 959 | mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1); |
812 | 960 | ||
813 | if (mci == NULL) { | 961 | if (mci == NULL) { |
814 | rc = -ENOMEM; | 962 | return -ENOMEM; |
815 | goto fail; | ||
816 | } | 963 | } |
817 | 964 | ||
818 | debugf3("%s(): init mci\n", __func__); | 965 | debugf3("%s(): init mci\n", __func__); |
@@ -827,113 +974,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
827 | debugf3("%s(): init pvt\n", __func__); | 974 | debugf3("%s(): init pvt\n", __func__); |
828 | pvt = (struct e752x_pvt *) mci->pvt_info; | 975 | pvt = (struct e752x_pvt *) mci->pvt_info; |
829 | pvt->dev_info = &e752x_devs[dev_idx]; | 976 | pvt->dev_info = &e752x_devs[dev_idx]; |
830 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | 977 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); |
831 | pvt->dev_info->err_dev, | ||
832 | pvt->bridge_ck); | ||
833 | |||
834 | if (pvt->bridge_ck == NULL) | ||
835 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, | ||
836 | PCI_DEVFN(0, 1)); | ||
837 | 978 | ||
838 | if (pvt->bridge_ck == NULL) { | 979 | if (e752x_get_devs(pdev, dev_idx, pvt)) { |
839 | e752x_printk(KERN_ERR, "error reporting device not found:" | 980 | edac_mc_free(mci); |
840 | "vendor %x device 0x%x (broken BIOS?)\n", | 981 | return -ENODEV; |
841 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); | ||
842 | goto fail; | ||
843 | } | 982 | } |
844 | 983 | ||
845 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); | ||
846 | debugf3("%s(): more mci init\n", __func__); | 984 | debugf3("%s(): more mci init\n", __func__); |
847 | mci->ctl_name = pvt->dev_info->ctl_name; | 985 | mci->ctl_name = pvt->dev_info->ctl_name; |
848 | mci->edac_check = e752x_check; | 986 | mci->edac_check = e752x_check; |
849 | mci->ctl_page_to_phys = ctl_page_to_phys; | 987 | mci->ctl_page_to_phys = ctl_page_to_phys; |
850 | 988 | ||
851 | /* find out the device types */ | 989 | e752x_init_csrows(mci, pdev, ddrcsr); |
852 | pci_read_config_dword(pdev, E752X_DRA, &dra); | 990 | e752x_init_mem_map_table(pdev, pvt); |
853 | |||
854 | /* | ||
855 | * The dram row boundary (DRB) reg values are boundary address for | ||
856 | * each DRAM row with a granularity of 64 or 128MB (single/dual | ||
857 | * channel operation). DRB regs are cumulative; therefore DRB7 will | ||
858 | * contain the total memory contained in all eight rows. | ||
859 | */ | ||
860 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | ||
861 | u8 value; | ||
862 | u32 cumul_size; | ||
863 | |||
864 | /* mem_dev 0=x8, 1=x4 */ | ||
865 | int mem_dev = (dra >> (index * 4 + 2)) & 0x3; | ||
866 | struct csrow_info *csrow = &mci->csrows[index]; | ||
867 | |||
868 | mem_dev = (mem_dev == 2); | ||
869 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | ||
870 | /* convert a 128 or 64 MiB DRB to a page size. */ | ||
871 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); | ||
872 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, | ||
873 | cumul_size); | ||
874 | |||
875 | if (cumul_size == last_cumul_size) | ||
876 | continue; /* not populated */ | ||
877 | |||
878 | csrow->first_page = last_cumul_size; | ||
879 | csrow->last_page = cumul_size - 1; | ||
880 | csrow->nr_pages = cumul_size - last_cumul_size; | ||
881 | last_cumul_size = cumul_size; | ||
882 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | ||
883 | csrow->mtype = MEM_RDDR; /* only one type supported */ | ||
884 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; | ||
885 | |||
886 | /* | ||
887 | * if single channel or x8 devices then SECDED | ||
888 | * if dual channel and x4 then S4ECD4ED | ||
889 | */ | ||
890 | if (drc_ddim) { | ||
891 | if (drc_chan && mem_dev) { | ||
892 | csrow->edac_mode = EDAC_S4ECD4ED; | ||
893 | mci->edac_cap |= EDAC_FLAG_S4ECD4ED; | ||
894 | } else { | ||
895 | csrow->edac_mode = EDAC_SECDED; | ||
896 | mci->edac_cap |= EDAC_FLAG_SECDED; | ||
897 | } | ||
898 | } else | ||
899 | csrow->edac_mode = EDAC_NONE; | ||
900 | } | ||
901 | |||
902 | /* Fill in the memory map table */ | ||
903 | { | ||
904 | u8 value; | ||
905 | u8 last = 0; | ||
906 | u8 row = 0; | ||
907 | |||
908 | for (index = 0; index < 8; index += 2) { | ||
909 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | ||
910 | |||
911 | /* test if there is a dimm in this slot */ | ||
912 | if (value == last) { | ||
913 | /* no dimm in the slot, so flag it as empty */ | ||
914 | pvt->map[index] = 0xff; | ||
915 | pvt->map[index + 1] = 0xff; | ||
916 | } else { /* there is a dimm in the slot */ | ||
917 | pvt->map[index] = row; | ||
918 | row++; | ||
919 | last = value; | ||
920 | /* test the next value to see if the dimm is | ||
921 | double sided */ | ||
922 | pci_read_config_byte(pdev, | ||
923 | E752X_DRB + index + 1, | ||
924 | &value); | ||
925 | pvt->map[index + 1] = (value == last) ? | ||
926 | 0xff : /* the dimm is single sided, | ||
927 | * so flag as empty | ||
928 | */ | ||
929 | row; /* this is a double sided dimm | ||
930 | * to save the next row # | ||
931 | */ | ||
932 | row++; | ||
933 | last = value; | ||
934 | } | ||
935 | } | ||
936 | } | ||
937 | 991 | ||
938 | /* set the map type. 1 = normal, 0 = reversed */ | 992 | /* set the map type. 1 = normal, 0 = reversed */ |
939 | pci_read_config_byte(pdev, E752X_DRM, &stat8); | 993 | pci_read_config_byte(pdev, E752X_DRM, &stat8); |
@@ -961,21 +1015,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
961 | goto fail; | 1015 | goto fail; |
962 | } | 1016 | } |
963 | 1017 | ||
964 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, | 1018 | e752x_init_error_reporting_regs(pvt); |
965 | NULL); | ||
966 | pvt->dev_d0f0 = dev; | ||
967 | /* find the error reporting device and clear errors */ | ||
968 | dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); | ||
969 | /* Turn off error disable & SMI in case the BIOS turned it on */ | ||
970 | pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); | ||
971 | pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); | ||
972 | pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); | ||
973 | pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); | ||
974 | pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); | ||
975 | pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); | ||
976 | pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); | ||
977 | pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); | ||
978 | |||
979 | e752x_get_error_info(mci, &discard); /* clear other MCH errors */ | 1019 | e752x_get_error_info(mci, &discard); /* clear other MCH errors */ |
980 | 1020 | ||
981 | /* get this far and it's successful */ | 1021 | /* get this far and it's successful */ |
@@ -983,20 +1023,12 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
983 | return 0; | 1023 | return 0; |
984 | 1024 | ||
985 | fail: | 1025 | fail: |
986 | if (mci) { | 1026 | pci_dev_put(pvt->dev_d0f0); |
987 | if (pvt->dev_d0f0) | 1027 | pci_dev_put(pvt->dev_d0f1); |
988 | pci_dev_put(pvt->dev_d0f0); | 1028 | pci_dev_put(pvt->bridge_ck); |
989 | 1029 | edac_mc_free(mci); | |
990 | if (pvt->dev_d0f1) | ||
991 | pci_dev_put(pvt->dev_d0f1); | ||
992 | |||
993 | if (pvt->bridge_ck) | ||
994 | pci_dev_put(pvt->bridge_ck); | ||
995 | |||
996 | edac_mc_free(mci); | ||
997 | } | ||
998 | 1030 | ||
999 | return rc; | 1031 | return -ENODEV; |
1000 | } | 1032 | } |
1001 | 1033 | ||
1002 | /* returns count (>= 0), or negative on error */ | 1034 | /* returns count (>= 0), or negative on error */ |