18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Intel e752x Memory Controller kernel module 38c2ecf20Sopenharmony_ci * (C) 2004 Linux Networx (http://lnxi.com) 48c2ecf20Sopenharmony_ci * This file may be distributed under the terms of the 58c2ecf20Sopenharmony_ci * GNU General Public License. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Implement support for the e7520, E7525, e7320 and i3100 memory controllers. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Datasheets: 108c2ecf20Sopenharmony_ci * https://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html 118c2ecf20Sopenharmony_ci * ftp://download.intel.com/design/intarch/datashts/31345803.pdf 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Written by Tom Zimmerman 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Contributors: 168c2ecf20Sopenharmony_ci * Thayne Harbaugh at realmsys.com (?) 178c2ecf20Sopenharmony_ci * Wang Zhenyu at intel.com 188c2ecf20Sopenharmony_ci * Dave Jiang at mvista.com 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/pci.h> 258c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 268c2ecf20Sopenharmony_ci#include <linux/edac.h> 278c2ecf20Sopenharmony_ci#include "edac_module.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define EDAC_MOD_STR "e752x_edac" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int report_non_memory_errors; 328c2ecf20Sopenharmony_cistatic int force_function_unhide; 338c2ecf20Sopenharmony_cistatic int sysbus_parity = -1; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct edac_pci_ctl_info *e752x_pci; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define e752x_printk(level, fmt, arg...) \ 388c2ecf20Sopenharmony_ci edac_printk(level, "e752x", fmt, ##arg) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define e752x_mc_printk(mci, level, fmt, arg...) \ 418c2ecf20Sopenharmony_ci edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7520_0 448c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7520_0 0x3590 458c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7520_0 */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR 488c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591 498c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7525_0 528c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7525_0 0x359E 538c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7525_0 */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR 568c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593 578c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7320_0 608c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7320_0 0x3592 618c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7320_0 */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR 648c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 658c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_3100_0 688c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 698c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_3100_0 */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR 728c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 738c2ecf20Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define E752X_NR_CSROWS 8 /* number of csrows */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* E752X register addresses - device 0 function 0 */ 788c2ecf20Sopenharmony_ci#define E752X_MCHSCRB 0x52 /* Memory Scrub register (16b) */ 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * 6:5 Scrub Completion Count 818c2ecf20Sopenharmony_ci * 3:2 Scrub Rate (i3100 only) 828c2ecf20Sopenharmony_ci * 01=fast 10=normal 838c2ecf20Sopenharmony_ci * 1:0 Scrub Mode enable 848c2ecf20Sopenharmony_ci * 00=off 10=on 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ 878c2ecf20Sopenharmony_ci#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * 31:30 Device width row 7 908c2ecf20Sopenharmony_ci * 01=x8 10=x4 11=x8 DDR2 918c2ecf20Sopenharmony_ci * 27:26 Device width row 6 928c2ecf20Sopenharmony_ci * 23:22 Device width row 5 938c2ecf20Sopenharmony_ci * 19:20 Device width row 4 948c2ecf20Sopenharmony_ci * 15:14 Device width row 3 958c2ecf20Sopenharmony_ci * 11:10 Device width row 2 968c2ecf20Sopenharmony_ci * 7:6 Device width row 1 978c2ecf20Sopenharmony_ci * 3:2 Device width row 0 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */ 1008c2ecf20Sopenharmony_ci /* FIXME:IS THIS RIGHT? */ 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * 22 Number channels 0=1,1=2 1038c2ecf20Sopenharmony_ci * 19:18 DRB Granularity 32/64MB 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci#define E752X_DRM 0x80 /* Dimm mapping register */ 1068c2ecf20Sopenharmony_ci#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */ 1078c2ecf20Sopenharmony_ci /* 1088c2ecf20Sopenharmony_ci * 14:12 1 single A, 2 single B, 3 dual 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ 1118c2ecf20Sopenharmony_ci#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ 1128c2ecf20Sopenharmony_ci#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ 1138c2ecf20Sopenharmony_ci#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* E752X register addresses - device 0 function 1 */ 1168c2ecf20Sopenharmony_ci#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */ 1178c2ecf20Sopenharmony_ci#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */ 1188c2ecf20Sopenharmony_ci#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */ 1198c2ecf20Sopenharmony_ci#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */ 1208c2ecf20Sopenharmony_ci#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */ 1218c2ecf20Sopenharmony_ci#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */ 1228c2ecf20Sopenharmony_ci#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */ 1238c2ecf20Sopenharmony_ci#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */ 1248c2ecf20Sopenharmony_ci#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */ 1258c2ecf20Sopenharmony_ci#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */ 1268c2ecf20Sopenharmony_ci#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */ 1278c2ecf20Sopenharmony_ci#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */ 1288c2ecf20Sopenharmony_ci#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */ 1298c2ecf20Sopenharmony_ci#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI cmd reg (8b) */ 1308c2ecf20Sopenharmony_ci#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */ 1318c2ecf20Sopenharmony_ci#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */ 1328c2ecf20Sopenharmony_ci#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */ 1338c2ecf20Sopenharmony_ci#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */ 1348c2ecf20Sopenharmony_ci#define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */ 1358c2ecf20Sopenharmony_ci#define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */ 1368c2ecf20Sopenharmony_ci /* error address register (32b) */ 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * 31 Reserved 1398c2ecf20Sopenharmony_ci * 30:2 CE address (64 byte block 34:6 1408c2ecf20Sopenharmony_ci * 1 Reserved 1418c2ecf20Sopenharmony_ci * 0 HiLoCS 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci#define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */ 1448c2ecf20Sopenharmony_ci /* error address register (32b) */ 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * 31 Reserved 1478c2ecf20Sopenharmony_ci * 30:2 CE address (64 byte block 34:6) 1488c2ecf20Sopenharmony_ci * 1 Reserved 1498c2ecf20Sopenharmony_ci * 0 HiLoCS 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci#define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */ 1528c2ecf20Sopenharmony_ci /* error address register (32b) */ 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * 31 Reserved 1558c2ecf20Sopenharmony_ci * 30:2 CE address (64 byte block 34:6) 1568c2ecf20Sopenharmony_ci * 1 Reserved 1578c2ecf20Sopenharmony_ci * 0 HiLoCS 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci#define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM 1st uncorrectable scrub mem */ 1608c2ecf20Sopenharmony_ci /* error address register (32b) */ 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * 31 Reserved 1638c2ecf20Sopenharmony_ci * 30:2 CE address (64 byte block 34:6 1648c2ecf20Sopenharmony_ci * 1 Reserved 1658c2ecf20Sopenharmony_ci * 0 HiLoCS 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci#define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */ 1688c2ecf20Sopenharmony_ci /* error syndrome register (16b) */ 1698c2ecf20Sopenharmony_ci#define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */ 1708c2ecf20Sopenharmony_ci /* error syndrome register (16b) */ 1718c2ecf20Sopenharmony_ci#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 3100 IMCH specific register addresses - device 0 function 1 */ 1748c2ecf20Sopenharmony_ci#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ 1758c2ecf20Sopenharmony_ci#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ 1768c2ecf20Sopenharmony_ci#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ 1778c2ecf20Sopenharmony_ci#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* ICH5R register addresses - device 30 function 0 */ 1808c2ecf20Sopenharmony_ci#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ 1818c2ecf20Sopenharmony_ci#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ 1828c2ecf20Sopenharmony_ci#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cienum e752x_chips { 1858c2ecf20Sopenharmony_ci E7520 = 0, 1868c2ecf20Sopenharmony_ci E7525 = 1, 1878c2ecf20Sopenharmony_ci E7320 = 2, 1888c2ecf20Sopenharmony_ci I3100 = 3 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* 1928c2ecf20Sopenharmony_ci * Those chips Support single-rank and dual-rank memories only. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * On e752x chips, the odd rows are present only on dual-rank memories. 1958c2ecf20Sopenharmony_ci * Dividing the rank by two will provide the dimm# 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * i3100 MC has a different mapping: it supports only 4 ranks. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * The mapping is (from 1 to n): 2008c2ecf20Sopenharmony_ci * slot single-ranked double-ranked 2018c2ecf20Sopenharmony_ci * dimm #1 -> rank #4 NA 2028c2ecf20Sopenharmony_ci * dimm #2 -> rank #3 NA 2038c2ecf20Sopenharmony_ci * dimm #3 -> rank #2 Ranks 2 and 3 2048c2ecf20Sopenharmony_ci * dimm #4 -> rank $1 Ranks 1 and 4 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * FIXME: The current mapping for i3100 considers that it supports up to 8 2078c2ecf20Sopenharmony_ci * ranks/chanel, but datasheet says that the MC supports only 4 ranks. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistruct e752x_pvt { 2118c2ecf20Sopenharmony_ci struct pci_dev *dev_d0f0; 2128c2ecf20Sopenharmony_ci struct pci_dev *dev_d0f1; 2138c2ecf20Sopenharmony_ci u32 tolm; 2148c2ecf20Sopenharmony_ci u32 remapbase; 2158c2ecf20Sopenharmony_ci u32 remaplimit; 2168c2ecf20Sopenharmony_ci int mc_symmetric; 2178c2ecf20Sopenharmony_ci u8 map[8]; 2188c2ecf20Sopenharmony_ci int map_type; 2198c2ecf20Sopenharmony_ci const struct e752x_dev_info *dev_info; 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistruct e752x_dev_info { 2238c2ecf20Sopenharmony_ci u16 err_dev; 2248c2ecf20Sopenharmony_ci u16 ctl_dev; 2258c2ecf20Sopenharmony_ci const char *ctl_name; 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct e752x_error_info { 2298c2ecf20Sopenharmony_ci u32 ferr_global; 2308c2ecf20Sopenharmony_ci u32 nerr_global; 2318c2ecf20Sopenharmony_ci u32 nsi_ferr; /* 3100 only */ 2328c2ecf20Sopenharmony_ci u32 nsi_nerr; /* 3100 only */ 2338c2ecf20Sopenharmony_ci u8 hi_ferr; /* all but 3100 */ 2348c2ecf20Sopenharmony_ci u8 hi_nerr; /* all but 3100 */ 2358c2ecf20Sopenharmony_ci u16 sysbus_ferr; 2368c2ecf20Sopenharmony_ci u16 sysbus_nerr; 2378c2ecf20Sopenharmony_ci u8 buf_ferr; 2388c2ecf20Sopenharmony_ci u8 buf_nerr; 2398c2ecf20Sopenharmony_ci u16 dram_ferr; 2408c2ecf20Sopenharmony_ci u16 dram_nerr; 2418c2ecf20Sopenharmony_ci u32 dram_sec1_add; 2428c2ecf20Sopenharmony_ci u32 dram_sec2_add; 2438c2ecf20Sopenharmony_ci u16 dram_sec1_syndrome; 2448c2ecf20Sopenharmony_ci u16 dram_sec2_syndrome; 2458c2ecf20Sopenharmony_ci u32 dram_ded_add; 2468c2ecf20Sopenharmony_ci u32 dram_scrb_add; 2478c2ecf20Sopenharmony_ci u32 dram_retr_add; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const struct e752x_dev_info e752x_devs[] = { 2518c2ecf20Sopenharmony_ci [E7520] = { 2528c2ecf20Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, 2538c2ecf20Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0, 2548c2ecf20Sopenharmony_ci .ctl_name = "E7520"}, 2558c2ecf20Sopenharmony_ci [E7525] = { 2568c2ecf20Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, 2578c2ecf20Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0, 2588c2ecf20Sopenharmony_ci .ctl_name = "E7525"}, 2598c2ecf20Sopenharmony_ci [E7320] = { 2608c2ecf20Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, 2618c2ecf20Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, 2628c2ecf20Sopenharmony_ci .ctl_name = "E7320"}, 2638c2ecf20Sopenharmony_ci [I3100] = { 2648c2ecf20Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, 2658c2ecf20Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, 2668c2ecf20Sopenharmony_ci .ctl_name = "3100"}, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* Valid scrub rates for the e752x/3100 hardware memory scrubber. We 2708c2ecf20Sopenharmony_ci * map the scrubbing bandwidth to a hardware register value. The 'set' 2718c2ecf20Sopenharmony_ci * operation finds the 'matching or higher value'. Note that scrubbing 2728c2ecf20Sopenharmony_ci * on the e752x can only be enabled/disabled. The 3100 supports 2738c2ecf20Sopenharmony_ci * a normal and fast mode. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci#define SDRATE_EOT 0xFFFFFFFF 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistruct scrubrate { 2798c2ecf20Sopenharmony_ci u32 bandwidth; /* bandwidth consumed by scrubbing in bytes/sec */ 2808c2ecf20Sopenharmony_ci u16 scrubval; /* register value for scrub rate */ 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Rate below assumes same performance as i3100 using PC3200 DDR2 in 2848c2ecf20Sopenharmony_ci * normal mode. e752x bridges don't support choosing normal or fast mode, 2858c2ecf20Sopenharmony_ci * so the scrubbing bandwidth value isn't all that important - scrubbing is 2868c2ecf20Sopenharmony_ci * either on or off. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_cistatic const struct scrubrate scrubrates_e752x[] = { 2898c2ecf20Sopenharmony_ci {0, 0x00}, /* Scrubbing Off */ 2908c2ecf20Sopenharmony_ci {500000, 0x02}, /* Scrubbing On */ 2918c2ecf20Sopenharmony_ci {SDRATE_EOT, 0x00} /* End of Table */ 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s 2958c2ecf20Sopenharmony_ci * Normal mode: 125 (32000 / 256) times slower than fast mode. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_cistatic const struct scrubrate scrubrates_i3100[] = { 2988c2ecf20Sopenharmony_ci {0, 0x00}, /* Scrubbing Off */ 2998c2ecf20Sopenharmony_ci {500000, 0x0a}, /* Normal mode - 32k clocks */ 3008c2ecf20Sopenharmony_ci {62500000, 0x06}, /* Fast mode - 256 clocks */ 3018c2ecf20Sopenharmony_ci {SDRATE_EOT, 0x00} /* End of Table */ 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, 3058c2ecf20Sopenharmony_ci unsigned long page) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci u32 remap; 3088c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (page < pvt->tolm) 3138c2ecf20Sopenharmony_ci return page; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if ((page >= 0x100000) && (page < pvt->remapbase)) 3168c2ecf20Sopenharmony_ci return page; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci remap = (page - pvt->tolm) + pvt->remapbase; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (remap < pvt->remaplimit) 3218c2ecf20Sopenharmony_ci return remap; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page); 3248c2ecf20Sopenharmony_ci return pvt->tolm - 1; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void do_process_ce(struct mem_ctl_info *mci, u16 error_one, 3288c2ecf20Sopenharmony_ci u32 sec1_add, u16 sec1_syndrome) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci u32 page; 3318c2ecf20Sopenharmony_ci int row; 3328c2ecf20Sopenharmony_ci int channel; 3338c2ecf20Sopenharmony_ci int i; 3348c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* convert the addr to 4k page */ 3398c2ecf20Sopenharmony_ci page = sec1_add >> (PAGE_SHIFT - 4); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* FIXME - check for -1 */ 3428c2ecf20Sopenharmony_ci if (pvt->mc_symmetric) { 3438c2ecf20Sopenharmony_ci /* chip select are bits 14 & 13 */ 3448c2ecf20Sopenharmony_ci row = ((page >> 1) & 3); 3458c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, 3468c2ecf20Sopenharmony_ci "Test row %d Table %d %d %d %d %d %d %d %d\n", row, 3478c2ecf20Sopenharmony_ci pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3], 3488c2ecf20Sopenharmony_ci pvt->map[4], pvt->map[5], pvt->map[6], 3498c2ecf20Sopenharmony_ci pvt->map[7]); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* test for channel remapping */ 3528c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3538c2ecf20Sopenharmony_ci if (pvt->map[i] == row) 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, "Test computed row %d\n", i); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (i < 8) 3608c2ecf20Sopenharmony_ci row = i; 3618c2ecf20Sopenharmony_ci else 3628c2ecf20Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, 3638c2ecf20Sopenharmony_ci "row %d not found in remap table\n", 3648c2ecf20Sopenharmony_ci row); 3658c2ecf20Sopenharmony_ci } else 3668c2ecf20Sopenharmony_ci row = edac_mc_find_csrow_by_page(mci, page); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* 0 = channel A, 1 = channel B */ 3698c2ecf20Sopenharmony_ci channel = !(error_one & 1); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 3728c2ecf20Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 3738c2ecf20Sopenharmony_ci page, offset_in_page(sec1_add << 4), sec1_syndrome, 3748c2ecf20Sopenharmony_ci row, channel, -1, 3758c2ecf20Sopenharmony_ci "e752x CE", ""); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic inline void process_ce(struct mem_ctl_info *mci, u16 error_one, 3798c2ecf20Sopenharmony_ci u32 sec1_add, u16 sec1_syndrome, int *error_found, 3808c2ecf20Sopenharmony_ci int handle_error) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci *error_found = 1; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (handle_error) 3858c2ecf20Sopenharmony_ci do_process_ce(mci, error_one, sec1_add, sec1_syndrome); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void do_process_ue(struct mem_ctl_info *mci, u16 error_one, 3898c2ecf20Sopenharmony_ci u32 ded_add, u32 scrb_add) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci u32 error_2b, block_page; 3928c2ecf20Sopenharmony_ci int row; 3938c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (error_one & 0x0202) { 3988c2ecf20Sopenharmony_ci error_2b = ded_add; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* convert to 4k address */ 4018c2ecf20Sopenharmony_ci block_page = error_2b >> (PAGE_SHIFT - 4); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci row = pvt->mc_symmetric ? 4048c2ecf20Sopenharmony_ci /* chip select are bits 14 & 13 */ 4058c2ecf20Sopenharmony_ci ((block_page >> 1) & 3) : 4068c2ecf20Sopenharmony_ci edac_mc_find_csrow_by_page(mci, block_page); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 4098c2ecf20Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 4108c2ecf20Sopenharmony_ci block_page, 4118c2ecf20Sopenharmony_ci offset_in_page(error_2b << 4), 0, 4128c2ecf20Sopenharmony_ci row, -1, -1, 4138c2ecf20Sopenharmony_ci "e752x UE from Read", ""); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci if (error_one & 0x0404) { 4178c2ecf20Sopenharmony_ci error_2b = scrb_add; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* convert to 4k address */ 4208c2ecf20Sopenharmony_ci block_page = error_2b >> (PAGE_SHIFT - 4); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci row = pvt->mc_symmetric ? 4238c2ecf20Sopenharmony_ci /* chip select are bits 14 & 13 */ 4248c2ecf20Sopenharmony_ci ((block_page >> 1) & 3) : 4258c2ecf20Sopenharmony_ci edac_mc_find_csrow_by_page(mci, block_page); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 4288c2ecf20Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 4298c2ecf20Sopenharmony_ci block_page, 4308c2ecf20Sopenharmony_ci offset_in_page(error_2b << 4), 0, 4318c2ecf20Sopenharmony_ci row, -1, -1, 4328c2ecf20Sopenharmony_ci "e752x UE from Scruber", ""); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic inline void process_ue(struct mem_ctl_info *mci, u16 error_one, 4378c2ecf20Sopenharmony_ci u32 ded_add, u32 scrb_add, int *error_found, 4388c2ecf20Sopenharmony_ci int handle_error) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci *error_found = 1; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (handle_error) 4438c2ecf20Sopenharmony_ci do_process_ue(mci, error_one, ded_add, scrb_add); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic inline void process_ue_no_info_wr(struct mem_ctl_info *mci, 4478c2ecf20Sopenharmony_ci int *error_found, int handle_error) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci *error_found = 1; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!handle_error) 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 4558c2ecf20Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 4568c2ecf20Sopenharmony_ci -1, -1, -1, 4578c2ecf20Sopenharmony_ci "e752x UE log memory write", ""); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, 4618c2ecf20Sopenharmony_ci u32 retry_add) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci u32 error_1b, page; 4648c2ecf20Sopenharmony_ci int row; 4658c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci error_1b = retry_add; 4688c2ecf20Sopenharmony_ci page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* chip select are bits 14 & 13 */ 4718c2ecf20Sopenharmony_ci row = pvt->mc_symmetric ? ((page >> 1) & 3) : 4728c2ecf20Sopenharmony_ci edac_mc_find_csrow_by_page(mci, page); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, 4758c2ecf20Sopenharmony_ci "CE page 0x%lx, row %d : Memory read retry\n", 4768c2ecf20Sopenharmony_ci (long unsigned int)page, row); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, 4808c2ecf20Sopenharmony_ci u32 retry_add, int *error_found, 4818c2ecf20Sopenharmony_ci int handle_error) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci *error_found = 1; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (handle_error) 4868c2ecf20Sopenharmony_ci do_process_ded_retry(mci, error, retry_add); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, 4908c2ecf20Sopenharmony_ci int *error_found, int handle_error) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci *error_found = 1; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (handle_error) 4958c2ecf20Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n"); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic char *global_message[11] = { 4998c2ecf20Sopenharmony_ci "PCI Express C1", 5008c2ecf20Sopenharmony_ci "PCI Express C", 5018c2ecf20Sopenharmony_ci "PCI Express B1", 5028c2ecf20Sopenharmony_ci "PCI Express B", 5038c2ecf20Sopenharmony_ci "PCI Express A1", 5048c2ecf20Sopenharmony_ci "PCI Express A", 5058c2ecf20Sopenharmony_ci "DMA Controller", 5068c2ecf20Sopenharmony_ci "HUB or NS Interface", 5078c2ecf20Sopenharmony_ci "System Bus", 5088c2ecf20Sopenharmony_ci "DRAM Controller", /* 9th entry */ 5098c2ecf20Sopenharmony_ci "Internal Buffer" 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci#define DRAM_ENTRY 9 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic char *fatal_message[2] = { "Non-Fatal ", "Fatal " }; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void do_global_error(int fatal, u32 errors) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci int i; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci for (i = 0; i < 11; i++) { 5218c2ecf20Sopenharmony_ci if (errors & (1 << i)) { 5228c2ecf20Sopenharmony_ci /* If the error is from DRAM Controller OR 5238c2ecf20Sopenharmony_ci * we are to report ALL errors, then 5248c2ecf20Sopenharmony_ci * report the error 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci if ((i == DRAM_ENTRY) || report_non_memory_errors) 5278c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError %s\n", 5288c2ecf20Sopenharmony_ci fatal_message[fatal], 5298c2ecf20Sopenharmony_ci global_message[i]); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic inline void global_error(int fatal, u32 errors, int *error_found, 5358c2ecf20Sopenharmony_ci int handle_error) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci *error_found = 1; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (handle_error) 5408c2ecf20Sopenharmony_ci do_global_error(fatal, errors); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic char *hub_message[7] = { 5448c2ecf20Sopenharmony_ci "HI Address or Command Parity", "HI Illegal Access", 5458c2ecf20Sopenharmony_ci "HI Internal Parity", "Out of Range Access", 5468c2ecf20Sopenharmony_ci "HI Data Parity", "Enhanced Config Access", 5478c2ecf20Sopenharmony_ci "Hub Interface Target Abort" 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void do_hub_error(int fatal, u8 errors) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci int i; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 5558c2ecf20Sopenharmony_ci if (errors & (1 << i)) 5568c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError %s\n", 5578c2ecf20Sopenharmony_ci fatal_message[fatal], hub_message[i]); 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic inline void hub_error(int fatal, u8 errors, int *error_found, 5628c2ecf20Sopenharmony_ci int handle_error) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci *error_found = 1; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (handle_error) 5678c2ecf20Sopenharmony_ci do_hub_error(fatal, errors); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci#define NSI_FATAL_MASK 0x0c080081 5718c2ecf20Sopenharmony_ci#define NSI_NON_FATAL_MASK 0x23a0ba64 5728c2ecf20Sopenharmony_ci#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic char *nsi_message[30] = { 5758c2ecf20Sopenharmony_ci "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ 5768c2ecf20Sopenharmony_ci "", /* reserved */ 5778c2ecf20Sopenharmony_ci "NSI Parity Error", /* bit 2, non-fatal */ 5788c2ecf20Sopenharmony_ci "", /* reserved */ 5798c2ecf20Sopenharmony_ci "", /* reserved */ 5808c2ecf20Sopenharmony_ci "Correctable Error Message", /* bit 5, non-fatal */ 5818c2ecf20Sopenharmony_ci "Non-Fatal Error Message", /* bit 6, non-fatal */ 5828c2ecf20Sopenharmony_ci "Fatal Error Message", /* bit 7, fatal */ 5838c2ecf20Sopenharmony_ci "", /* reserved */ 5848c2ecf20Sopenharmony_ci "Receiver Error", /* bit 9, non-fatal */ 5858c2ecf20Sopenharmony_ci "", /* reserved */ 5868c2ecf20Sopenharmony_ci "Bad TLP", /* bit 11, non-fatal */ 5878c2ecf20Sopenharmony_ci "Bad DLLP", /* bit 12, non-fatal */ 5888c2ecf20Sopenharmony_ci "REPLAY_NUM Rollover", /* bit 13, non-fatal */ 5898c2ecf20Sopenharmony_ci "", /* reserved */ 5908c2ecf20Sopenharmony_ci "Replay Timer Timeout", /* bit 15, non-fatal */ 5918c2ecf20Sopenharmony_ci "", /* reserved */ 5928c2ecf20Sopenharmony_ci "", /* reserved */ 5938c2ecf20Sopenharmony_ci "", /* reserved */ 5948c2ecf20Sopenharmony_ci "Data Link Protocol Error", /* bit 19, fatal */ 5958c2ecf20Sopenharmony_ci "", /* reserved */ 5968c2ecf20Sopenharmony_ci "Poisoned TLP", /* bit 21, non-fatal */ 5978c2ecf20Sopenharmony_ci "", /* reserved */ 5988c2ecf20Sopenharmony_ci "Completion Timeout", /* bit 23, non-fatal */ 5998c2ecf20Sopenharmony_ci "Completer Abort", /* bit 24, non-fatal */ 6008c2ecf20Sopenharmony_ci "Unexpected Completion", /* bit 25, non-fatal */ 6018c2ecf20Sopenharmony_ci "Receiver Overflow", /* bit 26, fatal */ 6028c2ecf20Sopenharmony_ci "Malformed TLP", /* bit 27, fatal */ 6038c2ecf20Sopenharmony_ci "", /* reserved */ 6048c2ecf20Sopenharmony_ci "Unsupported Request" /* bit 29, non-fatal */ 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void do_nsi_error(int fatal, u32 errors) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int i; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci for (i = 0; i < 30; i++) { 6128c2ecf20Sopenharmony_ci if (errors & (1 << i)) 6138c2ecf20Sopenharmony_ci printk(KERN_WARNING "%sError %s\n", 6148c2ecf20Sopenharmony_ci fatal_message[fatal], nsi_message[i]); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic inline void nsi_error(int fatal, u32 errors, int *error_found, 6198c2ecf20Sopenharmony_ci int handle_error) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci *error_found = 1; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (handle_error) 6248c2ecf20Sopenharmony_ci do_nsi_error(fatal, errors); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic char *membuf_message[4] = { 6288c2ecf20Sopenharmony_ci "Internal PMWB to DRAM parity", 6298c2ecf20Sopenharmony_ci "Internal PMWB to System Bus Parity", 6308c2ecf20Sopenharmony_ci "Internal System Bus or IO to PMWB Parity", 6318c2ecf20Sopenharmony_ci "Internal DRAM to PMWB Parity" 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic void do_membuf_error(u8 errors) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci int i; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 6398c2ecf20Sopenharmony_ci if (errors & (1 << i)) 6408c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n", 6418c2ecf20Sopenharmony_ci membuf_message[i]); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic inline void membuf_error(u8 errors, int *error_found, int handle_error) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci *error_found = 1; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (handle_error) 6508c2ecf20Sopenharmony_ci do_membuf_error(errors); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic char *sysbus_message[10] = { 6548c2ecf20Sopenharmony_ci "Addr or Request Parity", 6558c2ecf20Sopenharmony_ci "Data Strobe Glitch", 6568c2ecf20Sopenharmony_ci "Addr Strobe Glitch", 6578c2ecf20Sopenharmony_ci "Data Parity", 6588c2ecf20Sopenharmony_ci "Addr Above TOM", 6598c2ecf20Sopenharmony_ci "Non DRAM Lock Error", 6608c2ecf20Sopenharmony_ci "MCERR", "BINIT", 6618c2ecf20Sopenharmony_ci "Memory Parity", 6628c2ecf20Sopenharmony_ci "IO Subsystem Parity" 6638c2ecf20Sopenharmony_ci}; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic void do_sysbus_error(int fatal, u32 errors) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int i; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 6708c2ecf20Sopenharmony_ci if (errors & (1 << i)) 6718c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError System Bus %s\n", 6728c2ecf20Sopenharmony_ci fatal_message[fatal], sysbus_message[i]); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic inline void sysbus_error(int fatal, u32 errors, int *error_found, 6778c2ecf20Sopenharmony_ci int handle_error) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci *error_found = 1; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (handle_error) 6828c2ecf20Sopenharmony_ci do_sysbus_error(fatal, errors); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic void e752x_check_hub_interface(struct e752x_error_info *info, 6868c2ecf20Sopenharmony_ci int *error_found, int handle_error) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci u8 stat8; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci //pci_read_config_byte(dev,E752X_HI_FERR,&stat8); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci stat8 = info->hi_ferr; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (stat8 & 0x7f) { /* Error, so process */ 6958c2ecf20Sopenharmony_ci stat8 &= 0x7f; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (stat8 & 0x2b) 6988c2ecf20Sopenharmony_ci hub_error(1, stat8 & 0x2b, error_found, handle_error); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (stat8 & 0x54) 7018c2ecf20Sopenharmony_ci hub_error(0, stat8 & 0x54, error_found, handle_error); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci stat8 = info->hi_nerr; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (stat8 & 0x7f) { /* Error, so process */ 7088c2ecf20Sopenharmony_ci stat8 &= 0x7f; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (stat8 & 0x2b) 7118c2ecf20Sopenharmony_ci hub_error(1, stat8 & 0x2b, error_found, handle_error); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (stat8 & 0x54) 7148c2ecf20Sopenharmony_ci hub_error(0, stat8 & 0x54, error_found, handle_error); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic void e752x_check_ns_interface(struct e752x_error_info *info, 7198c2ecf20Sopenharmony_ci int *error_found, int handle_error) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci u32 stat32; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci stat32 = info->nsi_ferr; 7248c2ecf20Sopenharmony_ci if (stat32 & NSI_ERR_MASK) { /* Error, so process */ 7258c2ecf20Sopenharmony_ci if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ 7268c2ecf20Sopenharmony_ci nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, 7278c2ecf20Sopenharmony_ci handle_error); 7288c2ecf20Sopenharmony_ci if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ 7298c2ecf20Sopenharmony_ci nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, 7308c2ecf20Sopenharmony_ci handle_error); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci stat32 = info->nsi_nerr; 7338c2ecf20Sopenharmony_ci if (stat32 & NSI_ERR_MASK) { 7348c2ecf20Sopenharmony_ci if (stat32 & NSI_FATAL_MASK) 7358c2ecf20Sopenharmony_ci nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, 7368c2ecf20Sopenharmony_ci handle_error); 7378c2ecf20Sopenharmony_ci if (stat32 & NSI_NON_FATAL_MASK) 7388c2ecf20Sopenharmony_ci nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, 7398c2ecf20Sopenharmony_ci handle_error); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic void e752x_check_sysbus(struct e752x_error_info *info, 7448c2ecf20Sopenharmony_ci int *error_found, int handle_error) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci u32 stat32, error32; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32); 7498c2ecf20Sopenharmony_ci stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (stat32 == 0) 7528c2ecf20Sopenharmony_ci return; /* no errors */ 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci error32 = (stat32 >> 16) & 0x3ff; 7558c2ecf20Sopenharmony_ci stat32 = stat32 & 0x3ff; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (stat32 & 0x087) 7588c2ecf20Sopenharmony_ci sysbus_error(1, stat32 & 0x087, error_found, handle_error); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (stat32 & 0x378) 7618c2ecf20Sopenharmony_ci sysbus_error(0, stat32 & 0x378, error_found, handle_error); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (error32 & 0x087) 7648c2ecf20Sopenharmony_ci sysbus_error(1, error32 & 0x087, error_found, handle_error); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (error32 & 0x378) 7678c2ecf20Sopenharmony_ci sysbus_error(0, error32 & 0x378, error_found, handle_error); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic void e752x_check_membuf(struct e752x_error_info *info, 7718c2ecf20Sopenharmony_ci int *error_found, int handle_error) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci u8 stat8; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci stat8 = info->buf_ferr; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (stat8 & 0x0f) { /* Error, so process */ 7788c2ecf20Sopenharmony_ci stat8 &= 0x0f; 7798c2ecf20Sopenharmony_ci membuf_error(stat8, error_found, handle_error); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci stat8 = info->buf_nerr; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (stat8 & 0x0f) { /* Error, so process */ 7858c2ecf20Sopenharmony_ci stat8 &= 0x0f; 7868c2ecf20Sopenharmony_ci membuf_error(stat8, error_found, handle_error); 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic void e752x_check_dram(struct mem_ctl_info *mci, 7918c2ecf20Sopenharmony_ci struct e752x_error_info *info, int *error_found, 7928c2ecf20Sopenharmony_ci int handle_error) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci u16 error_one, error_next; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci error_one = info->dram_ferr; 7978c2ecf20Sopenharmony_ci error_next = info->dram_nerr; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* decode and report errors */ 8008c2ecf20Sopenharmony_ci if (error_one & 0x0101) /* check first error correctable */ 8018c2ecf20Sopenharmony_ci process_ce(mci, error_one, info->dram_sec1_add, 8028c2ecf20Sopenharmony_ci info->dram_sec1_syndrome, error_found, handle_error); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (error_next & 0x0101) /* check next error correctable */ 8058c2ecf20Sopenharmony_ci process_ce(mci, error_next, info->dram_sec2_add, 8068c2ecf20Sopenharmony_ci info->dram_sec2_syndrome, error_found, handle_error); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (error_one & 0x4040) 8098c2ecf20Sopenharmony_ci process_ue_no_info_wr(mci, error_found, handle_error); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (error_next & 0x4040) 8128c2ecf20Sopenharmony_ci process_ue_no_info_wr(mci, error_found, handle_error); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (error_one & 0x2020) 8158c2ecf20Sopenharmony_ci process_ded_retry(mci, error_one, info->dram_retr_add, 8168c2ecf20Sopenharmony_ci error_found, handle_error); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (error_next & 0x2020) 8198c2ecf20Sopenharmony_ci process_ded_retry(mci, error_next, info->dram_retr_add, 8208c2ecf20Sopenharmony_ci error_found, handle_error); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (error_one & 0x0808) 8238c2ecf20Sopenharmony_ci process_threshold_ce(mci, error_one, error_found, handle_error); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (error_next & 0x0808) 8268c2ecf20Sopenharmony_ci process_threshold_ce(mci, error_next, error_found, 8278c2ecf20Sopenharmony_ci handle_error); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (error_one & 0x0606) 8308c2ecf20Sopenharmony_ci process_ue(mci, error_one, info->dram_ded_add, 8318c2ecf20Sopenharmony_ci info->dram_scrb_add, error_found, handle_error); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (error_next & 0x0606) 8348c2ecf20Sopenharmony_ci process_ue(mci, error_next, info->dram_ded_add, 8358c2ecf20Sopenharmony_ci info->dram_scrb_add, error_found, handle_error); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic void e752x_get_error_info(struct mem_ctl_info *mci, 8398c2ecf20Sopenharmony_ci struct e752x_error_info *info) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct pci_dev *dev; 8428c2ecf20Sopenharmony_ci struct e752x_pvt *pvt; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 8458c2ecf20Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 8468c2ecf20Sopenharmony_ci dev = pvt->dev_d0f1; 8478c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (info->ferr_global) { 8508c2ecf20Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 8518c2ecf20Sopenharmony_ci pci_read_config_dword(dev, I3100_NSI_FERR, 8528c2ecf20Sopenharmony_ci &info->nsi_ferr); 8538c2ecf20Sopenharmony_ci info->hi_ferr = 0; 8548c2ecf20Sopenharmony_ci } else { 8558c2ecf20Sopenharmony_ci pci_read_config_byte(dev, E752X_HI_FERR, 8568c2ecf20Sopenharmony_ci &info->hi_ferr); 8578c2ecf20Sopenharmony_ci info->nsi_ferr = 0; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_SYSBUS_FERR, 8608c2ecf20Sopenharmony_ci &info->sysbus_ferr); 8618c2ecf20Sopenharmony_ci pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); 8628c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr); 8638c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD, 8648c2ecf20Sopenharmony_ci &info->dram_sec1_add); 8658c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME, 8668c2ecf20Sopenharmony_ci &info->dram_sec1_syndrome); 8678c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_DED_ADD, 8688c2ecf20Sopenharmony_ci &info->dram_ded_add); 8698c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD, 8708c2ecf20Sopenharmony_ci &info->dram_scrb_add); 8718c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, 8728c2ecf20Sopenharmony_ci &info->dram_retr_add); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* ignore the reserved bits just in case */ 8758c2ecf20Sopenharmony_ci if (info->hi_ferr & 0x7f) 8768c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_FERR, 8778c2ecf20Sopenharmony_ci info->hi_ferr); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (info->nsi_ferr & NSI_ERR_MASK) 8808c2ecf20Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_FERR, 8818c2ecf20Sopenharmony_ci info->nsi_ferr); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (info->sysbus_ferr) 8848c2ecf20Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_FERR, 8858c2ecf20Sopenharmony_ci info->sysbus_ferr); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (info->buf_ferr & 0x0f) 8888c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_FERR, 8898c2ecf20Sopenharmony_ci info->buf_ferr); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (info->dram_ferr) 8928c2ecf20Sopenharmony_ci pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR, 8938c2ecf20Sopenharmony_ci info->dram_ferr, info->dram_ferr); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci pci_write_config_dword(dev, E752X_FERR_GLOBAL, 8968c2ecf20Sopenharmony_ci info->ferr_global); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (info->nerr_global) { 9028c2ecf20Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 9038c2ecf20Sopenharmony_ci pci_read_config_dword(dev, I3100_NSI_NERR, 9048c2ecf20Sopenharmony_ci &info->nsi_nerr); 9058c2ecf20Sopenharmony_ci info->hi_nerr = 0; 9068c2ecf20Sopenharmony_ci } else { 9078c2ecf20Sopenharmony_ci pci_read_config_byte(dev, E752X_HI_NERR, 9088c2ecf20Sopenharmony_ci &info->hi_nerr); 9098c2ecf20Sopenharmony_ci info->nsi_nerr = 0; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_SYSBUS_NERR, 9128c2ecf20Sopenharmony_ci &info->sysbus_nerr); 9138c2ecf20Sopenharmony_ci pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); 9148c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr); 9158c2ecf20Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD, 9168c2ecf20Sopenharmony_ci &info->dram_sec2_add); 9178c2ecf20Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME, 9188c2ecf20Sopenharmony_ci &info->dram_sec2_syndrome); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (info->hi_nerr & 0x7f) 9218c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_NERR, 9228c2ecf20Sopenharmony_ci info->hi_nerr); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (info->nsi_nerr & NSI_ERR_MASK) 9258c2ecf20Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_NERR, 9268c2ecf20Sopenharmony_ci info->nsi_nerr); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (info->sysbus_nerr) 9298c2ecf20Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_NERR, 9308c2ecf20Sopenharmony_ci info->sysbus_nerr); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (info->buf_nerr & 0x0f) 9338c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_NERR, 9348c2ecf20Sopenharmony_ci info->buf_nerr); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (info->dram_nerr) 9378c2ecf20Sopenharmony_ci pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR, 9388c2ecf20Sopenharmony_ci info->dram_nerr, info->dram_nerr); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci pci_write_config_dword(dev, E752X_NERR_GLOBAL, 9418c2ecf20Sopenharmony_ci info->nerr_global); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic int e752x_process_error_info(struct mem_ctl_info *mci, 9468c2ecf20Sopenharmony_ci struct e752x_error_info *info, 9478c2ecf20Sopenharmony_ci int handle_errors) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci u32 error32, stat32; 9508c2ecf20Sopenharmony_ci int error_found; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci error_found = 0; 9538c2ecf20Sopenharmony_ci error32 = (info->ferr_global >> 18) & 0x3ff; 9548c2ecf20Sopenharmony_ci stat32 = (info->ferr_global >> 4) & 0x7ff; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (error32) 9578c2ecf20Sopenharmony_ci global_error(1, error32, &error_found, handle_errors); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (stat32) 9608c2ecf20Sopenharmony_ci global_error(0, stat32, &error_found, handle_errors); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci error32 = (info->nerr_global >> 18) & 0x3ff; 9638c2ecf20Sopenharmony_ci stat32 = (info->nerr_global >> 4) & 0x7ff; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (error32) 9668c2ecf20Sopenharmony_ci global_error(1, error32, &error_found, handle_errors); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (stat32) 9698c2ecf20Sopenharmony_ci global_error(0, stat32, &error_found, handle_errors); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci e752x_check_hub_interface(info, &error_found, handle_errors); 9728c2ecf20Sopenharmony_ci e752x_check_ns_interface(info, &error_found, handle_errors); 9738c2ecf20Sopenharmony_ci e752x_check_sysbus(info, &error_found, handle_errors); 9748c2ecf20Sopenharmony_ci e752x_check_membuf(info, &error_found, handle_errors); 9758c2ecf20Sopenharmony_ci e752x_check_dram(mci, info, &error_found, handle_errors); 9768c2ecf20Sopenharmony_ci return error_found; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic void e752x_check(struct mem_ctl_info *mci) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci struct e752x_error_info info; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 9848c2ecf20Sopenharmony_ci e752x_get_error_info(mci, &info); 9858c2ecf20Sopenharmony_ci e752x_process_error_info(mci, &info, 1); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci/* Program byte/sec bandwidth scrub rate to hardware */ 9898c2ecf20Sopenharmony_cistatic int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci const struct scrubrate *scrubrates; 9928c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; 9938c2ecf20Sopenharmony_ci struct pci_dev *pdev = pvt->dev_d0f0; 9948c2ecf20Sopenharmony_ci int i; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) 9978c2ecf20Sopenharmony_ci scrubrates = scrubrates_i3100; 9988c2ecf20Sopenharmony_ci else 9998c2ecf20Sopenharmony_ci scrubrates = scrubrates_e752x; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Translate the desired scrub rate to a e752x/3100 register value. 10028c2ecf20Sopenharmony_ci * Search for the bandwidth that is equal or greater than the 10038c2ecf20Sopenharmony_ci * desired rate and program the cooresponding register value. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) 10068c2ecf20Sopenharmony_ci if (scrubrates[i].bandwidth >= new_bw) 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (scrubrates[i].bandwidth == SDRATE_EOT) 10108c2ecf20Sopenharmony_ci return -1; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return scrubrates[i].bandwidth; 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci/* Convert current scrub rate value into byte/sec bandwidth */ 10188c2ecf20Sopenharmony_cistatic int get_sdram_scrub_rate(struct mem_ctl_info *mci) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci const struct scrubrate *scrubrates; 10218c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; 10228c2ecf20Sopenharmony_ci struct pci_dev *pdev = pvt->dev_d0f0; 10238c2ecf20Sopenharmony_ci u16 scrubval; 10248c2ecf20Sopenharmony_ci int i; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) 10278c2ecf20Sopenharmony_ci scrubrates = scrubrates_i3100; 10288c2ecf20Sopenharmony_ci else 10298c2ecf20Sopenharmony_ci scrubrates = scrubrates_e752x; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* Find the bandwidth matching the memory scrubber configuration */ 10328c2ecf20Sopenharmony_ci pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval); 10338c2ecf20Sopenharmony_ci scrubval = scrubval & 0x0f; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) 10368c2ecf20Sopenharmony_ci if (scrubrates[i].scrubval == scrubval) 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (scrubrates[i].bandwidth == SDRATE_EOT) { 10408c2ecf20Sopenharmony_ci e752x_printk(KERN_WARNING, 10418c2ecf20Sopenharmony_ci "Invalid sdram scrub control value: 0x%x\n", scrubval); 10428c2ecf20Sopenharmony_ci return -1; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci return scrubrates[i].bandwidth; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/* Return 1 if dual channel mode is active. Else return 0. */ 10498c2ecf20Sopenharmony_cistatic inline int dual_channel_active(u16 ddrcsr) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci return (((ddrcsr >> 12) & 3) == 3); 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci/* Remap csrow index numbers if map_type is "reverse" 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_cistatic inline int remap_csrow_index(struct mem_ctl_info *mci, int index) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct e752x_pvt *pvt = mci->pvt_info; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (!pvt->map_type) 10618c2ecf20Sopenharmony_ci return (7 - index); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci return (index); 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, 10678c2ecf20Sopenharmony_ci u16 ddrcsr) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct csrow_info *csrow; 10708c2ecf20Sopenharmony_ci enum edac_type edac_mode; 10718c2ecf20Sopenharmony_ci unsigned long last_cumul_size; 10728c2ecf20Sopenharmony_ci int index, mem_dev, drc_chan; 10738c2ecf20Sopenharmony_ci int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ 10748c2ecf20Sopenharmony_ci int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ 10758c2ecf20Sopenharmony_ci u8 value; 10768c2ecf20Sopenharmony_ci u32 dra, drc, cumul_size, i, nr_pages; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci dra = 0; 10798c2ecf20Sopenharmony_ci for (index = 0; index < 4; index++) { 10808c2ecf20Sopenharmony_ci u8 dra_reg; 10818c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg); 10828c2ecf20Sopenharmony_ci dra |= dra_reg << (index * 8); 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, E752X_DRC, &drc); 10858c2ecf20Sopenharmony_ci drc_chan = dual_channel_active(ddrcsr) ? 1 : 0; 10868c2ecf20Sopenharmony_ci drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ 10878c2ecf20Sopenharmony_ci drc_ddim = (drc >> 20) & 0x3; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* The dram row boundary (DRB) reg values are boundary address for 10908c2ecf20Sopenharmony_ci * each DRAM row with a granularity of 64 or 128MB (single/dual 10918c2ecf20Sopenharmony_ci * channel operation). DRB regs are cumulative; therefore DRB7 will 10928c2ecf20Sopenharmony_ci * contain the total memory contained in all eight rows. 10938c2ecf20Sopenharmony_ci */ 10948c2ecf20Sopenharmony_ci for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { 10958c2ecf20Sopenharmony_ci /* mem_dev 0=x8, 1=x4 */ 10968c2ecf20Sopenharmony_ci mem_dev = (dra >> (index * 4 + 2)) & 0x3; 10978c2ecf20Sopenharmony_ci csrow = mci->csrows[remap_csrow_index(mci, index)]; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci mem_dev = (mem_dev == 2); 11008c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index, &value); 11018c2ecf20Sopenharmony_ci /* convert a 128 or 64 MiB DRB to a page size. */ 11028c2ecf20Sopenharmony_ci cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); 11038c2ecf20Sopenharmony_ci edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size); 11048c2ecf20Sopenharmony_ci if (cumul_size == last_cumul_size) 11058c2ecf20Sopenharmony_ci continue; /* not populated */ 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci csrow->first_page = last_cumul_size; 11088c2ecf20Sopenharmony_ci csrow->last_page = cumul_size - 1; 11098c2ecf20Sopenharmony_ci nr_pages = cumul_size - last_cumul_size; 11108c2ecf20Sopenharmony_ci last_cumul_size = cumul_size; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* 11138c2ecf20Sopenharmony_ci * if single channel or x8 devices then SECDED 11148c2ecf20Sopenharmony_ci * if dual channel and x4 then S4ECD4ED 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_ci if (drc_ddim) { 11178c2ecf20Sopenharmony_ci if (drc_chan && mem_dev) { 11188c2ecf20Sopenharmony_ci edac_mode = EDAC_S4ECD4ED; 11198c2ecf20Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_S4ECD4ED; 11208c2ecf20Sopenharmony_ci } else { 11218c2ecf20Sopenharmony_ci edac_mode = EDAC_SECDED; 11228c2ecf20Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_SECDED; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci } else 11258c2ecf20Sopenharmony_ci edac_mode = EDAC_NONE; 11268c2ecf20Sopenharmony_ci for (i = 0; i < csrow->nr_channels; i++) { 11278c2ecf20Sopenharmony_ci struct dimm_info *dimm = csrow->channels[i]->dimm; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci edac_dbg(3, "Initializing rank at (%i,%i)\n", index, i); 11308c2ecf20Sopenharmony_ci dimm->nr_pages = nr_pages / csrow->nr_channels; 11318c2ecf20Sopenharmony_ci dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ 11328c2ecf20Sopenharmony_ci dimm->mtype = MEM_RDDR; /* only one type supported */ 11338c2ecf20Sopenharmony_ci dimm->dtype = mem_dev ? DEV_X4 : DEV_X8; 11348c2ecf20Sopenharmony_ci dimm->edac_mode = edac_mode; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic void e752x_init_mem_map_table(struct pci_dev *pdev, 11408c2ecf20Sopenharmony_ci struct e752x_pvt *pvt) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci int index; 11438c2ecf20Sopenharmony_ci u8 value, last, row; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci last = 0; 11468c2ecf20Sopenharmony_ci row = 0; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci for (index = 0; index < 8; index += 2) { 11498c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index, &value); 11508c2ecf20Sopenharmony_ci /* test if there is a dimm in this slot */ 11518c2ecf20Sopenharmony_ci if (value == last) { 11528c2ecf20Sopenharmony_ci /* no dimm in the slot, so flag it as empty */ 11538c2ecf20Sopenharmony_ci pvt->map[index] = 0xff; 11548c2ecf20Sopenharmony_ci pvt->map[index + 1] = 0xff; 11558c2ecf20Sopenharmony_ci } else { /* there is a dimm in the slot */ 11568c2ecf20Sopenharmony_ci pvt->map[index] = row; 11578c2ecf20Sopenharmony_ci row++; 11588c2ecf20Sopenharmony_ci last = value; 11598c2ecf20Sopenharmony_ci /* test the next value to see if the dimm is double 11608c2ecf20Sopenharmony_ci * sided 11618c2ecf20Sopenharmony_ci */ 11628c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index + 1, 11638c2ecf20Sopenharmony_ci &value); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* the dimm is single sided, so flag as empty */ 11668c2ecf20Sopenharmony_ci /* this is a double sided dimm to save the next row #*/ 11678c2ecf20Sopenharmony_ci pvt->map[index + 1] = (value == last) ? 0xff : row; 11688c2ecf20Sopenharmony_ci row++; 11698c2ecf20Sopenharmony_ci last = value; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci/* Return 0 on success or 1 on failure. */ 11758c2ecf20Sopenharmony_cistatic int e752x_get_devs(struct pci_dev *pdev, int dev_idx, 11768c2ecf20Sopenharmony_ci struct e752x_pvt *pvt) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL, 11798c2ecf20Sopenharmony_ci pvt->dev_info->err_dev, NULL); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (pvt->dev_d0f1 == NULL) { 11828c2ecf20Sopenharmony_ci pvt->dev_d0f1 = pci_scan_single_device(pdev->bus, 11838c2ecf20Sopenharmony_ci PCI_DEVFN(0, 1)); 11848c2ecf20Sopenharmony_ci pci_dev_get(pvt->dev_d0f1); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (pvt->dev_d0f1 == NULL) { 11888c2ecf20Sopenharmony_ci e752x_printk(KERN_ERR, "error reporting device not found:" 11898c2ecf20Sopenharmony_ci "vendor %x device 0x%x (broken BIOS?)\n", 11908c2ecf20Sopenharmony_ci PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); 11918c2ecf20Sopenharmony_ci return 1; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL, 11958c2ecf20Sopenharmony_ci e752x_devs[dev_idx].ctl_dev, 11968c2ecf20Sopenharmony_ci NULL); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (pvt->dev_d0f0 == NULL) 11998c2ecf20Sopenharmony_ci goto fail; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return 0; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cifail: 12048c2ecf20Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 12058c2ecf20Sopenharmony_ci return 1; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci/* Setup system bus parity mask register. 12098c2ecf20Sopenharmony_ci * Sysbus parity supported on: 12108c2ecf20Sopenharmony_ci * e7320/e7520/e7525 + Xeon 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_cistatic void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci char *cpu_id = cpu_data(0).x86_model_id; 12158c2ecf20Sopenharmony_ci struct pci_dev *dev = pvt->dev_d0f1; 12168c2ecf20Sopenharmony_ci int enable = 1; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* Allow module parameter override, else see if CPU supports parity */ 12198c2ecf20Sopenharmony_ci if (sysbus_parity != -1) { 12208c2ecf20Sopenharmony_ci enable = sysbus_parity; 12218c2ecf20Sopenharmony_ci } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) { 12228c2ecf20Sopenharmony_ci e752x_printk(KERN_INFO, "System Bus Parity not " 12238c2ecf20Sopenharmony_ci "supported by CPU, disabling\n"); 12248c2ecf20Sopenharmony_ci enable = 0; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (enable) 12288c2ecf20Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000); 12298c2ecf20Sopenharmony_ci else 12308c2ecf20Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct pci_dev *dev; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci dev = pvt->dev_d0f1; 12388c2ecf20Sopenharmony_ci /* Turn off error disable & SMI in case the BIOS turned it on */ 12398c2ecf20Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 12408c2ecf20Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_EMASK, 0); 12418c2ecf20Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); 12428c2ecf20Sopenharmony_ci } else { 12438c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); 12448c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci e752x_init_sysbus_parity_mask(pvt); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); 12508c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); 12518c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); 12528c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); 12538c2ecf20Sopenharmony_ci pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int e752x_probe1(struct pci_dev *pdev, int dev_idx) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci u16 pci_data; 12598c2ecf20Sopenharmony_ci u8 stat8; 12608c2ecf20Sopenharmony_ci struct mem_ctl_info *mci; 12618c2ecf20Sopenharmony_ci struct edac_mc_layer layers[2]; 12628c2ecf20Sopenharmony_ci struct e752x_pvt *pvt; 12638c2ecf20Sopenharmony_ci u16 ddrcsr; 12648c2ecf20Sopenharmony_ci int drc_chan; /* Number of channels 0=1chan,1=2chan */ 12658c2ecf20Sopenharmony_ci struct e752x_error_info discard; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci edac_dbg(0, "mci\n"); 12688c2ecf20Sopenharmony_ci edac_dbg(0, "Starting Probe1\n"); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* check to see if device 0 function 1 is enabled; if it isn't, we 12718c2ecf20Sopenharmony_ci * assume the BIOS has reserved it for a reason and is expecting 12728c2ecf20Sopenharmony_ci * exclusive access, we take care not to violate that assumption and 12738c2ecf20Sopenharmony_ci * fail the probe. */ 12748c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); 12758c2ecf20Sopenharmony_ci if (!force_function_unhide && !(stat8 & (1 << 5))) { 12768c2ecf20Sopenharmony_ci printk(KERN_INFO "Contact your BIOS vendor to see if the " 12778c2ecf20Sopenharmony_ci "E752x error registers can be safely un-hidden\n"); 12788c2ecf20Sopenharmony_ci return -ENODEV; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci stat8 |= (1 << 5); 12818c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); 12848c2ecf20Sopenharmony_ci /* FIXME: should check >>12 or 0xf, true for all? */ 12858c2ecf20Sopenharmony_ci /* Dual channel = 1, Single channel = 0 */ 12868c2ecf20Sopenharmony_ci drc_chan = dual_channel_active(ddrcsr); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 12898c2ecf20Sopenharmony_ci layers[0].size = E752X_NR_CSROWS; 12908c2ecf20Sopenharmony_ci layers[0].is_virt_csrow = true; 12918c2ecf20Sopenharmony_ci layers[1].type = EDAC_MC_LAYER_CHANNEL; 12928c2ecf20Sopenharmony_ci layers[1].size = drc_chan + 1; 12938c2ecf20Sopenharmony_ci layers[1].is_virt_csrow = false; 12948c2ecf20Sopenharmony_ci mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); 12958c2ecf20Sopenharmony_ci if (mci == NULL) 12968c2ecf20Sopenharmony_ci return -ENOMEM; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci edac_dbg(3, "init mci\n"); 12998c2ecf20Sopenharmony_ci mci->mtype_cap = MEM_FLAG_RDDR; 13008c2ecf20Sopenharmony_ci /* 3100 IMCH supports SECDEC only */ 13018c2ecf20Sopenharmony_ci mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : 13028c2ecf20Sopenharmony_ci (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); 13038c2ecf20Sopenharmony_ci /* FIXME - what if different memory types are in different csrows? */ 13048c2ecf20Sopenharmony_ci mci->mod_name = EDAC_MOD_STR; 13058c2ecf20Sopenharmony_ci mci->pdev = &pdev->dev; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci edac_dbg(3, "init pvt\n"); 13088c2ecf20Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 13098c2ecf20Sopenharmony_ci pvt->dev_info = &e752x_devs[dev_idx]; 13108c2ecf20Sopenharmony_ci pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (e752x_get_devs(pdev, dev_idx, pvt)) { 13138c2ecf20Sopenharmony_ci edac_mc_free(mci); 13148c2ecf20Sopenharmony_ci return -ENODEV; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci edac_dbg(3, "more mci init\n"); 13188c2ecf20Sopenharmony_ci mci->ctl_name = pvt->dev_info->ctl_name; 13198c2ecf20Sopenharmony_ci mci->dev_name = pci_name(pdev); 13208c2ecf20Sopenharmony_ci mci->edac_check = e752x_check; 13218c2ecf20Sopenharmony_ci mci->ctl_page_to_phys = ctl_page_to_phys; 13228c2ecf20Sopenharmony_ci mci->set_sdram_scrub_rate = set_sdram_scrub_rate; 13238c2ecf20Sopenharmony_ci mci->get_sdram_scrub_rate = get_sdram_scrub_rate; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* set the map type. 1 = normal, 0 = reversed 13268c2ecf20Sopenharmony_ci * Must be set before e752x_init_csrows in case csrow mapping 13278c2ecf20Sopenharmony_ci * is reversed. 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRM, &stat8); 13308c2ecf20Sopenharmony_ci pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci e752x_init_csrows(mci, pdev, ddrcsr); 13338c2ecf20Sopenharmony_ci e752x_init_mem_map_table(pdev, pvt); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci if (dev_idx == I3100) 13368c2ecf20Sopenharmony_ci mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ 13378c2ecf20Sopenharmony_ci else 13388c2ecf20Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_NONE; 13398c2ecf20Sopenharmony_ci edac_dbg(3, "tolm, remapbase, remaplimit\n"); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* load the top of low memory, remap base, and remap limit vars */ 13428c2ecf20Sopenharmony_ci pci_read_config_word(pdev, E752X_TOLM, &pci_data); 13438c2ecf20Sopenharmony_ci pvt->tolm = ((u32) pci_data) << 4; 13448c2ecf20Sopenharmony_ci pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data); 13458c2ecf20Sopenharmony_ci pvt->remapbase = ((u32) pci_data) << 14; 13468c2ecf20Sopenharmony_ci pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data); 13478c2ecf20Sopenharmony_ci pvt->remaplimit = ((u32) pci_data) << 14; 13488c2ecf20Sopenharmony_ci e752x_printk(KERN_INFO, 13498c2ecf20Sopenharmony_ci "tolm = %x, remapbase = %x, remaplimit = %x\n", 13508c2ecf20Sopenharmony_ci pvt->tolm, pvt->remapbase, pvt->remaplimit); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* Here we assume that we will never see multiple instances of this 13538c2ecf20Sopenharmony_ci * type of memory controller. The ID is therefore hardcoded to 0. 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci if (edac_mc_add_mc(mci)) { 13568c2ecf20Sopenharmony_ci edac_dbg(3, "failed edac_mc_add_mc()\n"); 13578c2ecf20Sopenharmony_ci goto fail; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci e752x_init_error_reporting_regs(pvt); 13618c2ecf20Sopenharmony_ci e752x_get_error_info(mci, &discard); /* clear other MCH errors */ 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* allocating generic PCI control info */ 13648c2ecf20Sopenharmony_ci e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 13658c2ecf20Sopenharmony_ci if (!e752x_pci) { 13668c2ecf20Sopenharmony_ci printk(KERN_WARNING 13678c2ecf20Sopenharmony_ci "%s(): Unable to create PCI control\n", __func__); 13688c2ecf20Sopenharmony_ci printk(KERN_WARNING 13698c2ecf20Sopenharmony_ci "%s(): PCI error report via EDAC not setup\n", 13708c2ecf20Sopenharmony_ci __func__); 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* get this far and it's successful */ 13748c2ecf20Sopenharmony_ci edac_dbg(3, "success\n"); 13758c2ecf20Sopenharmony_ci return 0; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cifail: 13788c2ecf20Sopenharmony_ci pci_dev_put(pvt->dev_d0f0); 13798c2ecf20Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 13808c2ecf20Sopenharmony_ci edac_mc_free(mci); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci return -ENODEV; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/* returns count (>= 0), or negative on error */ 13868c2ecf20Sopenharmony_cistatic int e752x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci edac_dbg(0, "\n"); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* wake up and enable device */ 13918c2ecf20Sopenharmony_ci if (pci_enable_device(pdev) < 0) 13928c2ecf20Sopenharmony_ci return -EIO; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return e752x_probe1(pdev, ent->driver_data); 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic void e752x_remove_one(struct pci_dev *pdev) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct mem_ctl_info *mci; 14008c2ecf20Sopenharmony_ci struct e752x_pvt *pvt; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci edac_dbg(0, "\n"); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (e752x_pci) 14058c2ecf20Sopenharmony_ci edac_pci_release_generic_ctl(e752x_pci); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) 14088c2ecf20Sopenharmony_ci return; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 14118c2ecf20Sopenharmony_ci pci_dev_put(pvt->dev_d0f0); 14128c2ecf20Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 14138c2ecf20Sopenharmony_ci edac_mc_free(mci); 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic const struct pci_device_id e752x_pci_tbl[] = { 14178c2ecf20Sopenharmony_ci { 14188c2ecf20Sopenharmony_ci PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14198c2ecf20Sopenharmony_ci E7520}, 14208c2ecf20Sopenharmony_ci { 14218c2ecf20Sopenharmony_ci PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14228c2ecf20Sopenharmony_ci E7525}, 14238c2ecf20Sopenharmony_ci { 14248c2ecf20Sopenharmony_ci PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14258c2ecf20Sopenharmony_ci E7320}, 14268c2ecf20Sopenharmony_ci { 14278c2ecf20Sopenharmony_ci PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14288c2ecf20Sopenharmony_ci I3100}, 14298c2ecf20Sopenharmony_ci { 14308c2ecf20Sopenharmony_ci 0, 14318c2ecf20Sopenharmony_ci } /* 0 terminated list. */ 14328c2ecf20Sopenharmony_ci}; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, e752x_pci_tbl); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic struct pci_driver e752x_driver = { 14378c2ecf20Sopenharmony_ci .name = EDAC_MOD_STR, 14388c2ecf20Sopenharmony_ci .probe = e752x_init_one, 14398c2ecf20Sopenharmony_ci .remove = e752x_remove_one, 14408c2ecf20Sopenharmony_ci .id_table = e752x_pci_tbl, 14418c2ecf20Sopenharmony_ci}; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic int __init e752x_init(void) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci int pci_rc; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 14508c2ecf20Sopenharmony_ci opstate_init(); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci pci_rc = pci_register_driver(&e752x_driver); 14538c2ecf20Sopenharmony_ci return (pci_rc < 0) ? pci_rc : 0; 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cistatic void __exit e752x_exit(void) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci edac_dbg(3, "\n"); 14598c2ecf20Sopenharmony_ci pci_unregister_driver(&e752x_driver); 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cimodule_init(e752x_init); 14638c2ecf20Sopenharmony_cimodule_exit(e752x_exit); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 14668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); 14678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cimodule_param(force_function_unhide, int, 0444); 14708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" 14718c2ecf20Sopenharmony_ci " 1=force unhide and hope BIOS doesn't fight driver for " 14728c2ecf20Sopenharmony_ci "Dev0:Fun1 access"); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cimodule_param(edac_op_state, int, 0444); 14758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cimodule_param(sysbus_parity, int, 0444); 14788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking," 14798c2ecf20Sopenharmony_ci " 1=enable system bus parity checking, default=auto-detect"); 14808c2ecf20Sopenharmony_cimodule_param(report_non_memory_errors, int, 0644); 14818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(report_non_memory_errors, "0=disable non-memory error " 14828c2ecf20Sopenharmony_ci "reporting, 1=enable non-memory error reporting"); 1483