12bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson#include "amd64_edac.h" 223ac4ae827e6264e21b898f2cd3f601450aa02a6Andreas Herrmann#include <asm/amd_nb.h> 32bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 42bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompsonstatic struct edac_pci_ctl_info *amd64_ctl_pci; 52bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 62bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompsonstatic int report_gart_errors; 72bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompsonmodule_param(report_gart_errors, int, 0644); 82bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 92bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson/* 102bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * Set by command line parameter. If BIOS has enabled the ECC, this override is 112bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * cleared to prevent re-enabling the hardware by this driver. 122bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 132bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompsonstatic int ecc_enable_override; 142bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompsonmodule_param(ecc_enable_override, int, 0644); 152bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 16a29d8b8e2d811a24bbe49215a0f0c536b72ebc18Tejun Heostatic struct msr __percpu *msrs; 17505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov 18360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov/* 19360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov * count successfully initialized driver instances for setup_pci_device() 20360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov */ 21360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic atomic_t drv_instances = ATOMIC_INIT(0); 22360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 23cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov/* Per-node driver instances */ 24cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkovstatic struct mem_ctl_info **mcis; 25ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkovstatic struct ecc_settings **ecc_stngs; 262bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 272bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson/* 28b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing 29b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching- 30b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov * or higher value'. 31b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov * 32b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov *FIXME: Produce a better mapping/linearisation. 33b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov */ 34390944439f746824faec51b576f50cb5ef18745bBorislav Petkovstruct scrubrate { 35390944439f746824faec51b576f50cb5ef18745bBorislav Petkov u32 scrubval; /* bit pattern for scrub rate */ 36390944439f746824faec51b576f50cb5ef18745bBorislav Petkov u32 bandwidth; /* bandwidth consumed (bytes/sec) */ 37390944439f746824faec51b576f50cb5ef18745bBorislav Petkov} scrubrates[] = { 38b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x01, 1600000000UL}, 39b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x02, 800000000UL}, 40b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x03, 400000000UL}, 41b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x04, 200000000UL}, 42b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x05, 100000000UL}, 43b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x06, 50000000UL}, 44b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x07, 25000000UL}, 45b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x08, 12284069UL}, 46b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x09, 6274509UL}, 47b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0A, 3121951UL}, 48b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0B, 1560975UL}, 49b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0C, 781440UL}, 50b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0D, 390720UL}, 51b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0E, 195300UL}, 52b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x0F, 97650UL}, 53b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x10, 48854UL}, 54b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x11, 24427UL}, 55b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x12, 12213UL}, 56b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x13, 6101UL}, 57b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x14, 3051UL}, 58b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x15, 1523UL}, 59b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x16, 761UL}, 60b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov { 0x00, 0UL}, /* scrubbing off */ 61b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov}; 62b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov 63b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, 64b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov u32 *val, const char *func) 65b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov{ 66b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov int err = 0; 67b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 68b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov err = pci_read_config_dword(pdev, offset, val); 69b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov if (err) 70b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov amd64_warn("%s: error reading F%dx%03x.\n", 71b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov func, PCI_FUNC(pdev->devfn), offset); 72b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 73b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return err; 74b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov} 75b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 76b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovint __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, 77b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov u32 val, const char *func) 78b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov{ 79b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov int err = 0; 80b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 81b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov err = pci_write_config_dword(pdev, offset, val); 82b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov if (err) 83b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov amd64_warn("%s: error writing to F%dx%03x.\n", 84b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov func, PCI_FUNC(pdev->devfn), offset); 85b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 86b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return err; 87b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov} 88b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 89b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov/* 90b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * 91b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * Depending on the family, F2 DCT reads need special handling: 92b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * 93b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * K8: has a single DCT only 94b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * 95b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * F10h: each DCT has its own set of regs 96b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * DCT0 -> F2x040.. 97b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * DCT1 -> F2x140.. 98b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * 99b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * F15h: we select which DCT we access using F1x10C[DctCfgSel] 100b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov * 101b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov */ 102b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, 103b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov const char *func) 104b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov{ 105b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov if (addr >= 0x100) 106b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return -EINVAL; 107b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 108b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); 109b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov} 110b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 111b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, 112b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov const char *func) 113b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov{ 114b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); 115b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov} 116b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 11773ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov/* 11873ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov * Select DCT to which PCI cfg accesses are routed 11973ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov */ 12073ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkovstatic void f15h_select_dct(struct amd64_pvt *pvt, u8 dct) 12173ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov{ 12273ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov u32 reg = 0; 12373ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov 12473ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®); 12573ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov reg &= 0xfffffffe; 12673ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov reg |= dct; 12773ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg); 12873ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov} 12973ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov 130b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, 131b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov const char *func) 132b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov{ 133b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov u8 dct = 0; 134b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 135b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov if (addr >= 0x140 && addr <= 0x1a0) { 136b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov dct = 1; 137b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov addr -= 0x100; 138b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov } 139b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 14073ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov f15h_select_dct(pvt, dct); 141b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 142b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); 143b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov} 144b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 145b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov/* 1462bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * Memory scrubber control interface. For K8, memory scrubbing is handled by 1472bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * hardware and can involve L2 cache, dcache as well as the main memory. With 1482bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * F10, this is extended to L3 cache scrubbing on CPU models sporting that 1492bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * functionality. 1502bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * 1512bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * This causes the "units" for the scrubbing speed to vary from 64 byte blocks 1522bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * (dram) over to cache lines. This is nasty, so we will use bandwidth in 1532bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * bytes/sec for the setting. 1542bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * 1552bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * Currently, we only do dram scrubbing. If the scrubbing is done in software on 1562bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * other archs, we might not have access to the caches directly. 1572bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 1582bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1592bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson/* 1602bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * scan the scrub rate mapping table for a close or matching bandwidth value to 1612bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * issue. If requested is too big, then use last maximum value found. 1622bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 163395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkovstatic int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) 1642bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson{ 1652bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson u32 scrubval; 1662bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson int i; 1672bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1682bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson /* 1692bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * map the configured rate (new_bw) to a value specific to the AMD64 1702bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * memory controller and apply to register. Search for the first 1712bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * bandwidth entry that is greater or equal than the setting requested 1722bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * and program that. If at last entry, turn off DRAM scrubbing. 1732bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 1742bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { 1752bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson /* 1762bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * skip scrub rates which aren't recommended 1772bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * (see F10 BKDG, F3x58) 1782bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 179395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov if (scrubrates[i].scrubval < min_rate) 1802bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson continue; 1812bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1822bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson if (scrubrates[i].bandwidth <= new_bw) 1832bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson break; 1842bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1852bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson /* 1862bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * if no suitable bandwidth found, turn off DRAM scrubbing 1872bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * entirely by falling back to the last element in the 1882bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson * scrubrates array. 1892bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson */ 1902bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson } 1912bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1922bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson scrubval = scrubrates[i].scrubval; 1932bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 1945980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov pci_write_bits32(ctl, SCRCTRL, scrubval, 0x001F); 1952bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 196390944439f746824faec51b576f50cb5ef18745bBorislav Petkov if (scrubval) 197390944439f746824faec51b576f50cb5ef18745bBorislav Petkov return scrubrates[i].bandwidth; 198390944439f746824faec51b576f50cb5ef18745bBorislav Petkov 1992bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson return 0; 2002bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson} 2012bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 202395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkovstatic int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw) 2032bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson{ 2042bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 20587b3e0e6e43b7e92575b79ed05ab86d221323642Borislav Petkov u32 min_scrubrate = 0x5; 2062bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 20787b3e0e6e43b7e92575b79ed05ab86d221323642Borislav Petkov if (boot_cpu_data.x86 == 0xf) 20887b3e0e6e43b7e92575b79ed05ab86d221323642Borislav Petkov min_scrubrate = 0x0; 20987b3e0e6e43b7e92575b79ed05ab86d221323642Borislav Petkov 21073ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov /* F15h Erratum #505 */ 21173ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov if (boot_cpu_data.x86 == 0x15) 21273ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov f15h_select_dct(pvt, 0); 21373ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov 21487b3e0e6e43b7e92575b79ed05ab86d221323642Borislav Petkov return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate); 2152bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson} 2162bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 217390944439f746824faec51b576f50cb5ef18745bBorislav Petkovstatic int amd64_get_scrub_rate(struct mem_ctl_info *mci) 2182bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson{ 2192bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 2202bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson u32 scrubval = 0; 221390944439f746824faec51b576f50cb5ef18745bBorislav Petkov int i, retval = -EINVAL; 2222bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 22373ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov /* F15h Erratum #505 */ 22473ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov if (boot_cpu_data.x86 == 0x15) 22573ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov f15h_select_dct(pvt, 0); 22673ba85937b2a07b6401ba0b7ca06a112762de9f7Borislav Petkov 2275980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); 2282bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 2292bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson scrubval = scrubval & 0x001F; 2302bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 231926311fd7dabcd284a1e8a87a3e2bb5f929c0c60Roel Kluin for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { 2322bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson if (scrubrates[i].scrubval == scrubval) { 233390944439f746824faec51b576f50cb5ef18745bBorislav Petkov retval = scrubrates[i].bandwidth; 2342bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson break; 2352bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson } 2362bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson } 237390944439f746824faec51b576f50cb5ef18745bBorislav Petkov return retval; 2382bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson} 2392bc65418724a0ddbb20c9eeb9de8285af7748c16Doug Thompson 2406775763a2377e1ea865299b6daadc875d622de3fDoug Thompson/* 2417f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov * returns true if the SysAddr given by sys_addr matches the 2427f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov * DRAM base/limit associated with node_id 2436775763a2377e1ea865299b6daadc875d622de3fDoug Thompson */ 244b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkovstatic bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, 245b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov unsigned nid) 2466775763a2377e1ea865299b6daadc875d622de3fDoug Thompson{ 2477f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov u64 addr; 2486775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2496775763a2377e1ea865299b6daadc875d622de3fDoug Thompson /* The K8 treats this as a 40-bit value. However, bits 63-40 will be 2506775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * all ones if the most significant implemented address bit is 1. 2516775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * Here we discard bits 63-40. See section 3.4.2 of AMD publication 2526775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1 2536775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * Application Programming. 2546775763a2377e1ea865299b6daadc875d622de3fDoug Thompson */ 2556775763a2377e1ea865299b6daadc875d622de3fDoug Thompson addr = sys_addr & 0x000000ffffffffffull; 2566775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2577f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov return ((addr >= get_dram_base(pvt, nid)) && 2587f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov (addr <= get_dram_limit(pvt, nid))); 2596775763a2377e1ea865299b6daadc875d622de3fDoug Thompson} 2606775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2616775763a2377e1ea865299b6daadc875d622de3fDoug Thompson/* 2626775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * Attempt to map a SysAddr to a node. On success, return a pointer to the 2636775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * mem_ctl_info structure for the node that the SysAddr maps to. 2646775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * 2656775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * On failure, return NULL. 2666775763a2377e1ea865299b6daadc875d622de3fDoug Thompson */ 2676775763a2377e1ea865299b6daadc875d622de3fDoug Thompsonstatic struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci, 2686775763a2377e1ea865299b6daadc875d622de3fDoug Thompson u64 sys_addr) 2696775763a2377e1ea865299b6daadc875d622de3fDoug Thompson{ 2706775763a2377e1ea865299b6daadc875d622de3fDoug Thompson struct amd64_pvt *pvt; 271b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov unsigned node_id; 2726775763a2377e1ea865299b6daadc875d622de3fDoug Thompson u32 intlv_en, bits; 2736775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2746775763a2377e1ea865299b6daadc875d622de3fDoug Thompson /* 2756775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section 2766775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * 3.4.4.2) registers to map the SysAddr to a node ID. 2776775763a2377e1ea865299b6daadc875d622de3fDoug Thompson */ 2786775763a2377e1ea865299b6daadc875d622de3fDoug Thompson pvt = mci->pvt_info; 2796775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2806775763a2377e1ea865299b6daadc875d622de3fDoug Thompson /* 2816775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * The value of this field should be the same for all DRAM Base 2826775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * registers. Therefore we arbitrarily choose to read it from the 2836775763a2377e1ea865299b6daadc875d622de3fDoug Thompson * register for node 0. 2846775763a2377e1ea865299b6daadc875d622de3fDoug Thompson */ 2857f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov intlv_en = dram_intlv_en(pvt, 0); 2866775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 2876775763a2377e1ea865299b6daadc875d622de3fDoug Thompson if (intlv_en == 0) { 2887f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov for (node_id = 0; node_id < DRAM_RANGES; node_id++) { 2896775763a2377e1ea865299b6daadc875d622de3fDoug Thompson if (amd64_base_limit_match(pvt, sys_addr, node_id)) 2908edc5445895dbcf050d6e8ac5488f70a3937753aBorislav Petkov goto found; 2916775763a2377e1ea865299b6daadc875d622de3fDoug Thompson } 2928edc5445895dbcf050d6e8ac5488f70a3937753aBorislav Petkov goto err_no_match; 2936775763a2377e1ea865299b6daadc875d622de3fDoug Thompson } 2946775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 29572f158fe6fc2033ceb0f3e0e9e5c2aa356fed6daBorislav Petkov if (unlikely((intlv_en != 0x01) && 29672f158fe6fc2033ceb0f3e0e9e5c2aa356fed6daBorislav Petkov (intlv_en != 0x03) && 29772f158fe6fc2033ceb0f3e0e9e5c2aa356fed6daBorislav Petkov (intlv_en != 0x07))) { 29824f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en); 2996775763a2377e1ea865299b6daadc875d622de3fDoug Thompson return NULL; 3006775763a2377e1ea865299b6daadc875d622de3fDoug Thompson } 3016775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3026775763a2377e1ea865299b6daadc875d622de3fDoug Thompson bits = (((u32) sys_addr) >> 12) & intlv_en; 3036775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3046775763a2377e1ea865299b6daadc875d622de3fDoug Thompson for (node_id = 0; ; ) { 3057f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits) 3066775763a2377e1ea865299b6daadc875d622de3fDoug Thompson break; /* intlv_sel field matches */ 3076775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3087f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if (++node_id >= DRAM_RANGES) 3096775763a2377e1ea865299b6daadc875d622de3fDoug Thompson goto err_no_match; 3106775763a2377e1ea865299b6daadc875d622de3fDoug Thompson } 3116775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3126775763a2377e1ea865299b6daadc875d622de3fDoug Thompson /* sanity test for sys_addr */ 3136775763a2377e1ea865299b6daadc875d622de3fDoug Thompson if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) { 31424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address" 31524f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "range for node %d with node interleaving enabled.\n", 31624f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov __func__, sys_addr, node_id); 3176775763a2377e1ea865299b6daadc875d622de3fDoug Thompson return NULL; 3186775763a2377e1ea865299b6daadc875d622de3fDoug Thompson } 3196775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3206775763a2377e1ea865299b6daadc875d622de3fDoug Thompsonfound: 321b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov return edac_mc_find((int)node_id); 3226775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3236775763a2377e1ea865299b6daadc875d622de3fDoug Thompsonerr_no_match: 3246775763a2377e1ea865299b6daadc875d622de3fDoug Thompson debugf2("sys_addr 0x%lx doesn't match any node\n", 3256775763a2377e1ea865299b6daadc875d622de3fDoug Thompson (unsigned long)sys_addr); 3266775763a2377e1ea865299b6daadc875d622de3fDoug Thompson 3276775763a2377e1ea865299b6daadc875d622de3fDoug Thompson return NULL; 3286775763a2377e1ea865299b6daadc875d622de3fDoug Thompson} 329e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 330e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson/* 33111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov * compute the CS base address of the @csrow on the DRAM controller @dct. 33211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov * For details see F2x[5C:40] in the processor's BKDG 333e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson */ 33411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkovstatic void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, 33511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u64 *base, u64 *mask) 336e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson{ 33711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u64 csbase, csmask, base_bits, mask_bits; 33811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u8 addr_shift; 339e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 34011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { 34111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csbase = pvt->csels[dct].csbases[csrow]; 34211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csmask = pvt->csels[dct].csmasks[csrow]; 34311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov base_bits = GENMASK(21, 31) | GENMASK(9, 15); 34411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov mask_bits = GENMASK(21, 29) | GENMASK(9, 15); 34511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov addr_shift = 4; 34611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov } else { 34711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csbase = pvt->csels[dct].csbases[csrow]; 34811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csmask = pvt->csels[dct].csmasks[csrow >> 1]; 34911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov addr_shift = 8; 350e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 35111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (boot_cpu_data.x86 == 0x15) 35211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); 35311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov else 35411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); 35511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov } 356e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 35711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov *base = (csbase & base_bits) << addr_shift; 358e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 35911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov *mask = ~0ULL; 36011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov /* poke holes for the csmask */ 36111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov *mask &= ~(mask_bits << addr_shift); 36211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov /* OR them in */ 36311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov *mask |= (csmask & mask_bits) << addr_shift; 364e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson} 365e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 36611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov#define for_each_chip_select(i, dct, pvt) \ 36711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for (i = 0; i < pvt->csels[dct].b_cnt; i++) 36811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov 369614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov#define chip_select_base(i, dct, pvt) \ 370614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov pvt->csels[dct].csbases[i] 371614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov 37211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov#define for_each_chip_select_mask(i, dct, pvt) \ 37311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for (i = 0; i < pvt->csels[dct].m_cnt; i++) 37411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov 375e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson/* 376e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * @input_addr is an InputAddr associated with the node given by mci. Return the 377e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr). 378e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson */ 379e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompsonstatic int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) 380e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson{ 381e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson struct amd64_pvt *pvt; 382e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson int csrow; 383e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson u64 base, mask; 384e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 385e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson pvt = mci->pvt_info; 386e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 38711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for_each_chip_select(csrow, 0, pvt) { 38811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!csrow_enabled(csrow, 0, pvt)) 389e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson continue; 390e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 39111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov get_cs_base_and_mask(pvt, csrow, 0, &base, &mask); 39211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov 39311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov mask = ~mask; 394e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 395e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson if ((input_addr & mask) == (base & mask)) { 396e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n", 397e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson (unsigned long)input_addr, csrow, 398e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson pvt->mc_node_id); 399e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 400e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return csrow; 401e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson } 402e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson } 403e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n", 404e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson (unsigned long)input_addr, pvt->mc_node_id); 405e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 406e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return -1; 407e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson} 408e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 409e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson/* 410e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094) 411e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * for the node represented by mci. Info is passed back in *hole_base, 412e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if 413e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * info is invalid. Info may be invalid for either of the following reasons: 414e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * 415e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * - The revision of the node is not E or greater. In this case, the DRAM Hole 416e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * Address Register does not exist. 417e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * 418e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * - The DramHoleValid bit is cleared in the DRAM Hole Address Register, 419e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * indicating that its contents are not valid. 420e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * 421e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * The values passed back in *hole_base, *hole_offset, and *hole_size are 422e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * complete 32-bit values despite the fact that the bitfields in the DHAR 423e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * only represent bits 31-24 of the base and offset values. 424e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson */ 425e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompsonint amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, 426e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson u64 *hole_offset, u64 *hole_size) 427e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson{ 428e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 429e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson u64 base; 430e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 431e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson /* only revE and later have the DRAM Hole Address Register */ 4321433eb9903408d1801d19a9c49893120874abc12Borislav Petkov if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) { 433e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf1(" revision %d for node %d does not support DHAR\n", 434e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson pvt->ext_model, pvt->mc_node_id); 435e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return 1; 436e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson } 437e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 438bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov /* valid for Fam10h and above */ 439c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) { 440e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf1(" Dram Memory Hoisting is DISABLED on this system\n"); 441e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return 1; 442e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson } 443e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 444c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov if (!dhar_valid(pvt)) { 445e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf1(" Dram Memory Hoisting is DISABLED on this node %d\n", 446e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson pvt->mc_node_id); 447e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return 1; 448e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson } 449e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 450e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson /* This node has Memory Hoisting */ 451e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 452e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson /* +------------------+--------------------+--------------------+----- 453e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | memory | DRAM hole | relocated | 454e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | [0, (x - 1)] | [x, 0xffffffff] | addresses from | 455e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | | | DRAM hole | 456e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | | | [0x100000000, | 457e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | | | (0x100000000+ | 458e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * | | | (0xffffffff-x))] | 459e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * +------------------+--------------------+--------------------+----- 460e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * 461e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * Above is a diagram of physical memory showing the DRAM hole and the 462e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * relocated addresses from the DRAM hole. As shown, the DRAM hole 463e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * starts at address x (the base address) and extends through address 464e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the 465e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson * addresses in the hole so that they start at 0x100000000. 466e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson */ 467e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 468bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov base = dhar_base(pvt); 469e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 470e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson *hole_base = base; 471e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson *hole_size = (0x1ull << 32) - base; 472e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 473e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson if (boot_cpu_data.x86 > 0xf) 474bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov *hole_offset = f10_dhar_offset(pvt); 475e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson else 476bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov *hole_offset = k8_dhar_offset(pvt); 477e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 478e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson debugf1(" DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n", 479e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson pvt->mc_node_id, (unsigned long)*hole_base, 480e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson (unsigned long)*hole_offset, (unsigned long)*hole_size); 481e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 482e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson return 0; 483e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson} 484e2ce7255e84db656853e91536e6023f92ff89f97Doug ThompsonEXPORT_SYMBOL_GPL(amd64_get_dram_hole_info); 485e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 48693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 48793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is 48893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * assumed that sys_addr maps to the node given by mci. 48993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 49093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section 49193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a 49293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled, 49393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * then it is also involved in translating a SysAddr to a DramAddr. Sections 49493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting. 49593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * These parts of the documentation are unclear. I interpret them as follows: 49693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 49793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * When node n receives a SysAddr, it processes the SysAddr as follows: 49893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 49993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM 50093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Limit registers for node n. If the SysAddr is not within the range 50193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * specified by the base and limit values, then node n ignores the Sysaddr 50293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * (since it does not map to node n). Otherwise continue to step 2 below. 50393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 50493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is 50593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * disabled so skip to step 3 below. Otherwise see if the SysAddr is within 50693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * the range of relocated addresses (starting at 0x100000000) from the DRAM 50793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * hole. If not, skip to step 3 below. Else get the value of the 50893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the 50993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * offset defined by this value from the SysAddr. 51093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 51193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 3. Obtain the base address for node n from the DRAMBase field of the DRAM 51293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Base register for node n. To obtain the DramAddr, subtract the base 51393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * address from the SysAddr, as shown near the start of section 3.4.4 (p.70). 51493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 51593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) 51693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 5177f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov struct amd64_pvt *pvt = mci->pvt_info; 51893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 dram_base, hole_base, hole_offset, hole_size, dram_addr; 51993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson int ret = 0; 52093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 5217f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov dram_base = get_dram_base(pvt, pvt->mc_node_id); 52293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 52393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, 52493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson &hole_size); 52593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if (!ret) { 52693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if ((sys_addr >= (1ull << 32)) && 52793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (sys_addr < ((1ull << 32) + hole_size))) { 52893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson /* use DHAR to translate SysAddr to DramAddr */ 52993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson dram_addr = sys_addr - hole_offset; 53093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 53193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf2("using DHAR to translate SysAddr 0x%lx to " 53293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson "DramAddr 0x%lx\n", 53393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)sys_addr, 53493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)dram_addr); 53593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 53693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return dram_addr; 53793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson } 53893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson } 53993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 54093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson /* 54193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Translate the SysAddr to a DramAddr as shown near the start of 54293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8 54393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * only deals with 40-bit values. Therefore we discard bits 63-40 of 54493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * sys_addr below. If bit 39 of sys_addr is 1 then the bits we 54593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * discard are all 1s. Otherwise the bits we discard are all 0s. See 54693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture 54793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Programmer's Manual Volume 1 Application Programming. 54893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 549f678b8ccce69dcf9c597e3029ee35421ba62a215Borislav Petkov dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base; 55093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 55193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf2("using DRAM Base register to translate SysAddr 0x%lx to " 55293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson "DramAddr 0x%lx\n", (unsigned long)sys_addr, 55393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)dram_addr); 55493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return dram_addr; 55593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 55693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 55793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 55893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @intlv_en is the value of the IntlvEn field from a DRAM Base register 55993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * (section 3.4.4.1). Return the number of bits from a SysAddr that are used 56093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * for node interleaving. 56193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 56293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic int num_node_interleave_bits(unsigned intlv_en) 56393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 56493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 }; 56593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson int n; 56693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 56793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson BUG_ON(intlv_en > 7); 56893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson n = intlv_shift_table[intlv_en]; 56993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return n; 57093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 57193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 57293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* Translate the DramAddr given by @dram_addr to an InputAddr. */ 57393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr) 57493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 57593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson struct amd64_pvt *pvt; 57693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson int intlv_shift; 57793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 input_addr; 57893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 57993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson pvt = mci->pvt_info; 58093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 58193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson /* 58293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E) 58393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * concerning translating a DramAddr to an InputAddr. 58493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 5857f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); 586f678b8ccce69dcf9c597e3029ee35421ba62a215Borislav Petkov input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) + 587f678b8ccce69dcf9c597e3029ee35421ba62a215Borislav Petkov (dram_addr & 0xfff); 58893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 58993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf2(" Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", 59093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson intlv_shift, (unsigned long)dram_addr, 59193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)input_addr); 59293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 59393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return input_addr; 59493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 59593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 59693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 59793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Translate the SysAddr represented by @sys_addr to an InputAddr. It is 59893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * assumed that @sys_addr maps to the node given by mci. 59993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 60093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr) 60193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 60293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 input_addr; 60393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 60493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson input_addr = 60593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr)); 60693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 60793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n", 60893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)sys_addr, (unsigned long)input_addr); 60993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 61093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return input_addr; 61193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 61293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 61393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 61493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 61593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @input_addr is an InputAddr associated with the node represented by mci. 61693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Translate @input_addr to a DramAddr and return the result. 61793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 61893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr) 61993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 62093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson struct amd64_pvt *pvt; 621b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov unsigned node_id, intlv_shift; 62293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 bits, dram_addr; 62393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u32 intlv_sel; 62493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 62593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson /* 62693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E) 62793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * shows how to translate a DramAddr to an InputAddr. Here we reverse 62893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * this procedure. When translating from a DramAddr to an InputAddr, the 62993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * bits used for node interleaving are discarded. Here we recover these 63093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * bits from the IntlvSel field of the DRAM Limit register (section 63193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 3.4.4.2) for the node that input_addr is associated with. 63293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 63393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson pvt = mci->pvt_info; 63493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson node_id = pvt->mc_node_id; 635b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov 636b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkov BUG_ON(node_id > 7); 63793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 6387f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); 63993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if (intlv_shift == 0) { 64093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf1(" InputAddr 0x%lx translates to DramAddr of " 64193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson "same value\n", (unsigned long)input_addr); 64293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 64393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return input_addr; 64493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson } 64593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 646f678b8ccce69dcf9c597e3029ee35421ba62a215Borislav Petkov bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) + 647f678b8ccce69dcf9c597e3029ee35421ba62a215Borislav Petkov (input_addr & 0xfff); 64893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 6497f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1); 65093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson dram_addr = bits + (intlv_sel << 12); 65193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 65293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx " 65393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson "(%d node interleave bits)\n", (unsigned long)input_addr, 65493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)dram_addr, intlv_shift); 65593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 65693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return dram_addr; 65793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 65893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 65993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 66093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @dram_addr is a DramAddr that maps to the node represented by mci. Convert 66193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @dram_addr to a SysAddr. 66293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 66393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr) 66493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 66593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 6667f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov u64 hole_base, hole_offset, hole_size, base, sys_addr; 66793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson int ret = 0; 66893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 66993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, 67093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson &hole_size); 67193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if (!ret) { 67293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if ((dram_addr >= hole_base) && 67393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (dram_addr < (hole_base + hole_size))) { 67493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson sys_addr = dram_addr + hole_offset; 67593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 67693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf1("using DHAR to translate DramAddr 0x%lx to " 67793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson "SysAddr 0x%lx\n", (unsigned long)dram_addr, 67893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)sys_addr); 67993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 68093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return sys_addr; 68193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson } 68293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson } 68393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 6847f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov base = get_dram_base(pvt, pvt->mc_node_id); 68593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson sys_addr = dram_addr + base; 68693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 68793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson /* 68893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * The sys_addr we have computed up to this point is a 40-bit value 68993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * because the k8 deals with 40-bit values. However, the value we are 69093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * supposed to return is a full 64-bit physical address. The AMD 69193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * x86-64 architecture specifies that the most significant implemented 69293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * address bit through bit 63 of a physical address must be either all 69393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a 69493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * 64-bit value below. See section 3.4.2 of AMD publication 24592: 69593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * AMD x86-64 Architecture Programmer's Manual Volume 1 Application 69693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Programming. 69793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 69893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson sys_addr |= ~((sys_addr & (1ull << 39)) - 1); 69993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 70093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson debugf1(" Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n", 70193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson pvt->mc_node_id, (unsigned long)dram_addr, 70293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson (unsigned long)sys_addr); 70393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 70493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return sys_addr; 70593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 70693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 70793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 70893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @input_addr is an InputAddr associated with the node given by mci. Translate 70993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @input_addr to a SysAddr. 71093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 71193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci, 71293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 input_addr) 71393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 71493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return dram_addr_to_sys_addr(mci, 71593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson input_addr_to_dram_addr(mci, input_addr)); 71693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 71793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 71893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 71993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Find the minimum and maximum InputAddr values that map to the given @csrow. 72093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Pass back these values in *input_addr_min and *input_addr_max. 72193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 72293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic void find_csrow_limits(struct mem_ctl_info *mci, int csrow, 72393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 *input_addr_min, u64 *input_addr_max) 72493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 72593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson struct amd64_pvt *pvt; 72693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u64 base, mask; 72793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 72893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson pvt = mci->pvt_info; 72911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt)); 73093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 73111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov get_cs_base_and_mask(pvt, csrow, 0, &base, &mask); 73293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 73393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson *input_addr_min = base & ~mask; 73411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov *input_addr_max = base | mask; 73593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 73693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 73793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* Map the Error address to a PAGE and PAGE OFFSET. */ 73893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic inline void error_address_to_page_and_offset(u64 error_address, 73993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson u32 *page, u32 *offset) 74093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 74193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson *page = (u32) (error_address >> PAGE_SHIFT); 74293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson *offset = ((u32) error_address) & ~PAGE_MASK; 74393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 74493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 74593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson/* 74693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address 74793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers 74893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * of a node that detected an ECC memory error. mci represents the node that 74993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * the error address maps to (possibly different from the node that detected 75093c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * the error). Return the number of the csrow that sys_addr maps to, or -1 on 75193c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson * error. 75293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson */ 75393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompsonstatic int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) 75493c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson{ 75593c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson int csrow; 75693c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 75793c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr)); 75893c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson 75993c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson if (csrow == -1) 76024f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "Failed to translate InputAddr to csrow for " 76124f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "address 0x%lx\n", (unsigned long)sys_addr); 76293c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson return csrow; 76393c2df58b5b1a434cca8f60067e0e12d1942b7f1Doug Thompson} 764e2ce7255e84db656853e91536e6023f92ff89f97Doug Thompson 765bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkovstatic int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16); 7662da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 7672da11654ea4d32c5700693675dfbd55c70619519Doug Thompson/* 7682da11654ea4d32c5700693675dfbd55c70619519Doug Thompson * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs 7692da11654ea4d32c5700693675dfbd55c70619519Doug Thompson * are ECC capable. 7702da11654ea4d32c5700693675dfbd55c70619519Doug Thompson */ 7711f6189ed18cbd99d90bffdbc76c3adc54418b2fdDan Carpenterstatic unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt) 7722da11654ea4d32c5700693675dfbd55c70619519Doug Thompson{ 773cb32850744b8b574966637ae98d55692717eced4Borislav Petkov u8 bit; 7741f6189ed18cbd99d90bffdbc76c3adc54418b2fdDan Carpenter unsigned long edac_cap = EDAC_FLAG_NONE; 7752da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 7761433eb9903408d1801d19a9c49893120874abc12Borislav Petkov bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F) 7772da11654ea4d32c5700693675dfbd55c70619519Doug Thompson ? 19 7782da11654ea4d32c5700693675dfbd55c70619519Doug Thompson : 17; 7792da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 780584fcff428bde3b9985ba21498764e9dba2fd3ceBorislav Petkov if (pvt->dclr0 & BIT(bit)) 7812da11654ea4d32c5700693675dfbd55c70619519Doug Thompson edac_cap = EDAC_FLAG_SECDED; 7822da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 7832da11654ea4d32c5700693675dfbd55c70619519Doug Thompson return edac_cap; 7842da11654ea4d32c5700693675dfbd55c70619519Doug Thompson} 7852da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 7868c6717510f8002ea31b309c84b7d7a7f7c15197bBorislav Petkovstatic void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8); 7872da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 78868798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkovstatic void amd64_dump_dramcfg_low(u32 dclr, int chan) 78968798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov{ 79068798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1("F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr); 79168798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 79268798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1(" DIMM type: %sbuffered; all DIMMs support ECC: %s\n", 79368798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(16)) ? "un" : "", 79468798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(19)) ? "yes" : "no"); 79568798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 79668798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1(" PAR/ERR parity: %s\n", 79768798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(8)) ? "enabled" : "disabled"); 79868798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 799cb32850744b8b574966637ae98d55692717eced4Borislav Petkov if (boot_cpu_data.x86 == 0x10) 800cb32850744b8b574966637ae98d55692717eced4Borislav Petkov debugf1(" DCT 128bit mode width: %s\n", 801cb32850744b8b574966637ae98d55692717eced4Borislav Petkov (dclr & BIT(11)) ? "128b" : "64b"); 80268798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 80368798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1(" x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n", 80468798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(12)) ? "yes" : "no", 80568798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(13)) ? "yes" : "no", 80668798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(14)) ? "yes" : "no", 80768798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov (dclr & BIT(15)) ? "yes" : "no"); 80868798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov} 80968798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 8102da11654ea4d32c5700693675dfbd55c70619519Doug Thompson/* Display and decode various NB registers for debug purposes. */ 811b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic void dump_misc_regs(struct amd64_pvt *pvt) 8122da11654ea4d32c5700693675dfbd55c70619519Doug Thompson{ 81368798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap); 81468798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 81568798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1(" NB two channel DRAM capable: %s\n", 8165980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no"); 8172da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 81868798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov debugf1(" ECC capable: %s, ChipKill ECC capable: %s\n", 8195980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no", 8205980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no"); 82168798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov 82268798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov amd64_dump_dramcfg_low(pvt->dclr0, 0); 8232da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 8248de1d91e628c19c1154ca15b1ea1fcc0a098b793Borislav Petkov debugf1("F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare); 8252da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 8268de1d91e628c19c1154ca15b1ea1fcc0a098b793Borislav Petkov debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, " 8278de1d91e628c19c1154ca15b1ea1fcc0a098b793Borislav Petkov "offset: 0x%08x\n", 828bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov pvt->dhar, dhar_base(pvt), 829bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt) 830bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov : f10_dhar_offset(pvt)); 8312da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 832c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov debugf1(" DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); 8332da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 8348c6717510f8002ea31b309c84b7d7a7f7c15197bBorislav Petkov amd64_debug_display_dimm_sizes(pvt, 0); 8354d7963648f1666ce10cb52391682589af5a62f9aBorislav Petkov 8368de1d91e628c19c1154ca15b1ea1fcc0a098b793Borislav Petkov /* everything below this point is Fam10h and above */ 8374d7963648f1666ce10cb52391682589af5a62f9aBorislav Petkov if (boot_cpu_data.x86 == 0xf) 8382da11654ea4d32c5700693675dfbd55c70619519Doug Thompson return; 8394d7963648f1666ce10cb52391682589af5a62f9aBorislav Petkov 8408c6717510f8002ea31b309c84b7d7a7f7c15197bBorislav Petkov amd64_debug_display_dimm_sizes(pvt, 1); 8412da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 842a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4")); 843ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov 8448de1d91e628c19c1154ca15b1ea1fcc0a098b793Borislav Petkov /* Only if NOT ganged does dclr1 have valid info */ 84568798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov if (!dct_ganging_enabled(pvt)) 84668798e176012750fe8487bcfa0aa66fee21eae3cBorislav Petkov amd64_dump_dramcfg_low(pvt->dclr1, 1); 8472da11654ea4d32c5700693675dfbd55c70619519Doug Thompson} 8482da11654ea4d32c5700693675dfbd55c70619519Doug Thompson 84994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson/* 85011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] 85194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson */ 85211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkovstatic void prep_chip_selects(struct amd64_pvt *pvt) 85394be4bff21990674ac418c970c708a1a01cf709fDoug Thompson{ 8541433eb9903408d1801d19a9c49893120874abc12Borislav Petkov if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { 85511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; 85611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8; 8579d858bb10a9907bbbaffbb4a80a31718d548868cBorislav Petkov } else { 85811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; 85911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; 86094be4bff21990674ac418c970c708a1a01cf709fDoug Thompson } 86194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson} 86294be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 86394be4bff21990674ac418c970c708a1a01cf709fDoug Thompson/* 86411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers 86594be4bff21990674ac418c970c708a1a01cf709fDoug Thompson */ 866b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkovstatic void read_dct_base_mask(struct amd64_pvt *pvt) 86794be4bff21990674ac418c970c708a1a01cf709fDoug Thompson{ 86811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov int cs; 86994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 87011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov prep_chip_selects(pvt); 87194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 87211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for_each_chip_select(cs, 0, pvt) { 87371d2a32e8e8411e160705aad88d26fb993a1fabaBorislav Petkov int reg0 = DCSB0 + (cs * 4); 87471d2a32e8e8411e160705aad88d26fb993a1fabaBorislav Petkov int reg1 = DCSB1 + (cs * 4); 87511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u32 *base0 = &pvt->csels[0].csbases[cs]; 87611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u32 *base1 = &pvt->csels[1].csbases[cs]; 877b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 87811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!amd64_read_dct_pci_cfg(pvt, reg0, base0)) 87994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n", 88011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs, *base0, reg0); 88194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 88211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) 88311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov continue; 884b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 88511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!amd64_read_dct_pci_cfg(pvt, reg1, base1)) 88611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n", 88711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs, *base1, reg1); 88894be4bff21990674ac418c970c708a1a01cf709fDoug Thompson } 88994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 89011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for_each_chip_select_mask(cs, 0, pvt) { 89171d2a32e8e8411e160705aad88d26fb993a1fabaBorislav Petkov int reg0 = DCSM0 + (cs * 4); 89271d2a32e8e8411e160705aad88d26fb993a1fabaBorislav Petkov int reg1 = DCSM1 + (cs * 4); 89311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u32 *mask0 = &pvt->csels[0].csmasks[cs]; 89411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u32 *mask1 = &pvt->csels[1].csmasks[cs]; 895b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 89611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0)) 89794be4bff21990674ac418c970c708a1a01cf709fDoug Thompson debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n", 89811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs, *mask0, reg0); 89994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 90011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) 90111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov continue; 902b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov 90311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1)) 90411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n", 90511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs, *mask1, reg1); 90694be4bff21990674ac418c970c708a1a01cf709fDoug Thompson } 90794be4bff21990674ac418c970c708a1a01cf709fDoug Thompson} 90894be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 90924f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkovstatic enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs) 91094be4bff21990674ac418c970c708a1a01cf709fDoug Thompson{ 91194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson enum mem_type type; 91294be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 913cb32850744b8b574966637ae98d55692717eced4Borislav Petkov /* F15h supports only DDR3 */ 914cb32850744b8b574966637ae98d55692717eced4Borislav Petkov if (boot_cpu_data.x86 >= 0x15) 915cb32850744b8b574966637ae98d55692717eced4Borislav Petkov type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; 916cb32850744b8b574966637ae98d55692717eced4Borislav Petkov else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) { 9176b4c0bdeb00f35cad2d3e0dc0d97bb4950a8f86eBorislav Petkov if (pvt->dchr0 & DDR3_MODE) 9186b4c0bdeb00f35cad2d3e0dc0d97bb4950a8f86eBorislav Petkov type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; 9196b4c0bdeb00f35cad2d3e0dc0d97bb4950a8f86eBorislav Petkov else 9206b4c0bdeb00f35cad2d3e0dc0d97bb4950a8f86eBorislav Petkov type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2; 92194be4bff21990674ac418c970c708a1a01cf709fDoug Thompson } else { 92294be4bff21990674ac418c970c708a1a01cf709fDoug Thompson type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR; 92394be4bff21990674ac418c970c708a1a01cf709fDoug Thompson } 92494be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 92524f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_info("CS%d: %s\n", cs, edac_mem_types[type]); 92694be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 92794be4bff21990674ac418c970c708a1a01cf709fDoug Thompson return type; 92894be4bff21990674ac418c970c708a1a01cf709fDoug Thompson} 92994be4bff21990674ac418c970c708a1a01cf709fDoug Thompson 930cb32850744b8b574966637ae98d55692717eced4Borislav Petkov/* Get the number of DCT channels the memory controller is using. */ 931ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompsonstatic int k8_early_channel_count(struct amd64_pvt *pvt) 932ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson{ 933cb32850744b8b574966637ae98d55692717eced4Borislav Petkov int flag; 934ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 9359f56da0e3c3269abe0b2745a54f1b082c3c14433Borislav Petkov if (pvt->ext_model >= K8_REV_F) 936ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* RevF (NPT) and later */ 93741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov flag = pvt->dclr0 & WIDTH_128; 9389f56da0e3c3269abe0b2745a54f1b082c3c14433Borislav Petkov else 939ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* RevE and earlier */ 940ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson flag = pvt->dclr0 & REVE_WIDTH_128; 941ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 942ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* not used */ 943ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson pvt->dclr1 = 0; 944ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 945ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson return (flag) ? 2 : 1; 946ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson} 947ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 948700466249f9bb787165da64d2615cee456d88751Borislav Petkov/* On F10h and later ErrAddr is MC4_ADDR[47:1] */ 949700466249f9bb787165da64d2615cee456d88751Borislav Petkovstatic u64 get_error_address(struct mce *m) 950ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson{ 951c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov struct cpuinfo_x86 *c = &boot_cpu_data; 952c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov u64 addr; 953700466249f9bb787165da64d2615cee456d88751Borislav Petkov u8 start_bit = 1; 954700466249f9bb787165da64d2615cee456d88751Borislav Petkov u8 end_bit = 47; 955700466249f9bb787165da64d2615cee456d88751Borislav Petkov 956c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov if (c->x86 == 0xf) { 957700466249f9bb787165da64d2615cee456d88751Borislav Petkov start_bit = 3; 958700466249f9bb787165da64d2615cee456d88751Borislav Petkov end_bit = 39; 959700466249f9bb787165da64d2615cee456d88751Borislav Petkov } 960700466249f9bb787165da64d2615cee456d88751Borislav Petkov 961c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov addr = m->addr & GENMASK(start_bit, end_bit); 962c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 963c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* 964c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov * Erratum 637 workaround 965c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov */ 966c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov if (c->x86 == 0x15) { 967c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov struct amd64_pvt *pvt; 968c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov u64 cc6_base, tmp_addr; 969c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov u32 tmp; 970c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov u8 mce_nid, intlv_en; 971c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 972c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) 973c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov return addr; 974c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 975c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov mce_nid = amd_get_nb_id(m->extcpu); 976c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov pvt = mcis[mce_nid]->pvt_info; 977c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 978c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp); 979c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov intlv_en = tmp >> 21 & 0x7; 980c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 981c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* add [47:27] + 3 trailing bits */ 982c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov cc6_base = (tmp & GENMASK(0, 20)) << 3; 983c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 984c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* reverse and add DramIntlvEn */ 985c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov cc6_base |= intlv_en ^ 0x7; 986c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 987c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* pin at [47:24] */ 988c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov cc6_base <<= 24; 989c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 990c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov if (!intlv_en) 991c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov return cc6_base | (addr & GENMASK(0, 23)); 992c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 993c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); 994c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 995c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* faster log2 */ 996c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); 997c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 998c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* OR DramIntlvSel into bits [14:12] */ 999c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; 1000c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 1001c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov /* add remaining [11:0] bits from original MC4_ADDR */ 1002c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov tmp_addr |= addr & GENMASK(0, 11); 1003c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 1004c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov return cc6_base | tmp_addr; 1005c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov } 1006c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov 1007c1ae68309b0c1ea67b72e9e94e26b4e819022fc7Borislav Petkov return addr; 1008ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson} 1009ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 10107f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkovstatic void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) 1011ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson{ 1012f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov struct cpuinfo_x86 *c = &boot_cpu_data; 101371d2a32e8e8411e160705aad88d26fb993a1fabaBorislav Petkov int off = range << 3; 1014ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 10157f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); 10167f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); 1017ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 1018f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov if (c->x86 == 0xf) 10197f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov return; 1020ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 10217f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if (!dram_rw(pvt, range)) 10227f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov return; 1023ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 10247f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); 10257f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); 1026f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1027f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov /* Factor in CC6 save area by reading dst node's limit reg */ 1028f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov if (c->x86 == 0x15) { 1029f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov struct pci_dev *f1 = NULL; 1030f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov u8 nid = dram_dst_node(pvt, range); 1031f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov u32 llim; 1032f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1033f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); 1034f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov if (WARN_ON(!f1)) 1035f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov return; 1036f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1037f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); 1038f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1039f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov pvt->ranges[range].lim.lo &= GENMASK(0, 15); 1040f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1041f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov /* {[39:27],111b} */ 1042f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; 1043f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1044f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov pvt->ranges[range].lim.hi &= GENMASK(0, 7); 1045f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1046f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov /* [47:40] */ 1047f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov pvt->ranges[range].lim.hi |= llim >> 13; 1048f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov 1049f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov pci_dev_put(f1); 1050f08e457cecece7fbbdad3add9defac3373a59b5aBorislav Petkov } 1051ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson} 1052ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 1053f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkovstatic void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, 1054f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u16 syndrome) 1055ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson{ 1056ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson struct mem_ctl_info *src_mci; 1057f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov struct amd64_pvt *pvt = mci->pvt_info; 1058ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson int channel, csrow; 1059ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson u32 page, offset; 1060ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 1061ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* CHIPKILL enabled */ 1062f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov if (pvt->nbcfg & NBCFG_CHIPKILL) { 1063bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov channel = get_channel_from_ecc_syndrome(mci, syndrome); 1064ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson if (channel < 0) { 1065ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* 1066ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * Syndrome didn't map, so we don't know which of the 1067ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * 2 DIMMs is in error. So we need to ID 'both' of them 1068ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * as suspect. 1069ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson */ 107024f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible " 107124f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "error reporting race\n", syndrome); 1072ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); 1073ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson return; 1074ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } 1075ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } else { 1076ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* 1077ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * non-chipkill ecc mode 1078ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * 1079ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * The k8 documentation is unclear about how to determine the 1080ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * channel number when using non-chipkill memory. This method 1081ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * was obtained from email communication with someone at AMD. 1082ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * (Wish the email was placed in this comment - norsk) 1083ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson */ 108444e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov channel = ((sys_addr & BIT(3)) != 0); 1085ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } 1086ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 1087ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson /* 1088ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * Find out which node the error address belongs to. This may be 1089ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson * different from the node that detected the error. 1090ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson */ 109144e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov src_mci = find_mc_by_sys_addr(mci, sys_addr); 10922cff18c22cfaa88216a5d8c62ea64d1fb575c145Keith Mannthey if (!src_mci) { 109324f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n", 109444e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov (unsigned long)sys_addr); 1095ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); 1096ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson return; 1097ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } 1098ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 109944e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov /* Now map the sys_addr to a CSROW */ 110044e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov csrow = sys_addr_to_csrow(src_mci, sys_addr); 1101ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson if (csrow < 0) { 1102ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR); 1103ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } else { 110444e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov error_address_to_page_and_offset(sys_addr, &page, &offset); 1105ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 1106ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow, 1107ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson channel, EDAC_MOD_STR); 1108ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson } 1109ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson} 1110ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 111141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic int ddr2_cs_size(unsigned i, bool dct_width) 1112ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson{ 111341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov unsigned shift = 0; 1114ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 111541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (i <= 2) 111641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = i; 111741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else if (!(i & 0x1)) 111841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = i >> 1; 11191433eb9903408d1801d19a9c49893120874abc12Borislav Petkov else 112041d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = (i + 1) >> 1; 1121ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 112241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return 128 << (shift + !!dct_width); 112341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov} 112441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 112541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, 112641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov unsigned cs_mode) 112741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov{ 112841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; 112941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 113041d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (pvt->ext_model >= K8_REV_F) { 113141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov WARN_ON(cs_mode > 11); 113241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return ddr2_cs_size(cs_mode, dclr & WIDTH_128); 113341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov } 113441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else if (pvt->ext_model >= K8_REV_D) { 113511b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov unsigned diff; 113641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov WARN_ON(cs_mode > 10); 113741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 113811b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov /* 113911b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * the below calculation, besides trying to win an obfuscated C 114011b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * contest, maps cs_mode values to DIMM chip select sizes. The 114111b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * mappings are: 114211b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 114311b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * cs_mode CS size (mb) 114411b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * ======= ============ 114511b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 0 32 114611b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 1 64 114711b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 2 128 114811b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 3 128 114911b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 4 256 115011b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 5 512 115111b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 6 256 115211b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 7 512 115311b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 8 1024 115411b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 9 1024 115511b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 10 2048 115611b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 115711b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * Basically, it calculates a value with which to shift the 115811b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * smallest CS size of 32MB. 115911b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * 116011b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov * ddr[23]_cs_size have a similar purpose. 116111b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov */ 116211b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov diff = cs_mode/3 + (unsigned)(cs_mode > 5); 116311b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov 116411b0a31473edf74b70ab6f8fe857b61bff82d7ccBorislav Petkov return 32 << (cs_mode - diff); 116541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov } 116641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else { 116741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov WARN_ON(cs_mode > 6); 116841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return 32 << cs_mode; 116941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov } 1170ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson} 1171ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 11721afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson/* 11731afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * Get the number of DCT channels in use. 11741afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * 11751afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * Return: 11761afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * number of Memory Channels in operation 11771afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * Pass back: 11781afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * contents of the DCL0_LOW register 11791afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson */ 11807d20d14da1bf24199add02cf4293871c277a4bdaBorislav Petkovstatic int f1x_early_channel_count(struct amd64_pvt *pvt) 11811afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson{ 11826ba5dcdc44624677bba0bef1dcb93a524f88f8c1Borislav Petkov int i, j, channels = 0; 11831afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 11847d20d14da1bf24199add02cf4293871c277a4bdaBorislav Petkov /* On F10h, if we are in 128 bit mode, then we are using 2 channels */ 118541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128)) 11867d20d14da1bf24199add02cf4293871c277a4bdaBorislav Petkov return 2; 11871afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 11881afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson /* 1189d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov * Need to check if in unganged mode: In such, there are 2 channels, 1190d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov * but they are not in 128 bit mode and thus the above 'dclr0' status 1191d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov * bit will be OFF. 11921afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * 11931afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * Need to check DCT0[0] and DCT1[0] to see if only one of them has 11941afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * their CSEnable bit on. If so, then SINGLE DIMM case. 11951afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson */ 1196d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov debugf0("Data width is not 128 bits - need more decoding\n"); 1197ddff876d2022c5e06509f6535bc4fd61c4d6ffd6Doug Thompson 11981afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson /* 11991afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * Check DRAM Bank Address Mapping values for each DIMM to see if there 12001afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * is more than just one DIMM present in unganged mode. Need to check 12011afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson * both controllers since DIMMs can be placed in either one. 12021afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson */ 1203525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov for (i = 0; i < 2; i++) { 1204525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov u32 dbam = (i ? pvt->dbam1 : pvt->dbam0); 12051afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 120657a30854c89f862eeada4cce822f3a87bc006c95Wan Wei for (j = 0; j < 4; j++) { 120757a30854c89f862eeada4cce822f3a87bc006c95Wan Wei if (DBAM_DIMM(j, dbam) > 0) { 120857a30854c89f862eeada4cce822f3a87bc006c95Wan Wei channels++; 120957a30854c89f862eeada4cce822f3a87bc006c95Wan Wei break; 121057a30854c89f862eeada4cce822f3a87bc006c95Wan Wei } 121157a30854c89f862eeada4cce822f3a87bc006c95Wan Wei } 12121afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson } 12131afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 1214d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov if (channels > 2) 1215d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov channels = 2; 1216d16149e8c378ab7011e600980af51d2477aa5307Borislav Petkov 121724f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_info("MCT channel count: %d\n", channels); 12181afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 12191afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson return channels; 12201afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson} 12211afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 122241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic int ddr3_cs_size(unsigned i, bool dct_width) 12231afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson{ 122441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov unsigned shift = 0; 122541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov int cs_size = 0; 122641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 122741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (i == 0 || i == 3 || i == 4) 122841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov cs_size = -1; 122941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else if (i <= 2) 123041d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = i; 123141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else if (i == 12) 123241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = 7; 123341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else if (!(i & 0x1)) 123441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = i >> 1; 123541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov else 123641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov shift = (i + 1) >> 1; 123741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 123841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (cs_size != -1) 123941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov cs_size = (128 * (1 << !!dct_width)) << shift; 124041d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 124141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return cs_size; 124241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov} 124341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 124441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, 124541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov unsigned cs_mode) 124641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov{ 124741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; 124841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 124941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov WARN_ON(cs_mode > 11); 12501433eb9903408d1801d19a9c49893120874abc12Borislav Petkov 12511433eb9903408d1801d19a9c49893120874abc12Borislav Petkov if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE) 125241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return ddr3_cs_size(cs_mode, dclr & WIDTH_128); 12531433eb9903408d1801d19a9c49893120874abc12Borislav Petkov else 125441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return ddr2_cs_size(cs_mode, dclr & WIDTH_128); 125541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov} 125641d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov 125741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov/* 125841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov * F15h supports only 64bit DCT interfaces 125941d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov */ 126041d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, 126141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov unsigned cs_mode) 126241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov{ 126341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov WARN_ON(cs_mode > 12); 12641433eb9903408d1801d19a9c49893120874abc12Borislav Petkov 126541d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov return ddr3_cs_size(cs_mode, false); 12661afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson} 12671afd3c98b5e8df68e1840b56c0ced15f314ce30dDoug Thompson 12685a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkovstatic void read_dram_ctl_register(struct amd64_pvt *pvt) 12696163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson{ 12706163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 12715a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov if (boot_cpu_data.x86 == 0xf) 12725a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov return; 12735a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov 127478da121e1560805a0e6e11952de30b416accef62Borislav Petkov if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) { 127578da121e1560805a0e6e11952de30b416accef62Borislav Petkov debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n", 127678da121e1560805a0e6e11952de30b416accef62Borislav Petkov pvt->dct_sel_lo, dct_sel_baseaddr(pvt)); 127772381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov 12785a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov debugf0(" DCTs operate in %s mode.\n", 12795a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov (dct_ganging_enabled(pvt) ? "ganged" : "unganged")); 128072381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov 128172381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov if (!dct_ganging_enabled(pvt)) 128272381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov debugf0(" Address range split per DCT: %s\n", 128372381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov (dct_high_range_enabled(pvt) ? "yes" : "no")); 128472381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov 128578da121e1560805a0e6e11952de30b416accef62Borislav Petkov debugf0(" data interleave for ECC: %s, " 128672381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov "DRAM cleared since last warm reset: %s\n", 128772381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"), 128872381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov (dct_memory_cleared(pvt) ? "yes" : "no")); 128972381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov 129078da121e1560805a0e6e11952de30b416accef62Borislav Petkov debugf0(" channel interleave: %s, " 129178da121e1560805a0e6e11952de30b416accef62Borislav Petkov "interleave bits selector: 0x%x\n", 129272381bd55e4ce2aaed8660551e8f56a2c959c11fBorislav Petkov (dct_interleave_enabled(pvt) ? "enabled" : "disabled"), 12936163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson dct_sel_interleave_addr(pvt)); 12946163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } 12956163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 129678da121e1560805a0e6e11952de30b416accef62Borislav Petkov amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi); 12976163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson} 12986163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1299f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson/* 1300229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory 1301f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson * Interleaving Modes. 1302f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson */ 1303b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkovstatic u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, 1304229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov bool hi_range_sel, u8 intlv_en) 13056163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson{ 1306151fa71c581d1295f3f44f4882ceb17ca014dc8dBorislav Petkov u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1; 13076163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 13086163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson if (dct_ganging_enabled(pvt)) 1309229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return 0; 13106163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1311229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov if (hi_range_sel) 1312229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return dct_sel_high; 13136163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1314229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov /* 1315229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov * see F2x110[DctSelIntLvAddr] - channel interleave mode 1316229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov */ 1317229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov if (dct_interleave_enabled(pvt)) { 1318229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov u8 intlv_addr = dct_sel_interleave_addr(pvt); 1319229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov 1320229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov /* return DCT select function: 0=DCT0, 1=DCT1 */ 1321229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov if (!intlv_addr) 1322229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return sys_addr >> 6 & 1; 1323229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov 1324229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov if (intlv_addr & 0x2) { 1325229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov u8 shift = intlv_addr & 0x1 ? 9 : 6; 1326229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; 1327229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov 1328229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return ((sys_addr >> shift) & 1) ^ temp; 1329229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov } 1330229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov 1331229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return (sys_addr >> (12 + hweight8(intlv_en))) & 1; 1332229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov } 1333229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov 1334229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov if (dct_high_range_enabled(pvt)) 1335229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov return ~dct_sel_high & 1; 13366163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 13376163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson return 0; 13386163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson} 13396163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1340c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov/* Convert the sys_addr to the normalized DCT address */ 1341e761359a25c26b59c2c1ddcc180a441bb442a5baBorislav Petkovstatic u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range, 1342c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u64 sys_addr, bool hi_rng, 1343c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u32 dct_sel_base_addr) 13446163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson{ 13456163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson u64 chan_off; 1346c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u64 dram_base = get_dram_base(pvt, range); 1347c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u64 hole_off = f10_dhar_offset(pvt); 1348c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16; 13496163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1350c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov if (hi_rng) { 1351c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov /* 1352c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * if 1353c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * base address of high range is below 4Gb 1354c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * (bits [47:27] at [31:11]) 1355c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * DRAM address space on this DCT is hoisted above 4Gb && 1356c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * sys_addr > 4Gb 1357c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * 1358c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * remove hole offset from sys_addr 1359c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * else 1360c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * remove high range offset from sys_addr 1361c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov */ 1362c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov if ((!(dct_sel_base_addr >> 16) || 1363c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov dct_sel_base_addr < dhar_base(pvt)) && 1364972ea17ab9116cca513a45526c93651d769fefc6Borislav Petkov dhar_valid(pvt) && 1365c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov (sys_addr >= BIT_64(32))) 1366bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov chan_off = hole_off; 13676163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson else 13686163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson chan_off = dct_sel_base_off; 13696163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } else { 1370c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov /* 1371c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * if 1372c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * we have a valid hole && 1373c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * sys_addr > 4Gb 1374c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * 1375c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * remove hole 1376c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * else 1377c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov * remove dram base to normalize to DCT address 1378c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov */ 1379972ea17ab9116cca513a45526c93651d769fefc6Borislav Petkov if (dhar_valid(pvt) && (sys_addr >= BIT_64(32))) 1380bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov chan_off = hole_off; 13816163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson else 1382c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov chan_off = dram_base; 13836163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } 13846163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1385c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47)); 13866163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson} 13876163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 13886163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson/* 13896163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * checks if the csrow passed in is marked as SPARED, if so returns the new 13906163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * spare row 13916163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson */ 139211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkovstatic int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow) 13936163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson{ 1394614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov int tmp_cs; 1395614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov 1396614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov if (online_spare_swap_done(pvt, dct) && 1397614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov csrow == online_spare_bad_dramcs(pvt, dct)) { 1398614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov 1399614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov for_each_chip_select(tmp_cs, dct, pvt) { 1400614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov if (chip_select_base(tmp_cs, dct, pvt) & 0x2) { 1401614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov csrow = tmp_cs; 1402614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov break; 1403614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov } 1404614ec9d8532cc6b2f6b471c399daffdfd1c32d03Borislav Petkov } 14056163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } 14066163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson return csrow; 14076163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson} 14086163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 14096163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson/* 14106163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * Iterate over the DRAM DCT "base" and "mask" registers looking for a 14116163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * SystemAddr match on the specified 'ChannelSelect' and 'NodeID' 14126163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * 14136163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * Return: 14146163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * -EINVAL: NOT FOUND 14156163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson * 0..csrow = Chip-Select Row 14166163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson */ 1417b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkovstatic int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct) 14186163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson{ 14196163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson struct mem_ctl_info *mci; 14206163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson struct amd64_pvt *pvt; 142111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u64 cs_base, cs_mask; 14226163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson int cs_found = -EINVAL; 14236163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson int csrow; 14246163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 1425cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov mci = mcis[nid]; 14266163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson if (!mci) 14276163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson return cs_found; 14286163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 14296163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson pvt = mci->pvt_info; 14306163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 143111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct); 14326163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 143311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for_each_chip_select(csrow, dct, pvt) { 143411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (!csrow_enabled(csrow, dct, pvt)) 14356163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson continue; 14366163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 143711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask); 14386163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 143911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov debugf1(" CSROW=%d CSBase=0x%llx CSMask=0x%llx\n", 144011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csrow, cs_base, cs_mask); 14416163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 144211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs_mask = ~cs_mask; 14436163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 144411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov debugf1(" (InputAddr & ~CSMask)=0x%llx " 144511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov "(CSBase & ~CSMask)=0x%llx\n", 144611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov (in_addr & cs_mask), (cs_base & cs_mask)); 14476163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 144811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if ((in_addr & cs_mask) == (cs_base & cs_mask)) { 144911c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov cs_found = f10_process_possible_spare(pvt, dct, csrow); 14506163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 14516163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson debugf1(" MATCH csrow=%d\n", cs_found); 14526163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson break; 14536163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } 14546163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson } 14556163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson return cs_found; 14566163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson} 14576163b5d4fb45d20e3eb92d627943f26572726889Doug Thompson 145895b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov/* 145995b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is 146095b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov * swapped with a region located at the bottom of memory so that the GPU can use 146195b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov * the interleaved region and thus two channels. 146295b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov */ 1463b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkovstatic u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr) 146495b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov{ 146595b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr; 146695b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 146795b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov if (boot_cpu_data.x86 == 0x10) { 146895b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov /* only revC3 and revE have that feature */ 146995b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov if (boot_cpu_data.x86_model < 4 || 147095b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov (boot_cpu_data.x86_model < 0xa && 147195b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov boot_cpu_data.x86_mask < 3)) 147295b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov return sys_addr; 147395b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov } 147495b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 147595b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg); 147695b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 147795b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov if (!(swap_reg & 0x1)) 147895b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov return sys_addr; 147995b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 148095b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov swap_base = (swap_reg >> 3) & 0x7f; 148195b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov swap_limit = (swap_reg >> 11) & 0x7f; 148295b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov rgn_size = (swap_reg >> 20) & 0x7f; 148395b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov tmp_addr = sys_addr >> 27; 148495b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 148595b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov if (!(sys_addr >> 34) && 148695b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov (((tmp_addr >= swap_base) && 148795b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov (tmp_addr <= swap_limit)) || 148895b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov (tmp_addr < rgn_size))) 148995b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov return sys_addr ^ (u64)swap_base << 27; 149095b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 149195b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov return sys_addr; 149295b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov} 149395b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 1494f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson/* For a given @dram_range, check if @sys_addr falls within it. */ 1495e761359a25c26b59c2c1ddcc180a441bb442a5baBorislav Petkovstatic int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, 1496f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson u64 sys_addr, int *nid, int *chan_sel) 1497f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson{ 1498229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov int cs_found = -EINVAL; 1499c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov u64 chan_addr; 15005d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov u32 dct_sel_base; 150111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u8 channel; 1502229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov bool high_range = false; 1503f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15047f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov u8 node_id = dram_dst_node(pvt, range); 1505229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov u8 intlv_en = dram_intlv_en(pvt, range); 15067f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov u32 intlv_sel = dram_intlv_sel(pvt, range); 1507f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1508c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n", 1509c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov range, sys_addr, get_dram_limit(pvt, range)); 1510f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1511355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov if (dhar_valid(pvt) && 1512355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov dhar_base(pvt) <= sys_addr && 1513355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov sys_addr < BIT_64(32)) { 1514355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n", 1515355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov sys_addr); 1516355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov return -EINVAL; 1517355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov } 1518355fba600549cfcfab227f928eab3ccae444ec8eBorislav Petkov 1519f030ddfb3752df36bb73285353374fc04feabb80Borislav Petkov if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en))) 1520f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson return -EINVAL; 1521f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1522b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov sys_addr = f1x_swap_interleaved_region(pvt, sys_addr); 152395b0ef55cd8a8278b64c7ba98c29cda5f4e4b617Borislav Petkov 1524f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson dct_sel_base = dct_sel_baseaddr(pvt); 1525f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1526f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson /* 1527f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson * check whether addresses >= DctSelBaseAddr[47:27] are to be used to 1528f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson * select between DCT0 and DCT1. 1529f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson */ 1530f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson if (dct_high_range_enabled(pvt) && 1531f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson !dct_ganging_enabled(pvt) && 1532f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson ((sys_addr >> 27) >= (dct_sel_base >> 11))) 1533229a7a11ac1afa84db2eac91b3fc38a0f5464696Borislav Petkov high_range = true; 1534f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1535b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en); 1536f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1537b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr, 1538c8e518d5673d6b694ab843ee586438cdff0b3809Borislav Petkov high_range, dct_sel_base); 1539f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1540e2f79dbdfbf4326fcec50a3c2568476df24b16b6Borislav Petkov /* Remove node interleaving, see F1x120 */ 1541e2f79dbdfbf4326fcec50a3c2568476df24b16b6Borislav Petkov if (intlv_en) 1542e2f79dbdfbf4326fcec50a3c2568476df24b16b6Borislav Petkov chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) | 1543e2f79dbdfbf4326fcec50a3c2568476df24b16b6Borislav Petkov (chan_addr & 0xfff); 1544f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15455d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov /* remove channel interleave */ 1546f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson if (dct_interleave_enabled(pvt) && 1547f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson !dct_high_range_enabled(pvt) && 1548f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson !dct_ganging_enabled(pvt)) { 15495d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov 15505d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov if (dct_sel_interleave_addr(pvt) != 1) { 15515d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov if (dct_sel_interleave_addr(pvt) == 0x3) 15525d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov /* hash 9 */ 15535d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov chan_addr = ((chan_addr >> 10) << 9) | 15545d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov (chan_addr & 0x1ff); 15555d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov else 15565d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov /* A[6] or hash 6 */ 15575d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov chan_addr = ((chan_addr >> 7) << 6) | 15585d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov (chan_addr & 0x3f); 15595d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov } else 15605d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov /* A[12] */ 15615d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov chan_addr = ((chan_addr >> 13) << 12) | 15625d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov (chan_addr & 0xfff); 1563f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson } 1564f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15655d4b58e84a382309dfa4dbe19220cd1f78ffc71fBorislav Petkov debugf1(" Normalized DCT addr: 0x%llx\n", chan_addr); 1566f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1567b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel); 1568f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1569f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson if (cs_found >= 0) { 1570f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson *nid = node_id; 1571f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson *chan_sel = channel; 1572f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson } 1573f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson return cs_found; 1574f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson} 1575f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1576b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkovstatic int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, 1577f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson int *node, int *chan_sel) 1578f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson{ 1579e761359a25c26b59c2c1ddcc180a441bb442a5baBorislav Petkov int cs_found = -EINVAL; 1580e761359a25c26b59c2c1ddcc180a441bb442a5baBorislav Petkov unsigned range; 1581f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15827f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov for (range = 0; range < DRAM_RANGES; range++) { 1583f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15847f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if (!dram_rw(pvt, range)) 1585f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson continue; 1586f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 15877f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if ((get_dram_base(pvt, range) <= sys_addr) && 15887f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov (get_dram_limit(pvt, range) >= sys_addr)) { 1589f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1590b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov cs_found = f1x_match_to_this_node(pvt, range, 1591f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson sys_addr, node, 1592f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson chan_sel); 1593f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson if (cs_found >= 0) 1594f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson break; 1595f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson } 1596f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson } 1597f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson return cs_found; 1598f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson} 1599f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1600f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson/* 1601bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps 1602bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW). 1603f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson * 1604bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * The @sys_addr is usually an error address received from the hardware 1605bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * (MCX_ADDR). 1606f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson */ 1607b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkovstatic void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, 1608f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u16 syndrome) 1609f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson{ 1610f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 1611f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson u32 page, offset; 1612f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson int nid, csrow, chan = 0; 1613f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1614b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan); 1615f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1616bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov if (csrow < 0) { 1617bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); 1618bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov return; 1619bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov } 1620bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov 1621bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov error_address_to_page_and_offset(sys_addr, &page, &offset); 1622f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1623bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov /* 1624bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * We need the syndromes for channel detection only when we're 1625bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * ganged. Otherwise @chan should already contain the channel at 1626bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * this point. 1627bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov */ 1628a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov if (dct_ganging_enabled(pvt)) 1629bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov chan = get_channel_from_ecc_syndrome(mci, syndrome); 1630f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1631bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov if (chan >= 0) 1632bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov edac_mc_handle_ce(mci, page, offset, syndrome, csrow, chan, 1633bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov EDAC_MOD_STR); 1634bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov else 1635f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson /* 1636bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov * Channel unknown, report all channels on this CSROW as failed. 1637f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson */ 1638bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov for (chan = 0; chan < mci->csrows[csrow].nr_channels; chan++) 1639f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson edac_mc_handle_ce(mci, page, offset, syndrome, 1640bdc30a0c8c7427a1c1d2e4d149d372d4d77781eeBorislav Petkov csrow, chan, EDAC_MOD_STR); 1641f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson} 1642f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1643f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson/* 16448566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov * debug routine to display the memory sizes of all logical DIMMs and its 1645cb32850744b8b574966637ae98d55692717eced4Borislav Petkov * CSROWs 1646f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson */ 16478c6717510f8002ea31b309c84b7d7a7f7c15197bBorislav Petkovstatic void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) 1648f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson{ 1649603adaf6b3e37450235f0ddb5986b961b3146a79Borislav Petkov int dimm, size0, size1, factor = 0; 1650525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; 1651525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; 1652f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 16538566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov if (boot_cpu_data.x86 == 0xf) { 165441d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov if (pvt->dclr0 & WIDTH_128) 1655603adaf6b3e37450235f0ddb5986b961b3146a79Borislav Petkov factor = 1; 1656603adaf6b3e37450235f0ddb5986b961b3146a79Borislav Petkov 16578566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov /* K8 families < revF not supported yet */ 16581433eb9903408d1801d19a9c49893120874abc12Borislav Petkov if (pvt->ext_model < K8_REV_F) 16598566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov return; 16608566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov else 16618566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov WARN_ON(ctrl != 0); 16628566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov } 16638566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov 16644d7963648f1666ce10cb52391682589af5a62f9aBorislav Petkov dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0; 166511c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases 166611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov : pvt->csels[0].csbases; 1667f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 16684d7963648f1666ce10cb52391682589af5a62f9aBorislav Petkov debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam); 1669f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 16708566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); 16718566c4df1690f3862ae338a4c533f4bb5a863f9aBorislav Petkov 1672f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson /* Dump memory sizes for DIMM and its CSROWs */ 1673f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson for (dimm = 0; dimm < 4; dimm++) { 1674f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1675f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson size0 = 0; 167611c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (dcsb[dimm*2] & DCSB_CS_ENABLE) 167741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 167841d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov DBAM_DIMM(dimm, dbam)); 1679f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 1680f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson size1 = 0; 168111c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) 168241d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 168341d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov DBAM_DIMM(dimm, dbam)); 1684f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 168524f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", 168624f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov dimm * 2, size0 << factor, 168724f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov dimm * 2 + 1, size1 << factor); 1688f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson } 1689f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson} 1690f71d0a05001afd10e2be491ca002c55c7df42ed8Doug Thompson 16914d37607adbff69596a3170cf84badaf26efc59acDoug Thompsonstatic struct amd64_family_type amd64_family_types[] = { 16924d37607adbff69596a3170cf84badaf26efc59acDoug Thompson [K8_CPUS] = { 16930092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov .ctl_name = "K8", 16948d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, 16958d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC, 16964d37607adbff69596a3170cf84badaf26efc59acDoug Thompson .ops = { 16971433eb9903408d1801d19a9c49893120874abc12Borislav Petkov .early_channel_count = k8_early_channel_count, 16981433eb9903408d1801d19a9c49893120874abc12Borislav Petkov .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, 16991433eb9903408d1801d19a9c49893120874abc12Borislav Petkov .dbam_to_cs = k8_dbam_to_chip_select, 1700b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov .read_dct_pci_cfg = k8_read_dct_pci_cfg, 17014d37607adbff69596a3170cf84badaf26efc59acDoug Thompson } 17024d37607adbff69596a3170cf84badaf26efc59acDoug Thompson }, 17034d37607adbff69596a3170cf84badaf26efc59acDoug Thompson [F10_CPUS] = { 17040092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov .ctl_name = "F10h", 17058d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP, 17068d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC, 17074d37607adbff69596a3170cf84badaf26efc59acDoug Thompson .ops = { 17087d20d14da1bf24199add02cf4293871c277a4bdaBorislav Petkov .early_channel_count = f1x_early_channel_count, 1709b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, 17101433eb9903408d1801d19a9c49893120874abc12Borislav Petkov .dbam_to_cs = f10_dbam_to_chip_select, 1711b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov .read_dct_pci_cfg = f10_read_dct_pci_cfg, 1712b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov } 1713b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov }, 1714b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov [F15_CPUS] = { 1715b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov .ctl_name = "F15h", 1716df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1, 1717df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3, 1718b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov .ops = { 17197d20d14da1bf24199add02cf4293871c277a4bdaBorislav Petkov .early_channel_count = f1x_early_channel_count, 1720b15f0fcab1ab85c773c9fa235c76e6ce90b7462eBorislav Petkov .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, 172141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov .dbam_to_cs = f15_dbam_to_chip_select, 1722b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov .read_dct_pci_cfg = f15_read_dct_pci_cfg, 17234d37607adbff69596a3170cf84badaf26efc59acDoug Thompson } 17244d37607adbff69596a3170cf84badaf26efc59acDoug Thompson }, 17254d37607adbff69596a3170cf84badaf26efc59acDoug Thompson}; 17264d37607adbff69596a3170cf84badaf26efc59acDoug Thompson 17274d37607adbff69596a3170cf84badaf26efc59acDoug Thompsonstatic struct pci_dev *pci_get_related_function(unsigned int vendor, 17284d37607adbff69596a3170cf84badaf26efc59acDoug Thompson unsigned int device, 17294d37607adbff69596a3170cf84badaf26efc59acDoug Thompson struct pci_dev *related) 17304d37607adbff69596a3170cf84badaf26efc59acDoug Thompson{ 17314d37607adbff69596a3170cf84badaf26efc59acDoug Thompson struct pci_dev *dev = NULL; 17324d37607adbff69596a3170cf84badaf26efc59acDoug Thompson 17334d37607adbff69596a3170cf84badaf26efc59acDoug Thompson dev = pci_get_device(vendor, device, dev); 17344d37607adbff69596a3170cf84badaf26efc59acDoug Thompson while (dev) { 17354d37607adbff69596a3170cf84badaf26efc59acDoug Thompson if ((dev->bus->number == related->bus->number) && 17364d37607adbff69596a3170cf84badaf26efc59acDoug Thompson (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn))) 17374d37607adbff69596a3170cf84badaf26efc59acDoug Thompson break; 17384d37607adbff69596a3170cf84badaf26efc59acDoug Thompson dev = pci_get_device(vendor, device, dev); 17394d37607adbff69596a3170cf84badaf26efc59acDoug Thompson } 17404d37607adbff69596a3170cf84badaf26efc59acDoug Thompson 17414d37607adbff69596a3170cf84badaf26efc59acDoug Thompson return dev; 17424d37607adbff69596a3170cf84badaf26efc59acDoug Thompson} 17434d37607adbff69596a3170cf84badaf26efc59acDoug Thompson 1744b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson/* 1745bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov * These are tables of eigenvectors (one per line) which can be used for the 1746bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov * construction of the syndrome tables. The modified syndrome search algorithm 1747bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov * uses those to find the symbol in error and thus the DIMM. 1748b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson * 1749bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov * Algorithm courtesy of Ross LaFetra from AMD. 1750b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson */ 1751bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkovstatic u16 x4_vectors[] = { 1752bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x2f57, 0x1afe, 0x66cc, 0xdd88, 1753bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x11eb, 0x3396, 0x7f4c, 0xeac8, 1754bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0001, 0x0002, 0x0004, 0x0008, 1755bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1013, 0x3032, 0x4044, 0x8088, 1756bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x106b, 0x30d6, 0x70fc, 0xe0a8, 1757bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4857, 0xc4fe, 0x13cc, 0x3288, 1758bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1ac5, 0x2f4a, 0x5394, 0xa1e8, 1759bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1f39, 0x251e, 0xbd6c, 0x6bd8, 1760bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x15c1, 0x2a42, 0x89ac, 0x4758, 1761bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x2b03, 0x1602, 0x4f0c, 0xca08, 1762bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1f07, 0x3a0e, 0x6b04, 0xbd08, 1763bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x8ba7, 0x465e, 0x244c, 0x1cc8, 1764bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x2b87, 0x164e, 0x642c, 0xdc18, 1765bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x40b9, 0x80de, 0x1094, 0x20e8, 1766bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x27db, 0x1eb6, 0x9dac, 0x7b58, 1767bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x11c1, 0x2242, 0x84ac, 0x4c58, 1768bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1be5, 0x2d7a, 0x5e34, 0xa718, 1769bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4b39, 0x8d1e, 0x14b4, 0x28d8, 1770bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4c97, 0xc87e, 0x11fc, 0x33a8, 1771bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x8e97, 0x497e, 0x2ffc, 0x1aa8, 1772bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x16b3, 0x3d62, 0x4f34, 0x8518, 1773bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1e2f, 0x391a, 0x5cac, 0xf858, 1774bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1d9f, 0x3b7a, 0x572c, 0xfe18, 1775bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x15f5, 0x2a5a, 0x5264, 0xa3b8, 1776bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1dbb, 0x3b66, 0x715c, 0xe3f8, 1777bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4397, 0xc27e, 0x17fc, 0x3ea8, 1778bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1617, 0x3d3e, 0x6464, 0xb8b8, 1779bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x23ff, 0x12aa, 0xab6c, 0x56d8, 1780bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x2dfb, 0x1ba6, 0x913c, 0x7328, 1781bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x185d, 0x2ca6, 0x7914, 0x9e28, 1782bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x171b, 0x3e36, 0x7d7c, 0xebe8, 1783bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4199, 0x82ee, 0x19f4, 0x2e58, 1784bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4807, 0xc40e, 0x130c, 0x3208, 1785bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1905, 0x2e0a, 0x5804, 0xac08, 1786bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x213f, 0x132a, 0xadfc, 0x5ba8, 1787bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x19a9, 0x2efe, 0xb5cc, 0x6f88, 1788b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson}; 1789b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson 1790bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkovstatic u16 x8_vectors[] = { 1791bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480, 1792bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80, 1793bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80, 1794bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80, 1795bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780, 1796bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080, 1797bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080, 1798bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080, 1799bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80, 1800bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580, 1801bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880, 1802bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280, 1803bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180, 1804bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580, 1805bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280, 1806bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180, 1807bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080, 1808bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 1809bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 1810bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov}; 1811bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1812d34a6ecd45c1362d388af8d83ed329c609d1712bBorislav Petkovstatic int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs, 1813d34a6ecd45c1362d388af8d83ed329c609d1712bBorislav Petkov unsigned v_dim) 1814b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson{ 1815bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov unsigned int i, err_sym; 1816bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1817bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) { 1818bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov u16 s = syndrome; 1819d34a6ecd45c1362d388af8d83ed329c609d1712bBorislav Petkov unsigned v_idx = err_sym * v_dim; 1820d34a6ecd45c1362d388af8d83ed329c609d1712bBorislav Petkov unsigned v_end = (err_sym + 1) * v_dim; 1821bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1822bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* walk over all 16 bits of the syndrome */ 1823bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov for (i = 1; i < (1U << 16); i <<= 1) { 1824bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1825bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* if bit is set in that eigenvector... */ 1826bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov if (v_idx < v_end && vectors[v_idx] & i) { 1827bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov u16 ev_comp = vectors[v_idx++]; 1828bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1829bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* ... and bit set in the modified syndrome, */ 1830bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov if (s & i) { 1831bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* remove it. */ 1832bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov s ^= ev_comp; 18334d37607adbff69596a3170cf84badaf26efc59acDoug Thompson 1834bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov if (!s) 1835bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return err_sym; 1836bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } 1837b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson 1838bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } else if (s & i) 1839bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* can't get to zero, move to next symbol */ 1840bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1841bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } 1842b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson } 1843b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson 1844b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson debugf0("syndrome(%x) not found\n", syndrome); 1845b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson return -1; 1846b1289d6f9d23abab396077abb65d5a23a775cdb0Doug Thompson} 1847d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1848bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkovstatic int map_err_sym_to_channel(int err_sym, int sym_size) 1849bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov{ 1850bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov if (sym_size == 4) 1851bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov switch (err_sym) { 1852bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x20: 1853bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x21: 1854bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return 0; 1855bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1856bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x22: 1857bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x23: 1858bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return 1; 1859bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1860bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov default: 1861bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return err_sym >> 4; 1862bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1863bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } 1864bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* x8 symbols */ 1865bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov else 1866bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov switch (err_sym) { 1867bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov /* imaginary bits not in a DIMM */ 1868bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x10: 1869bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n", 1870bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov err_sym); 1871bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return -1; 1872bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1873bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1874bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x11: 1875bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return 0; 1876bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1877bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov case 0x12: 1878bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return 1; 1879bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1880bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov default: 1881bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return err_sym >> 3; 1882bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov break; 1883bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } 1884bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov return -1; 1885bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov} 1886bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1887bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkovstatic int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome) 1888bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov{ 1889bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov struct amd64_pvt *pvt = mci->pvt_info; 1890ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov int err_sym = -1; 1891ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov 1892a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov if (pvt->ecc_sym_sz == 8) 1893ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov err_sym = decode_syndrome(syndrome, x8_vectors, 1894ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov ARRAY_SIZE(x8_vectors), 1895a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov pvt->ecc_sym_sz); 1896a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov else if (pvt->ecc_sym_sz == 4) 1897ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov err_sym = decode_syndrome(syndrome, x4_vectors, 1898ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov ARRAY_SIZE(x4_vectors), 1899a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov pvt->ecc_sym_sz); 1900ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov else { 1901a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz); 1902ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov return err_sym; 1903bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov } 1904ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov 1905a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz); 1906bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov} 1907bfc04aec7d687282b5e7adb26799d3eb50d05f01Borislav Petkov 1908d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson/* 1909d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR 1910d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson * ADDRESS and process. 1911d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson */ 1912f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkovstatic void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m) 1913d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson{ 1914d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 191544e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov u64 sys_addr; 1916f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u16 syndrome; 1917d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1918d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson /* Ensure that the Error Address is VALID */ 1919f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov if (!(m->status & MCI_STATUS_ADDRV)) { 192024f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); 1921d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); 1922d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson return; 1923d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson } 1924d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1925700466249f9bb787165da64d2615cee456d88751Borislav Petkov sys_addr = get_error_address(m); 1926f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov syndrome = extract_syndrome(m->status); 1927d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 192824f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr); 1929d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1930f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome); 1931d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson} 1932d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1933d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson/* Handle any Un-correctable Errors (UEs) */ 1934f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkovstatic void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) 1935d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson{ 19361f6bcee75e83bc5b580bfa5b909b1b5ce106b800Borislav Petkov struct mem_ctl_info *log_mci, *src_mci = NULL; 1937d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson int csrow; 193844e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov u64 sys_addr; 1939d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson u32 page, offset; 1940d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1941d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson log_mci = mci; 1942d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1943f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov if (!(m->status & MCI_STATUS_ADDRV)) { 194424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); 1945d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); 1946d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson return; 1947d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson } 1948d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1949700466249f9bb787165da64d2615cee456d88751Borislav Petkov sys_addr = get_error_address(m); 1950d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1951d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson /* 1952d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson * Find out which node the error address belongs to. This may be 1953d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson * different from the node that detected the error. 1954d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson */ 195544e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov src_mci = find_mc_by_sys_addr(mci, sys_addr); 1956d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson if (!src_mci) { 195724f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n", 195824f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov (unsigned long)sys_addr); 1959d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); 1960d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson return; 1961d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson } 1962d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1963d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson log_mci = src_mci; 1964d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 196544e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov csrow = sys_addr_to_csrow(log_mci, sys_addr); 1966d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson if (csrow < 0) { 196724f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n", 196824f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov (unsigned long)sys_addr); 1969d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); 1970d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson } else { 197144e9e2ee2196fdec9893371d36c33e703965f804Borislav Petkov error_address_to_page_and_offset(sys_addr, &page, &offset); 1972d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR); 1973d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson } 1974d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson} 1975d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1976549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkovstatic inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, 1977f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov struct mce *m) 1978d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson{ 1979f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u16 ec = EC(m->status); 1980f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u8 xec = XEC(m->status, 0x1f); 1981f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov u8 ecc_type = (m->status >> 45) & 0x3; 1982d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1983b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov /* Bail early out if this was an 'observed' error */ 19845980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov if (PP(ec) == NBSL_PP_OBS) 1985b70ef01016850de87b9a28a6af19fed8801df076Borislav Petkov return; 1986d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1987ecaf5606de65cdd04de5f526185fe28fb0df654eBorislav Petkov /* Do only ECC errors */ 1988ecaf5606de65cdd04de5f526185fe28fb0df654eBorislav Petkov if (xec && xec != F10_NBSL_EXT_ERR_ECC) 1989d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson return; 1990d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1991ecaf5606de65cdd04de5f526185fe28fb0df654eBorislav Petkov if (ecc_type == 2) 1992f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov amd64_handle_ce(mci, m); 1993ecaf5606de65cdd04de5f526185fe28fb0df654eBorislav Petkov else if (ecc_type == 1) 1994f192c7b16c98839c1945733f1013f75daec5f380Borislav Petkov amd64_handle_ue(mci, m); 1995d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson} 1996d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 1997b0b07a2bd4fbb6198d4e7142337214eeb77c417aBorislav Petkovvoid amd64_decode_bus_error(int node_id, struct mce *m) 1998d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson{ 1999b0b07a2bd4fbb6198d4e7142337214eeb77c417aBorislav Petkov __amd64_decode_bus_error(mcis[node_id], m); 2000d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson} 2001d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 20020ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson/* 20038d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov * Use pvt->F2 which contains the F2 CPU PCI device to get the related 2004bbd0c1f675d7d64fc02393d4985a069be5037b54Borislav Petkov * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error. 20050ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2006360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id) 20070ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson{ 20080ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* Reserve the ADDRESS MAP Device */ 20098d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2); 20108d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov if (!pvt->F1) { 201124f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_err("error address map device not found: " 201224f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "vendor %x device 0x%x (broken BIOS?)\n", 201324f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov PCI_VENDOR_ID_AMD, f1_id); 2014bbd0c1f675d7d64fc02393d4985a069be5037b54Borislav Petkov return -ENODEV; 20150ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 20160ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20170ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* Reserve the MISC Device */ 20188d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2); 20198d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov if (!pvt->F3) { 20208d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pci_dev_put(pvt->F1); 20218d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pvt->F1 = NULL; 20220ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 202324f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_err("error F3 device not found: " 202424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "vendor %x device 0x%x (broken BIOS?)\n", 202524f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov PCI_VENDOR_ID_AMD, f3_id); 20260ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2027bbd0c1f675d7d64fc02393d4985a069be5037b54Borislav Petkov return -ENODEV; 20280ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 20298d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov debugf1("F1: %s\n", pci_name(pvt->F1)); 20308d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov debugf1("F2: %s\n", pci_name(pvt->F2)); 20318d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov debugf1("F3: %s\n", pci_name(pvt->F3)); 20320ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20330ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson return 0; 20340ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson} 20350ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2036360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic void free_mc_sibling_devs(struct amd64_pvt *pvt) 20370ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson{ 20388d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pci_dev_put(pvt->F1); 20398d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pci_dev_put(pvt->F3); 20400ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson} 20410ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20420ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson/* 20430ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Retrieve the hardware registers of the memory controller (this includes the 20440ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 'Address Map' and 'Misc' device regs) 20450ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2046360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic void read_mc_regs(struct amd64_pvt *pvt) 20470ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson{ 2048a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov struct cpuinfo_x86 *c = &boot_cpu_data; 20490ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson u64 msr_val; 2050ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov u32 tmp; 2051e761359a25c26b59c2c1ddcc180a441bb442a5baBorislav Petkov unsigned range; 20520ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20530ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* 20540ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since 20550ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * those are Read-As-Zero 20560ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2057e97f8bb8ce5611a855c5a0dba949706ec37d4155Borislav Petkov rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem); 2058e97f8bb8ce5611a855c5a0dba949706ec37d4155Borislav Petkov debugf0(" TOP_MEM: 0x%016llx\n", pvt->top_mem); 20590ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20600ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* check first whether TOP_MEM2 is enabled */ 20610ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson rdmsrl(MSR_K8_SYSCFG, msr_val); 20620ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson if (msr_val & (1U << 21)) { 2063e97f8bb8ce5611a855c5a0dba949706ec37d4155Borislav Petkov rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2); 2064e97f8bb8ce5611a855c5a0dba949706ec37d4155Borislav Petkov debugf0(" TOP_MEM2: 0x%016llx\n", pvt->top_mem2); 20650ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } else 20660ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf0(" TOP_MEM2 disabled.\n"); 20670ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20685980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap); 20690ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20705a5d237169152d4d7e4b6105eab15831829fb8e7Borislav Petkov read_dram_ctl_register(pvt); 20710ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20727f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov for (range = 0; range < DRAM_RANGES; range++) { 20737f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov u8 rw; 20740ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 20757f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov /* read settings for this DRAM range */ 20767f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov read_dram_base_limit_regs(pvt, range); 20777f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov 20787f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov rw = dram_rw(pvt, range); 20797f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov if (!rw) 20807f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov continue; 20817f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov 20827f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov debugf1(" DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n", 20837f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov range, 20847f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov get_dram_base(pvt, range), 20857f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov get_dram_limit(pvt, range)); 20867f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov 20877f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov debugf1(" IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n", 20887f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov dram_intlv_en(pvt, range) ? "Enabled" : "Disabled", 20897f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov (rw & 0x1) ? "R" : "-", 20907f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov (rw & 0x2) ? "W" : "-", 20917f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov dram_intlv_sel(pvt, range), 20927f19bf755ced6fa16dbf118c0eff60586760496bBorislav Petkov dram_dst_node(pvt, range)); 20930ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 20940ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2095b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov read_dct_base_mask(pvt); 20960ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2097bc21fa578742924aa129a493657f797c13d34ad2Borislav Petkov amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar); 2098525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0); 20990ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21008d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare); 21010ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2102cb32850744b8b574966637ae98d55692717eced4Borislav Petkov amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0); 2103cb32850744b8b574966637ae98d55692717eced4Borislav Petkov amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0); 21040ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 210578da121e1560805a0e6e11952de30b416accef62Borislav Petkov if (!dct_ganging_enabled(pvt)) { 2106cb32850744b8b574966637ae98d55692717eced4Borislav Petkov amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1); 2107cb32850744b8b574966637ae98d55692717eced4Borislav Petkov amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1); 21080ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 2109ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov 2110a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov pvt->ecc_sym_sz = 4; 2111a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov 2112a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov if (c->x86 >= 0x10) { 2113b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); 2114525a1b20a6830317db17b62df322b45d92ecd550Borislav Petkov amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1); 2115ad6a32e96939a0eb0eb382e7d78dbf33457aed1aBorislav Petkov 2116a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov /* F10h, revD and later can do x8 ECC too */ 2117a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25)) 2118a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov pvt->ecc_sym_sz = 8; 2119a3b7db09a6d5a6b8d237766b0b320447bb609bc5Borislav Petkov } 2120b2b0c605436e343a9a24f00e7fc8fb89a8316e20Borislav Petkov dump_misc_regs(pvt); 21210ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson} 21220ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21230ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson/* 21240ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * NOTE: CPU Revision Dependent code 21250ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21260ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Input: 212711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1) 21280ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * k8 private pointer to --> 21290ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * DRAM Bank Address mapping register 21300ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * node_id 21310ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * DCL register where dual_channel_active is 21320ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21330ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The DBAM register consists of 4 sets of 4 bits each definitions: 21340ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21350ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Bits: CSROWs 21360ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 0-3 CSROWs 0 and 1 21370ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 4-7 CSROWs 2 and 3 21380ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 8-11 CSROWs 4 and 5 21390ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 12-15 CSROWs 6 and 7 21400ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21410ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Values range from: 0 to 15 21420ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The meaning of the values depends on CPU revision and dual-channel state, 21430ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * see relevant BKDG more info. 21440ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21450ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The memory controller provides for total of only 8 CSROWs in its current 21460ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * architecture. Each "pair" of CSROWs normally represents just one DIMM in 21470ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * single channel or two (2) DIMMs in dual channel mode. 21480ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21490ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The following code logic collapses the various tables for CSROW based on CPU 21500ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * revision. 21510ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21520ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Returns: 21530ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The number of PAGE_SIZE pages on the specified CSROW number it 21540ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * encompasses 21550ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * 21560ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 215741d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkovstatic u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) 21580ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson{ 21591433eb9903408d1801d19a9c49893120874abc12Borislav Petkov u32 cs_mode, nr_pages; 2160f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy u32 dbam = dct ? pvt->dbam1 : pvt->dbam0; 21610ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21620ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* 21630ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * The math on this doesn't look right on the surface because x/2*4 can 21640ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * be simplified to x*2 but this expression makes use of the fact that 21650ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * it is integral math where 1/2=0. This intermediate value becomes the 21660ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * number of bits to shift the DBAM register to extract the proper CSROW 21670ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * field. 21680ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2169f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy cs_mode = (dbam >> ((csrow_nr / 2) * 4)) & 0xF; 21700ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 217141d8bfaba70311c2fa0666554ef160ea8ffc9dafBorislav Petkov nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT); 21720ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21731433eb9903408d1801d19a9c49893120874abc12Borislav Petkov debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode); 21740ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf0(" nr_pages= %u channel-count = %d\n", 21750ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson nr_pages, pvt->channel_count); 21760ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21770ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson return nr_pages; 21780ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson} 21790ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21800ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson/* 21810ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * Initialize the array of csrow attribute instances, based on the values 21820ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * from pci config hardware registers. 21830ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2184360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic int init_csrows(struct mem_ctl_info *mci) 21850ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson{ 21860ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson struct csrow_info *csrow; 21872299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov struct amd64_pvt *pvt = mci->pvt_info; 218811c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov u64 input_addr_min, input_addr_max, sys_addr, base, mask; 21892299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov u32 val; 21906ba5dcdc44624677bba0bef1dcb93a524f88f8c1Borislav Petkov int i, empty = 1; 21910ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2192a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_read_pci_cfg(pvt->F3, NBCFG, &val); 21930ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21942299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov pvt->nbcfg = val; 21950ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 21962299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", 21972299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov pvt->mc_node_id, val, 2198a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); 21990ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 220011c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov for_each_chip_select(i, 0, pvt) { 22010ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow = &mci->csrows[i]; 22020ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 2203f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) { 22040ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1("----CSROW %d EMPTY for node %d\n", i, 22050ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson pvt->mc_node_id); 22060ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson continue; 22070ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 22080ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 22090ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1("----CSROW %d VALID for MC node %d\n", 22100ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson i, pvt->mc_node_id); 22110ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 22120ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson empty = 0; 2213f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy if (csrow_enabled(i, 0, pvt)) 2214f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i); 2215f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy if (csrow_enabled(i, 1, pvt)) 2216f92cae45263b25cdb4c4d24e297e07945d3bc01bAshish Shenoy csrow->nr_pages += amd64_csrow_nr_pages(pvt, 1, i); 22170ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson find_csrow_limits(mci, i, &input_addr_min, &input_addr_max); 22180ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson sys_addr = input_addr_to_sys_addr(mci, input_addr_min); 22190ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT); 22200ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson sys_addr = input_addr_to_sys_addr(mci, input_addr_max); 22210ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT); 222211c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov 222311c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov get_cs_base_and_mask(pvt, i, 0, &base, &mask); 222411c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov csrow->page_mask = ~mask; 22250ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* 8 bytes of resolution */ 22260ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 222724f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov csrow->mtype = amd64_determine_memory_type(pvt, i); 22280ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 22290ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i); 22300ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n", 22310ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson (unsigned long)input_addr_min, 22320ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson (unsigned long)input_addr_max); 22330ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n", 22340ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson (unsigned long)sys_addr, csrow->page_mask); 22350ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson debugf1(" nr_pages: %u first_page: 0x%lx " 22360ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson "last_page: 0x%lx\n", 22370ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson (unsigned)csrow->nr_pages, 22380ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow->first_page, csrow->last_page); 22390ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 22400ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson /* 22410ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson * determine whether CHIPKILL or JUST ECC or NO ECC is operating 22420ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson */ 2243a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov if (pvt->nbcfg & NBCFG_ECC_ENABLE) 22440ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow->edac_mode = 2245a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov (pvt->nbcfg & NBCFG_CHIPKILL) ? 22460ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson EDAC_S4ECD4ED : EDAC_SECDED; 22470ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson else 22480ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson csrow->edac_mode = EDAC_NONE; 22490ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson } 22500ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson 22510ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson return empty; 22520ec449ee95b20245fef4aa9fa2486456f1540514Doug Thompson} 2253d27bf6fa369ca0272df10558d2f290d6fc72e675Doug Thompson 2254f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov/* get all cores on this DCT */ 2255b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkovstatic void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid) 2256f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov{ 2257f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov int cpu; 2258f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2259f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov for_each_online_cpu(cpu) 2260f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov if (amd_get_nb_id(cpu) == nid) 2261f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov cpumask_set_cpu(cpu, mask); 2262f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov} 2263f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2264f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov/* check MCG_CTL on all the cpus on this node */ 2265b487c33e55eb7e18cd98094f7159c6d9e8b6beddBorislav Petkovstatic bool amd64_nb_mce_bank_enabled_on_node(unsigned nid) 2266f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov{ 2267f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov cpumask_var_t mask; 2268505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov int cpu, nbe; 2269f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov bool ret = false; 2270f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2271f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) { 227224f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("%s: Error allocating mask\n", __func__); 2273f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov return false; 2274f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } 2275f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2276f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov get_cpus_on_this_dct_cpumask(mask, nid); 2277f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2278f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs); 2279f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2280f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov for_each_cpu(cpu, mask) { 2281505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov struct msr *reg = per_cpu_ptr(msrs, cpu); 22825980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov nbe = reg->l & MSR_MCGCTL_NBE; 2283f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2284f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", 2285505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov cpu, reg->q, 2286f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov (nbe ? "enabled" : "disabled")); 2287f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2288f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov if (!nbe) 2289f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov goto out; 2290f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } 2291f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov ret = true; 2292f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2293f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkovout: 2294f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov free_cpumask_var(mask); 2295f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov return ret; 2296f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov} 2297f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 22982299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkovstatic int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on) 2299f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov{ 2300f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov cpumask_var_t cmask; 2301505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov int cpu; 2302f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2303f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) { 230424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("%s: error allocating mask\n", __func__); 2305f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov return false; 2306f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } 2307f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2308ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov get_cpus_on_this_dct_cpumask(cmask, nid); 2309f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2310f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); 2311f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2312f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov for_each_cpu(cpu, cmask) { 2313f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2314505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov struct msr *reg = per_cpu_ptr(msrs, cpu); 2315505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov 2316f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov if (on) { 23175980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov if (reg->l & MSR_MCGCTL_NBE) 2318ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s->flags.nb_mce_enable = 1; 2319f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 23205980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov reg->l |= MSR_MCGCTL_NBE; 2321f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } else { 2322f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov /* 2323d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov * Turn off NB MCE reporting only when it was off before 2324f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov */ 2325ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov if (!s->flags.nb_mce_enable) 23265980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov reg->l &= ~MSR_MCGCTL_NBE; 2327f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } 2328f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov } 2329f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); 2330f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2331f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov free_cpumask_var(cmask); 2332f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 2333f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov return 0; 2334f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov} 2335f6d6ae965760906d79ab29bc38507608c5971549Borislav Petkov 23362299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkovstatic bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, 23372299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov struct pci_dev *F3) 2338f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson{ 23392299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov bool ret = true; 2340c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov u32 value, mask = 0x3; /* UECC/CECC enable */ 2341f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 23422299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (toggle_ecc_err_reporting(s, nid, ON)) { 23432299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov amd64_warn("Error enabling ECC reporting over MCGCTL!\n"); 23442299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov return false; 23452299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov } 23462299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 2347c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov amd64_read_pci_cfg(F3, NBCTL, &value); 2348f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2349ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s->old_nbctl = value & mask; 2350ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s->nbctl_valid = true; 2351f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2352f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson value |= mask; 2353c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov amd64_write_pci_cfg(F3, NBCTL, value); 2354f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2355a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_read_pci_cfg(F3, NBCFG, &value); 2356f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2357a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n", 2358a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov nid, value, !!(value & NBCFG_ECC_ENABLE)); 2359f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2360a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov if (!(value & NBCFG_ECC_ENABLE)) { 236124f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("DRAM ECC disabled on this node, enabling...\n"); 2362f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2363ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s->flags.nb_ecc_prev = 0; 2364d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov 2365f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson /* Attempt to turn on DRAM ECC Enable */ 2366a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov value |= NBCFG_ECC_ENABLE; 2367a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_write_pci_cfg(F3, NBCFG, value); 2368f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2369a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_read_pci_cfg(F3, NBCFG, &value); 2370f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2371a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov if (!(value & NBCFG_ECC_ENABLE)) { 237224f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("Hardware rejected DRAM ECC enable," 237324f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov "check memory DIMM configuration.\n"); 23742299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov ret = false; 2375f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson } else { 237624f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_info("Hardware accepted DRAM ECC Enable\n"); 2377f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson } 2378d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov } else { 2379ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s->flags.nb_ecc_prev = 1; 2380f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson } 2381d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov 2382a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n", 2383a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov nid, value, !!(value & NBCFG_ECC_ENABLE)); 2384f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 23852299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov return ret; 2386f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson} 2387f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2388360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid, 2389360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov struct pci_dev *F3) 2390f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson{ 2391c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov u32 value, mask = 0x3; /* UECC/CECC enable */ 2392c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov 2393f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2394ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov if (!s->nbctl_valid) 2395f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson return; 2396f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2397c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov amd64_read_pci_cfg(F3, NBCTL, &value); 2398f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson value &= ~mask; 2399ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov value |= s->old_nbctl; 2400f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2401c9f4f26eae096c39547139666e8af607c2447f94Borislav Petkov amd64_write_pci_cfg(F3, NBCTL, value); 2402f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2403ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov /* restore previous BIOS DRAM ECC "off" setting we force-enabled */ 2404ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov if (!s->flags.nb_ecc_prev) { 2405a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_read_pci_cfg(F3, NBCFG, &value); 2406a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov value &= ~NBCFG_ECC_ENABLE; 2407a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_write_pci_cfg(F3, NBCFG, value); 2408d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov } 2409d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov 2410d95cf4de6a1c9c1025ac375bc6d2da6af18fdf35Borislav Petkov /* restore the NB Enable MCGCTL bit */ 24112299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (toggle_ecc_err_reporting(s, nid, OFF)) 241224f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_warn("Error restoring NB MCGCTL settings!\n"); 2413f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson} 2414f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2415f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson/* 24162299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov * EDAC requires that the BIOS have ECC enabled before 24172299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov * taking over the processing of ECC errors. A command line 24182299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov * option allows to force-enable hardware ECC later in 24192299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov * enable_ecc_error_reporting(). 2420f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson */ 2421cab4d27764d5a8654212b3e96eb0ae793aec5b94Borislav Petkovstatic const char *ecc_msg = 2422cab4d27764d5a8654212b3e96eb0ae793aec5b94Borislav Petkov "ECC disabled in the BIOS or no ECC capability, module will not load.\n" 2423cab4d27764d5a8654212b3e96eb0ae793aec5b94Borislav Petkov " Either enable ECC checking or force module loading by setting " 2424cab4d27764d5a8654212b3e96eb0ae793aec5b94Borislav Petkov "'ecc_enable_override'.\n" 2425cab4d27764d5a8654212b3e96eb0ae793aec5b94Borislav Petkov " (Note that use of the override may cause unknown side effects.)\n"; 2426be3468e8ff768c986849870b24e85fa84806da73Borislav Petkov 24272299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkovstatic bool ecc_enabled(struct pci_dev *F3, u8 nid) 2428f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson{ 2429f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson u32 value; 24302299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov u8 ecc_en = 0; 243106724535f8fa26e78238bf8adfc9c81650a665f7Borislav Petkov bool nb_mce_en = false; 2432f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2433a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov amd64_read_pci_cfg(F3, NBCFG, &value); 2434f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 2435a97fa68ec403e2761a37b28651de8fd9da8c5e1fBorislav Petkov ecc_en = !!(value & NBCFG_ECC_ENABLE); 24362299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled")); 2437f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 24382299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid); 243906724535f8fa26e78238bf8adfc9c81650a665f7Borislav Petkov if (!nb_mce_en) 24402299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov amd64_notice("NB MCE bank disabled, set MSR " 24412299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov "0x%08x[4] on node %d to enable.\n", 24422299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov MSR_IA32_MCG_CTL, nid); 2443f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 24442299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (!ecc_en || !nb_mce_en) { 24452299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov amd64_notice("%s", ecc_msg); 24462299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov return false; 24472299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov } 24482299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov return true; 2449f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson} 2450f9431992b6227069bc54800d55531c6f78d276a7Doug Thompson 24517d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstruct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) + 24527d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ARRAY_SIZE(amd64_inj_attrs) + 24537d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 1]; 24547d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24557d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstruct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } }; 24567d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2457360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic void set_mc_sysfs_attrs(struct mem_ctl_info *mci) 24587d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 24597d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson unsigned int i = 0, j = 0; 24607d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24617d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++) 24627d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson sysfs_attrs[i] = amd64_dbg_attrs[i]; 24637d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2464a135cef79a2927ecff800492a26cd314e9cba996Borislav Petkov if (boot_cpu_data.x86 >= 0x10) 2465a135cef79a2927ecff800492a26cd314e9cba996Borislav Petkov for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++) 2466a135cef79a2927ecff800492a26cd314e9cba996Borislav Petkov sysfs_attrs[i] = amd64_inj_attrs[j]; 24677d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24687d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson sysfs_attrs[i] = terminator; 24697d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24707d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->mc_driver_sysfs_attributes = sysfs_attrs; 24717d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 24727d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2473df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkovstatic void setup_mci_misc_attrs(struct mem_ctl_info *mci, 2474df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov struct amd64_family_type *fam) 24757d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 24767d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct amd64_pvt *pvt = mci->pvt_info; 24777d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24787d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; 24797d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->edac_ctl_cap = EDAC_FLAG_NONE; 24807d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24815980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov if (pvt->nbcap & NBCAP_SECDED) 24827d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->edac_ctl_cap |= EDAC_FLAG_SECDED; 24837d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24845980bb9cd88a3fa44cc5beab599f08fbc928b832Borislav Petkov if (pvt->nbcap & NBCAP_CHIPKILL) 24857d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; 24867d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24877d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->edac_cap = amd64_determine_edac_cap(pvt); 24887d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->mod_name = EDAC_MOD_STR; 24897d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->mod_ver = EDAC_AMD64_VERSION; 2490df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov mci->ctl_name = fam->ctl_name; 24918d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov mci->dev_name = pci_name(pvt->F2); 24927d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->ctl_page_to_phys = NULL; 24937d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24947d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson /* memory scrubber interface */ 24957d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->set_sdram_scrub_rate = amd64_set_scrub_rate; 24967d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->get_sdram_scrub_rate = amd64_get_scrub_rate; 24977d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 24987d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 24990092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov/* 25000092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov * returns a pointer to the family descriptor on success, NULL otherwise. 25010092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov */ 25020092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkovstatic struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) 2503395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov{ 25040092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov u8 fam = boot_cpu_data.x86; 25050092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov struct amd64_family_type *fam_type = NULL; 25060092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov 25070092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov switch (fam) { 2508395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov case 0xf: 25090092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov fam_type = &amd64_family_types[K8_CPUS]; 2510b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov pvt->ops = &amd64_family_types[K8_CPUS].ops; 2511395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov break; 2512df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov 2513395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov case 0x10: 25140092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov fam_type = &amd64_family_types[F10_CPUS]; 2515b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov pvt->ops = &amd64_family_types[F10_CPUS].ops; 2516df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov break; 2517df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov 2518df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov case 0x15: 2519df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov fam_type = &amd64_family_types[F15_CPUS]; 2520df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov pvt->ops = &amd64_family_types[F15_CPUS].ops; 2521395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov break; 2522395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov 2523395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov default: 252424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov amd64_err("Unsupported family!\n"); 25250092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov return NULL; 2526395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov } 25270092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov 2528b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov pvt->ext_model = boot_cpu_data.x86_model >> 4; 2529b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov 2530df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, 25310092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov (fam == 0xf ? 253224f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov (pvt->ext_model >= K8_REV_F ? "revF or later " 253324f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov : "revE or earlier ") 253424f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov : ""), pvt->mc_node_id); 25350092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov return fam_type; 2536395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov} 2537395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov 25382299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkovstatic int amd64_init_one_instance(struct pci_dev *F2) 25397d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 25407d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct amd64_pvt *pvt = NULL; 25410092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov struct amd64_family_type *fam_type = NULL; 2542360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov struct mem_ctl_info *mci = NULL; 25437d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson int err = 0, ret; 2544360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov u8 nid = get_node_id(F2); 25457d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 25467d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ret = -ENOMEM; 25477d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); 25487d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (!pvt) 2549360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov goto err_ret; 25507d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2551360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov pvt->mc_node_id = nid; 25528d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov pvt->F2 = F2; 25537d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2554395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov ret = -EINVAL; 25550092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov fam_type = amd64_per_family_init(pvt); 25560092b20d4cf3de243b5c82b410ee02644cec2707Borislav Petkov if (!fam_type) 2557395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov goto err_free; 2558395ae783b384e5243804b07fba3e3f8379ddf1d6Borislav Petkov 25597d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ret = -ENODEV; 2560360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id); 25617d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (err) 25627d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson goto err_free; 25637d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2564360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov read_mc_regs(pvt); 25657d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 25667d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson /* 25677d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson * We need to determine how many memory channels there are. Then use 25687d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson * that information for calculating the size of the dynamic instance 2569360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov * tables in the 'mci' structure. 25707d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson */ 2571360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov ret = -EINVAL; 25727d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pvt->channel_count = pvt->ops->early_channel_count(pvt); 25737d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (pvt->channel_count < 0) 2574360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov goto err_siblings; 25757d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 25767d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ret = -ENOMEM; 257711c75eadaf75fe6320325aa13dc135f26ad724b8Borislav Petkov mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid); 25787d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (!mci) 2579360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov goto err_siblings; 25807d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 25817d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->pvt_info = pvt; 25828d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov mci->dev = &pvt->F2->dev; 25837d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2584df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov setup_mci_misc_attrs(mci, fam_type); 2585360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 2586360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov if (init_csrows(mci)) 25877d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci->edac_cap = EDAC_FLAG_NONE; 25887d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2589360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov set_mc_sysfs_attrs(mci); 25907d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 25917d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ret = -ENODEV; 25927d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (edac_mc_add_mc(mci)) { 25937d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson debugf1("failed edac_mc_add_mc()\n"); 25947d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson goto err_add_mc; 25957d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson } 25967d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2597549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov /* register stuff with EDAC MCE */ 2598549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov if (report_gart_errors) 2599549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov amd_report_gart_errors(true); 2600549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov 2601549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov amd_register_ecc_decoder(amd64_decode_bus_error); 2602549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov 2603360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov mcis[nid] = mci; 2604360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 2605360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov atomic_inc(&drv_instances); 2606360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 26077d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return 0; 26087d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26097d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonerr_add_mc: 26107d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson edac_mc_free(mci); 26117d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2612360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkoverr_siblings: 2613360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov free_mc_sibling_devs(pvt); 26147d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2615360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkoverr_free: 2616360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov kfree(pvt); 26177d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2618360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkoverr_ret: 26197d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return ret; 26207d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 26217d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26222299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkovstatic int __devinit amd64_probe_one_instance(struct pci_dev *pdev, 2623b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov const struct pci_device_id *mc_type) 26247d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 2625ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov u8 nid = get_node_id(pdev); 26262299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov struct pci_dev *F3 = node_to_amd_nb(nid)->misc; 2627ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov struct ecc_settings *s; 26282299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov int ret = 0; 26297d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26307d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson ret = pci_enable_device(pdev); 2631b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov if (ret < 0) { 2632b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov debugf0("ret=%d\n", ret); 2633b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov return -EIO; 2634b8cfa02f833a614e80f851747c4ce14989a4cfd0Borislav Petkov } 26357d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2636ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov ret = -ENOMEM; 2637ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL); 2638ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov if (!s) 26392299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov goto err_out; 2640ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov 2641ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov ecc_stngs[nid] = s; 2642ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov 26432299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (!ecc_enabled(F3, nid)) { 26442299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov ret = -ENODEV; 26452299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26462299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (!ecc_enable_override) 26472299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov goto err_enable; 26482299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26492299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov amd64_warn("Forcing ECC on!\n"); 26502299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26512299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov if (!enable_ecc_error_reporting(s, nid, F3)) 26522299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov goto err_enable; 26532299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov } 26542299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26552299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov ret = amd64_init_one_instance(pdev); 2656360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov if (ret < 0) { 2657ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov amd64_err("Error probing instance: %d\n", nid); 2658360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov restore_ecc_error_reporting(s, nid, F3); 2659360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov } 26607d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26617d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return ret; 26622299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26632299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkoverr_enable: 26642299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov kfree(s); 26652299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov ecc_stngs[nid] = NULL; 26662299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov 26672299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkoverr_out: 26682299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov return ret; 26697d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 26707d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26717d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstatic void __devexit amd64_remove_one_instance(struct pci_dev *pdev) 26727d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 26737d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct mem_ctl_info *mci; 26747d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct amd64_pvt *pvt; 2675360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov u8 nid = get_node_id(pdev); 2676360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov struct pci_dev *F3 = node_to_amd_nb(nid)->misc; 2677360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov struct ecc_settings *s = ecc_stngs[nid]; 26787d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26797d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson /* Remove from EDAC CORE tracking list */ 26807d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson mci = edac_mc_del_mc(&pdev->dev); 26817d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (!mci) 26827d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return; 26837d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 26847d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pvt = mci->pvt_info; 26857d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2686360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov restore_ecc_error_reporting(s, nid, F3); 26877d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2688360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov free_mc_sibling_devs(pvt); 26897d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2690549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov /* unregister from EDAC MCE */ 2691549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov amd_report_gart_errors(false); 2692549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov amd_unregister_ecc_decoder(amd64_decode_bus_error); 2693549d042df240dfb4203bab40ad44f9336751b7d6Borislav Petkov 2694360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov kfree(ecc_stngs[nid]); 2695360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov ecc_stngs[nid] = NULL; 2696ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov 26977d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson /* Free the EDAC CORE resources */ 26988f68ed9728193b1f2fb53ba06031b06bd8b3d1b4Borislav Petkov mci->pvt_info = NULL; 2699360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov mcis[nid] = NULL; 27008f68ed9728193b1f2fb53ba06031b06bd8b3d1b4Borislav Petkov 27018f68ed9728193b1f2fb53ba06031b06bd8b3d1b4Borislav Petkov kfree(pvt); 27027d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson edac_mc_free(mci); 27037d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 27047d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27057d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson/* 27067d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson * This table is part of the interface for loading drivers for PCI devices. The 27077d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson * PCI core identifies what devices are on a system during boot, and then 27087d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson * inquiry this table to see if this driver is for a given device found. 27097d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson */ 271036c46f31df910b092aaaed27c7c616bb8e2302a1Lionel Debrouxstatic DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = { 27117d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson { 27127d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .vendor = PCI_VENDOR_ID_AMD, 27137d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, 27147d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .subvendor = PCI_ANY_ID, 27157d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .subdevice = PCI_ANY_ID, 27167d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .class = 0, 27177d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .class_mask = 0, 27187d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson }, 27197d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson { 27207d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .vendor = PCI_VENDOR_ID_AMD, 27217d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM, 27227d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .subvendor = PCI_ANY_ID, 27237d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .subdevice = PCI_ANY_ID, 27247d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .class = 0, 27257d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .class_mask = 0, 27267d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson }, 2727df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov { 2728df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .vendor = PCI_VENDOR_ID_AMD, 2729df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .device = PCI_DEVICE_ID_AMD_15H_NB_F2, 2730df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .subvendor = PCI_ANY_ID, 2731df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .subdevice = PCI_ANY_ID, 2732df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .class = 0, 2733df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov .class_mask = 0, 2734df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov }, 2735df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov 27367d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson {0, } 27377d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson}; 27387d6034d3213e2dd1c0f8678e11064007413011c4Doug ThompsonMODULE_DEVICE_TABLE(pci, amd64_pci_table); 27397d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27407d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstatic struct pci_driver amd64_pci_driver = { 27417d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .name = EDAC_MOD_STR, 27422299ef7114000f8e403797b7f9a972f54bc05fadBorislav Petkov .probe = amd64_probe_one_instance, 27437d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .remove = __devexit_p(amd64_remove_one_instance), 27447d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson .id_table = amd64_pci_table, 27457d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson}; 27467d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2747360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkovstatic void setup_pci_device(void) 27487d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 27497d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct mem_ctl_info *mci; 27507d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson struct amd64_pvt *pvt; 27517d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27527d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (amd64_ctl_pci) 27537d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return; 27547d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2755cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov mci = mcis[0]; 27567d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (mci) { 27577d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27587d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pvt = mci->pvt_info; 27597d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson amd64_ctl_pci = 27608d5b5d9c7b86e44fda29a367db3ccd2815a52f7cBorislav Petkov edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR); 27617d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27627d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (!amd64_ctl_pci) { 27637d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pr_warning("%s(): Unable to create PCI control\n", 27647d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson __func__); 27657d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27667d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pr_warning("%s(): PCI error report via EDAC not set\n", 27677d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson __func__); 27687d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson } 27697d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson } 27707d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 27717d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27727d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstatic int __init amd64_edac_init(void) 27737d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 2774360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov int err = -ENODEV; 27757d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2776df71a053241548b728d3bf45b0c11ed092a20319Borislav Petkov printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION); 27777d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27787d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson opstate_init(); 27797d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 27809653a5c76c8677b05b45b3b999d3b39988d2a064Hans Rosenfeld if (amd_cache_northbridges() < 0) 278156b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov goto err_ret; 27827d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2783cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov err = -ENOMEM; 2784ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); 2785ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); 2786360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov if (!(mcis && ecc_stngs)) 2787a9f0fbe2bbf328f869fc5ee5a12c6a4118c32689Borislav Petkov goto err_free; 2788cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov 2789505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov msrs = msrs_alloc(); 279056b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov if (!msrs) 2791360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov goto err_free; 2792505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov 27937d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson err = pci_register_driver(&amd64_pci_driver); 27947d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (err) 279556b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov goto err_pci; 27967d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 279756b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov err = -ENODEV; 2798360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov if (!atomic_read(&drv_instances)) 2799360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov goto err_no_instances; 28007d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2801360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov setup_pci_device(); 2802360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov return 0; 28037d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 2804360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkoverr_no_instances: 28057d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pci_unregister_driver(&amd64_pci_driver); 2806cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov 280756b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkoverr_pci: 280856b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov msrs_free(msrs); 280956b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkov msrs = NULL; 2810cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov 2811360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkoverr_free: 2812360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov kfree(mcis); 2813360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov mcis = NULL; 2814360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 2815360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov kfree(ecc_stngs); 2816360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov ecc_stngs = NULL; 2817360b7f3c602ed80ce8c6b2585dcb76883a440c17Borislav Petkov 281856b34b91e22313294154cee0c16e294cf8a45b61Borislav Petkoverr_ret: 28197d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson return err; 28207d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 28217d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 28227d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonstatic void __exit amd64_edac_exit(void) 28237d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson{ 28247d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson if (amd64_ctl_pci) 28257d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson edac_pci_release_generic_ctl(amd64_ctl_pci); 28267d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 28277d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson pci_unregister_driver(&amd64_pci_driver); 2828505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov 2829ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov kfree(ecc_stngs); 2830ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov ecc_stngs = NULL; 2831ae7bb7c679e7ddba6c52d1a78a30f9bc868d9738Borislav Petkov 2832cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov kfree(mcis); 2833cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov mcis = NULL; 2834cc4d8860fc37dd315b16a43202400d822ab63221Borislav Petkov 2835505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov msrs_free(msrs); 2836505422517d3f126bb939439e9d15dece94e11d2cBorislav Petkov msrs = NULL; 28377d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson} 28387d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 28397d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonmodule_init(amd64_edac_init); 28407d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonmodule_exit(amd64_edac_exit); 28417d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 28427d6034d3213e2dd1c0f8678e11064007413011c4Doug ThompsonMODULE_LICENSE("GPL"); 28437d6034d3213e2dd1c0f8678e11064007413011c4Doug ThompsonMODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, " 28447d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson "Dave Peterson, Thayne Harbaugh"); 28457d6034d3213e2dd1c0f8678e11064007413011c4Doug ThompsonMODULE_DESCRIPTION("MC support for AMD64 memory controllers - " 28467d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson EDAC_AMD64_VERSION); 28477d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompson 28487d6034d3213e2dd1c0f8678e11064007413011c4Doug Thompsonmodule_param(edac_op_state, int, 0444); 28497d6034d3213e2dd1c0f8678e11064007413011c4Doug ThompsonMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 2850