162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Intel e752x Memory Controller kernel module 362306a36Sopenharmony_ci * (C) 2004 Linux Networx (http://lnxi.com) 462306a36Sopenharmony_ci * This file may be distributed under the terms of the 562306a36Sopenharmony_ci * GNU General Public License. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Implement support for the e7520, E7525, e7320 and i3100 memory controllers. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Datasheets: 1062306a36Sopenharmony_ci * https://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html 1162306a36Sopenharmony_ci * ftp://download.intel.com/design/intarch/datashts/31345803.pdf 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Written by Tom Zimmerman 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Contributors: 1662306a36Sopenharmony_ci * Thayne Harbaugh at realmsys.com (?) 1762306a36Sopenharmony_ci * Wang Zhenyu at intel.com 1862306a36Sopenharmony_ci * Dave Jiang at mvista.com 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/init.h> 2462306a36Sopenharmony_ci#include <linux/pci.h> 2562306a36Sopenharmony_ci#include <linux/pci_ids.h> 2662306a36Sopenharmony_ci#include <linux/edac.h> 2762306a36Sopenharmony_ci#include "edac_module.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define EDAC_MOD_STR "e752x_edac" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int report_non_memory_errors; 3262306a36Sopenharmony_cistatic int force_function_unhide; 3362306a36Sopenharmony_cistatic int sysbus_parity = -1; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic struct edac_pci_ctl_info *e752x_pci; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define e752x_printk(level, fmt, arg...) \ 3862306a36Sopenharmony_ci edac_printk(level, "e752x", fmt, ##arg) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define e752x_mc_printk(mci, level, fmt, arg...) \ 4162306a36Sopenharmony_ci edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7520_0 4462306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7520_0 0x3590 4562306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7520_0 */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR 4862306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591 4962306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7525_0 5262306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7525_0 0x359E 5362306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7525_0 */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR 5662306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593 5762306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7320_0 6062306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7320_0 0x3592 6162306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7320_0 */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR 6462306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 6562306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_3100_0 6862306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 6962306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_3100_0 */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR 7262306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 7362306a36Sopenharmony_ci#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define E752X_NR_CSROWS 8 /* number of csrows */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* E752X register addresses - device 0 function 0 */ 7862306a36Sopenharmony_ci#define E752X_MCHSCRB 0x52 /* Memory Scrub register (16b) */ 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * 6:5 Scrub Completion Count 8162306a36Sopenharmony_ci * 3:2 Scrub Rate (i3100 only) 8262306a36Sopenharmony_ci * 01=fast 10=normal 8362306a36Sopenharmony_ci * 1:0 Scrub Mode enable 8462306a36Sopenharmony_ci * 00=off 10=on 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ 8762306a36Sopenharmony_ci#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * 31:30 Device width row 7 9062306a36Sopenharmony_ci * 01=x8 10=x4 11=x8 DDR2 9162306a36Sopenharmony_ci * 27:26 Device width row 6 9262306a36Sopenharmony_ci * 23:22 Device width row 5 9362306a36Sopenharmony_ci * 19:20 Device width row 4 9462306a36Sopenharmony_ci * 15:14 Device width row 3 9562306a36Sopenharmony_ci * 11:10 Device width row 2 9662306a36Sopenharmony_ci * 7:6 Device width row 1 9762306a36Sopenharmony_ci * 3:2 Device width row 0 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */ 10062306a36Sopenharmony_ci /* FIXME:IS THIS RIGHT? */ 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * 22 Number channels 0=1,1=2 10362306a36Sopenharmony_ci * 19:18 DRB Granularity 32/64MB 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci#define E752X_DRM 0x80 /* Dimm mapping register */ 10662306a36Sopenharmony_ci#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */ 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * 14:12 1 single A, 2 single B, 3 dual 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ 11162306a36Sopenharmony_ci#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ 11262306a36Sopenharmony_ci#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ 11362306a36Sopenharmony_ci#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* E752X register addresses - device 0 function 1 */ 11662306a36Sopenharmony_ci#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */ 11762306a36Sopenharmony_ci#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */ 11862306a36Sopenharmony_ci#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */ 11962306a36Sopenharmony_ci#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */ 12062306a36Sopenharmony_ci#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */ 12162306a36Sopenharmony_ci#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */ 12262306a36Sopenharmony_ci#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */ 12362306a36Sopenharmony_ci#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */ 12462306a36Sopenharmony_ci#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */ 12562306a36Sopenharmony_ci#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */ 12662306a36Sopenharmony_ci#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */ 12762306a36Sopenharmony_ci#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */ 12862306a36Sopenharmony_ci#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */ 12962306a36Sopenharmony_ci#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI cmd reg (8b) */ 13062306a36Sopenharmony_ci#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */ 13162306a36Sopenharmony_ci#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */ 13262306a36Sopenharmony_ci#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */ 13362306a36Sopenharmony_ci#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */ 13462306a36Sopenharmony_ci#define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */ 13562306a36Sopenharmony_ci#define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */ 13662306a36Sopenharmony_ci /* error address register (32b) */ 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * 31 Reserved 13962306a36Sopenharmony_ci * 30:2 CE address (64 byte block 34:6 14062306a36Sopenharmony_ci * 1 Reserved 14162306a36Sopenharmony_ci * 0 HiLoCS 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci#define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */ 14462306a36Sopenharmony_ci /* error address register (32b) */ 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * 31 Reserved 14762306a36Sopenharmony_ci * 30:2 CE address (64 byte block 34:6) 14862306a36Sopenharmony_ci * 1 Reserved 14962306a36Sopenharmony_ci * 0 HiLoCS 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci#define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */ 15262306a36Sopenharmony_ci /* error address register (32b) */ 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * 31 Reserved 15562306a36Sopenharmony_ci * 30:2 CE address (64 byte block 34:6) 15662306a36Sopenharmony_ci * 1 Reserved 15762306a36Sopenharmony_ci * 0 HiLoCS 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci#define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM 1st uncorrectable scrub mem */ 16062306a36Sopenharmony_ci /* error address register (32b) */ 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * 31 Reserved 16362306a36Sopenharmony_ci * 30:2 CE address (64 byte block 34:6 16462306a36Sopenharmony_ci * 1 Reserved 16562306a36Sopenharmony_ci * 0 HiLoCS 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci#define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */ 16862306a36Sopenharmony_ci /* error syndrome register (16b) */ 16962306a36Sopenharmony_ci#define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */ 17062306a36Sopenharmony_ci /* error syndrome register (16b) */ 17162306a36Sopenharmony_ci#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 3100 IMCH specific register addresses - device 0 function 1 */ 17462306a36Sopenharmony_ci#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ 17562306a36Sopenharmony_ci#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ 17662306a36Sopenharmony_ci#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ 17762306a36Sopenharmony_ci#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* ICH5R register addresses - device 30 function 0 */ 18062306a36Sopenharmony_ci#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ 18162306a36Sopenharmony_ci#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ 18262306a36Sopenharmony_ci#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cienum e752x_chips { 18562306a36Sopenharmony_ci E7520 = 0, 18662306a36Sopenharmony_ci E7525 = 1, 18762306a36Sopenharmony_ci E7320 = 2, 18862306a36Sopenharmony_ci I3100 = 3 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* 19262306a36Sopenharmony_ci * Those chips Support single-rank and dual-rank memories only. 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * On e752x chips, the odd rows are present only on dual-rank memories. 19562306a36Sopenharmony_ci * Dividing the rank by two will provide the dimm# 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * i3100 MC has a different mapping: it supports only 4 ranks. 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * The mapping is (from 1 to n): 20062306a36Sopenharmony_ci * slot single-ranked double-ranked 20162306a36Sopenharmony_ci * dimm #1 -> rank #4 NA 20262306a36Sopenharmony_ci * dimm #2 -> rank #3 NA 20362306a36Sopenharmony_ci * dimm #3 -> rank #2 Ranks 2 and 3 20462306a36Sopenharmony_ci * dimm #4 -> rank $1 Ranks 1 and 4 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * FIXME: The current mapping for i3100 considers that it supports up to 8 20762306a36Sopenharmony_ci * ranks/chanel, but datasheet says that the MC supports only 4 ranks. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistruct e752x_pvt { 21162306a36Sopenharmony_ci struct pci_dev *dev_d0f0; 21262306a36Sopenharmony_ci struct pci_dev *dev_d0f1; 21362306a36Sopenharmony_ci u32 tolm; 21462306a36Sopenharmony_ci u32 remapbase; 21562306a36Sopenharmony_ci u32 remaplimit; 21662306a36Sopenharmony_ci int mc_symmetric; 21762306a36Sopenharmony_ci u8 map[8]; 21862306a36Sopenharmony_ci int map_type; 21962306a36Sopenharmony_ci const struct e752x_dev_info *dev_info; 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistruct e752x_dev_info { 22362306a36Sopenharmony_ci u16 err_dev; 22462306a36Sopenharmony_ci u16 ctl_dev; 22562306a36Sopenharmony_ci const char *ctl_name; 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistruct e752x_error_info { 22962306a36Sopenharmony_ci u32 ferr_global; 23062306a36Sopenharmony_ci u32 nerr_global; 23162306a36Sopenharmony_ci u32 nsi_ferr; /* 3100 only */ 23262306a36Sopenharmony_ci u32 nsi_nerr; /* 3100 only */ 23362306a36Sopenharmony_ci u8 hi_ferr; /* all but 3100 */ 23462306a36Sopenharmony_ci u8 hi_nerr; /* all but 3100 */ 23562306a36Sopenharmony_ci u16 sysbus_ferr; 23662306a36Sopenharmony_ci u16 sysbus_nerr; 23762306a36Sopenharmony_ci u8 buf_ferr; 23862306a36Sopenharmony_ci u8 buf_nerr; 23962306a36Sopenharmony_ci u16 dram_ferr; 24062306a36Sopenharmony_ci u16 dram_nerr; 24162306a36Sopenharmony_ci u32 dram_sec1_add; 24262306a36Sopenharmony_ci u32 dram_sec2_add; 24362306a36Sopenharmony_ci u16 dram_sec1_syndrome; 24462306a36Sopenharmony_ci u16 dram_sec2_syndrome; 24562306a36Sopenharmony_ci u32 dram_ded_add; 24662306a36Sopenharmony_ci u32 dram_scrb_add; 24762306a36Sopenharmony_ci u32 dram_retr_add; 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic const struct e752x_dev_info e752x_devs[] = { 25162306a36Sopenharmony_ci [E7520] = { 25262306a36Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, 25362306a36Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0, 25462306a36Sopenharmony_ci .ctl_name = "E7520"}, 25562306a36Sopenharmony_ci [E7525] = { 25662306a36Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, 25762306a36Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0, 25862306a36Sopenharmony_ci .ctl_name = "E7525"}, 25962306a36Sopenharmony_ci [E7320] = { 26062306a36Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, 26162306a36Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, 26262306a36Sopenharmony_ci .ctl_name = "E7320"}, 26362306a36Sopenharmony_ci [I3100] = { 26462306a36Sopenharmony_ci .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, 26562306a36Sopenharmony_ci .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, 26662306a36Sopenharmony_ci .ctl_name = "3100"}, 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* Valid scrub rates for the e752x/3100 hardware memory scrubber. We 27062306a36Sopenharmony_ci * map the scrubbing bandwidth to a hardware register value. The 'set' 27162306a36Sopenharmony_ci * operation finds the 'matching or higher value'. Note that scrubbing 27262306a36Sopenharmony_ci * on the e752x can only be enabled/disabled. The 3100 supports 27362306a36Sopenharmony_ci * a normal and fast mode. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci#define SDRATE_EOT 0xFFFFFFFF 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistruct scrubrate { 27962306a36Sopenharmony_ci u32 bandwidth; /* bandwidth consumed by scrubbing in bytes/sec */ 28062306a36Sopenharmony_ci u16 scrubval; /* register value for scrub rate */ 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* Rate below assumes same performance as i3100 using PC3200 DDR2 in 28462306a36Sopenharmony_ci * normal mode. e752x bridges don't support choosing normal or fast mode, 28562306a36Sopenharmony_ci * so the scrubbing bandwidth value isn't all that important - scrubbing is 28662306a36Sopenharmony_ci * either on or off. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic const struct scrubrate scrubrates_e752x[] = { 28962306a36Sopenharmony_ci {0, 0x00}, /* Scrubbing Off */ 29062306a36Sopenharmony_ci {500000, 0x02}, /* Scrubbing On */ 29162306a36Sopenharmony_ci {SDRATE_EOT, 0x00} /* End of Table */ 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s 29562306a36Sopenharmony_ci * Normal mode: 125 (32000 / 256) times slower than fast mode. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic const struct scrubrate scrubrates_i3100[] = { 29862306a36Sopenharmony_ci {0, 0x00}, /* Scrubbing Off */ 29962306a36Sopenharmony_ci {500000, 0x0a}, /* Normal mode - 32k clocks */ 30062306a36Sopenharmony_ci {62500000, 0x06}, /* Fast mode - 256 clocks */ 30162306a36Sopenharmony_ci {SDRATE_EOT, 0x00} /* End of Table */ 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, 30562306a36Sopenharmony_ci unsigned long page) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci u32 remap; 30862306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci edac_dbg(3, "\n"); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (page < pvt->tolm) 31362306a36Sopenharmony_ci return page; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if ((page >= 0x100000) && (page < pvt->remapbase)) 31662306a36Sopenharmony_ci return page; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci remap = (page - pvt->tolm) + pvt->remapbase; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (remap < pvt->remaplimit) 32162306a36Sopenharmony_ci return remap; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page); 32462306a36Sopenharmony_ci return pvt->tolm - 1; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void do_process_ce(struct mem_ctl_info *mci, u16 error_one, 32862306a36Sopenharmony_ci u32 sec1_add, u16 sec1_syndrome) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci u32 page; 33162306a36Sopenharmony_ci int row; 33262306a36Sopenharmony_ci int channel; 33362306a36Sopenharmony_ci int i; 33462306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci edac_dbg(3, "\n"); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* convert the addr to 4k page */ 33962306a36Sopenharmony_ci page = sec1_add >> (PAGE_SHIFT - 4); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* FIXME - check for -1 */ 34262306a36Sopenharmony_ci if (pvt->mc_symmetric) { 34362306a36Sopenharmony_ci /* chip select are bits 14 & 13 */ 34462306a36Sopenharmony_ci row = ((page >> 1) & 3); 34562306a36Sopenharmony_ci e752x_printk(KERN_WARNING, 34662306a36Sopenharmony_ci "Test row %d Table %d %d %d %d %d %d %d %d\n", row, 34762306a36Sopenharmony_ci pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3], 34862306a36Sopenharmony_ci pvt->map[4], pvt->map[5], pvt->map[6], 34962306a36Sopenharmony_ci pvt->map[7]); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* test for channel remapping */ 35262306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 35362306a36Sopenharmony_ci if (pvt->map[i] == row) 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci e752x_printk(KERN_WARNING, "Test computed row %d\n", i); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (i < 8) 36062306a36Sopenharmony_ci row = i; 36162306a36Sopenharmony_ci else 36262306a36Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, 36362306a36Sopenharmony_ci "row %d not found in remap table\n", 36462306a36Sopenharmony_ci row); 36562306a36Sopenharmony_ci } else 36662306a36Sopenharmony_ci row = edac_mc_find_csrow_by_page(mci, page); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* 0 = channel A, 1 = channel B */ 36962306a36Sopenharmony_ci channel = !(error_one & 1); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 37262306a36Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 37362306a36Sopenharmony_ci page, offset_in_page(sec1_add << 4), sec1_syndrome, 37462306a36Sopenharmony_ci row, channel, -1, 37562306a36Sopenharmony_ci "e752x CE", ""); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic inline void process_ce(struct mem_ctl_info *mci, u16 error_one, 37962306a36Sopenharmony_ci u32 sec1_add, u16 sec1_syndrome, int *error_found, 38062306a36Sopenharmony_ci int handle_error) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci *error_found = 1; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (handle_error) 38562306a36Sopenharmony_ci do_process_ce(mci, error_one, sec1_add, sec1_syndrome); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic void do_process_ue(struct mem_ctl_info *mci, u16 error_one, 38962306a36Sopenharmony_ci u32 ded_add, u32 scrb_add) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci u32 error_2b, block_page; 39262306a36Sopenharmony_ci int row; 39362306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci edac_dbg(3, "\n"); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (error_one & 0x0202) { 39862306a36Sopenharmony_ci error_2b = ded_add; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* convert to 4k address */ 40162306a36Sopenharmony_ci block_page = error_2b >> (PAGE_SHIFT - 4); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci row = pvt->mc_symmetric ? 40462306a36Sopenharmony_ci /* chip select are bits 14 & 13 */ 40562306a36Sopenharmony_ci ((block_page >> 1) & 3) : 40662306a36Sopenharmony_ci edac_mc_find_csrow_by_page(mci, block_page); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 40962306a36Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 41062306a36Sopenharmony_ci block_page, 41162306a36Sopenharmony_ci offset_in_page(error_2b << 4), 0, 41262306a36Sopenharmony_ci row, -1, -1, 41362306a36Sopenharmony_ci "e752x UE from Read", ""); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci if (error_one & 0x0404) { 41762306a36Sopenharmony_ci error_2b = scrb_add; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* convert to 4k address */ 42062306a36Sopenharmony_ci block_page = error_2b >> (PAGE_SHIFT - 4); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci row = pvt->mc_symmetric ? 42362306a36Sopenharmony_ci /* chip select are bits 14 & 13 */ 42462306a36Sopenharmony_ci ((block_page >> 1) & 3) : 42562306a36Sopenharmony_ci edac_mc_find_csrow_by_page(mci, block_page); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* e752x mc reads 34:6 of the DRAM linear address */ 42862306a36Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 42962306a36Sopenharmony_ci block_page, 43062306a36Sopenharmony_ci offset_in_page(error_2b << 4), 0, 43162306a36Sopenharmony_ci row, -1, -1, 43262306a36Sopenharmony_ci "e752x UE from Scruber", ""); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic inline void process_ue(struct mem_ctl_info *mci, u16 error_one, 43762306a36Sopenharmony_ci u32 ded_add, u32 scrb_add, int *error_found, 43862306a36Sopenharmony_ci int handle_error) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci *error_found = 1; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (handle_error) 44362306a36Sopenharmony_ci do_process_ue(mci, error_one, ded_add, scrb_add); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic inline void process_ue_no_info_wr(struct mem_ctl_info *mci, 44762306a36Sopenharmony_ci int *error_found, int handle_error) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci *error_found = 1; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!handle_error) 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci edac_dbg(3, "\n"); 45562306a36Sopenharmony_ci edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, 45662306a36Sopenharmony_ci -1, -1, -1, 45762306a36Sopenharmony_ci "e752x UE log memory write", ""); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, 46162306a36Sopenharmony_ci u32 retry_add) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci u32 error_1b, page; 46462306a36Sopenharmony_ci int row; 46562306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci error_1b = retry_add; 46862306a36Sopenharmony_ci page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* chip select are bits 14 & 13 */ 47162306a36Sopenharmony_ci row = pvt->mc_symmetric ? ((page >> 1) & 3) : 47262306a36Sopenharmony_ci edac_mc_find_csrow_by_page(mci, page); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, 47562306a36Sopenharmony_ci "CE page 0x%lx, row %d : Memory read retry\n", 47662306a36Sopenharmony_ci (long unsigned int)page, row); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, 48062306a36Sopenharmony_ci u32 retry_add, int *error_found, 48162306a36Sopenharmony_ci int handle_error) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci *error_found = 1; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (handle_error) 48662306a36Sopenharmony_ci do_process_ded_retry(mci, error, retry_add); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, 49062306a36Sopenharmony_ci int *error_found, int handle_error) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci *error_found = 1; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (handle_error) 49562306a36Sopenharmony_ci e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n"); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic char *global_message[11] = { 49962306a36Sopenharmony_ci "PCI Express C1", 50062306a36Sopenharmony_ci "PCI Express C", 50162306a36Sopenharmony_ci "PCI Express B1", 50262306a36Sopenharmony_ci "PCI Express B", 50362306a36Sopenharmony_ci "PCI Express A1", 50462306a36Sopenharmony_ci "PCI Express A", 50562306a36Sopenharmony_ci "DMA Controller", 50662306a36Sopenharmony_ci "HUB or NS Interface", 50762306a36Sopenharmony_ci "System Bus", 50862306a36Sopenharmony_ci "DRAM Controller", /* 9th entry */ 50962306a36Sopenharmony_ci "Internal Buffer" 51062306a36Sopenharmony_ci}; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci#define DRAM_ENTRY 9 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic char *fatal_message[2] = { "Non-Fatal ", "Fatal " }; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic void do_global_error(int fatal, u32 errors) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci int i; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci for (i = 0; i < 11; i++) { 52162306a36Sopenharmony_ci if (errors & (1 << i)) { 52262306a36Sopenharmony_ci /* If the error is from DRAM Controller OR 52362306a36Sopenharmony_ci * we are to report ALL errors, then 52462306a36Sopenharmony_ci * report the error 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci if ((i == DRAM_ENTRY) || report_non_memory_errors) 52762306a36Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError %s\n", 52862306a36Sopenharmony_ci fatal_message[fatal], 52962306a36Sopenharmony_ci global_message[i]); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic inline void global_error(int fatal, u32 errors, int *error_found, 53562306a36Sopenharmony_ci int handle_error) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci *error_found = 1; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (handle_error) 54062306a36Sopenharmony_ci do_global_error(fatal, errors); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic char *hub_message[7] = { 54462306a36Sopenharmony_ci "HI Address or Command Parity", "HI Illegal Access", 54562306a36Sopenharmony_ci "HI Internal Parity", "Out of Range Access", 54662306a36Sopenharmony_ci "HI Data Parity", "Enhanced Config Access", 54762306a36Sopenharmony_ci "Hub Interface Target Abort" 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void do_hub_error(int fatal, u8 errors) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci int i; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 55562306a36Sopenharmony_ci if (errors & (1 << i)) 55662306a36Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError %s\n", 55762306a36Sopenharmony_ci fatal_message[fatal], hub_message[i]); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic inline void hub_error(int fatal, u8 errors, int *error_found, 56262306a36Sopenharmony_ci int handle_error) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci *error_found = 1; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (handle_error) 56762306a36Sopenharmony_ci do_hub_error(fatal, errors); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci#define NSI_FATAL_MASK 0x0c080081 57162306a36Sopenharmony_ci#define NSI_NON_FATAL_MASK 0x23a0ba64 57262306a36Sopenharmony_ci#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic char *nsi_message[30] = { 57562306a36Sopenharmony_ci "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ 57662306a36Sopenharmony_ci "", /* reserved */ 57762306a36Sopenharmony_ci "NSI Parity Error", /* bit 2, non-fatal */ 57862306a36Sopenharmony_ci "", /* reserved */ 57962306a36Sopenharmony_ci "", /* reserved */ 58062306a36Sopenharmony_ci "Correctable Error Message", /* bit 5, non-fatal */ 58162306a36Sopenharmony_ci "Non-Fatal Error Message", /* bit 6, non-fatal */ 58262306a36Sopenharmony_ci "Fatal Error Message", /* bit 7, fatal */ 58362306a36Sopenharmony_ci "", /* reserved */ 58462306a36Sopenharmony_ci "Receiver Error", /* bit 9, non-fatal */ 58562306a36Sopenharmony_ci "", /* reserved */ 58662306a36Sopenharmony_ci "Bad TLP", /* bit 11, non-fatal */ 58762306a36Sopenharmony_ci "Bad DLLP", /* bit 12, non-fatal */ 58862306a36Sopenharmony_ci "REPLAY_NUM Rollover", /* bit 13, non-fatal */ 58962306a36Sopenharmony_ci "", /* reserved */ 59062306a36Sopenharmony_ci "Replay Timer Timeout", /* bit 15, non-fatal */ 59162306a36Sopenharmony_ci "", /* reserved */ 59262306a36Sopenharmony_ci "", /* reserved */ 59362306a36Sopenharmony_ci "", /* reserved */ 59462306a36Sopenharmony_ci "Data Link Protocol Error", /* bit 19, fatal */ 59562306a36Sopenharmony_ci "", /* reserved */ 59662306a36Sopenharmony_ci "Poisoned TLP", /* bit 21, non-fatal */ 59762306a36Sopenharmony_ci "", /* reserved */ 59862306a36Sopenharmony_ci "Completion Timeout", /* bit 23, non-fatal */ 59962306a36Sopenharmony_ci "Completer Abort", /* bit 24, non-fatal */ 60062306a36Sopenharmony_ci "Unexpected Completion", /* bit 25, non-fatal */ 60162306a36Sopenharmony_ci "Receiver Overflow", /* bit 26, fatal */ 60262306a36Sopenharmony_ci "Malformed TLP", /* bit 27, fatal */ 60362306a36Sopenharmony_ci "", /* reserved */ 60462306a36Sopenharmony_ci "Unsupported Request" /* bit 29, non-fatal */ 60562306a36Sopenharmony_ci}; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void do_nsi_error(int fatal, u32 errors) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int i; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci for (i = 0; i < 30; i++) { 61262306a36Sopenharmony_ci if (errors & (1 << i)) 61362306a36Sopenharmony_ci printk(KERN_WARNING "%sError %s\n", 61462306a36Sopenharmony_ci fatal_message[fatal], nsi_message[i]); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic inline void nsi_error(int fatal, u32 errors, int *error_found, 61962306a36Sopenharmony_ci int handle_error) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci *error_found = 1; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (handle_error) 62462306a36Sopenharmony_ci do_nsi_error(fatal, errors); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic char *membuf_message[4] = { 62862306a36Sopenharmony_ci "Internal PMWB to DRAM parity", 62962306a36Sopenharmony_ci "Internal PMWB to System Bus Parity", 63062306a36Sopenharmony_ci "Internal System Bus or IO to PMWB Parity", 63162306a36Sopenharmony_ci "Internal DRAM to PMWB Parity" 63262306a36Sopenharmony_ci}; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic void do_membuf_error(u8 errors) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci int i; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 63962306a36Sopenharmony_ci if (errors & (1 << i)) 64062306a36Sopenharmony_ci e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n", 64162306a36Sopenharmony_ci membuf_message[i]); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic inline void membuf_error(u8 errors, int *error_found, int handle_error) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci *error_found = 1; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (handle_error) 65062306a36Sopenharmony_ci do_membuf_error(errors); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic char *sysbus_message[10] = { 65462306a36Sopenharmony_ci "Addr or Request Parity", 65562306a36Sopenharmony_ci "Data Strobe Glitch", 65662306a36Sopenharmony_ci "Addr Strobe Glitch", 65762306a36Sopenharmony_ci "Data Parity", 65862306a36Sopenharmony_ci "Addr Above TOM", 65962306a36Sopenharmony_ci "Non DRAM Lock Error", 66062306a36Sopenharmony_ci "MCERR", "BINIT", 66162306a36Sopenharmony_ci "Memory Parity", 66262306a36Sopenharmony_ci "IO Subsystem Parity" 66362306a36Sopenharmony_ci}; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic void do_sysbus_error(int fatal, u32 errors) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci int i; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 67062306a36Sopenharmony_ci if (errors & (1 << i)) 67162306a36Sopenharmony_ci e752x_printk(KERN_WARNING, "%sError System Bus %s\n", 67262306a36Sopenharmony_ci fatal_message[fatal], sysbus_message[i]); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic inline void sysbus_error(int fatal, u32 errors, int *error_found, 67762306a36Sopenharmony_ci int handle_error) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci *error_found = 1; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (handle_error) 68262306a36Sopenharmony_ci do_sysbus_error(fatal, errors); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void e752x_check_hub_interface(struct e752x_error_info *info, 68662306a36Sopenharmony_ci int *error_found, int handle_error) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci u8 stat8; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci //pci_read_config_byte(dev,E752X_HI_FERR,&stat8); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci stat8 = info->hi_ferr; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (stat8 & 0x7f) { /* Error, so process */ 69562306a36Sopenharmony_ci stat8 &= 0x7f; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (stat8 & 0x2b) 69862306a36Sopenharmony_ci hub_error(1, stat8 & 0x2b, error_found, handle_error); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (stat8 & 0x54) 70162306a36Sopenharmony_ci hub_error(0, stat8 & 0x54, error_found, handle_error); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci stat8 = info->hi_nerr; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (stat8 & 0x7f) { /* Error, so process */ 70862306a36Sopenharmony_ci stat8 &= 0x7f; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (stat8 & 0x2b) 71162306a36Sopenharmony_ci hub_error(1, stat8 & 0x2b, error_found, handle_error); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (stat8 & 0x54) 71462306a36Sopenharmony_ci hub_error(0, stat8 & 0x54, error_found, handle_error); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic void e752x_check_ns_interface(struct e752x_error_info *info, 71962306a36Sopenharmony_ci int *error_found, int handle_error) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci u32 stat32; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci stat32 = info->nsi_ferr; 72462306a36Sopenharmony_ci if (stat32 & NSI_ERR_MASK) { /* Error, so process */ 72562306a36Sopenharmony_ci if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ 72662306a36Sopenharmony_ci nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, 72762306a36Sopenharmony_ci handle_error); 72862306a36Sopenharmony_ci if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ 72962306a36Sopenharmony_ci nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, 73062306a36Sopenharmony_ci handle_error); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci stat32 = info->nsi_nerr; 73362306a36Sopenharmony_ci if (stat32 & NSI_ERR_MASK) { 73462306a36Sopenharmony_ci if (stat32 & NSI_FATAL_MASK) 73562306a36Sopenharmony_ci nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, 73662306a36Sopenharmony_ci handle_error); 73762306a36Sopenharmony_ci if (stat32 & NSI_NON_FATAL_MASK) 73862306a36Sopenharmony_ci nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, 73962306a36Sopenharmony_ci handle_error); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void e752x_check_sysbus(struct e752x_error_info *info, 74462306a36Sopenharmony_ci int *error_found, int handle_error) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci u32 stat32, error32; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32); 74962306a36Sopenharmony_ci stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (stat32 == 0) 75262306a36Sopenharmony_ci return; /* no errors */ 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci error32 = (stat32 >> 16) & 0x3ff; 75562306a36Sopenharmony_ci stat32 = stat32 & 0x3ff; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (stat32 & 0x087) 75862306a36Sopenharmony_ci sysbus_error(1, stat32 & 0x087, error_found, handle_error); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (stat32 & 0x378) 76162306a36Sopenharmony_ci sysbus_error(0, stat32 & 0x378, error_found, handle_error); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (error32 & 0x087) 76462306a36Sopenharmony_ci sysbus_error(1, error32 & 0x087, error_found, handle_error); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (error32 & 0x378) 76762306a36Sopenharmony_ci sysbus_error(0, error32 & 0x378, error_found, handle_error); 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void e752x_check_membuf(struct e752x_error_info *info, 77162306a36Sopenharmony_ci int *error_found, int handle_error) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci u8 stat8; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci stat8 = info->buf_ferr; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (stat8 & 0x0f) { /* Error, so process */ 77862306a36Sopenharmony_ci stat8 &= 0x0f; 77962306a36Sopenharmony_ci membuf_error(stat8, error_found, handle_error); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci stat8 = info->buf_nerr; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (stat8 & 0x0f) { /* Error, so process */ 78562306a36Sopenharmony_ci stat8 &= 0x0f; 78662306a36Sopenharmony_ci membuf_error(stat8, error_found, handle_error); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic void e752x_check_dram(struct mem_ctl_info *mci, 79162306a36Sopenharmony_ci struct e752x_error_info *info, int *error_found, 79262306a36Sopenharmony_ci int handle_error) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci u16 error_one, error_next; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci error_one = info->dram_ferr; 79762306a36Sopenharmony_ci error_next = info->dram_nerr; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* decode and report errors */ 80062306a36Sopenharmony_ci if (error_one & 0x0101) /* check first error correctable */ 80162306a36Sopenharmony_ci process_ce(mci, error_one, info->dram_sec1_add, 80262306a36Sopenharmony_ci info->dram_sec1_syndrome, error_found, handle_error); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (error_next & 0x0101) /* check next error correctable */ 80562306a36Sopenharmony_ci process_ce(mci, error_next, info->dram_sec2_add, 80662306a36Sopenharmony_ci info->dram_sec2_syndrome, error_found, handle_error); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (error_one & 0x4040) 80962306a36Sopenharmony_ci process_ue_no_info_wr(mci, error_found, handle_error); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (error_next & 0x4040) 81262306a36Sopenharmony_ci process_ue_no_info_wr(mci, error_found, handle_error); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (error_one & 0x2020) 81562306a36Sopenharmony_ci process_ded_retry(mci, error_one, info->dram_retr_add, 81662306a36Sopenharmony_ci error_found, handle_error); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (error_next & 0x2020) 81962306a36Sopenharmony_ci process_ded_retry(mci, error_next, info->dram_retr_add, 82062306a36Sopenharmony_ci error_found, handle_error); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (error_one & 0x0808) 82362306a36Sopenharmony_ci process_threshold_ce(mci, error_one, error_found, handle_error); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (error_next & 0x0808) 82662306a36Sopenharmony_ci process_threshold_ce(mci, error_next, error_found, 82762306a36Sopenharmony_ci handle_error); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (error_one & 0x0606) 83062306a36Sopenharmony_ci process_ue(mci, error_one, info->dram_ded_add, 83162306a36Sopenharmony_ci info->dram_scrb_add, error_found, handle_error); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (error_next & 0x0606) 83462306a36Sopenharmony_ci process_ue(mci, error_next, info->dram_ded_add, 83562306a36Sopenharmony_ci info->dram_scrb_add, error_found, handle_error); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void e752x_get_error_info(struct mem_ctl_info *mci, 83962306a36Sopenharmony_ci struct e752x_error_info *info) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct pci_dev *dev; 84262306a36Sopenharmony_ci struct e752x_pvt *pvt; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci memset(info, 0, sizeof(*info)); 84562306a36Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 84662306a36Sopenharmony_ci dev = pvt->dev_d0f1; 84762306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (info->ferr_global) { 85062306a36Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 85162306a36Sopenharmony_ci pci_read_config_dword(dev, I3100_NSI_FERR, 85262306a36Sopenharmony_ci &info->nsi_ferr); 85362306a36Sopenharmony_ci info->hi_ferr = 0; 85462306a36Sopenharmony_ci } else { 85562306a36Sopenharmony_ci pci_read_config_byte(dev, E752X_HI_FERR, 85662306a36Sopenharmony_ci &info->hi_ferr); 85762306a36Sopenharmony_ci info->nsi_ferr = 0; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci pci_read_config_word(dev, E752X_SYSBUS_FERR, 86062306a36Sopenharmony_ci &info->sysbus_ferr); 86162306a36Sopenharmony_ci pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); 86262306a36Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr); 86362306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD, 86462306a36Sopenharmony_ci &info->dram_sec1_add); 86562306a36Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME, 86662306a36Sopenharmony_ci &info->dram_sec1_syndrome); 86762306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_DED_ADD, 86862306a36Sopenharmony_ci &info->dram_ded_add); 86962306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD, 87062306a36Sopenharmony_ci &info->dram_scrb_add); 87162306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, 87262306a36Sopenharmony_ci &info->dram_retr_add); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* ignore the reserved bits just in case */ 87562306a36Sopenharmony_ci if (info->hi_ferr & 0x7f) 87662306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_FERR, 87762306a36Sopenharmony_ci info->hi_ferr); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (info->nsi_ferr & NSI_ERR_MASK) 88062306a36Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_FERR, 88162306a36Sopenharmony_ci info->nsi_ferr); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (info->sysbus_ferr) 88462306a36Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_FERR, 88562306a36Sopenharmony_ci info->sysbus_ferr); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (info->buf_ferr & 0x0f) 88862306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_FERR, 88962306a36Sopenharmony_ci info->buf_ferr); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (info->dram_ferr) 89262306a36Sopenharmony_ci pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR, 89362306a36Sopenharmony_ci info->dram_ferr, info->dram_ferr); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci pci_write_config_dword(dev, E752X_FERR_GLOBAL, 89662306a36Sopenharmony_ci info->ferr_global); 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (info->nerr_global) { 90262306a36Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 90362306a36Sopenharmony_ci pci_read_config_dword(dev, I3100_NSI_NERR, 90462306a36Sopenharmony_ci &info->nsi_nerr); 90562306a36Sopenharmony_ci info->hi_nerr = 0; 90662306a36Sopenharmony_ci } else { 90762306a36Sopenharmony_ci pci_read_config_byte(dev, E752X_HI_NERR, 90862306a36Sopenharmony_ci &info->hi_nerr); 90962306a36Sopenharmony_ci info->nsi_nerr = 0; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci pci_read_config_word(dev, E752X_SYSBUS_NERR, 91262306a36Sopenharmony_ci &info->sysbus_nerr); 91362306a36Sopenharmony_ci pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); 91462306a36Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr); 91562306a36Sopenharmony_ci pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD, 91662306a36Sopenharmony_ci &info->dram_sec2_add); 91762306a36Sopenharmony_ci pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME, 91862306a36Sopenharmony_ci &info->dram_sec2_syndrome); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (info->hi_nerr & 0x7f) 92162306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_NERR, 92262306a36Sopenharmony_ci info->hi_nerr); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (info->nsi_nerr & NSI_ERR_MASK) 92562306a36Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_NERR, 92662306a36Sopenharmony_ci info->nsi_nerr); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (info->sysbus_nerr) 92962306a36Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_NERR, 93062306a36Sopenharmony_ci info->sysbus_nerr); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (info->buf_nerr & 0x0f) 93362306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_NERR, 93462306a36Sopenharmony_ci info->buf_nerr); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (info->dram_nerr) 93762306a36Sopenharmony_ci pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR, 93862306a36Sopenharmony_ci info->dram_nerr, info->dram_nerr); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci pci_write_config_dword(dev, E752X_NERR_GLOBAL, 94162306a36Sopenharmony_ci info->nerr_global); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int e752x_process_error_info(struct mem_ctl_info *mci, 94662306a36Sopenharmony_ci struct e752x_error_info *info, 94762306a36Sopenharmony_ci int handle_errors) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci u32 error32, stat32; 95062306a36Sopenharmony_ci int error_found; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci error_found = 0; 95362306a36Sopenharmony_ci error32 = (info->ferr_global >> 18) & 0x3ff; 95462306a36Sopenharmony_ci stat32 = (info->ferr_global >> 4) & 0x7ff; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (error32) 95762306a36Sopenharmony_ci global_error(1, error32, &error_found, handle_errors); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (stat32) 96062306a36Sopenharmony_ci global_error(0, stat32, &error_found, handle_errors); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci error32 = (info->nerr_global >> 18) & 0x3ff; 96362306a36Sopenharmony_ci stat32 = (info->nerr_global >> 4) & 0x7ff; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (error32) 96662306a36Sopenharmony_ci global_error(1, error32, &error_found, handle_errors); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (stat32) 96962306a36Sopenharmony_ci global_error(0, stat32, &error_found, handle_errors); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci e752x_check_hub_interface(info, &error_found, handle_errors); 97262306a36Sopenharmony_ci e752x_check_ns_interface(info, &error_found, handle_errors); 97362306a36Sopenharmony_ci e752x_check_sysbus(info, &error_found, handle_errors); 97462306a36Sopenharmony_ci e752x_check_membuf(info, &error_found, handle_errors); 97562306a36Sopenharmony_ci e752x_check_dram(mci, info, &error_found, handle_errors); 97662306a36Sopenharmony_ci return error_found; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic void e752x_check(struct mem_ctl_info *mci) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct e752x_error_info info; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci e752x_get_error_info(mci, &info); 98462306a36Sopenharmony_ci e752x_process_error_info(mci, &info, 1); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/* Program byte/sec bandwidth scrub rate to hardware */ 98862306a36Sopenharmony_cistatic int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci const struct scrubrate *scrubrates; 99162306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; 99262306a36Sopenharmony_ci struct pci_dev *pdev = pvt->dev_d0f0; 99362306a36Sopenharmony_ci int i; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) 99662306a36Sopenharmony_ci scrubrates = scrubrates_i3100; 99762306a36Sopenharmony_ci else 99862306a36Sopenharmony_ci scrubrates = scrubrates_e752x; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Translate the desired scrub rate to a e752x/3100 register value. 100162306a36Sopenharmony_ci * Search for the bandwidth that is equal or greater than the 100262306a36Sopenharmony_ci * desired rate and program the cooresponding register value. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) 100562306a36Sopenharmony_ci if (scrubrates[i].bandwidth >= new_bw) 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (scrubrates[i].bandwidth == SDRATE_EOT) 100962306a36Sopenharmony_ci return -1; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return scrubrates[i].bandwidth; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/* Convert current scrub rate value into byte/sec bandwidth */ 101762306a36Sopenharmony_cistatic int get_sdram_scrub_rate(struct mem_ctl_info *mci) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci const struct scrubrate *scrubrates; 102062306a36Sopenharmony_ci struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; 102162306a36Sopenharmony_ci struct pci_dev *pdev = pvt->dev_d0f0; 102262306a36Sopenharmony_ci u16 scrubval; 102362306a36Sopenharmony_ci int i; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) 102662306a36Sopenharmony_ci scrubrates = scrubrates_i3100; 102762306a36Sopenharmony_ci else 102862306a36Sopenharmony_ci scrubrates = scrubrates_e752x; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* Find the bandwidth matching the memory scrubber configuration */ 103162306a36Sopenharmony_ci pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval); 103262306a36Sopenharmony_ci scrubval = scrubval & 0x0f; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) 103562306a36Sopenharmony_ci if (scrubrates[i].scrubval == scrubval) 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (scrubrates[i].bandwidth == SDRATE_EOT) { 103962306a36Sopenharmony_ci e752x_printk(KERN_WARNING, 104062306a36Sopenharmony_ci "Invalid sdram scrub control value: 0x%x\n", scrubval); 104162306a36Sopenharmony_ci return -1; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci return scrubrates[i].bandwidth; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci/* Return 1 if dual channel mode is active. Else return 0. */ 104862306a36Sopenharmony_cistatic inline int dual_channel_active(u16 ddrcsr) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci return (((ddrcsr >> 12) & 3) == 3); 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci/* Remap csrow index numbers if map_type is "reverse" 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_cistatic inline int remap_csrow_index(struct mem_ctl_info *mci, int index) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct e752x_pvt *pvt = mci->pvt_info; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (!pvt->map_type) 106062306a36Sopenharmony_ci return (7 - index); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return (index); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, 106662306a36Sopenharmony_ci u16 ddrcsr) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct csrow_info *csrow; 106962306a36Sopenharmony_ci enum edac_type edac_mode; 107062306a36Sopenharmony_ci unsigned long last_cumul_size; 107162306a36Sopenharmony_ci int index, mem_dev, drc_chan; 107262306a36Sopenharmony_ci int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ 107362306a36Sopenharmony_ci int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ 107462306a36Sopenharmony_ci u8 value; 107562306a36Sopenharmony_ci u32 dra, drc, cumul_size, i, nr_pages; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci dra = 0; 107862306a36Sopenharmony_ci for (index = 0; index < 4; index++) { 107962306a36Sopenharmony_ci u8 dra_reg; 108062306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg); 108162306a36Sopenharmony_ci dra |= dra_reg << (index * 8); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci pci_read_config_dword(pdev, E752X_DRC, &drc); 108462306a36Sopenharmony_ci drc_chan = dual_channel_active(ddrcsr) ? 1 : 0; 108562306a36Sopenharmony_ci drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ 108662306a36Sopenharmony_ci drc_ddim = (drc >> 20) & 0x3; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* The dram row boundary (DRB) reg values are boundary address for 108962306a36Sopenharmony_ci * each DRAM row with a granularity of 64 or 128MB (single/dual 109062306a36Sopenharmony_ci * channel operation). DRB regs are cumulative; therefore DRB7 will 109162306a36Sopenharmony_ci * contain the total memory contained in all eight rows. 109262306a36Sopenharmony_ci */ 109362306a36Sopenharmony_ci for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { 109462306a36Sopenharmony_ci /* mem_dev 0=x8, 1=x4 */ 109562306a36Sopenharmony_ci mem_dev = (dra >> (index * 4 + 2)) & 0x3; 109662306a36Sopenharmony_ci csrow = mci->csrows[remap_csrow_index(mci, index)]; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci mem_dev = (mem_dev == 2); 109962306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index, &value); 110062306a36Sopenharmony_ci /* convert a 128 or 64 MiB DRB to a page size. */ 110162306a36Sopenharmony_ci cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); 110262306a36Sopenharmony_ci edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size); 110362306a36Sopenharmony_ci if (cumul_size == last_cumul_size) 110462306a36Sopenharmony_ci continue; /* not populated */ 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci csrow->first_page = last_cumul_size; 110762306a36Sopenharmony_ci csrow->last_page = cumul_size - 1; 110862306a36Sopenharmony_ci nr_pages = cumul_size - last_cumul_size; 110962306a36Sopenharmony_ci last_cumul_size = cumul_size; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* 111262306a36Sopenharmony_ci * if single channel or x8 devices then SECDED 111362306a36Sopenharmony_ci * if dual channel and x4 then S4ECD4ED 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci if (drc_ddim) { 111662306a36Sopenharmony_ci if (drc_chan && mem_dev) { 111762306a36Sopenharmony_ci edac_mode = EDAC_S4ECD4ED; 111862306a36Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_S4ECD4ED; 111962306a36Sopenharmony_ci } else { 112062306a36Sopenharmony_ci edac_mode = EDAC_SECDED; 112162306a36Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_SECDED; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci } else 112462306a36Sopenharmony_ci edac_mode = EDAC_NONE; 112562306a36Sopenharmony_ci for (i = 0; i < csrow->nr_channels; i++) { 112662306a36Sopenharmony_ci struct dimm_info *dimm = csrow->channels[i]->dimm; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci edac_dbg(3, "Initializing rank at (%i,%i)\n", index, i); 112962306a36Sopenharmony_ci dimm->nr_pages = nr_pages / csrow->nr_channels; 113062306a36Sopenharmony_ci dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ 113162306a36Sopenharmony_ci dimm->mtype = MEM_RDDR; /* only one type supported */ 113262306a36Sopenharmony_ci dimm->dtype = mem_dev ? DEV_X4 : DEV_X8; 113362306a36Sopenharmony_ci dimm->edac_mode = edac_mode; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic void e752x_init_mem_map_table(struct pci_dev *pdev, 113962306a36Sopenharmony_ci struct e752x_pvt *pvt) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci int index; 114262306a36Sopenharmony_ci u8 value, last, row; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci last = 0; 114562306a36Sopenharmony_ci row = 0; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci for (index = 0; index < 8; index += 2) { 114862306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index, &value); 114962306a36Sopenharmony_ci /* test if there is a dimm in this slot */ 115062306a36Sopenharmony_ci if (value == last) { 115162306a36Sopenharmony_ci /* no dimm in the slot, so flag it as empty */ 115262306a36Sopenharmony_ci pvt->map[index] = 0xff; 115362306a36Sopenharmony_ci pvt->map[index + 1] = 0xff; 115462306a36Sopenharmony_ci } else { /* there is a dimm in the slot */ 115562306a36Sopenharmony_ci pvt->map[index] = row; 115662306a36Sopenharmony_ci row++; 115762306a36Sopenharmony_ci last = value; 115862306a36Sopenharmony_ci /* test the next value to see if the dimm is double 115962306a36Sopenharmony_ci * sided 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRB + index + 1, 116262306a36Sopenharmony_ci &value); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* the dimm is single sided, so flag as empty */ 116562306a36Sopenharmony_ci /* this is a double sided dimm to save the next row #*/ 116662306a36Sopenharmony_ci pvt->map[index + 1] = (value == last) ? 0xff : row; 116762306a36Sopenharmony_ci row++; 116862306a36Sopenharmony_ci last = value; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci/* Return 0 on success or 1 on failure. */ 117462306a36Sopenharmony_cistatic int e752x_get_devs(struct pci_dev *pdev, int dev_idx, 117562306a36Sopenharmony_ci struct e752x_pvt *pvt) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL, 117862306a36Sopenharmony_ci pvt->dev_info->err_dev, NULL); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (pvt->dev_d0f1 == NULL) { 118162306a36Sopenharmony_ci pvt->dev_d0f1 = pci_scan_single_device(pdev->bus, 118262306a36Sopenharmony_ci PCI_DEVFN(0, 1)); 118362306a36Sopenharmony_ci pci_dev_get(pvt->dev_d0f1); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (pvt->dev_d0f1 == NULL) { 118762306a36Sopenharmony_ci e752x_printk(KERN_ERR, "error reporting device not found:" 118862306a36Sopenharmony_ci "vendor %x device 0x%x (broken BIOS?)\n", 118962306a36Sopenharmony_ci PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); 119062306a36Sopenharmony_ci return 1; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL, 119462306a36Sopenharmony_ci e752x_devs[dev_idx].ctl_dev, 119562306a36Sopenharmony_ci NULL); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (pvt->dev_d0f0 == NULL) 119862306a36Sopenharmony_ci goto fail; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cifail: 120362306a36Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 120462306a36Sopenharmony_ci return 1; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci/* Setup system bus parity mask register. 120862306a36Sopenharmony_ci * Sysbus parity supported on: 120962306a36Sopenharmony_ci * e7320/e7520/e7525 + Xeon 121062306a36Sopenharmony_ci */ 121162306a36Sopenharmony_cistatic void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci char *cpu_id = cpu_data(0).x86_model_id; 121462306a36Sopenharmony_ci struct pci_dev *dev = pvt->dev_d0f1; 121562306a36Sopenharmony_ci int enable = 1; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* Allow module parameter override, else see if CPU supports parity */ 121862306a36Sopenharmony_ci if (sysbus_parity != -1) { 121962306a36Sopenharmony_ci enable = sysbus_parity; 122062306a36Sopenharmony_ci } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) { 122162306a36Sopenharmony_ci e752x_printk(KERN_INFO, "System Bus Parity not " 122262306a36Sopenharmony_ci "supported by CPU, disabling\n"); 122362306a36Sopenharmony_ci enable = 0; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (enable) 122762306a36Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000); 122862306a36Sopenharmony_ci else 122962306a36Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309); 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct pci_dev *dev; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci dev = pvt->dev_d0f1; 123762306a36Sopenharmony_ci /* Turn off error disable & SMI in case the BIOS turned it on */ 123862306a36Sopenharmony_ci if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { 123962306a36Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_EMASK, 0); 124062306a36Sopenharmony_ci pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); 124162306a36Sopenharmony_ci } else { 124262306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); 124362306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci e752x_init_sysbus_parity_mask(pvt); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); 124962306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); 125062306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); 125162306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); 125262306a36Sopenharmony_ci pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int e752x_probe1(struct pci_dev *pdev, int dev_idx) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci u16 pci_data; 125862306a36Sopenharmony_ci u8 stat8; 125962306a36Sopenharmony_ci struct mem_ctl_info *mci; 126062306a36Sopenharmony_ci struct edac_mc_layer layers[2]; 126162306a36Sopenharmony_ci struct e752x_pvt *pvt; 126262306a36Sopenharmony_ci u16 ddrcsr; 126362306a36Sopenharmony_ci int drc_chan; /* Number of channels 0=1chan,1=2chan */ 126462306a36Sopenharmony_ci struct e752x_error_info discard; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci edac_dbg(0, "mci\n"); 126762306a36Sopenharmony_ci edac_dbg(0, "Starting Probe1\n"); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* check to see if device 0 function 1 is enabled; if it isn't, we 127062306a36Sopenharmony_ci * assume the BIOS has reserved it for a reason and is expecting 127162306a36Sopenharmony_ci * exclusive access, we take care not to violate that assumption and 127262306a36Sopenharmony_ci * fail the probe. */ 127362306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); 127462306a36Sopenharmony_ci if (!force_function_unhide && !(stat8 & (1 << 5))) { 127562306a36Sopenharmony_ci printk(KERN_INFO "Contact your BIOS vendor to see if the " 127662306a36Sopenharmony_ci "E752x error registers can be safely un-hidden\n"); 127762306a36Sopenharmony_ci return -ENODEV; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci stat8 |= (1 << 5); 128062306a36Sopenharmony_ci pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); 128362306a36Sopenharmony_ci /* FIXME: should check >>12 or 0xf, true for all? */ 128462306a36Sopenharmony_ci /* Dual channel = 1, Single channel = 0 */ 128562306a36Sopenharmony_ci drc_chan = dual_channel_active(ddrcsr); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 128862306a36Sopenharmony_ci layers[0].size = E752X_NR_CSROWS; 128962306a36Sopenharmony_ci layers[0].is_virt_csrow = true; 129062306a36Sopenharmony_ci layers[1].type = EDAC_MC_LAYER_CHANNEL; 129162306a36Sopenharmony_ci layers[1].size = drc_chan + 1; 129262306a36Sopenharmony_ci layers[1].is_virt_csrow = false; 129362306a36Sopenharmony_ci mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); 129462306a36Sopenharmony_ci if (mci == NULL) 129562306a36Sopenharmony_ci return -ENOMEM; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci edac_dbg(3, "init mci\n"); 129862306a36Sopenharmony_ci mci->mtype_cap = MEM_FLAG_RDDR; 129962306a36Sopenharmony_ci /* 3100 IMCH supports SECDEC only */ 130062306a36Sopenharmony_ci mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : 130162306a36Sopenharmony_ci (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); 130262306a36Sopenharmony_ci /* FIXME - what if different memory types are in different csrows? */ 130362306a36Sopenharmony_ci mci->mod_name = EDAC_MOD_STR; 130462306a36Sopenharmony_ci mci->pdev = &pdev->dev; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci edac_dbg(3, "init pvt\n"); 130762306a36Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 130862306a36Sopenharmony_ci pvt->dev_info = &e752x_devs[dev_idx]; 130962306a36Sopenharmony_ci pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (e752x_get_devs(pdev, dev_idx, pvt)) { 131262306a36Sopenharmony_ci edac_mc_free(mci); 131362306a36Sopenharmony_ci return -ENODEV; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci edac_dbg(3, "more mci init\n"); 131762306a36Sopenharmony_ci mci->ctl_name = pvt->dev_info->ctl_name; 131862306a36Sopenharmony_ci mci->dev_name = pci_name(pdev); 131962306a36Sopenharmony_ci mci->edac_check = e752x_check; 132062306a36Sopenharmony_ci mci->ctl_page_to_phys = ctl_page_to_phys; 132162306a36Sopenharmony_ci mci->set_sdram_scrub_rate = set_sdram_scrub_rate; 132262306a36Sopenharmony_ci mci->get_sdram_scrub_rate = get_sdram_scrub_rate; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* set the map type. 1 = normal, 0 = reversed 132562306a36Sopenharmony_ci * Must be set before e752x_init_csrows in case csrow mapping 132662306a36Sopenharmony_ci * is reversed. 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_ci pci_read_config_byte(pdev, E752X_DRM, &stat8); 132962306a36Sopenharmony_ci pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci e752x_init_csrows(mci, pdev, ddrcsr); 133262306a36Sopenharmony_ci e752x_init_mem_map_table(pdev, pvt); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (dev_idx == I3100) 133562306a36Sopenharmony_ci mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ 133662306a36Sopenharmony_ci else 133762306a36Sopenharmony_ci mci->edac_cap |= EDAC_FLAG_NONE; 133862306a36Sopenharmony_ci edac_dbg(3, "tolm, remapbase, remaplimit\n"); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* load the top of low memory, remap base, and remap limit vars */ 134162306a36Sopenharmony_ci pci_read_config_word(pdev, E752X_TOLM, &pci_data); 134262306a36Sopenharmony_ci pvt->tolm = ((u32) pci_data) << 4; 134362306a36Sopenharmony_ci pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data); 134462306a36Sopenharmony_ci pvt->remapbase = ((u32) pci_data) << 14; 134562306a36Sopenharmony_ci pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data); 134662306a36Sopenharmony_ci pvt->remaplimit = ((u32) pci_data) << 14; 134762306a36Sopenharmony_ci e752x_printk(KERN_INFO, 134862306a36Sopenharmony_ci "tolm = %x, remapbase = %x, remaplimit = %x\n", 134962306a36Sopenharmony_ci pvt->tolm, pvt->remapbase, pvt->remaplimit); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* Here we assume that we will never see multiple instances of this 135262306a36Sopenharmony_ci * type of memory controller. The ID is therefore hardcoded to 0. 135362306a36Sopenharmony_ci */ 135462306a36Sopenharmony_ci if (edac_mc_add_mc(mci)) { 135562306a36Sopenharmony_ci edac_dbg(3, "failed edac_mc_add_mc()\n"); 135662306a36Sopenharmony_ci goto fail; 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci e752x_init_error_reporting_regs(pvt); 136062306a36Sopenharmony_ci e752x_get_error_info(mci, &discard); /* clear other MCH errors */ 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* allocating generic PCI control info */ 136362306a36Sopenharmony_ci e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 136462306a36Sopenharmony_ci if (!e752x_pci) { 136562306a36Sopenharmony_ci printk(KERN_WARNING 136662306a36Sopenharmony_ci "%s(): Unable to create PCI control\n", __func__); 136762306a36Sopenharmony_ci printk(KERN_WARNING 136862306a36Sopenharmony_ci "%s(): PCI error report via EDAC not setup\n", 136962306a36Sopenharmony_ci __func__); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* get this far and it's successful */ 137362306a36Sopenharmony_ci edac_dbg(3, "success\n"); 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cifail: 137762306a36Sopenharmony_ci pci_dev_put(pvt->dev_d0f0); 137862306a36Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 137962306a36Sopenharmony_ci edac_mc_free(mci); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci return -ENODEV; 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci/* returns count (>= 0), or negative on error */ 138562306a36Sopenharmony_cistatic int e752x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci edac_dbg(0, "\n"); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci /* wake up and enable device */ 139062306a36Sopenharmony_ci if (pci_enable_device(pdev) < 0) 139162306a36Sopenharmony_ci return -EIO; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci return e752x_probe1(pdev, ent->driver_data); 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic void e752x_remove_one(struct pci_dev *pdev) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci struct mem_ctl_info *mci; 139962306a36Sopenharmony_ci struct e752x_pvt *pvt; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci edac_dbg(0, "\n"); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (e752x_pci) 140462306a36Sopenharmony_ci edac_pci_release_generic_ctl(e752x_pci); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) 140762306a36Sopenharmony_ci return; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci pvt = (struct e752x_pvt *)mci->pvt_info; 141062306a36Sopenharmony_ci pci_dev_put(pvt->dev_d0f0); 141162306a36Sopenharmony_ci pci_dev_put(pvt->dev_d0f1); 141262306a36Sopenharmony_ci edac_mc_free(mci); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic const struct pci_device_id e752x_pci_tbl[] = { 141662306a36Sopenharmony_ci { 141762306a36Sopenharmony_ci PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 141862306a36Sopenharmony_ci E7520}, 141962306a36Sopenharmony_ci { 142062306a36Sopenharmony_ci PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 142162306a36Sopenharmony_ci E7525}, 142262306a36Sopenharmony_ci { 142362306a36Sopenharmony_ci PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 142462306a36Sopenharmony_ci E7320}, 142562306a36Sopenharmony_ci { 142662306a36Sopenharmony_ci PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 142762306a36Sopenharmony_ci I3100}, 142862306a36Sopenharmony_ci { 142962306a36Sopenharmony_ci 0, 143062306a36Sopenharmony_ci } /* 0 terminated list. */ 143162306a36Sopenharmony_ci}; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, e752x_pci_tbl); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic struct pci_driver e752x_driver = { 143662306a36Sopenharmony_ci .name = EDAC_MOD_STR, 143762306a36Sopenharmony_ci .probe = e752x_init_one, 143862306a36Sopenharmony_ci .remove = e752x_remove_one, 143962306a36Sopenharmony_ci .id_table = e752x_pci_tbl, 144062306a36Sopenharmony_ci}; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int __init e752x_init(void) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci int pci_rc; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci edac_dbg(3, "\n"); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 144962306a36Sopenharmony_ci opstate_init(); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci pci_rc = pci_register_driver(&e752x_driver); 145262306a36Sopenharmony_ci return (pci_rc < 0) ? pci_rc : 0; 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic void __exit e752x_exit(void) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci edac_dbg(3, "\n"); 145862306a36Sopenharmony_ci pci_unregister_driver(&e752x_driver); 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cimodule_init(e752x_init); 146262306a36Sopenharmony_cimodule_exit(e752x_exit); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 146562306a36Sopenharmony_ciMODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman"); 146662306a36Sopenharmony_ciMODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cimodule_param(force_function_unhide, int, 0444); 146962306a36Sopenharmony_ciMODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" 147062306a36Sopenharmony_ci " 1=force unhide and hope BIOS doesn't fight driver for " 147162306a36Sopenharmony_ci "Dev0:Fun1 access"); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cimodule_param(edac_op_state, int, 0444); 147462306a36Sopenharmony_ciMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cimodule_param(sysbus_parity, int, 0444); 147762306a36Sopenharmony_ciMODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking," 147862306a36Sopenharmony_ci " 1=enable system bus parity checking, default=auto-detect"); 147962306a36Sopenharmony_cimodule_param(report_non_memory_errors, int, 0644); 148062306a36Sopenharmony_ciMODULE_PARM_DESC(report_non_memory_errors, "0=disable non-memory error " 148162306a36Sopenharmony_ci "reporting, 1=enable non-memory error reporting"); 1482