17ee40b89SJason Baron /* 27ee40b89SJason Baron * Intel E3-1200 37ee40b89SJason Baron * Copyright (C) 2014 Jason Baron <jbaron@akamai.com> 47ee40b89SJason Baron * 57ee40b89SJason Baron * Support for the E3-1200 processor family. Heavily based on previous 67ee40b89SJason Baron * Intel EDAC drivers. 77ee40b89SJason Baron * 87ee40b89SJason Baron * Since the DRAM controller is on the cpu chip, we can use its PCI device 97ee40b89SJason Baron * id to identify these processors. 107ee40b89SJason Baron * 117ee40b89SJason Baron * PCI DRAM controller device ids (Taken from The PCI ID Repository - http://pci-ids.ucw.cz/) 127ee40b89SJason Baron * 137ee40b89SJason Baron * 0108: Xeon E3-1200 Processor Family DRAM Controller 147ee40b89SJason Baron * 010c: Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller 157ee40b89SJason Baron * 0150: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller 167ee40b89SJason Baron * 0158: Xeon E3-1200 v2/Ivy Bridge DRAM Controller 177ee40b89SJason Baron * 015c: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller 187ee40b89SJason Baron * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller 197ee40b89SJason Baron * 0c08: Xeon E3-1200 v3 Processor DRAM Controller 207ee40b89SJason Baron * 217ee40b89SJason Baron * Based on Intel specification: 227ee40b89SJason Baron * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf 237ee40b89SJason Baron * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html 247ee40b89SJason Baron * 257ee40b89SJason Baron * According to the above datasheet (p.16): 267ee40b89SJason Baron * " 277ee40b89SJason Baron * 6. Software must not access B0/D0/F0 32-bit memory-mapped registers with 287ee40b89SJason Baron * requests that cross a DW boundary. 297ee40b89SJason Baron * " 307ee40b89SJason Baron * 317ee40b89SJason Baron * Thus, we make use of the explicit: lo_hi_readq(), which breaks the readq into 327ee40b89SJason Baron * 2 readl() calls. This restriction may be lifted in subsequent chip releases, 337ee40b89SJason Baron * but lo_hi_readq() ensures that we are safe across all e3-1200 processors. 347ee40b89SJason Baron */ 357ee40b89SJason Baron 367ee40b89SJason Baron #include <linux/module.h> 377ee40b89SJason Baron #include <linux/init.h> 387ee40b89SJason Baron #include <linux/pci.h> 397ee40b89SJason Baron #include <linux/pci_ids.h> 407ee40b89SJason Baron #include <linux/edac.h> 417ee40b89SJason Baron 427ee40b89SJason Baron #include <asm-generic/io-64-nonatomic-lo-hi.h> 437ee40b89SJason Baron #include "edac_core.h" 447ee40b89SJason Baron 457ee40b89SJason Baron #define IE31200_REVISION "1.0" 467ee40b89SJason Baron #define EDAC_MOD_STR "ie31200_edac" 477ee40b89SJason Baron 487ee40b89SJason Baron #define ie31200_printk(level, fmt, arg...) \ 497ee40b89SJason Baron edac_printk(level, "ie31200", fmt, ##arg) 507ee40b89SJason Baron 517ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108 527ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c 537ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150 547ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158 557ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c 567ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04 577ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08 587ee40b89SJason Baron 597ee40b89SJason Baron #define IE31200_DIMMS 4 607ee40b89SJason Baron #define IE31200_RANKS 8 617ee40b89SJason Baron #define IE31200_RANKS_PER_CHANNEL 4 627ee40b89SJason Baron #define IE31200_DIMMS_PER_CHANNEL 2 637ee40b89SJason Baron #define IE31200_CHANNELS 2 647ee40b89SJason Baron 657ee40b89SJason Baron /* Intel IE31200 register addresses - device 0 function 0 - DRAM Controller */ 667ee40b89SJason Baron #define IE31200_MCHBAR_LOW 0x48 677ee40b89SJason Baron #define IE31200_MCHBAR_HIGH 0x4c 687ee40b89SJason Baron #define IE31200_MCHBAR_MASK GENMASK_ULL(38, 15) 697ee40b89SJason Baron #define IE31200_MMR_WINDOW_SIZE BIT(15) 707ee40b89SJason Baron 717ee40b89SJason Baron /* 727ee40b89SJason Baron * Error Status Register (16b) 737ee40b89SJason Baron * 747ee40b89SJason Baron * 15 reserved 757ee40b89SJason Baron * 14 Isochronous TBWRR Run Behind FIFO Full 767ee40b89SJason Baron * (ITCV) 777ee40b89SJason Baron * 13 Isochronous TBWRR Run Behind FIFO Put 787ee40b89SJason Baron * (ITSTV) 797ee40b89SJason Baron * 12 reserved 807ee40b89SJason Baron * 11 MCH Thermal Sensor Event 817ee40b89SJason Baron * for SMI/SCI/SERR (GTSE) 827ee40b89SJason Baron * 10 reserved 837ee40b89SJason Baron * 9 LOCK to non-DRAM Memory Flag (LCKF) 847ee40b89SJason Baron * 8 reserved 857ee40b89SJason Baron * 7 DRAM Throttle Flag (DTF) 867ee40b89SJason Baron * 6:2 reserved 877ee40b89SJason Baron * 1 Multi-bit DRAM ECC Error Flag (DMERR) 887ee40b89SJason Baron * 0 Single-bit DRAM ECC Error Flag (DSERR) 897ee40b89SJason Baron */ 907ee40b89SJason Baron #define IE31200_ERRSTS 0xc8 917ee40b89SJason Baron #define IE31200_ERRSTS_UE BIT(1) 927ee40b89SJason Baron #define IE31200_ERRSTS_CE BIT(0) 937ee40b89SJason Baron #define IE31200_ERRSTS_BITS (IE31200_ERRSTS_UE | IE31200_ERRSTS_CE) 947ee40b89SJason Baron 957ee40b89SJason Baron /* 967ee40b89SJason Baron * Channel 0 ECC Error Log (64b) 977ee40b89SJason Baron * 987ee40b89SJason Baron * 63:48 Error Column Address (ERRCOL) 997ee40b89SJason Baron * 47:32 Error Row Address (ERRROW) 1007ee40b89SJason Baron * 31:29 Error Bank Address (ERRBANK) 1017ee40b89SJason Baron * 28:27 Error Rank Address (ERRRANK) 1027ee40b89SJason Baron * 26:24 reserved 1037ee40b89SJason Baron * 23:16 Error Syndrome (ERRSYND) 1047ee40b89SJason Baron * 15: 2 reserved 1057ee40b89SJason Baron * 1 Multiple Bit Error Status (MERRSTS) 1067ee40b89SJason Baron * 0 Correctable Error Status (CERRSTS) 1077ee40b89SJason Baron */ 1087ee40b89SJason Baron #define IE31200_C0ECCERRLOG 0x40c8 1097ee40b89SJason Baron #define IE31200_C1ECCERRLOG 0x44c8 1107ee40b89SJason Baron #define IE31200_ECCERRLOG_CE BIT(0) 1117ee40b89SJason Baron #define IE31200_ECCERRLOG_UE BIT(1) 1127ee40b89SJason Baron #define IE31200_ECCERRLOG_RANK_BITS GENMASK_ULL(28, 27) 1137ee40b89SJason Baron #define IE31200_ECCERRLOG_RANK_SHIFT 27 1147ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME_BITS GENMASK_ULL(23, 16) 1157ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME_SHIFT 16 1167ee40b89SJason Baron 1177ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME(log) \ 1187ee40b89SJason Baron ((log & IE31200_ECCERRLOG_SYNDROME_BITS) >> \ 1197ee40b89SJason Baron IE31200_ECCERRLOG_SYNDROME_SHIFT) 1207ee40b89SJason Baron 1217ee40b89SJason Baron #define IE31200_CAPID0 0xe4 1227ee40b89SJason Baron #define IE31200_CAPID0_PDCD BIT(4) 1237ee40b89SJason Baron #define IE31200_CAPID0_DDPCD BIT(6) 1247ee40b89SJason Baron #define IE31200_CAPID0_ECC BIT(1) 1257ee40b89SJason Baron 1267ee40b89SJason Baron #define IE31200_MAD_DIMM_0_OFFSET 0x5004 1277ee40b89SJason Baron #define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0) 1287ee40b89SJason Baron #define IE31200_MAD_DIMM_A_RANK BIT(17) 1297ee40b89SJason Baron #define IE31200_MAD_DIMM_A_WIDTH BIT(19) 1307ee40b89SJason Baron 1317ee40b89SJason Baron #define IE31200_PAGES(n) (n << (28 - PAGE_SHIFT)) 1327ee40b89SJason Baron 1337ee40b89SJason Baron static int nr_channels; 1347ee40b89SJason Baron 1357ee40b89SJason Baron struct ie31200_priv { 1367ee40b89SJason Baron void __iomem *window; 1377ee40b89SJason Baron }; 1387ee40b89SJason Baron 1397ee40b89SJason Baron enum ie31200_chips { 1407ee40b89SJason Baron IE31200 = 0, 1417ee40b89SJason Baron }; 1427ee40b89SJason Baron 1437ee40b89SJason Baron struct ie31200_dev_info { 1447ee40b89SJason Baron const char *ctl_name; 1457ee40b89SJason Baron }; 1467ee40b89SJason Baron 1477ee40b89SJason Baron struct ie31200_error_info { 1487ee40b89SJason Baron u16 errsts; 1497ee40b89SJason Baron u16 errsts2; 1507ee40b89SJason Baron u64 eccerrlog[IE31200_CHANNELS]; 1517ee40b89SJason Baron }; 1527ee40b89SJason Baron 1537ee40b89SJason Baron static const struct ie31200_dev_info ie31200_devs[] = { 1547ee40b89SJason Baron [IE31200] = { 1557ee40b89SJason Baron .ctl_name = "IE31200" 1567ee40b89SJason Baron }, 1577ee40b89SJason Baron }; 1587ee40b89SJason Baron 1597ee40b89SJason Baron struct dimm_data { 1607ee40b89SJason Baron u8 size; /* in 256MB multiples */ 1617ee40b89SJason Baron u8 dual_rank : 1, 1627ee40b89SJason Baron x16_width : 1; /* 0 means x8 width */ 1637ee40b89SJason Baron }; 1647ee40b89SJason Baron 1657ee40b89SJason Baron static int how_many_channels(struct pci_dev *pdev) 1667ee40b89SJason Baron { 1677ee40b89SJason Baron int n_channels; 1687ee40b89SJason Baron unsigned char capid0_2b; /* 2nd byte of CAPID0 */ 1697ee40b89SJason Baron 1707ee40b89SJason Baron pci_read_config_byte(pdev, IE31200_CAPID0 + 1, &capid0_2b); 1717ee40b89SJason Baron 1727ee40b89SJason Baron /* check PDCD: Dual Channel Disable */ 1737ee40b89SJason Baron if (capid0_2b & IE31200_CAPID0_PDCD) { 1747ee40b89SJason Baron edac_dbg(0, "In single channel mode\n"); 1757ee40b89SJason Baron n_channels = 1; 1767ee40b89SJason Baron } else { 1777ee40b89SJason Baron edac_dbg(0, "In dual channel mode\n"); 1787ee40b89SJason Baron n_channels = 2; 1797ee40b89SJason Baron } 1807ee40b89SJason Baron 1817ee40b89SJason Baron /* check DDPCD - check if both channels are filled */ 1827ee40b89SJason Baron if (capid0_2b & IE31200_CAPID0_DDPCD) 1837ee40b89SJason Baron edac_dbg(0, "2 DIMMS per channel disabled\n"); 1847ee40b89SJason Baron else 1857ee40b89SJason Baron edac_dbg(0, "2 DIMMS per channel enabled\n"); 1867ee40b89SJason Baron 1877ee40b89SJason Baron return n_channels; 1887ee40b89SJason Baron } 1897ee40b89SJason Baron 1907ee40b89SJason Baron static bool ecc_capable(struct pci_dev *pdev) 1917ee40b89SJason Baron { 1927ee40b89SJason Baron unsigned char capid0_4b; /* 4th byte of CAPID0 */ 1937ee40b89SJason Baron 1947ee40b89SJason Baron pci_read_config_byte(pdev, IE31200_CAPID0 + 3, &capid0_4b); 1957ee40b89SJason Baron if (capid0_4b & IE31200_CAPID0_ECC) 1967ee40b89SJason Baron return false; 1977ee40b89SJason Baron return true; 1987ee40b89SJason Baron } 1997ee40b89SJason Baron 2007ee40b89SJason Baron static int eccerrlog_row(int channel, u64 log) 2017ee40b89SJason Baron { 2027ee40b89SJason Baron int rank = ((log & IE31200_ECCERRLOG_RANK_BITS) >> 2037ee40b89SJason Baron IE31200_ECCERRLOG_RANK_SHIFT); 2047ee40b89SJason Baron return rank | (channel * IE31200_RANKS_PER_CHANNEL); 2057ee40b89SJason Baron } 2067ee40b89SJason Baron 2077ee40b89SJason Baron static void ie31200_clear_error_info(struct mem_ctl_info *mci) 2087ee40b89SJason Baron { 2097ee40b89SJason Baron /* 2107ee40b89SJason Baron * Clear any error bits. 2117ee40b89SJason Baron * (Yes, we really clear bits by writing 1 to them.) 2127ee40b89SJason Baron */ 2137ee40b89SJason Baron pci_write_bits16(to_pci_dev(mci->pdev), IE31200_ERRSTS, 2147ee40b89SJason Baron IE31200_ERRSTS_BITS, IE31200_ERRSTS_BITS); 2157ee40b89SJason Baron } 2167ee40b89SJason Baron 2177ee40b89SJason Baron static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci, 2187ee40b89SJason Baron struct ie31200_error_info *info) 2197ee40b89SJason Baron { 2207ee40b89SJason Baron struct pci_dev *pdev; 2217ee40b89SJason Baron struct ie31200_priv *priv = mci->pvt_info; 2227ee40b89SJason Baron void __iomem *window = priv->window; 2237ee40b89SJason Baron 2247ee40b89SJason Baron pdev = to_pci_dev(mci->pdev); 2257ee40b89SJason Baron 2267ee40b89SJason Baron /* 2277ee40b89SJason Baron * This is a mess because there is no atomic way to read all the 2287ee40b89SJason Baron * registers at once and the registers can transition from CE being 2297ee40b89SJason Baron * overwritten by UE. 2307ee40b89SJason Baron */ 2317ee40b89SJason Baron pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts); 2327ee40b89SJason Baron if (!(info->errsts & IE31200_ERRSTS_BITS)) 2337ee40b89SJason Baron return; 2347ee40b89SJason Baron 2357ee40b89SJason Baron info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG); 2367ee40b89SJason Baron if (nr_channels == 2) 2377ee40b89SJason Baron info->eccerrlog[1] = lo_hi_readq(window + IE31200_C1ECCERRLOG); 2387ee40b89SJason Baron 2397ee40b89SJason Baron pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2); 2407ee40b89SJason Baron 2417ee40b89SJason Baron /* 2427ee40b89SJason Baron * If the error is the same for both reads then the first set 2437ee40b89SJason Baron * of reads is valid. If there is a change then there is a CE 2447ee40b89SJason Baron * with no info and the second set of reads is valid and 2457ee40b89SJason Baron * should be UE info. 2467ee40b89SJason Baron */ 2477ee40b89SJason Baron if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) { 2487ee40b89SJason Baron info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG); 2497ee40b89SJason Baron if (nr_channels == 2) 2507ee40b89SJason Baron info->eccerrlog[1] = 2517ee40b89SJason Baron lo_hi_readq(window + IE31200_C1ECCERRLOG); 2527ee40b89SJason Baron } 2537ee40b89SJason Baron 2547ee40b89SJason Baron ie31200_clear_error_info(mci); 2557ee40b89SJason Baron } 2567ee40b89SJason Baron 2577ee40b89SJason Baron static void ie31200_process_error_info(struct mem_ctl_info *mci, 2587ee40b89SJason Baron struct ie31200_error_info *info) 2597ee40b89SJason Baron { 2607ee40b89SJason Baron int channel; 2617ee40b89SJason Baron u64 log; 2627ee40b89SJason Baron 2637ee40b89SJason Baron if (!(info->errsts & IE31200_ERRSTS_BITS)) 2647ee40b89SJason Baron return; 2657ee40b89SJason Baron 2667ee40b89SJason Baron if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) { 2677ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 2687ee40b89SJason Baron -1, -1, -1, "UE overwrote CE", ""); 2697ee40b89SJason Baron info->errsts = info->errsts2; 2707ee40b89SJason Baron } 2717ee40b89SJason Baron 2727ee40b89SJason Baron for (channel = 0; channel < nr_channels; channel++) { 2737ee40b89SJason Baron log = info->eccerrlog[channel]; 2747ee40b89SJason Baron if (log & IE31200_ECCERRLOG_UE) { 2757ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 2767ee40b89SJason Baron 0, 0, 0, 2777ee40b89SJason Baron eccerrlog_row(channel, log), 2787ee40b89SJason Baron channel, -1, 2797ee40b89SJason Baron "ie31200 UE", ""); 2807ee40b89SJason Baron } else if (log & IE31200_ECCERRLOG_CE) { 2817ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 2827ee40b89SJason Baron 0, 0, 2837ee40b89SJason Baron IE31200_ECCERRLOG_SYNDROME(log), 2847ee40b89SJason Baron eccerrlog_row(channel, log), 2857ee40b89SJason Baron channel, -1, 2867ee40b89SJason Baron "ie31200 CE", ""); 2877ee40b89SJason Baron } 2887ee40b89SJason Baron } 2897ee40b89SJason Baron } 2907ee40b89SJason Baron 2917ee40b89SJason Baron static void ie31200_check(struct mem_ctl_info *mci) 2927ee40b89SJason Baron { 2937ee40b89SJason Baron struct ie31200_error_info info; 2947ee40b89SJason Baron 2957ee40b89SJason Baron edac_dbg(1, "MC%d\n", mci->mc_idx); 2967ee40b89SJason Baron ie31200_get_and_clear_error_info(mci, &info); 2977ee40b89SJason Baron ie31200_process_error_info(mci, &info); 2987ee40b89SJason Baron } 2997ee40b89SJason Baron 3007ee40b89SJason Baron static void __iomem *ie31200_map_mchbar(struct pci_dev *pdev) 3017ee40b89SJason Baron { 3027ee40b89SJason Baron union { 3037ee40b89SJason Baron u64 mchbar; 3047ee40b89SJason Baron struct { 3057ee40b89SJason Baron u32 mchbar_low; 3067ee40b89SJason Baron u32 mchbar_high; 3077ee40b89SJason Baron }; 3087ee40b89SJason Baron } u; 3097ee40b89SJason Baron void __iomem *window; 3107ee40b89SJason Baron 3117ee40b89SJason Baron pci_read_config_dword(pdev, IE31200_MCHBAR_LOW, &u.mchbar_low); 3127ee40b89SJason Baron pci_read_config_dword(pdev, IE31200_MCHBAR_HIGH, &u.mchbar_high); 3137ee40b89SJason Baron u.mchbar &= IE31200_MCHBAR_MASK; 3147ee40b89SJason Baron 3157ee40b89SJason Baron if (u.mchbar != (resource_size_t)u.mchbar) { 3167ee40b89SJason Baron ie31200_printk(KERN_ERR, "mmio space beyond accessible range (0x%llx)\n", 3177ee40b89SJason Baron (unsigned long long)u.mchbar); 3187ee40b89SJason Baron return NULL; 3197ee40b89SJason Baron } 3207ee40b89SJason Baron 3217ee40b89SJason Baron window = ioremap_nocache(u.mchbar, IE31200_MMR_WINDOW_SIZE); 3227ee40b89SJason Baron if (!window) 3237ee40b89SJason Baron ie31200_printk(KERN_ERR, "Cannot map mmio space at 0x%llx\n", 3247ee40b89SJason Baron (unsigned long long)u.mchbar); 3257ee40b89SJason Baron 3267ee40b89SJason Baron return window; 3277ee40b89SJason Baron } 3287ee40b89SJason Baron 3297ee40b89SJason Baron static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) 3307ee40b89SJason Baron { 3317ee40b89SJason Baron int rc; 3327ee40b89SJason Baron int i, j; 3337ee40b89SJason Baron struct mem_ctl_info *mci = NULL; 3347ee40b89SJason Baron struct edac_mc_layer layers[2]; 3357ee40b89SJason Baron struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL]; 3367ee40b89SJason Baron void __iomem *window; 3377ee40b89SJason Baron struct ie31200_priv *priv; 3387ee40b89SJason Baron u32 addr_decode; 3397ee40b89SJason Baron 3407ee40b89SJason Baron edac_dbg(0, "MC:\n"); 3417ee40b89SJason Baron 3427ee40b89SJason Baron if (!ecc_capable(pdev)) { 3437ee40b89SJason Baron ie31200_printk(KERN_INFO, "No ECC support\n"); 3447ee40b89SJason Baron return -ENODEV; 3457ee40b89SJason Baron } 3467ee40b89SJason Baron 3477ee40b89SJason Baron window = ie31200_map_mchbar(pdev); 3487ee40b89SJason Baron if (!window) 3497ee40b89SJason Baron return -ENODEV; 3507ee40b89SJason Baron 3517ee40b89SJason Baron /* populate DIMM info */ 3527ee40b89SJason Baron for (i = 0; i < IE31200_CHANNELS; i++) { 3537ee40b89SJason Baron addr_decode = readl(window + IE31200_MAD_DIMM_0_OFFSET + 3547ee40b89SJason Baron (i * 4)); 3557ee40b89SJason Baron edac_dbg(0, "addr_decode: 0x%x\n", addr_decode); 3567ee40b89SJason Baron for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) { 3577ee40b89SJason Baron dimm_info[i][j].size = (addr_decode >> (j * 8)) & 3587ee40b89SJason Baron IE31200_MAD_DIMM_SIZE; 3597ee40b89SJason Baron dimm_info[i][j].dual_rank = (addr_decode & 3607ee40b89SJason Baron (IE31200_MAD_DIMM_A_RANK << j)) ? 1 : 0; 3617ee40b89SJason Baron dimm_info[i][j].x16_width = (addr_decode & 3627ee40b89SJason Baron (IE31200_MAD_DIMM_A_WIDTH << j)) ? 1 : 0; 3637ee40b89SJason Baron edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", 3647ee40b89SJason Baron dimm_info[i][j].size, 3657ee40b89SJason Baron dimm_info[i][j].dual_rank, 3667ee40b89SJason Baron dimm_info[i][j].x16_width); 3677ee40b89SJason Baron } 3687ee40b89SJason Baron } 3697ee40b89SJason Baron 3707ee40b89SJason Baron nr_channels = how_many_channels(pdev); 3717ee40b89SJason Baron 3727ee40b89SJason Baron layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 3737ee40b89SJason Baron layers[0].size = IE31200_DIMMS; 3747ee40b89SJason Baron layers[0].is_virt_csrow = true; 3757ee40b89SJason Baron layers[1].type = EDAC_MC_LAYER_CHANNEL; 3767ee40b89SJason Baron layers[1].size = nr_channels; 3777ee40b89SJason Baron layers[1].is_virt_csrow = false; 3787ee40b89SJason Baron mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 3797ee40b89SJason Baron sizeof(struct ie31200_priv)); 3807ee40b89SJason Baron 3817ee40b89SJason Baron rc = -ENOMEM; 3827ee40b89SJason Baron if (!mci) 3837ee40b89SJason Baron goto fail_unmap; 3847ee40b89SJason Baron 3857ee40b89SJason Baron edac_dbg(3, "MC: init mci\n"); 3867ee40b89SJason Baron 3877ee40b89SJason Baron mci->pdev = &pdev->dev; 3887ee40b89SJason Baron mci->mtype_cap = MEM_FLAG_DDR3; 3897ee40b89SJason Baron 3907ee40b89SJason Baron mci->edac_ctl_cap = EDAC_FLAG_SECDED; 3917ee40b89SJason Baron mci->edac_cap = EDAC_FLAG_SECDED; 3927ee40b89SJason Baron 3937ee40b89SJason Baron mci->mod_name = EDAC_MOD_STR; 3947ee40b89SJason Baron mci->mod_ver = IE31200_REVISION; 3957ee40b89SJason Baron mci->ctl_name = ie31200_devs[dev_idx].ctl_name; 3967ee40b89SJason Baron mci->dev_name = pci_name(pdev); 3977ee40b89SJason Baron mci->edac_check = ie31200_check; 3987ee40b89SJason Baron mci->ctl_page_to_phys = NULL; 3997ee40b89SJason Baron priv = mci->pvt_info; 4007ee40b89SJason Baron priv->window = window; 4017ee40b89SJason Baron 4027ee40b89SJason Baron /* 4037ee40b89SJason Baron * The dram rank boundary (DRB) reg values are boundary addresses 4047ee40b89SJason Baron * for each DRAM rank with a granularity of 64MB. DRB regs are 4057ee40b89SJason Baron * cumulative; the last one will contain the total memory 4067ee40b89SJason Baron * contained in all ranks. 4077ee40b89SJason Baron */ 4087ee40b89SJason Baron for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) { 4097ee40b89SJason Baron for (j = 0; j < IE31200_CHANNELS; j++) { 4107ee40b89SJason Baron struct dimm_info *dimm; 4117ee40b89SJason Baron unsigned long nr_pages; 4127ee40b89SJason Baron 4137ee40b89SJason Baron nr_pages = IE31200_PAGES(dimm_info[j][i].size); 4147ee40b89SJason Baron if (nr_pages == 0) 4157ee40b89SJason Baron continue; 4167ee40b89SJason Baron 4177ee40b89SJason Baron if (dimm_info[j][i].dual_rank) { 4187ee40b89SJason Baron nr_pages = nr_pages / 2; 4197ee40b89SJason Baron dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, 4207ee40b89SJason Baron mci->n_layers, (i * 2) + 1, 4217ee40b89SJason Baron j, 0); 4227ee40b89SJason Baron dimm->nr_pages = nr_pages; 4237ee40b89SJason Baron edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages); 4247ee40b89SJason Baron dimm->grain = 8; /* just a guess */ 4257ee40b89SJason Baron dimm->mtype = MEM_DDR3; 4267ee40b89SJason Baron dimm->dtype = DEV_UNKNOWN; 4277ee40b89SJason Baron dimm->edac_mode = EDAC_UNKNOWN; 4287ee40b89SJason Baron } 4297ee40b89SJason Baron dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, 4307ee40b89SJason Baron mci->n_layers, i * 2, j, 0); 4317ee40b89SJason Baron dimm->nr_pages = nr_pages; 4327ee40b89SJason Baron edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages); 4337ee40b89SJason Baron dimm->grain = 8; /* same guess */ 4347ee40b89SJason Baron dimm->mtype = MEM_DDR3; 4357ee40b89SJason Baron dimm->dtype = DEV_UNKNOWN; 4367ee40b89SJason Baron dimm->edac_mode = EDAC_UNKNOWN; 4377ee40b89SJason Baron } 4387ee40b89SJason Baron } 4397ee40b89SJason Baron 4407ee40b89SJason Baron ie31200_clear_error_info(mci); 4417ee40b89SJason Baron 4427ee40b89SJason Baron rc = -ENODEV; 4437ee40b89SJason Baron if (edac_mc_add_mc(mci)) { 4447ee40b89SJason Baron edac_dbg(3, "MC: failed edac_mc_add_mc()\n"); 4457ee40b89SJason Baron goto fail_free; 4467ee40b89SJason Baron } 4477ee40b89SJason Baron 4487ee40b89SJason Baron /* get this far and it's successful */ 4497ee40b89SJason Baron edac_dbg(3, "MC: success\n"); 4507ee40b89SJason Baron return 0; 4517ee40b89SJason Baron 4527ee40b89SJason Baron fail_free: 4537ee40b89SJason Baron if (mci) 4547ee40b89SJason Baron edac_mc_free(mci); 4557ee40b89SJason Baron fail_unmap: 4567ee40b89SJason Baron iounmap(window); 4577ee40b89SJason Baron 4587ee40b89SJason Baron return rc; 4597ee40b89SJason Baron } 4607ee40b89SJason Baron 4617ee40b89SJason Baron static int ie31200_init_one(struct pci_dev *pdev, 4627ee40b89SJason Baron const struct pci_device_id *ent) 4637ee40b89SJason Baron { 4647ee40b89SJason Baron edac_dbg(0, "MC:\n"); 4657ee40b89SJason Baron 4667ee40b89SJason Baron if (pci_enable_device(pdev) < 0) 4677ee40b89SJason Baron return -EIO; 4687ee40b89SJason Baron 4697ee40b89SJason Baron return ie31200_probe1(pdev, ent->driver_data); 4707ee40b89SJason Baron } 4717ee40b89SJason Baron 4727ee40b89SJason Baron static void ie31200_remove_one(struct pci_dev *pdev) 4737ee40b89SJason Baron { 4747ee40b89SJason Baron struct mem_ctl_info *mci; 4757ee40b89SJason Baron struct ie31200_priv *priv; 4767ee40b89SJason Baron 4777ee40b89SJason Baron edac_dbg(0, "\n"); 4787ee40b89SJason Baron mci = edac_mc_del_mc(&pdev->dev); 4797ee40b89SJason Baron if (!mci) 4807ee40b89SJason Baron return; 4817ee40b89SJason Baron priv = mci->pvt_info; 4827ee40b89SJason Baron iounmap(priv->window); 4837ee40b89SJason Baron edac_mc_free(mci); 4847ee40b89SJason Baron } 4857ee40b89SJason Baron 4867ee40b89SJason Baron static const struct pci_device_id ie31200_pci_tbl[] = { 4877ee40b89SJason Baron { 4887ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4897ee40b89SJason Baron IE31200}, 4907ee40b89SJason Baron { 4917ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4927ee40b89SJason Baron IE31200}, 4937ee40b89SJason Baron { 4947ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4957ee40b89SJason Baron IE31200}, 4967ee40b89SJason Baron { 4977ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4987ee40b89SJason Baron IE31200}, 4997ee40b89SJason Baron { 5007ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5017ee40b89SJason Baron IE31200}, 5027ee40b89SJason Baron { 5037ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5047ee40b89SJason Baron IE31200}, 5057ee40b89SJason Baron { 5067ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5077ee40b89SJason Baron IE31200}, 5087ee40b89SJason Baron { 5097ee40b89SJason Baron 0, 5107ee40b89SJason Baron } /* 0 terminated list. */ 5117ee40b89SJason Baron }; 5127ee40b89SJason Baron MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); 5137ee40b89SJason Baron 5147ee40b89SJason Baron static struct pci_driver ie31200_driver = { 5157ee40b89SJason Baron .name = EDAC_MOD_STR, 5167ee40b89SJason Baron .probe = ie31200_init_one, 5177ee40b89SJason Baron .remove = ie31200_remove_one, 5187ee40b89SJason Baron .id_table = ie31200_pci_tbl, 5197ee40b89SJason Baron }; 5207ee40b89SJason Baron 5217ee40b89SJason Baron static int __init ie31200_init(void) 5227ee40b89SJason Baron { 5237ee40b89SJason Baron edac_dbg(3, "MC:\n"); 5247ee40b89SJason Baron /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 5257ee40b89SJason Baron opstate_init(); 5267ee40b89SJason Baron 5277ee40b89SJason Baron return pci_register_driver(&ie31200_driver); 5287ee40b89SJason Baron } 5297ee40b89SJason Baron 5307ee40b89SJason Baron static void __exit ie31200_exit(void) 5317ee40b89SJason Baron { 5327ee40b89SJason Baron edac_dbg(3, "MC:\n"); 5337ee40b89SJason Baron pci_unregister_driver(&ie31200_driver); 5347ee40b89SJason Baron } 5357ee40b89SJason Baron 5367ee40b89SJason Baron module_init(ie31200_init); 5377ee40b89SJason Baron module_exit(ie31200_exit); 5387ee40b89SJason Baron 5397ee40b89SJason Baron MODULE_LICENSE("GPL"); 5407ee40b89SJason Baron MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 5417ee40b89SJason Baron MODULE_DESCRIPTION("MC support for Intel Processor E31200 memory hub controllers"); 542