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, &reg);
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