109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27ee40b89SJason Baron /* 37ee40b89SJason Baron * Intel E3-1200 47ee40b89SJason Baron * Copyright (C) 2014 Jason Baron <jbaron@akamai.com> 57ee40b89SJason Baron * 67ee40b89SJason Baron * Support for the E3-1200 processor family. Heavily based on previous 77ee40b89SJason Baron * Intel EDAC drivers. 87ee40b89SJason Baron * 97ee40b89SJason Baron * Since the DRAM controller is on the cpu chip, we can use its PCI device 107ee40b89SJason Baron * id to identify these processors. 117ee40b89SJason Baron * 127ee40b89SJason Baron * PCI DRAM controller device ids (Taken from The PCI ID Repository - http://pci-ids.ucw.cz/) 137ee40b89SJason Baron * 147ee40b89SJason Baron * 0108: Xeon E3-1200 Processor Family DRAM Controller 157ee40b89SJason Baron * 010c: Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller 167ee40b89SJason Baron * 0150: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller 177ee40b89SJason Baron * 0158: Xeon E3-1200 v2/Ivy Bridge DRAM Controller 187ee40b89SJason Baron * 015c: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller 197ee40b89SJason Baron * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller 207ee40b89SJason Baron * 0c08: Xeon E3-1200 v3 Processor DRAM Controller 21953dee9bSJason Baron * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers 227103de0eSJason Baron * 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers 237ee40b89SJason Baron * 247ee40b89SJason Baron * Based on Intel specification: 257ee40b89SJason Baron * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf 267ee40b89SJason Baron * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html 277103de0eSJason Baron * http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html 287ee40b89SJason Baron * 297ee40b89SJason Baron * According to the above datasheet (p.16): 307ee40b89SJason Baron * " 317ee40b89SJason Baron * 6. Software must not access B0/D0/F0 32-bit memory-mapped registers with 327ee40b89SJason Baron * requests that cross a DW boundary. 337ee40b89SJason Baron * " 347ee40b89SJason Baron * 357ee40b89SJason Baron * Thus, we make use of the explicit: lo_hi_readq(), which breaks the readq into 367ee40b89SJason Baron * 2 readl() calls. This restriction may be lifted in subsequent chip releases, 377ee40b89SJason Baron * but lo_hi_readq() ensures that we are safe across all e3-1200 processors. 387ee40b89SJason Baron */ 397ee40b89SJason Baron 407ee40b89SJason Baron #include <linux/module.h> 417ee40b89SJason Baron #include <linux/init.h> 427ee40b89SJason Baron #include <linux/pci.h> 437ee40b89SJason Baron #include <linux/pci_ids.h> 447ee40b89SJason Baron #include <linux/edac.h> 457ee40b89SJason Baron 462f8e2c87SChristoph Hellwig #include <linux/io-64-nonatomic-lo-hi.h> 4778d88e8aSMauro Carvalho Chehab #include "edac_module.h" 487ee40b89SJason Baron 497ee40b89SJason Baron #define EDAC_MOD_STR "ie31200_edac" 507ee40b89SJason Baron 517ee40b89SJason Baron #define ie31200_printk(level, fmt, arg...) \ 527ee40b89SJason Baron edac_printk(level, "ie31200", fmt, ##arg) 537ee40b89SJason Baron 547ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108 557ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c 567ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150 577ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158 587ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c 597ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04 607ee40b89SJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08 61953dee9bSJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918 627103de0eSJason Baron #define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918 637ee40b89SJason Baron 647ee40b89SJason Baron #define IE31200_DIMMS 4 657ee40b89SJason Baron #define IE31200_RANKS 8 667ee40b89SJason Baron #define IE31200_RANKS_PER_CHANNEL 4 677ee40b89SJason Baron #define IE31200_DIMMS_PER_CHANNEL 2 687ee40b89SJason Baron #define IE31200_CHANNELS 2 697ee40b89SJason Baron 707ee40b89SJason Baron /* Intel IE31200 register addresses - device 0 function 0 - DRAM Controller */ 717ee40b89SJason Baron #define IE31200_MCHBAR_LOW 0x48 727ee40b89SJason Baron #define IE31200_MCHBAR_HIGH 0x4c 737ee40b89SJason Baron #define IE31200_MCHBAR_MASK GENMASK_ULL(38, 15) 747ee40b89SJason Baron #define IE31200_MMR_WINDOW_SIZE BIT(15) 757ee40b89SJason Baron 767ee40b89SJason Baron /* 777ee40b89SJason Baron * Error Status Register (16b) 787ee40b89SJason Baron * 797ee40b89SJason Baron * 15 reserved 807ee40b89SJason Baron * 14 Isochronous TBWRR Run Behind FIFO Full 817ee40b89SJason Baron * (ITCV) 827ee40b89SJason Baron * 13 Isochronous TBWRR Run Behind FIFO Put 837ee40b89SJason Baron * (ITSTV) 847ee40b89SJason Baron * 12 reserved 857ee40b89SJason Baron * 11 MCH Thermal Sensor Event 867ee40b89SJason Baron * for SMI/SCI/SERR (GTSE) 877ee40b89SJason Baron * 10 reserved 887ee40b89SJason Baron * 9 LOCK to non-DRAM Memory Flag (LCKF) 897ee40b89SJason Baron * 8 reserved 907ee40b89SJason Baron * 7 DRAM Throttle Flag (DTF) 917ee40b89SJason Baron * 6:2 reserved 927ee40b89SJason Baron * 1 Multi-bit DRAM ECC Error Flag (DMERR) 937ee40b89SJason Baron * 0 Single-bit DRAM ECC Error Flag (DSERR) 947ee40b89SJason Baron */ 957ee40b89SJason Baron #define IE31200_ERRSTS 0xc8 967ee40b89SJason Baron #define IE31200_ERRSTS_UE BIT(1) 977ee40b89SJason Baron #define IE31200_ERRSTS_CE BIT(0) 987ee40b89SJason Baron #define IE31200_ERRSTS_BITS (IE31200_ERRSTS_UE | IE31200_ERRSTS_CE) 997ee40b89SJason Baron 1007ee40b89SJason Baron /* 1017ee40b89SJason Baron * Channel 0 ECC Error Log (64b) 1027ee40b89SJason Baron * 1037ee40b89SJason Baron * 63:48 Error Column Address (ERRCOL) 1047ee40b89SJason Baron * 47:32 Error Row Address (ERRROW) 1057ee40b89SJason Baron * 31:29 Error Bank Address (ERRBANK) 1067ee40b89SJason Baron * 28:27 Error Rank Address (ERRRANK) 1077ee40b89SJason Baron * 26:24 reserved 1087ee40b89SJason Baron * 23:16 Error Syndrome (ERRSYND) 1097ee40b89SJason Baron * 15: 2 reserved 1107ee40b89SJason Baron * 1 Multiple Bit Error Status (MERRSTS) 1117ee40b89SJason Baron * 0 Correctable Error Status (CERRSTS) 1127ee40b89SJason Baron */ 113953dee9bSJason Baron 1147ee40b89SJason Baron #define IE31200_C0ECCERRLOG 0x40c8 1157ee40b89SJason Baron #define IE31200_C1ECCERRLOG 0x44c8 116953dee9bSJason Baron #define IE31200_C0ECCERRLOG_SKL 0x4048 117953dee9bSJason Baron #define IE31200_C1ECCERRLOG_SKL 0x4448 1187ee40b89SJason Baron #define IE31200_ECCERRLOG_CE BIT(0) 1197ee40b89SJason Baron #define IE31200_ECCERRLOG_UE BIT(1) 1207ee40b89SJason Baron #define IE31200_ECCERRLOG_RANK_BITS GENMASK_ULL(28, 27) 1217ee40b89SJason Baron #define IE31200_ECCERRLOG_RANK_SHIFT 27 1227ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME_BITS GENMASK_ULL(23, 16) 1237ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME_SHIFT 16 1247ee40b89SJason Baron 1257ee40b89SJason Baron #define IE31200_ECCERRLOG_SYNDROME(log) \ 1267ee40b89SJason Baron ((log & IE31200_ECCERRLOG_SYNDROME_BITS) >> \ 1277ee40b89SJason Baron IE31200_ECCERRLOG_SYNDROME_SHIFT) 1287ee40b89SJason Baron 1297ee40b89SJason Baron #define IE31200_CAPID0 0xe4 1307ee40b89SJason Baron #define IE31200_CAPID0_PDCD BIT(4) 1317ee40b89SJason Baron #define IE31200_CAPID0_DDPCD BIT(6) 1327ee40b89SJason Baron #define IE31200_CAPID0_ECC BIT(1) 1337ee40b89SJason Baron 1347ee40b89SJason Baron #define IE31200_MAD_DIMM_0_OFFSET 0x5004 135953dee9bSJason Baron #define IE31200_MAD_DIMM_0_OFFSET_SKL 0x500C 1367ee40b89SJason Baron #define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0) 1377ee40b89SJason Baron #define IE31200_MAD_DIMM_A_RANK BIT(17) 138953dee9bSJason Baron #define IE31200_MAD_DIMM_A_RANK_SHIFT 17 139953dee9bSJason Baron #define IE31200_MAD_DIMM_A_RANK_SKL BIT(10) 140953dee9bSJason Baron #define IE31200_MAD_DIMM_A_RANK_SKL_SHIFT 10 1417ee40b89SJason Baron #define IE31200_MAD_DIMM_A_WIDTH BIT(19) 142953dee9bSJason Baron #define IE31200_MAD_DIMM_A_WIDTH_SHIFT 19 143953dee9bSJason Baron #define IE31200_MAD_DIMM_A_WIDTH_SKL GENMASK_ULL(9, 8) 144953dee9bSJason Baron #define IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT 8 1457ee40b89SJason Baron 146953dee9bSJason Baron /* Skylake reports 1GB increments, everything else is 256MB */ 147953dee9bSJason Baron #define IE31200_PAGES(n, skl) \ 148953dee9bSJason Baron (n << (28 + (2 * skl) - PAGE_SHIFT)) 1497ee40b89SJason Baron 1507ee40b89SJason Baron static int nr_channels; 1517ee40b89SJason Baron 1527ee40b89SJason Baron struct ie31200_priv { 1537ee40b89SJason Baron void __iomem *window; 154953dee9bSJason Baron void __iomem *c0errlog; 155953dee9bSJason Baron void __iomem *c1errlog; 1567ee40b89SJason Baron }; 1577ee40b89SJason Baron 1587ee40b89SJason Baron enum ie31200_chips { 1597ee40b89SJason Baron IE31200 = 0, 1607ee40b89SJason Baron }; 1617ee40b89SJason Baron 1627ee40b89SJason Baron struct ie31200_dev_info { 1637ee40b89SJason Baron const char *ctl_name; 1647ee40b89SJason Baron }; 1657ee40b89SJason Baron 1667ee40b89SJason Baron struct ie31200_error_info { 1677ee40b89SJason Baron u16 errsts; 1687ee40b89SJason Baron u16 errsts2; 1697ee40b89SJason Baron u64 eccerrlog[IE31200_CHANNELS]; 1707ee40b89SJason Baron }; 1717ee40b89SJason Baron 1727ee40b89SJason Baron static const struct ie31200_dev_info ie31200_devs[] = { 1737ee40b89SJason Baron [IE31200] = { 1747ee40b89SJason Baron .ctl_name = "IE31200" 1757ee40b89SJason Baron }, 1767ee40b89SJason Baron }; 1777ee40b89SJason Baron 1787ee40b89SJason Baron struct dimm_data { 179953dee9bSJason Baron u8 size; /* in multiples of 256MB, except Skylake is 1GB */ 1807ee40b89SJason Baron u8 dual_rank : 1, 181953dee9bSJason Baron x16_width : 2; /* 0 means x8 width */ 1827ee40b89SJason Baron }; 1837ee40b89SJason Baron 1847ee40b89SJason Baron static int how_many_channels(struct pci_dev *pdev) 1857ee40b89SJason Baron { 1867ee40b89SJason Baron int n_channels; 1877ee40b89SJason Baron unsigned char capid0_2b; /* 2nd byte of CAPID0 */ 1887ee40b89SJason Baron 1897ee40b89SJason Baron pci_read_config_byte(pdev, IE31200_CAPID0 + 1, &capid0_2b); 1907ee40b89SJason Baron 1917ee40b89SJason Baron /* check PDCD: Dual Channel Disable */ 1927ee40b89SJason Baron if (capid0_2b & IE31200_CAPID0_PDCD) { 1937ee40b89SJason Baron edac_dbg(0, "In single channel mode\n"); 1947ee40b89SJason Baron n_channels = 1; 1957ee40b89SJason Baron } else { 1967ee40b89SJason Baron edac_dbg(0, "In dual channel mode\n"); 1977ee40b89SJason Baron n_channels = 2; 1987ee40b89SJason Baron } 1997ee40b89SJason Baron 2007ee40b89SJason Baron /* check DDPCD - check if both channels are filled */ 2017ee40b89SJason Baron if (capid0_2b & IE31200_CAPID0_DDPCD) 2027ee40b89SJason Baron edac_dbg(0, "2 DIMMS per channel disabled\n"); 2037ee40b89SJason Baron else 2047ee40b89SJason Baron edac_dbg(0, "2 DIMMS per channel enabled\n"); 2057ee40b89SJason Baron 2067ee40b89SJason Baron return n_channels; 2077ee40b89SJason Baron } 2087ee40b89SJason Baron 2097ee40b89SJason Baron static bool ecc_capable(struct pci_dev *pdev) 2107ee40b89SJason Baron { 2117ee40b89SJason Baron unsigned char capid0_4b; /* 4th byte of CAPID0 */ 2127ee40b89SJason Baron 2137ee40b89SJason Baron pci_read_config_byte(pdev, IE31200_CAPID0 + 3, &capid0_4b); 2147ee40b89SJason Baron if (capid0_4b & IE31200_CAPID0_ECC) 2157ee40b89SJason Baron return false; 2167ee40b89SJason Baron return true; 2177ee40b89SJason Baron } 2187ee40b89SJason Baron 219953dee9bSJason Baron static int eccerrlog_row(u64 log) 2207ee40b89SJason Baron { 221953dee9bSJason Baron return ((log & IE31200_ECCERRLOG_RANK_BITS) >> 2227ee40b89SJason Baron IE31200_ECCERRLOG_RANK_SHIFT); 2237ee40b89SJason Baron } 2247ee40b89SJason Baron 2257ee40b89SJason Baron static void ie31200_clear_error_info(struct mem_ctl_info *mci) 2267ee40b89SJason Baron { 2277ee40b89SJason Baron /* 2287ee40b89SJason Baron * Clear any error bits. 2297ee40b89SJason Baron * (Yes, we really clear bits by writing 1 to them.) 2307ee40b89SJason Baron */ 2317ee40b89SJason Baron pci_write_bits16(to_pci_dev(mci->pdev), IE31200_ERRSTS, 2327ee40b89SJason Baron IE31200_ERRSTS_BITS, IE31200_ERRSTS_BITS); 2337ee40b89SJason Baron } 2347ee40b89SJason Baron 2357ee40b89SJason Baron static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci, 2367ee40b89SJason Baron struct ie31200_error_info *info) 2377ee40b89SJason Baron { 2387ee40b89SJason Baron struct pci_dev *pdev; 2397ee40b89SJason Baron struct ie31200_priv *priv = mci->pvt_info; 2407ee40b89SJason Baron 2417ee40b89SJason Baron pdev = to_pci_dev(mci->pdev); 2427ee40b89SJason Baron 2437ee40b89SJason Baron /* 2447ee40b89SJason Baron * This is a mess because there is no atomic way to read all the 2457ee40b89SJason Baron * registers at once and the registers can transition from CE being 2467ee40b89SJason Baron * overwritten by UE. 2477ee40b89SJason Baron */ 2487ee40b89SJason Baron pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts); 2497ee40b89SJason Baron if (!(info->errsts & IE31200_ERRSTS_BITS)) 2507ee40b89SJason Baron return; 2517ee40b89SJason Baron 252953dee9bSJason Baron info->eccerrlog[0] = lo_hi_readq(priv->c0errlog); 2537ee40b89SJason Baron if (nr_channels == 2) 254953dee9bSJason Baron info->eccerrlog[1] = lo_hi_readq(priv->c1errlog); 2557ee40b89SJason Baron 2567ee40b89SJason Baron pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2); 2577ee40b89SJason Baron 2587ee40b89SJason Baron /* 2597ee40b89SJason Baron * If the error is the same for both reads then the first set 2607ee40b89SJason Baron * of reads is valid. If there is a change then there is a CE 2617ee40b89SJason Baron * with no info and the second set of reads is valid and 2627ee40b89SJason Baron * should be UE info. 2637ee40b89SJason Baron */ 2647ee40b89SJason Baron if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) { 265953dee9bSJason Baron info->eccerrlog[0] = lo_hi_readq(priv->c0errlog); 2667ee40b89SJason Baron if (nr_channels == 2) 2677ee40b89SJason Baron info->eccerrlog[1] = 268953dee9bSJason Baron lo_hi_readq(priv->c1errlog); 2697ee40b89SJason Baron } 2707ee40b89SJason Baron 2717ee40b89SJason Baron ie31200_clear_error_info(mci); 2727ee40b89SJason Baron } 2737ee40b89SJason Baron 2747ee40b89SJason Baron static void ie31200_process_error_info(struct mem_ctl_info *mci, 2757ee40b89SJason Baron struct ie31200_error_info *info) 2767ee40b89SJason Baron { 2777ee40b89SJason Baron int channel; 2787ee40b89SJason Baron u64 log; 2797ee40b89SJason Baron 2807ee40b89SJason Baron if (!(info->errsts & IE31200_ERRSTS_BITS)) 2817ee40b89SJason Baron return; 2827ee40b89SJason Baron 2837ee40b89SJason Baron if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) { 2847ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 2857ee40b89SJason Baron -1, -1, -1, "UE overwrote CE", ""); 2867ee40b89SJason Baron info->errsts = info->errsts2; 2877ee40b89SJason Baron } 2887ee40b89SJason Baron 2897ee40b89SJason Baron for (channel = 0; channel < nr_channels; channel++) { 2907ee40b89SJason Baron log = info->eccerrlog[channel]; 2917ee40b89SJason Baron if (log & IE31200_ECCERRLOG_UE) { 2927ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 2937ee40b89SJason Baron 0, 0, 0, 294953dee9bSJason Baron eccerrlog_row(log), 2957ee40b89SJason Baron channel, -1, 2967ee40b89SJason Baron "ie31200 UE", ""); 2977ee40b89SJason Baron } else if (log & IE31200_ECCERRLOG_CE) { 2987ee40b89SJason Baron edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 2997ee40b89SJason Baron 0, 0, 3007ee40b89SJason Baron IE31200_ECCERRLOG_SYNDROME(log), 301953dee9bSJason Baron eccerrlog_row(log), 3027ee40b89SJason Baron channel, -1, 3037ee40b89SJason Baron "ie31200 CE", ""); 3047ee40b89SJason Baron } 3057ee40b89SJason Baron } 3067ee40b89SJason Baron } 3077ee40b89SJason Baron 3087ee40b89SJason Baron static void ie31200_check(struct mem_ctl_info *mci) 3097ee40b89SJason Baron { 3107ee40b89SJason Baron struct ie31200_error_info info; 3117ee40b89SJason Baron 3127ee40b89SJason Baron edac_dbg(1, "MC%d\n", mci->mc_idx); 3137ee40b89SJason Baron ie31200_get_and_clear_error_info(mci, &info); 3147ee40b89SJason Baron ie31200_process_error_info(mci, &info); 3157ee40b89SJason Baron } 3167ee40b89SJason Baron 3177ee40b89SJason Baron static void __iomem *ie31200_map_mchbar(struct pci_dev *pdev) 3187ee40b89SJason Baron { 3197ee40b89SJason Baron union { 3207ee40b89SJason Baron u64 mchbar; 3217ee40b89SJason Baron struct { 3227ee40b89SJason Baron u32 mchbar_low; 3237ee40b89SJason Baron u32 mchbar_high; 3247ee40b89SJason Baron }; 3257ee40b89SJason Baron } u; 3267ee40b89SJason Baron void __iomem *window; 3277ee40b89SJason Baron 3287ee40b89SJason Baron pci_read_config_dword(pdev, IE31200_MCHBAR_LOW, &u.mchbar_low); 3297ee40b89SJason Baron pci_read_config_dword(pdev, IE31200_MCHBAR_HIGH, &u.mchbar_high); 3307ee40b89SJason Baron u.mchbar &= IE31200_MCHBAR_MASK; 3317ee40b89SJason Baron 3327ee40b89SJason Baron if (u.mchbar != (resource_size_t)u.mchbar) { 3337ee40b89SJason Baron ie31200_printk(KERN_ERR, "mmio space beyond accessible range (0x%llx)\n", 3347ee40b89SJason Baron (unsigned long long)u.mchbar); 3357ee40b89SJason Baron return NULL; 3367ee40b89SJason Baron } 3377ee40b89SJason Baron 3387ee40b89SJason Baron window = ioremap_nocache(u.mchbar, IE31200_MMR_WINDOW_SIZE); 3397ee40b89SJason Baron if (!window) 3407ee40b89SJason Baron ie31200_printk(KERN_ERR, "Cannot map mmio space at 0x%llx\n", 3417ee40b89SJason Baron (unsigned long long)u.mchbar); 3427ee40b89SJason Baron 3437ee40b89SJason Baron return window; 3447ee40b89SJason Baron } 3457ee40b89SJason Baron 346953dee9bSJason Baron static void __skl_populate_dimm_info(struct dimm_data *dd, u32 addr_decode, 347953dee9bSJason Baron int chan) 348953dee9bSJason Baron { 349953dee9bSJason Baron dd->size = (addr_decode >> (chan << 4)) & IE31200_MAD_DIMM_SIZE; 350953dee9bSJason Baron dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK_SKL << (chan << 4))) ? 1 : 0; 351953dee9bSJason Baron dd->x16_width = ((addr_decode & (IE31200_MAD_DIMM_A_WIDTH_SKL << (chan << 4))) >> 352953dee9bSJason Baron (IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT + (chan << 4))); 353953dee9bSJason Baron } 354953dee9bSJason Baron 355953dee9bSJason Baron static void __populate_dimm_info(struct dimm_data *dd, u32 addr_decode, 356953dee9bSJason Baron int chan) 357953dee9bSJason Baron { 358953dee9bSJason Baron dd->size = (addr_decode >> (chan << 3)) & IE31200_MAD_DIMM_SIZE; 359953dee9bSJason Baron dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK << chan)) ? 1 : 0; 360953dee9bSJason Baron dd->x16_width = (addr_decode & (IE31200_MAD_DIMM_A_WIDTH << chan)) ? 1 : 0; 361953dee9bSJason Baron } 362953dee9bSJason Baron 363953dee9bSJason Baron static void populate_dimm_info(struct dimm_data *dd, u32 addr_decode, int chan, 364953dee9bSJason Baron bool skl) 365953dee9bSJason Baron { 366953dee9bSJason Baron if (skl) 367953dee9bSJason Baron __skl_populate_dimm_info(dd, addr_decode, chan); 368953dee9bSJason Baron else 369953dee9bSJason Baron __populate_dimm_info(dd, addr_decode, chan); 370953dee9bSJason Baron } 371953dee9bSJason Baron 372953dee9bSJason Baron 3737ee40b89SJason Baron static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) 3747ee40b89SJason Baron { 37578fd4d12SJason Baron int i, j, ret; 3767ee40b89SJason Baron struct mem_ctl_info *mci = NULL; 3777ee40b89SJason Baron struct edac_mc_layer layers[2]; 3787ee40b89SJason Baron struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL]; 3797ee40b89SJason Baron void __iomem *window; 3807ee40b89SJason Baron struct ie31200_priv *priv; 381953dee9bSJason Baron u32 addr_decode, mad_offset; 3827103de0eSJason Baron 3837103de0eSJason Baron /* 3847103de0eSJason Baron * Kaby Lake seems to work like Skylake. Please re-visit this logic 3857103de0eSJason Baron * when adding new CPU support. 3867103de0eSJason Baron */ 3877103de0eSJason Baron bool skl = (pdev->device >= PCI_DEVICE_ID_INTEL_IE31200_HB_8); 3887ee40b89SJason Baron 3897ee40b89SJason Baron edac_dbg(0, "MC:\n"); 3907ee40b89SJason Baron 3917ee40b89SJason Baron if (!ecc_capable(pdev)) { 3927ee40b89SJason Baron ie31200_printk(KERN_INFO, "No ECC support\n"); 3937ee40b89SJason Baron return -ENODEV; 3947ee40b89SJason Baron } 3957ee40b89SJason Baron 39678fd4d12SJason Baron nr_channels = how_many_channels(pdev); 39778fd4d12SJason Baron layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 39878fd4d12SJason Baron layers[0].size = IE31200_DIMMS; 39978fd4d12SJason Baron layers[0].is_virt_csrow = true; 40078fd4d12SJason Baron layers[1].type = EDAC_MC_LAYER_CHANNEL; 40178fd4d12SJason Baron layers[1].size = nr_channels; 40278fd4d12SJason Baron layers[1].is_virt_csrow = false; 40378fd4d12SJason Baron mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 40478fd4d12SJason Baron sizeof(struct ie31200_priv)); 40578fd4d12SJason Baron if (!mci) 40678fd4d12SJason Baron return -ENOMEM; 40778fd4d12SJason Baron 4087ee40b89SJason Baron window = ie31200_map_mchbar(pdev); 40978fd4d12SJason Baron if (!window) { 41078fd4d12SJason Baron ret = -ENODEV; 41178fd4d12SJason Baron goto fail_free; 41278fd4d12SJason Baron } 41378fd4d12SJason Baron 41478fd4d12SJason Baron edac_dbg(3, "MC: init mci\n"); 41578fd4d12SJason Baron mci->pdev = &pdev->dev; 416953dee9bSJason Baron if (skl) 417953dee9bSJason Baron mci->mtype_cap = MEM_FLAG_DDR4; 418953dee9bSJason Baron else 41978fd4d12SJason Baron mci->mtype_cap = MEM_FLAG_DDR3; 42078fd4d12SJason Baron mci->edac_ctl_cap = EDAC_FLAG_SECDED; 42178fd4d12SJason Baron mci->edac_cap = EDAC_FLAG_SECDED; 42278fd4d12SJason Baron mci->mod_name = EDAC_MOD_STR; 42378fd4d12SJason Baron mci->ctl_name = ie31200_devs[dev_idx].ctl_name; 42478fd4d12SJason Baron mci->dev_name = pci_name(pdev); 42578fd4d12SJason Baron mci->edac_check = ie31200_check; 42678fd4d12SJason Baron mci->ctl_page_to_phys = NULL; 42778fd4d12SJason Baron priv = mci->pvt_info; 42878fd4d12SJason Baron priv->window = window; 429953dee9bSJason Baron if (skl) { 430953dee9bSJason Baron priv->c0errlog = window + IE31200_C0ECCERRLOG_SKL; 431953dee9bSJason Baron priv->c1errlog = window + IE31200_C1ECCERRLOG_SKL; 432953dee9bSJason Baron mad_offset = IE31200_MAD_DIMM_0_OFFSET_SKL; 433953dee9bSJason Baron } else { 434953dee9bSJason Baron priv->c0errlog = window + IE31200_C0ECCERRLOG; 435953dee9bSJason Baron priv->c1errlog = window + IE31200_C1ECCERRLOG; 436953dee9bSJason Baron mad_offset = IE31200_MAD_DIMM_0_OFFSET; 437953dee9bSJason Baron } 4387ee40b89SJason Baron 4397ee40b89SJason Baron /* populate DIMM info */ 4407ee40b89SJason Baron for (i = 0; i < IE31200_CHANNELS; i++) { 441953dee9bSJason Baron addr_decode = readl(window + mad_offset + 4427ee40b89SJason Baron (i * 4)); 4437ee40b89SJason Baron edac_dbg(0, "addr_decode: 0x%x\n", addr_decode); 4447ee40b89SJason Baron for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) { 445953dee9bSJason Baron populate_dimm_info(&dimm_info[i][j], addr_decode, j, 446953dee9bSJason Baron skl); 4477ee40b89SJason Baron edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", 4487ee40b89SJason Baron dimm_info[i][j].size, 4497ee40b89SJason Baron dimm_info[i][j].dual_rank, 4507ee40b89SJason Baron dimm_info[i][j].x16_width); 4517ee40b89SJason Baron } 4527ee40b89SJason Baron } 4537ee40b89SJason Baron 4547ee40b89SJason Baron /* 4557ee40b89SJason Baron * The dram rank boundary (DRB) reg values are boundary addresses 4567ee40b89SJason Baron * for each DRAM rank with a granularity of 64MB. DRB regs are 4577ee40b89SJason Baron * cumulative; the last one will contain the total memory 4587ee40b89SJason Baron * contained in all ranks. 4597ee40b89SJason Baron */ 4607ee40b89SJason Baron for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) { 4617ee40b89SJason Baron for (j = 0; j < IE31200_CHANNELS; j++) { 4627ee40b89SJason Baron struct dimm_info *dimm; 4637ee40b89SJason Baron unsigned long nr_pages; 4647ee40b89SJason Baron 465953dee9bSJason Baron nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl); 4667ee40b89SJason Baron if (nr_pages == 0) 4677ee40b89SJason Baron continue; 4687ee40b89SJason Baron 4697ee40b89SJason Baron if (dimm_info[j][i].dual_rank) { 4707ee40b89SJason Baron nr_pages = nr_pages / 2; 4717ee40b89SJason Baron dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, 4727ee40b89SJason Baron mci->n_layers, (i * 2) + 1, 4737ee40b89SJason Baron j, 0); 4747ee40b89SJason Baron dimm->nr_pages = nr_pages; 4757ee40b89SJason Baron edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages); 4767ee40b89SJason Baron dimm->grain = 8; /* just a guess */ 477953dee9bSJason Baron if (skl) 478953dee9bSJason Baron dimm->mtype = MEM_DDR4; 479953dee9bSJason Baron else 4807ee40b89SJason Baron dimm->mtype = MEM_DDR3; 4817ee40b89SJason Baron dimm->dtype = DEV_UNKNOWN; 4827ee40b89SJason Baron dimm->edac_mode = EDAC_UNKNOWN; 4837ee40b89SJason Baron } 4847ee40b89SJason Baron dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, 4857ee40b89SJason Baron mci->n_layers, i * 2, j, 0); 4867ee40b89SJason Baron dimm->nr_pages = nr_pages; 4877ee40b89SJason Baron edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages); 4887ee40b89SJason Baron dimm->grain = 8; /* same guess */ 489953dee9bSJason Baron if (skl) 490953dee9bSJason Baron dimm->mtype = MEM_DDR4; 491953dee9bSJason Baron else 4927ee40b89SJason Baron dimm->mtype = MEM_DDR3; 4937ee40b89SJason Baron dimm->dtype = DEV_UNKNOWN; 4947ee40b89SJason Baron dimm->edac_mode = EDAC_UNKNOWN; 4957ee40b89SJason Baron } 4967ee40b89SJason Baron } 4977ee40b89SJason Baron 4987ee40b89SJason Baron ie31200_clear_error_info(mci); 4997ee40b89SJason Baron 5007ee40b89SJason Baron if (edac_mc_add_mc(mci)) { 5017ee40b89SJason Baron edac_dbg(3, "MC: failed edac_mc_add_mc()\n"); 50278fd4d12SJason Baron ret = -ENODEV; 50378fd4d12SJason Baron goto fail_unmap; 5047ee40b89SJason Baron } 5057ee40b89SJason Baron 5067ee40b89SJason Baron /* get this far and it's successful */ 5077ee40b89SJason Baron edac_dbg(3, "MC: success\n"); 5087ee40b89SJason Baron return 0; 5097ee40b89SJason Baron 5107ee40b89SJason Baron fail_unmap: 5117ee40b89SJason Baron iounmap(window); 5127ee40b89SJason Baron 51378fd4d12SJason Baron fail_free: 51478fd4d12SJason Baron edac_mc_free(mci); 51578fd4d12SJason Baron 51678fd4d12SJason Baron return ret; 5177ee40b89SJason Baron } 5187ee40b89SJason Baron 5197ee40b89SJason Baron static int ie31200_init_one(struct pci_dev *pdev, 5207ee40b89SJason Baron const struct pci_device_id *ent) 5217ee40b89SJason Baron { 5227ee40b89SJason Baron edac_dbg(0, "MC:\n"); 5237ee40b89SJason Baron 5247ee40b89SJason Baron if (pci_enable_device(pdev) < 0) 5257ee40b89SJason Baron return -EIO; 5267ee40b89SJason Baron 5277ee40b89SJason Baron return ie31200_probe1(pdev, ent->driver_data); 5287ee40b89SJason Baron } 5297ee40b89SJason Baron 5307ee40b89SJason Baron static void ie31200_remove_one(struct pci_dev *pdev) 5317ee40b89SJason Baron { 5327ee40b89SJason Baron struct mem_ctl_info *mci; 5337ee40b89SJason Baron struct ie31200_priv *priv; 5347ee40b89SJason Baron 5357ee40b89SJason Baron edac_dbg(0, "\n"); 5367ee40b89SJason Baron mci = edac_mc_del_mc(&pdev->dev); 5377ee40b89SJason Baron if (!mci) 5387ee40b89SJason Baron return; 5397ee40b89SJason Baron priv = mci->pvt_info; 5407ee40b89SJason Baron iounmap(priv->window); 5417ee40b89SJason Baron edac_mc_free(mci); 5427ee40b89SJason Baron } 5437ee40b89SJason Baron 5447ee40b89SJason Baron static const struct pci_device_id ie31200_pci_tbl[] = { 5457ee40b89SJason Baron { 5467ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5477ee40b89SJason Baron IE31200}, 5487ee40b89SJason Baron { 5497ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5507ee40b89SJason Baron IE31200}, 5517ee40b89SJason Baron { 5527ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5537ee40b89SJason Baron IE31200}, 5547ee40b89SJason Baron { 5557ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5567ee40b89SJason Baron IE31200}, 5577ee40b89SJason Baron { 5587ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5597ee40b89SJason Baron IE31200}, 5607ee40b89SJason Baron { 5617ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5627ee40b89SJason Baron IE31200}, 5637ee40b89SJason Baron { 5647ee40b89SJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5657ee40b89SJason Baron IE31200}, 5667ee40b89SJason Baron { 567953dee9bSJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 568953dee9bSJason Baron IE31200}, 569953dee9bSJason Baron { 5707103de0eSJason Baron PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5717103de0eSJason Baron IE31200}, 5727103de0eSJason Baron { 5737ee40b89SJason Baron 0, 5747ee40b89SJason Baron } /* 0 terminated list. */ 5757ee40b89SJason Baron }; 5767ee40b89SJason Baron MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); 5777ee40b89SJason Baron 5787ee40b89SJason Baron static struct pci_driver ie31200_driver = { 5797ee40b89SJason Baron .name = EDAC_MOD_STR, 5807ee40b89SJason Baron .probe = ie31200_init_one, 5817ee40b89SJason Baron .remove = ie31200_remove_one, 5827ee40b89SJason Baron .id_table = ie31200_pci_tbl, 5837ee40b89SJason Baron }; 5847ee40b89SJason Baron 5857ee40b89SJason Baron static int __init ie31200_init(void) 5867ee40b89SJason Baron { 5877ee40b89SJason Baron edac_dbg(3, "MC:\n"); 5887ee40b89SJason Baron /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 5897ee40b89SJason Baron opstate_init(); 5907ee40b89SJason Baron 5917ee40b89SJason Baron return pci_register_driver(&ie31200_driver); 5927ee40b89SJason Baron } 5937ee40b89SJason Baron 5947ee40b89SJason Baron static void __exit ie31200_exit(void) 5957ee40b89SJason Baron { 5967ee40b89SJason Baron edac_dbg(3, "MC:\n"); 5977ee40b89SJason Baron pci_unregister_driver(&ie31200_driver); 5987ee40b89SJason Baron } 5997ee40b89SJason Baron 6007ee40b89SJason Baron module_init(ie31200_init); 6017ee40b89SJason Baron module_exit(ie31200_exit); 6027ee40b89SJason Baron 6037ee40b89SJason Baron MODULE_LICENSE("GPL"); 6047ee40b89SJason Baron MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 6057ee40b89SJason Baron MODULE_DESCRIPTION("MC support for Intel Processor E31200 memory hub controllers"); 606