1fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
2fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Intel 7300 class Memory Controllers kernel module (Clarksboro)
3fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
4fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * This file may be distributed under the terms of the
5fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * GNU General Public License version 2 only.
6fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
7fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Copyright (c) 2010 by:
837e59f876bc710d67a30b660826a5e83e07101ceMauro Carvalho Chehab *	 Mauro Carvalho Chehab
9fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
10fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Red Hat Inc. http://www.redhat.com
11fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
12fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet
13fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	http://www.intel.com/Assets/PDF/datasheet/318082.pdf
14fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
15fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * TODO: The chipset allow checking for PCI Express errors also. Currently,
16fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	 the driver covers only memory error errors
17fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
18fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * This driver uses "csrows" EDAC attribute to represent DIMM slot#
19fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
20fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
21fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/module.h>
22fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/init.h>
23fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/pci.h>
24fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/pci_ids.h>
25fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/slab.h>
26fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/edac.h>
27fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include <linux/mmzone.h>
28fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
29fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#include "edac_core.h"
30fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
31fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
32fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Alter this version for the I7300 module when modifications are made
33fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
34152ba3942276c2a240703669ae4a3099e0a79451Michal Marek#define I7300_REVISION    " Ver: 1.0.0"
35fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
36fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define EDAC_MOD_STR      "i7300_edac"
37fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
38fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define i7300_printk(level, fmt, arg...) \
39fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	edac_printk(level, "i7300", fmt, ##arg)
40fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
41fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define i7300_mc_printk(mci, level, fmt, arg...) \
42fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg)
43fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
44b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/***********************************************
45b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab * i7300 Limit constants Structs and static vars
46b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab ***********************************************/
47b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
48fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
49fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Memory topology is organized as:
50fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0)
51fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0)
52fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Each channel can have to 8 DIMM sets (called as SLOTS)
53fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Slots should generally be filled in pairs
54fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	Except on Single Channel mode of operation
55fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *		just slot 0/channel0 filled on this mode
56fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	On normal operation mode, the two channels on a branch should be
57c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab *		filled together for the same SLOT#
58fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four
59fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *		channels on both branches should be filled
60fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
61fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
62fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/* Limits for i7300 */
63fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MAX_SLOTS		8
64fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MAX_BRANCHES		2
65fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MAX_CH_PER_BRANCH	2
66fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MAX_CHANNELS		(MAX_CH_PER_BRANCH * MAX_BRANCHES)
67fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MAX_MIR			3
68fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
69fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define to_channel(ch, branch)	((((branch)) << 1) | (ch))
70fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
71fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define to_csrow(slot, ch, branch)					\
72fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		(to_channel(ch, branch) | ((slot) << 2))
73fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
74b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/* Device name and register DID (Device ID) */
75b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehabstruct i7300_dev_info {
76b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	const char *ctl_name;	/* name for this device */
77b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u16 fsb_mapping_errors;	/* DID for the branchmap,control */
78b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab};
79b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
80b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/* Table of devices attributes supported by this driver */
81b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehabstatic const struct i7300_dev_info i7300_devs[] = {
82b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	{
83b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab		.ctl_name = "I7300",
84b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab		.fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
85b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	},
86b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab};
87b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
88b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehabstruct i7300_dimm_info {
89b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	int megabytes;		/* size, 0 means not present  */
90b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab};
91b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
92b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/* driver private data structure */
93b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehabstruct i7300_pvt {
94b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	struct pci_dev *pci_dev_16_0_fsb_ctlr;		/* 16.0 */
95b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	struct pci_dev *pci_dev_16_1_fsb_addr_map;	/* 16.1 */
96b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	struct pci_dev *pci_dev_16_2_fsb_err_regs;	/* 16.2 */
97b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES];	/* 21.0  and 22.0 */
98b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
99b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u16 tolm;				/* top of low memory */
100b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u64 ambase;				/* AMB BAR */
101b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
102b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u32 mc_settings;			/* Report several settings */
103b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u32 mc_settings_a;
104b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
105b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u16 mir[MAX_MIR];			/* Memory Interleave Reg*/
106b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
1079c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab	u16 mtr[MAX_SLOTS][MAX_BRANCHES];	/* Memory Technlogy Reg */
108b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	u16 ambpresent[MAX_CHANNELS];		/* AMB present regs */
109b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
110b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	/* DIMM information matrix, allocating architecture maximums */
111b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS];
112b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
113b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	/* Temporary buffer for use when preparing error messages */
114b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab	char *tmp_prt_buffer;
115b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab};
116b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
117b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/* FIXME: Why do we need to have this static? */
118b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehabstatic struct edac_pci_ctl_info *i7300_pci;
119b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
120b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/***************************************************
121b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab * i7300 Register definitions for memory enumeration
122b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab ***************************************************/
123b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab
124c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab/*
125c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab * Device 16,
126c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab * Function 0: System Address (not documented)
127c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab * Function 1: Memory Branch Map, Control, Errors Register
128c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab */
129c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab
130fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* OFFSETS for Function 0 */
131af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define AMBASE			0x48 /* AMB Mem Mapped Reg Region Base */
132af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MAXCH			0x56 /* Max Channel Number */
133af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MAXDIMMPERCH		0x57 /* Max DIMM PER Channel Number */
134fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
135fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* OFFSETS for Function 1 */
136af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MC_SETTINGS		0x40
137bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab  #define IS_MIRRORED(mc)		((mc) & (1 << 16))
138bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab  #define IS_ECC_ENABLED(mc)		((mc) & (1 << 5))
139bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab  #define IS_RETRY_ENABLED(mc)		((mc) & (1 << 31))
140bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab  #define IS_SCRBALGO_ENHANCED(mc)	((mc) & (1 << 8))
141fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
142bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab#define MC_SETTINGS_A		0x58
143bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab  #define IS_SINGLE_MODE(mca)		((mca) & (1 << 14))
144d7de2bdb0e15c594aefbc71d899c4684a5ce6559Mauro Carvalho Chehab
145af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define TOLM			0x6C
146af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab
147af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MIR0			0x80
148af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MIR1			0x84
149af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab#define MIR2			0x88
150fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
151fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
152fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available
153fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it
154fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * seems that we cannot use this information directly for the same usage.
155fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Each memory slot may have up to 2 AMB interfaces, one for income and another
156fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * for outcome interface to the next slot.
157fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * For now, the driver just stores the AMB present registers, but rely only at
158fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * the MTR info to detect memory.
159fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * Datasheet is also not clear about how to map each AMBPRESENT registers to
160fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab * one of the 4 available channels.
161fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
162fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define AMBPRESENT_0	0x64
163fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define AMBPRESENT_1	0x66
164fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
16542b16b3fbb5ee4555f5dee6220f3ccaa6e1ebe47Jesper Juhlstatic const u16 mtr_regs[MAX_SLOTS] = {
166fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	0x80, 0x84, 0x88, 0x8c,
167fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	0x82, 0x86, 0x8a, 0x8e
168fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab};
169fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
170b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab/*
171b4552aceb37ef953db14b9851bd4ededabc3c77bMauro Carvalho Chehab * Defines to extract the vaious fields from the
172fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *	MTRx - Memory Technology Registers
173fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
174fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMMS_PRESENT(mtr)		((mtr) & (1 << 8))
175fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMMS_ETHROTTLE(mtr)	((mtr) & (1 << 7))
176fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DRAM_WIDTH(mtr)		(((mtr) & (1 << 6)) ? 8 : 4)
177fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DRAM_BANKS(mtr)		(((mtr) & (1 << 5)) ? 8 : 4)
178fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMM_RANKS(mtr)		(((mtr) & (1 << 4)) ? 1 : 0)
179fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMM_ROWS(mtr)		(((mtr) >> 2) & 0x3)
180fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DRAM_BANKS_ADDR_BITS	2
181fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMM_ROWS_ADDR_BITS(mtr)	(MTR_DIMM_ROWS(mtr) + 13)
182fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
183fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab#define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
184fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
185c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab/************************************************
186c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab * i7300 Register definitions for error detection
187c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab ************************************************/
18857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
18957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab/*
19057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab * Device 16.1: FBD Error Registers
19157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab */
19257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab#define FERR_FAT_FBD	0x98
19357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehabstatic const char *ferr_fat_fbd_name[] = {
19457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[22] = "Non-Redundant Fast Reset Timeout",
19557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[2]  = ">Tmid Thermal event with intelligent throttling disabled",
19657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[1]  = "Memory or FBD configuration CRC read error",
19757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[0]  = "Memory Write error on non-redundant retry or "
19857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	       "FBD configuration Write error on retry",
19957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab};
2007e06b7a3333f5c7a0cec12aff20d39c5c87c0795Jean Delvare#define GET_FBD_FAT_IDX(fbderr)	(((fbderr) >> 28) & 3)
2017e06b7a3333f5c7a0cec12aff20d39c5c87c0795Jean Delvare#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22))
20257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
20357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab#define FERR_NF_FBD	0xa0
20457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehabstatic const char *ferr_nf_fbd_name[] = {
20557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[24] = "DIMM-Spare Copy Completed",
20657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[23] = "DIMM-Spare Copy Initiated",
20757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[22] = "Redundant Fast Reset Timeout",
20857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[21] = "Memory Write error on redundant retry",
20957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[18] = "SPD protocol Error",
21057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[17] = "FBD Northbound parity error on FBD Sync Status",
21157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[16] = "Correctable Patrol Data ECC",
21257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[15] = "Correctable Resilver- or Spare-Copy Data ECC",
21357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[14] = "Correctable Mirrored Demand Data ECC",
21457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[13] = "Correctable Non-Mirrored Demand Data ECC",
21557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[11] = "Memory or FBD configuration CRC read error",
21657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[10] = "FBD Configuration Write error on first attempt",
21757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[9]  = "Memory Write error on first attempt",
21857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[8]  = "Non-Aliased Uncorrectable Patrol Data ECC",
21957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[7]  = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
22057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[6]  = "Non-Aliased Uncorrectable Mirrored Demand Data ECC",
22157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[5]  = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC",
22257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[4]  = "Aliased Uncorrectable Patrol Data ECC",
22357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[3]  = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
22457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[2]  = "Aliased Uncorrectable Mirrored Demand Data ECC",
22557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[1]  = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
22657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	[0]  = "Uncorrectable Data ECC on Replay",
22757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab};
2287e06b7a3333f5c7a0cec12aff20d39c5c87c0795Jean Delvare#define GET_FBD_NF_IDX(fbderr)	(((fbderr) >> 28) & 3)
22957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
23057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
23157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
23257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
23357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
23457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      (1 << 1)  | (1 << 0))
23557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
23657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab#define EMASK_FBD	0xa8
23757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab#define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\
23857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\
23957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\
24057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\
24157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
24257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
24357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			    (1 << 1)  | (1 << 0))
24457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
245c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab/*
246c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab * Device 16.2: Global Error Registers
247c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab */
248c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab
2495de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab#define FERR_GLOBAL_HI	0x48
2505de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehabstatic const char *ferr_global_hi_name[] = {
2515de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	[3] = "FSB 3 Fatal Error",
2525de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	[2] = "FSB 2 Fatal Error",
2535de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	[1] = "FSB 1 Fatal Error",
2545de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	[0] = "FSB 0 Fatal Error",
2555de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab};
2565de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab#define ferr_global_hi_is_fatal(errno)	1
2575de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab
258c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab#define FERR_GLOBAL_LO	0x40
2595de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehabstatic const char *ferr_global_lo_name[] = {
260c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[31] = "Internal MCH Fatal Error",
261c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[30] = "Intel QuickData Technology Device Fatal Error",
262c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[29] = "FSB1 Fatal Error",
263c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[28] = "FSB0 Fatal Error",
264c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[27] = "FBD Channel 3 Fatal Error",
265c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[26] = "FBD Channel 2 Fatal Error",
266c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[25] = "FBD Channel 1 Fatal Error",
267c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[24] = "FBD Channel 0 Fatal Error",
268c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[23] = "PCI Express Device 7Fatal Error",
269c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[22] = "PCI Express Device 6 Fatal Error",
270c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[21] = "PCI Express Device 5 Fatal Error",
271c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[20] = "PCI Express Device 4 Fatal Error",
272c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[19] = "PCI Express Device 3 Fatal Error",
273c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[18] = "PCI Express Device 2 Fatal Error",
274c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[17] = "PCI Express Device 1 Fatal Error",
275c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[16] = "ESI Fatal Error",
276c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[15] = "Internal MCH Non-Fatal Error",
277c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[14] = "Intel QuickData Technology Device Non Fatal Error",
278c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[13] = "FSB1 Non-Fatal Error",
279c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[12] = "FSB 0 Non-Fatal Error",
280c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[11] = "FBD Channel 3 Non-Fatal Error",
281c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[10] = "FBD Channel 2 Non-Fatal Error",
282c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[9]  = "FBD Channel 1 Non-Fatal Error",
283c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[8]  = "FBD Channel 0 Non-Fatal Error",
284c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[7]  = "PCI Express Device 7 Non-Fatal Error",
285c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[6]  = "PCI Express Device 6 Non-Fatal Error",
286c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[5]  = "PCI Express Device 5 Non-Fatal Error",
287c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[4]  = "PCI Express Device 4 Non-Fatal Error",
288c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[3]  = "PCI Express Device 3 Non-Fatal Error",
289c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[2]  = "PCI Express Device 2 Non-Fatal Error",
290c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[1]  = "PCI Express Device 1 Non-Fatal Error",
291c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab	[0]  = "ESI Non-Fatal Error",
292c3af2eaf7a3257f7b44165ec487215574c47fd32Mauro Carvalho Chehab};
2935de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab#define ferr_global_lo_is_fatal(errno)	((errno < 16) ? 0 : 1)
294fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
2958199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab#define NRECMEMA	0xbe
2968199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab  #define NRECMEMA_BANK(v)	(((v) >> 12) & 7)
2978199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab  #define NRECMEMA_RANK(v)	(((v) >> 8) & 15)
2988199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab
2998199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab#define NRECMEMB	0xc0
3008199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab  #define NRECMEMB_IS_WR(v)	((v) & (1 << 31))
3018199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab  #define NRECMEMB_CAS(v)	(((v) >> 16) & 0x1fff)
3028199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab  #define NRECMEMB_RAS(v)	((v) & 0xffff)
3038199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab
30432f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab#define REDMEMA		0xdc
30532f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
30637b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab#define REDMEMB		0x7c
30737b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab  #define IS_SECOND_CH(v)	((v) * (1 << 17))
30837b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab
30932f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab#define RECMEMA		0xe0
31032f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab  #define RECMEMA_BANK(v)	(((v) >> 12) & 7)
31132f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab  #define RECMEMA_RANK(v)	(((v) >> 8) & 15)
31232f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
31332f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab#define RECMEMB		0xe4
31432f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab  #define RECMEMB_IS_WR(v)	((v) & (1 << 31))
31532f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab  #define RECMEMB_CAS(v)	(((v) >> 16) & 0x1fff)
31632f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab  #define RECMEMB_RAS(v)	((v) & 0xffff)
31732f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
3185de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab/********************************************
3195de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab * i7300 Functions related to error detection
3205de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab ********************************************/
321fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
322d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
323d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * get_err_from_table() - Gets the error message from a table
324d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @table:	table name (array of char *)
325d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @size:	number of elements at the table
326d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @pos:	position of the element to be returned
327d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *
328d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * This is a small routine that gets the pos-th element of a table. If the
329d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * element doesn't exist (or it is empty), it returns "reserved".
330d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * Instead of calling it directly, the better is to call via the macro
331d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * GET_ERR_FROM_TABLE(), that automatically checks the table size via
332d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * ARRAY_SIZE() macro
333d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab */
334d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehabstatic const char *get_err_from_table(const char *table[], int size, int pos)
335fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
336d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	if (unlikely(pos >= size))
337d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab		return "Reserved";
338d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab
339d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	if (unlikely(!table[pos]))
3405de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		return "Reserved";
3415de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab
3425de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	return table[pos];
343fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
344fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
3455de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab#define GET_ERR_FROM_TABLE(table, pos)				\
3465de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	get_err_from_table(table, ARRAY_SIZE(table), pos)
3475de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab
348d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
349d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_process_error_global() - Retrieve the hardware error information from
350d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *				  the hardware global error registers and
351d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *				  sends it to dmesg
352d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
353fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
354f42774224860d7c3f7c06559f98b681197999f9eMauro Carvalho Chehabstatic void i7300_process_error_global(struct mem_ctl_info *mci)
355fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
3565de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	struct i7300_pvt *pvt;
3575f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	u32 errnum, error_reg;
3585de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	unsigned long errors;
3595de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	const char *specific;
3605de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	bool is_fatal;
361fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
3625de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	pvt = mci->pvt_info;
363fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
3645de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	/* read in the 1st FATAL error register */
3655de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3665f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab			      FERR_GLOBAL_HI, &error_reg);
3675f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	if (unlikely(error_reg)) {
3685f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		errors = error_reg;
3695de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		errnum = find_first_bit(&errors,
3705de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab					ARRAY_SIZE(ferr_global_hi_name));
3715de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum);
3725de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		is_fatal = ferr_global_hi_is_fatal(errnum);
37386002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab
37486002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab		/* Clear the error bit */
37586002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3765f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab				       FERR_GLOBAL_HI, error_reg);
37786002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab
3785de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		goto error_global;
379fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
380fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
3815de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3825f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab			      FERR_GLOBAL_LO, &error_reg);
3835f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	if (unlikely(error_reg)) {
3845f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		errors = error_reg;
3855de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		errnum = find_first_bit(&errors,
3865de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab					ARRAY_SIZE(ferr_global_lo_name));
3875de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum);
3885de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		is_fatal = ferr_global_lo_is_fatal(errnum);
38986002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab
39086002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab		/* Clear the error bit */
39186002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3925f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab				       FERR_GLOBAL_LO, error_reg);
39386002324cf8809c72858741ab20bb7a855654b4cMauro Carvalho Chehab
3945de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab		goto error_global;
3955de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	}
3965de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	return;
397fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
3985de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehaberror_global:
3995de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab	i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n",
4005de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab			is_fatal ? "Fatal" : "NOT fatal", specific);
401fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
402fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
403d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
404d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_process_fbd_error() - Retrieve the hardware error information from
405d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *			       the FBD error registers and sends it via
406d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *			       EDAC error API calls
407d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
40857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab */
409f42774224860d7c3f7c06559f98b681197999f9eMauro Carvalho Chehabstatic void i7300_process_fbd_error(struct mem_ctl_info *mci)
41057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab{
41157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	struct i7300_pvt *pvt;
4125f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	u32 errnum, value, error_reg;
4138199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab	u16 val16;
41437b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab	unsigned branch, channel, bank, rank, cas, ras;
41532f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab	u32 syndrome;
41632f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
41757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	unsigned long errors;
41857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	const char *specific;
41932f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab	bool is_wr;
42057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
42157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	pvt = mci->pvt_info;
42257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
42357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	/* read in the 1st FATAL error register */
42457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
4255f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab			      FERR_FAT_FBD, &error_reg);
4265f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	if (unlikely(error_reg & FERR_FAT_FBD_ERR_MASK)) {
4275f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		errors = error_reg & FERR_FAT_FBD_ERR_MASK ;
42857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab		errnum = find_first_bit(&errors,
42957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab					ARRAY_SIZE(ferr_fat_fbd_name));
43057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab		specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
4315f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0;
43257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
4338199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
4348199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab				     NRECMEMA, &val16);
4358199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		bank = NRECMEMA_BANK(val16);
4368199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		rank = NRECMEMA_RANK(val16);
4378199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab
4388199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
4398199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab				NRECMEMB, &value);
4408199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		is_wr = NRECMEMB_IS_WR(value);
4418199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		cas = NRECMEMB_CAS(value);
4428199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		ras = NRECMEMB_RAS(value);
4438199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab
4445f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		/* Clean the error register */
4455f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
4465f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab				FERR_FAT_FBD, error_reg);
4475f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab
4488199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab		snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
44970e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab			 "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))",
45070e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab			 bank, ras, cas, errors, specific);
45170e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab
4529eb07a7fb8a90ee39fa9d5489afc0330cfcfbea7Mauro Carvalho Chehab		edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0,
45370e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				     branch, -1, rank,
45470e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				     is_wr ? "Write error" : "Read error",
45503f7eae80f4b913929be84e0c883ee98196fd6ffMauro Carvalho Chehab				     pvt->tmp_prt_buffer);
45670e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab
45757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	}
45857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
45957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	/* read in the 1st NON-FATAL error register */
46057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
4615f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab			      FERR_NF_FBD, &error_reg);
4625f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab	if (unlikely(error_reg & FERR_NF_FBD_ERR_MASK)) {
4635f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		errors = error_reg & FERR_NF_FBD_ERR_MASK;
46457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab		errnum = find_first_bit(&errors,
46557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab					ARRAY_SIZE(ferr_nf_fbd_name));
46657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab		specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
4677e06b7a3333f5c7a0cec12aff20d39c5c87c0795Jean Delvare		branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0;
46857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
46932f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
47032f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab			REDMEMA, &syndrome);
47132f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
47232f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
47332f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab				     RECMEMA, &val16);
47432f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		bank = RECMEMA_BANK(val16);
47532f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		rank = RECMEMA_RANK(val16);
47632f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab
47732f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
47832f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab				RECMEMB, &value);
47932f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		is_wr = RECMEMB_IS_WR(value);
48032f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		cas = RECMEMB_CAS(value);
48132f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		ras = RECMEMB_RAS(value);
4828199d8cc65787bfd83abbfb69d9de1b51e027c41Mauro Carvalho Chehab
48337b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
48437b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab				     REDMEMB, &value);
48537b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab		channel = (branch << 1);
48637b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab		if (IS_SECOND_CH(value))
48737b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab			channel++;
48837b69cf91c2c6e60856ad1ac4c37ccb2005ebbd3Mauro Carvalho Chehab
4895f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		/* Clear the error bit */
4905f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab		pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
4915f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab				FERR_NF_FBD, error_reg);
4925f032119d6f1cc48d0d1a28b8014f270ca4c4e47Mauro Carvalho Chehab
49332f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		/* Form out message */
49432f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab		snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
49570e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab			 "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))",
49670e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab			 bank, ras, cas, errors, specific);
49770e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab
4989eb07a7fb8a90ee39fa9d5489afc0330cfcfbea7Mauro Carvalho Chehab		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0,
49970e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				     syndrome,
50070e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				     branch >> 1, channel % 2, rank,
50170e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				     is_wr ? "Write error" : "Read error",
50203f7eae80f4b913929be84e0c883ee98196fd6ffMauro Carvalho Chehab				     pvt->tmp_prt_buffer);
50332f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab	}
50432f9472613b30791d8cb5a953791cf4647166744Mauro Carvalho Chehab	return;
50557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab}
50657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
507d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
508d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_check_error() - Calls the error checking subroutines
509d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
510fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
511f42774224860d7c3f7c06559f98b681197999f9eMauro Carvalho Chehabstatic void i7300_check_error(struct mem_ctl_info *mci)
5125de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab{
513f42774224860d7c3f7c06559f98b681197999f9eMauro Carvalho Chehab	i7300_process_error_global(mci);
514f42774224860d7c3f7c06559f98b681197999f9eMauro Carvalho Chehab	i7300_process_fbd_error(mci);
5155de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab};
516fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
517d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
518d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_clear_error() - Clears the error registers
519d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
520fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
521fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void i7300_clear_error(struct mem_ctl_info *mci)
522fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
523e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	struct i7300_pvt *pvt = mci->pvt_info;
524e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	u32 value;
525e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	/*
526e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	 * All error values are RWC - we need to read and write 1 to the
527e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	 * bit that we want to cleanup
528e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	 */
529fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
530e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	/* Clear global error registers */
531e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
532e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_GLOBAL_HI, &value);
533e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
534e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_GLOBAL_HI, value);
535e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab
536e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
537e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_GLOBAL_LO, &value);
538e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
539e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_GLOBAL_LO, value);
540e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab
541e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	/* Clear FBD error registers */
542e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
543e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_FAT_FBD, &value);
544e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
545e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_FAT_FBD, value);
546e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab
547e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
548e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_NF_FBD, &value);
549e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
550e43276050927c7dfc45b1e2f090b94f72f87c052Mauro Carvalho Chehab			      FERR_NF_FBD, value);
551fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
552fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
553d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
554d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_enable_error_reporting() - Enable the memory reporting logic at the
555d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *				    hardware
556d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
557fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
558fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void i7300_enable_error_reporting(struct mem_ctl_info *mci)
559fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
56057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	struct i7300_pvt *pvt = mci->pvt_info;
56157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	u32 fbd_error_mask;
56257021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
56357021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	/* Read the FBD Error Mask Register */
56457021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
56557021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			      EMASK_FBD, &fbd_error_mask);
56657021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
56757021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	/* Enable with a '0' */
56857021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
56957021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab
57057021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
57157021918aa9c310524d7e9754506e4e8272b4c0eMauro Carvalho Chehab			       EMASK_FBD, fbd_error_mask);
572fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
5735de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab
5745de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab/************************************************
5755de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab * i7300 Functions related to memory enumberation
5765de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab ************************************************/
577fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
578d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
579d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * decode_mtr() - Decodes the MTR descriptor, filling the edac structs
580d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver
581d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @slot: DIMM slot (0 to 7)
582d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @ch: Channel number within the branch (0 or 1)
583d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @branch: Branch number (0 or 1)
584d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @dinfo: Pointer to DIMM info where dimm size is stored
585d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @p_csrow: Pointer to the struct csrow_info that corresponds to that element
586fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
587fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic int decode_mtr(struct i7300_pvt *pvt,
588fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		      int slot, int ch, int branch,
589fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		      struct i7300_dimm_info *dinfo,
590a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab		      struct dimm_info *dimm)
591fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
592fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int mtr, ans, addrBits, channel;
593fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
594fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	channel = to_channel(ch, branch);
595fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
596fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mtr = pvt->mtr[slot][branch];
597fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
598fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
599956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\tMTR%d CH%d: DIMMs are %sPresent (mtr)\n",
600956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 slot, channel, ans ? "" : "NOT ");
601fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
602fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Determine if there is a DIMM present in this DIMM slot */
603fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (!ans)
604fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		return 0;
605fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
606fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Start with the number of bits for a Bank
607fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	* on the DRAM */
608fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits = MTR_DRAM_BANKS_ADDR_BITS;
609fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Add thenumber of ROW bits */
610fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
611fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* add the number of COLUMN bits */
612fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
613fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* add the number of RANK bits */
614fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits += MTR_DIMM_RANKS(mtr);
615fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
616fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits += 6;	/* add 64 bits per DIMM */
617fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits -= 20;	/* divide by 2^^20 */
618fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	addrBits -= 3;	/* 8 bits per bytes */
619fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
620fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	dinfo->megabytes = 1 << addrBits;
621fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
622956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
623956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches
624956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n",
625956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
626956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches
627956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
628956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tNUMRANK: %s\n",
629956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_RANKS(mtr) ? "double" : "single");
630956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tNUMROW: %s\n",
631956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
632956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
633956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
634956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 "65,536 - 16 rows");
635956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tNUMCOL: %s\n",
636956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
637956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
638956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
639956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 "reserved");
640956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\t\tSIZE: %d MB\n", dinfo->megabytes);
641fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
642116389ed21e4ad88f65e7ec5ed6ca224acb89115Mauro Carvalho Chehab	/*
64315154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	 * The type of error detection actually depends of the
644116389ed21e4ad88f65e7ec5ed6ca224acb89115Mauro Carvalho Chehab	 * mode of operation. When it is just one single memory chip, at
64515154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	 * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code.
64615154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	 * In normal or mirrored mode, it uses Lockstep mode,
647116389ed21e4ad88f65e7ec5ed6ca224acb89115Mauro Carvalho Chehab	 * with the possibility of using an extended algorithm for x8 memories
648116389ed21e4ad88f65e7ec5ed6ca224acb89115Mauro Carvalho Chehab	 * See datasheet Sections 7.3.6 to 7.3.8
649116389ed21e4ad88f65e7ec5ed6ca224acb89115Mauro Carvalho Chehab	 */
65015154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab
651a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab	dimm->nr_pages = MiB_TO_PAGES(dinfo->megabytes);
652084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab	dimm->grain = 8;
653084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab	dimm->mtype = MEM_FB_DDR2;
65415154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
655084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab		dimm->edac_mode = EDAC_SECDED;
656956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
65715154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	} else {
658956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "\t\tECC code is on Lockstep mode\n");
65928c2ce7c8b275a8e6950bacb2dbad70b36a2996bMauro Carvalho Chehab		if (MTR_DRAM_WIDTH(mtr) == 8)
660084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab			dimm->edac_mode = EDAC_S8ECD8ED;
66115154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab		else
662084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab			dimm->edac_mode = EDAC_S4ECD4ED;
66315154c57c62494292f43df9133a7b370cbbf1ecbMauro Carvalho Chehab	}
664fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
665fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* ask what device type on this row */
66628c2ce7c8b275a8e6950bacb2dbad70b36a2996bMauro Carvalho Chehab	if (MTR_DRAM_WIDTH(mtr) == 8) {
667956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "\t\tScrub algorithm for x8 is on %s mode\n",
668956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
669956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 "enhanced" : "normal");
670d7de2bdb0e15c594aefbc71d899c4684a5ce6559Mauro Carvalho Chehab
671084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab		dimm->dtype = DEV_X8;
672d7de2bdb0e15c594aefbc71d899c4684a5ce6559Mauro Carvalho Chehab	} else
673084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab		dimm->dtype = DEV_X4;
674fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
675fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return mtr;
676fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
677fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
678d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
679d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * print_dimm_size() - Prints dump of the memory organization
680d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver
681fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
682d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * Useful for debug. If debug is disabled, this routine do nothing
683fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
684fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void print_dimm_size(struct i7300_pvt *pvt)
685fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
686d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab#ifdef CONFIG_EDAC_DEBUG
687fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_dimm_info *dinfo;
68885580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	char *p;
689fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int space, n;
690fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int channel, slot;
691fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
692fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space = PAGE_SIZE;
69385580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	p = pvt->tmp_prt_buffer;
694fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
695fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	n = snprintf(p, space, "              ");
696fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	p += n;
697fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space -= n;
698fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	for (channel = 0; channel < MAX_CHANNELS; channel++) {
699fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		n = snprintf(p, space, "channel %d | ", channel);
700fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		p += n;
701fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		space -= n;
702fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
703956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
70485580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	p = pvt->tmp_prt_buffer;
705fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space = PAGE_SIZE;
706fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	n = snprintf(p, space, "-------------------------------"
7079c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab			       "------------------------------");
708fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	p += n;
709fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space -= n;
710956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
71185580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	p = pvt->tmp_prt_buffer;
712fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space = PAGE_SIZE;
713fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
714fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	for (slot = 0; slot < MAX_SLOTS; slot++) {
715fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		n = snprintf(p, space, "csrow/SLOT %d  ", slot);
716fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		p += n;
717fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		space -= n;
718fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
719fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		for (channel = 0; channel < MAX_CHANNELS; channel++) {
720fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			dinfo = &pvt->dimm_info[slot][channel];
721fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
722fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			p += n;
723fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			space -= n;
724fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		}
725fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
726956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
72785580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab		p = pvt->tmp_prt_buffer;
728fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		space = PAGE_SIZE;
729fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
730fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
731fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	n = snprintf(p, space, "-------------------------------"
7329c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab			       "------------------------------");
733fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	p += n;
734fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space -= n;
735956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
73685580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	p = pvt->tmp_prt_buffer;
737fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	space = PAGE_SIZE;
738d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab#endif
739fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
740fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
741d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
742d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_init_csrows() - Initialize the 'csrows' table within
743d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *			 the mci control structure with the
744d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *			 addressing of memory.
745d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
746fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
747fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic int i7300_init_csrows(struct mem_ctl_info *mci)
748fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
749fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_pvt *pvt;
750fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_dimm_info *dinfo;
751d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	int rc = -ENODEV;
752fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int mtr;
75333ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab	int ch, branch, slot, channel, max_channel, max_branch;
754084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab	struct dimm_info *dimm;
755fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
756fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt = mci->pvt_info;
757fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
758956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "Memory Technology Registers:\n");
759fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
76033ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab	if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
76133ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		max_branch = 1;
76233ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		max_channel = 1;
76333ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab	} else {
76433ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		max_branch = MAX_BRANCHES;
76533ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		max_channel = MAX_CH_PER_BRANCH;
76633ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab	}
76733ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab
768fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Get the AMB present registers for the four channels */
76933ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab	for (branch = 0; branch < max_branch; branch++) {
770fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		/* Read and dump branch 0's MTRs */
771fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		channel = to_channel(0, branch);
7729c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
7739c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab				     AMBPRESENT_0,
774fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				&pvt->ambpresent[channel]);
775956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
776956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 channel, pvt->ambpresent[channel]);
777fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
77833ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		if (max_channel == 1)
77933ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab			continue;
78033ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab
781fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		channel = to_channel(1, branch);
7829c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
7839c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab				     AMBPRESENT_1,
784fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				&pvt->ambpresent[channel]);
785956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
786956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 channel, pvt->ambpresent[channel]);
787fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
788fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
789fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Get the set of MTR[0-7] regs by each branch */
790fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	for (slot = 0; slot < MAX_SLOTS; slot++) {
791fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		int where = mtr_regs[slot];
79233ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab		for (branch = 0; branch < max_branch; branch++) {
7933e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab			pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
794fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					where,
795fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					&pvt->mtr[slot][branch]);
79633ad41263da5df8ac55d4010a015063ff88712e8Mauro Carvalho Chehab			for (ch = 0; ch < max_channel; ch++) {
797fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				int channel = to_channel(ch, branch);
798fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
79970e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
80070e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab					       mci->n_layers, branch, ch, slot);
801fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
80270e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab				dinfo = &pvt->dimm_info[slot][channel];
803084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab
804fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				mtr = decode_mtr(pvt, slot, ch, branch,
805a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab						 dinfo, dimm);
806a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab
807fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				/* if no DIMMS on this row, continue */
808fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab				if (!MTR_DIMMS_PRESENT(mtr))
809fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					continue;
810fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
811d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab				rc = 0;
812a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab
813fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			}
814fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		}
815fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
816fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
817d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	return rc;
818fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
819fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
820d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
821d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * decode_mir() - Decodes Memory Interleave Register (MIR) info
822d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @int mir_no: number of the MIR register to decode
823d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mir: array with the MIR data cached on the driver
824d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab */
825fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void decode_mir(int mir_no, u16 mir[MAX_MIR])
826fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
827fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (mir[mir_no] & 3)
828956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(2, "MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n",
829956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 mir_no,
830956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 (mir[mir_no] >> 4) & 0xfff,
831956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 (mir[mir_no] & 1) ? "B0" : "",
832956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 (mir[mir_no] & 2) ? "B1" : "");
833fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
834fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
835d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
836d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_get_mc_regs() - Get the contents of the MC enumeration registers
837d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
838fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
839d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * Data read is cached internally for its usage when needed
840fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
841fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic int i7300_get_mc_regs(struct mem_ctl_info *mci)
842fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
843fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_pvt *pvt;
844fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	u32 actual_tolm;
845fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int i, rc;
846fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
847fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt = mci->pvt_info;
848fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
8493e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
850fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			(u32 *) &pvt->ambase);
851fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
852956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
853fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
854fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Get the Branch Map regs */
8553e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
856fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt->tolm >>= 12;
857956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n",
858956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->tolm, pvt->tolm);
859fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
860fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
861956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
862956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
863fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
864af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab	/* Get memory controller settings */
8653e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
866af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab			     &pvt->mc_settings);
867bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A,
868bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab			     &pvt->mc_settings_a);
869d7de2bdb0e15c594aefbc71d899c4684a5ce6559Mauro Carvalho Chehab
870bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab	if (IS_SINGLE_MODE(pvt->mc_settings_a))
871956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(0, "Memory controller operating on single mode\n");
872bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab	else
873956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(0, "Memory controller operating on %smirrored mode\n",
874956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches			 IS_MIRRORED(pvt->mc_settings) ? "" : "non-");
875bb81a21637f84e2192bf327575645a7843c70cdbMauro Carvalho Chehab
876956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(0, "Error detection is %s\n",
877956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
878956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(0, "Retry is %s\n",
879956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
880af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab
881af3d8831e7e2036cd453c852d206b892b19c8820Mauro Carvalho Chehab	/* Get Memory Interleave Range registers */
8829c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0,
8839c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab			     &pvt->mir[0]);
8849c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1,
8859c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab			     &pvt->mir[1]);
8869c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2,
8879c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab			     &pvt->mir[2]);
888fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
889fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Decode the MIR regs */
890fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	for (i = 0; i < MAX_MIR; i++)
891fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		decode_mir(i, pvt->mir);
892fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
893fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	rc = i7300_init_csrows(mci);
894fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (rc < 0)
895fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		return rc;
896fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
897fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Go and determine the size of each DIMM and place in an
898fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	 * orderly matrix */
899fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	print_dimm_size(pvt);
900fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
901fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return 0;
902fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
903fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
9045de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab/*************************************************
9055de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab * i7300 Functions related to device probe/release
9065de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab *************************************************/
9075de6e07ed75ee29a302f50e149339ca747131121Mauro Carvalho Chehab
908d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
909d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_put_devices() - Release the PCI devices
910d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
911fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
912fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void i7300_put_devices(struct mem_ctl_info *mci)
913fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
914fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_pvt *pvt;
915fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int branch;
916fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
917fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt = mci->pvt_info;
918fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
919fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Decrement usage count for devices */
920fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++)
9213e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab		pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]);
9223e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs);
9233e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map);
924fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
925fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
926d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
927d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_get_devices() - Find and perform 'get' operation on the MCH's
928d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *			 device/functions we want to reference for this driver
929d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer
930fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
931d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * Access and prepare the several devices for usage:
932d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * I7300 devices used by this driver:
933d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *    Device 16, functions 0,1 and 2:	PCI_DEVICE_ID_INTEL_I7300_MCH_ERR
934d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *    Device 21 function 0:		PCI_DEVICE_ID_INTEL_I7300_MCH_FB0
935d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab *    Device 22 function 0:		PCI_DEVICE_ID_INTEL_I7300_MCH_FB1
936fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
9379b3c6e85c2cfa731cf67d5a8c49f7d8c60ec0b04Greg Kroah-Hartmanstatic int i7300_get_devices(struct mem_ctl_info *mci)
938fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
939fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_pvt *pvt;
940fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct pci_dev *pdev;
941fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
942fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt = mci->pvt_info;
943fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
944fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Attempt to 'get' the MCH register we want */
945fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pdev = NULL;
94675135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare	while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
94775135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare				      PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
94875135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare				      pdev))) {
949fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		/* Store device 16 funcs 1 and 2 */
950fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		switch (PCI_FUNC(pdev->devfn)) {
951fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		case 1:
95275135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			if (!pvt->pci_dev_16_1_fsb_addr_map)
95375135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare				pvt->pci_dev_16_1_fsb_addr_map =
95475135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare							pci_dev_get(pdev);
955fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			break;
956fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		case 2:
95775135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			if (!pvt->pci_dev_16_2_fsb_err_regs)
95875135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare				pvt->pci_dev_16_2_fsb_err_regs =
95975135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare							pci_dev_get(pdev);
960fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			break;
961fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		}
962fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
963fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
96475135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare	if (!pvt->pci_dev_16_1_fsb_addr_map ||
96575135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare	    !pvt->pci_dev_16_2_fsb_err_regs) {
96675135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare		/* At least one device was not found */
96775135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare		i7300_printk(KERN_ERR,
96875135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			"'system address,Process Bus' device not found:"
96975135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			"vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
97075135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			PCI_VENDOR_ID_INTEL,
97175135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare			PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
97275135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare		goto error;
97375135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare	}
97475135da0d68419ef8a925f4c1d5f63d8046e314dJean Delvare
975956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
976956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pci_name(pvt->pci_dev_16_0_fsb_ctlr),
977956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_0_fsb_ctlr->vendor,
978956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_0_fsb_ctlr->device);
979956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
980956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pci_name(pvt->pci_dev_16_1_fsb_addr_map),
981956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_1_fsb_addr_map->vendor,
982956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_1_fsb_addr_map->device);
983956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
984956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pci_name(pvt->pci_dev_16_2_fsb_err_regs),
985956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_2_fsb_err_regs->vendor,
986956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pvt->pci_dev_16_2_fsb_err_regs->device);
987fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
9883e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
9899c6f6b65d25aa7fe890377a92ea049c8e20da906Mauro Carvalho Chehab					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
990fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					    NULL);
9913e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	if (!pvt->pci_dev_2x_0_fbd_branch[0]) {
992fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		i7300_printk(KERN_ERR,
993fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"MC: 'BRANCH 0' device not found:"
994fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
995fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0);
996fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		goto error;
997fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
998fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
9993e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL,
1000fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB1,
1001fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab					    NULL);
10023e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	if (!pvt->pci_dev_2x_0_fbd_branch[1]) {
1003fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		i7300_printk(KERN_ERR,
1004fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"MC: 'BRANCH 1' device not found:"
1005fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"vendor 0x%x device 0x%x Func 0 "
1006fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"(broken BIOS?)\n",
1007fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			PCI_VENDOR_ID_INTEL,
1008fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			PCI_DEVICE_ID_INTEL_I7300_MCH_FB1);
1009fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		goto error;
1010fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
1011fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1012fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return 0;
1013fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1014fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehaberror:
1015fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	i7300_put_devices(mci);
1016fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return -ENODEV;
1017fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
1018fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1019d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
1020d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_init_one() - Probe for one instance of the device
1021d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @pdev: struct pci_dev pointer
1022d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @id: struct pci_device_id pointer - currently unused
1023fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
10249b3c6e85c2cfa731cf67d5a8c49f7d8c60ec0b04Greg Kroah-Hartmanstatic int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
1025fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
1026fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct mem_ctl_info *mci;
102770e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	struct edac_mc_layer layers[3];
1028fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct i7300_pvt *pvt;
1029d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	int rc;
1030fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1031d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	/* wake up device */
1032d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	rc = pci_enable_device(pdev);
1033d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	if (rc == -EIO)
1034d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab		return rc;
1035fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1036956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
1037956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 pdev->bus->number,
1038956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
1039fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1040fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* We only are looking for func 0 of the set */
1041fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (PCI_FUNC(pdev->devfn) != 0)
1042fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		return -ENODEV;
1043fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1044fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* allocate a new MC control structure */
104570e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[0].type = EDAC_MC_LAYER_BRANCH;
104670e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[0].size = MAX_BRANCHES;
104770e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[0].is_virt_csrow = false;
104870e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[1].type = EDAC_MC_LAYER_CHANNEL;
104970e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[1].size = MAX_CH_PER_BRANCH;
105070e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[1].is_virt_csrow = true;
105170e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[2].type = EDAC_MC_LAYER_SLOT;
105270e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[2].size = MAX_SLOTS;
105370e2a8379b6e704b2e8cdfcf151954171c36e779Mauro Carvalho Chehab	layers[2].is_virt_csrow = true;
1054ca0907b9e413bb1d1f3ea123b663535b74928846Mauro Carvalho Chehab	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
1055fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (mci == NULL)
1056fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		return -ENOMEM;
1057fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1058956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(0, "MC: mci = %p\n", mci);
1059fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1060fd687502dc8037aa5a4b84c570ada971106574eeMauro Carvalho Chehab	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
1061fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1062fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pvt = mci->pvt_info;
10633e57eef64c53d4a45790fb7bb60a4ee6bf2bad30Mauro Carvalho Chehab	pvt->pci_dev_16_0_fsb_ctlr = pdev;	/* Record this device in our private */
1064fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
106585580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
106685580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	if (!pvt->tmp_prt_buffer) {
106785580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab		edac_mc_free(mci);
106885580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab		return -ENOMEM;
106985580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	}
107085580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab
1071fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* 'get' the pci devices we want to reserve for our use */
1072d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	if (i7300_get_devices(mci))
1073fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		goto fail0;
1074fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1075fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->mc_idx = 0;
1076fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->mtype_cap = MEM_FLAG_FB_DDR2;
1077fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->edac_ctl_cap = EDAC_FLAG_NONE;
1078fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->edac_cap = EDAC_FLAG_NONE;
1079fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->mod_name = "i7300_edac.c";
1080fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->mod_ver = I7300_REVISION;
1081d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab	mci->ctl_name = i7300_devs[0].ctl_name;
1082fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->dev_name = pci_name(pdev);
1083fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->ctl_page_to_phys = NULL;
1084fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1085fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Set the function pointer to an actual operation function */
1086fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci->edac_check = i7300_check_error;
1087fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1088fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* initialize the MC control structure 'csrows' table
1089fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	 * with the mapping and control information */
1090fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (i7300_get_mc_regs(mci)) {
1091956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n");
1092fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
1093fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	} else {
1094956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(1, "MC: Enable error reporting now\n");
1095fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		i7300_enable_error_reporting(mci);
1096fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
1097fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1098fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* add this new MC control structure to EDAC's list of MCs */
1099fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (edac_mc_add_mc(mci)) {
1100956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
1101fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		/* FIXME: perhaps some code should go here that disables error
1102fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		 * reporting if we just enabled it
1103fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		 */
1104fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		goto fail1;
1105fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
1106fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1107fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	i7300_clear_error(mci);
1108fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1109fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* allocating generic PCI control info */
1110fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1111fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (!i7300_pci) {
1112fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		printk(KERN_WARNING
1113fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"%s(): Unable to create PCI control\n",
1114fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			__func__);
1115fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		printk(KERN_WARNING
1116fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			"%s(): PCI error report via EDAC not setup\n",
1117fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab			__func__);
1118fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	}
1119fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1120fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return 0;
1121fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1122fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Error exit unwinding stack */
1123fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabfail1:
1124fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1125fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	i7300_put_devices(mci);
1126fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1127fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabfail0:
112885580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	kfree(pvt->tmp_prt_buffer);
1129fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	edac_mc_free(mci);
1130fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return -ENODEV;
1131fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
1132fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1133d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
1134d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_remove_one() - Remove the driver
1135d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * @pdev: struct pci_dev pointer
1136fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
11379b3c6e85c2cfa731cf67d5a8c49f7d8c60ec0b04Greg Kroah-Hartmanstatic void i7300_remove_one(struct pci_dev *pdev)
1138fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
1139fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	struct mem_ctl_info *mci;
114085580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	char *tmp;
1141fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1142956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(0, "\n");
1143fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1144fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (i7300_pci)
1145fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		edac_pci_release_generic_ctl(i7300_pci);
1146fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1147fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	mci = edac_mc_del_mc(&pdev->dev);
1148fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	if (!mci)
1149fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		return;
1150fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
115185580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer;
115285580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab
1153fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* retrieve references to resources, and free those resources */
1154fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	i7300_put_devices(mci);
1155fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
115685580ea4f72ce08e4d9140a3bb22806185a0bba9Mauro Carvalho Chehab	kfree(tmp);
1157fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	edac_mc_free(mci);
1158fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
1159fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1160fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
1161d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * pci_device_id: table for which devices we are looking for
1162fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab *
1163d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * Has only 8086:360c PCI ID
1164fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
1165ba935f40979b32924824759111ed95d35469c5faJingoo Hanstatic const struct pci_device_id i7300_pci_tbl[] = {
1166fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
1167fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	{0,}			/* 0 terminated list. */
1168fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab};
1169fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1170fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho ChehabMODULE_DEVICE_TABLE(pci, i7300_pci_tbl);
1171fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1172fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab/*
1173d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_driver: pci_driver structure for this module
1174fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
1175fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic struct pci_driver i7300_driver = {
1176fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	.name = "i7300_edac",
1177fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	.probe = i7300_init_one,
11789b3c6e85c2cfa731cf67d5a8c49f7d8c60ec0b04Greg Kroah-Hartman	.remove = i7300_remove_one,
1179fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	.id_table = i7300_pci_tbl,
1180fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab};
1181fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1182d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
1183d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_init() - Registers the driver
1184fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
1185fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic int __init i7300_init(void)
1186fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
1187fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	int pci_rc;
1188fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1189956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\n");
1190fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1191fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
1192fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	opstate_init();
1193fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1194fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pci_rc = pci_register_driver(&i7300_driver);
1195fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1196fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	return (pci_rc < 0) ? pci_rc : 0;
1197fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
1198fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1199d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab/**
1200d091a6eb177dd3da8f55f8fd73c5b80db0e1656fMauro Carvalho Chehab * i7300_init() - Unregisters the driver
1201fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab */
1202fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabstatic void __exit i7300_exit(void)
1203fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab{
1204956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches	edac_dbg(2, "\n");
1205fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab	pci_unregister_driver(&i7300_driver);
1206fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab}
1207fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1208fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabmodule_init(i7300_init);
1209fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabmodule_exit(i7300_exit);
1210fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1211fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho ChehabMODULE_LICENSE("GPL");
121237e59f876bc710d67a30b660826a5e83e07101ceMauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab");
1213fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho ChehabMODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
1214fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho ChehabMODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
1215fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab		   I7300_REVISION);
1216fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehab
1217fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho Chehabmodule_param(edac_op_state, int, 0444);
1218fcaf780b2ad352edaeb1d1c07a6da053266b1eedMauro Carvalho ChehabMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
1219