xref: /openbmc/linux/drivers/edac/i7300_edac.c (revision 85580ea4f72ce08e4d9140a3bb22806185a0bba9)
1fcaf780bSMauro Carvalho Chehab /*
2fcaf780bSMauro Carvalho Chehab  * Intel 7300 class Memory Controllers kernel module (Clarksboro)
3fcaf780bSMauro Carvalho Chehab  *
4fcaf780bSMauro Carvalho Chehab  * This file may be distributed under the terms of the
5fcaf780bSMauro Carvalho Chehab  * GNU General Public License version 2 only.
6fcaf780bSMauro Carvalho Chehab  *
7fcaf780bSMauro Carvalho Chehab  * Copyright (c) 2010 by:
8fcaf780bSMauro Carvalho Chehab  *	 Mauro Carvalho Chehab <mchehab@redhat.com>
9fcaf780bSMauro Carvalho Chehab  *
10fcaf780bSMauro Carvalho Chehab  * Red Hat Inc. http://www.redhat.com
11fcaf780bSMauro Carvalho Chehab  *
12fcaf780bSMauro Carvalho Chehab  * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet
13fcaf780bSMauro Carvalho Chehab  *	http://www.intel.com/Assets/PDF/datasheet/318082.pdf
14fcaf780bSMauro Carvalho Chehab  *
15fcaf780bSMauro Carvalho Chehab  * TODO: The chipset allow checking for PCI Express errors also. Currently,
16fcaf780bSMauro Carvalho Chehab  *	 the driver covers only memory error errors
17fcaf780bSMauro Carvalho Chehab  *
18fcaf780bSMauro Carvalho Chehab  * This driver uses "csrows" EDAC attribute to represent DIMM slot#
19fcaf780bSMauro Carvalho Chehab  */
20fcaf780bSMauro Carvalho Chehab 
21fcaf780bSMauro Carvalho Chehab #include <linux/module.h>
22fcaf780bSMauro Carvalho Chehab #include <linux/init.h>
23fcaf780bSMauro Carvalho Chehab #include <linux/pci.h>
24fcaf780bSMauro Carvalho Chehab #include <linux/pci_ids.h>
25fcaf780bSMauro Carvalho Chehab #include <linux/slab.h>
26fcaf780bSMauro Carvalho Chehab #include <linux/edac.h>
27fcaf780bSMauro Carvalho Chehab #include <linux/mmzone.h>
28fcaf780bSMauro Carvalho Chehab 
29fcaf780bSMauro Carvalho Chehab #include "edac_core.h"
30fcaf780bSMauro Carvalho Chehab 
31fcaf780bSMauro Carvalho Chehab /*
32fcaf780bSMauro Carvalho Chehab  * Alter this version for the I7300 module when modifications are made
33fcaf780bSMauro Carvalho Chehab  */
34fcaf780bSMauro Carvalho Chehab #define I7300_REVISION    " Ver: 1.0.0 " __DATE__
35fcaf780bSMauro Carvalho Chehab 
36fcaf780bSMauro Carvalho Chehab #define EDAC_MOD_STR      "i7300_edac"
37fcaf780bSMauro Carvalho Chehab 
38fcaf780bSMauro Carvalho Chehab #define i7300_printk(level, fmt, arg...) \
39fcaf780bSMauro Carvalho Chehab 	edac_printk(level, "i7300", fmt, ##arg)
40fcaf780bSMauro Carvalho Chehab 
41fcaf780bSMauro Carvalho Chehab #define i7300_mc_printk(mci, level, fmt, arg...) \
42fcaf780bSMauro Carvalho Chehab 	edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg)
43fcaf780bSMauro Carvalho Chehab 
44fcaf780bSMauro Carvalho Chehab /*
45fcaf780bSMauro Carvalho Chehab  * Memory topology is organized as:
46fcaf780bSMauro Carvalho Chehab  *	Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0)
47fcaf780bSMauro Carvalho Chehab  *	Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0)
48fcaf780bSMauro Carvalho Chehab  * Each channel can have to 8 DIMM sets (called as SLOTS)
49fcaf780bSMauro Carvalho Chehab  * Slots should generally be filled in pairs
50fcaf780bSMauro Carvalho Chehab  *	Except on Single Channel mode of operation
51fcaf780bSMauro Carvalho Chehab  *		just slot 0/channel0 filled on this mode
52fcaf780bSMauro Carvalho Chehab  *	On normal operation mode, the two channels on a branch should be
53c3af2eafSMauro Carvalho Chehab  *		filled together for the same SLOT#
54fcaf780bSMauro Carvalho Chehab  * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four
55fcaf780bSMauro Carvalho Chehab  *		channels on both branches should be filled
56fcaf780bSMauro Carvalho Chehab  */
57fcaf780bSMauro Carvalho Chehab 
58fcaf780bSMauro Carvalho Chehab /* Limits for i7300 */
59fcaf780bSMauro Carvalho Chehab #define MAX_SLOTS		8
60fcaf780bSMauro Carvalho Chehab #define MAX_BRANCHES		2
61fcaf780bSMauro Carvalho Chehab #define MAX_CH_PER_BRANCH	2
62fcaf780bSMauro Carvalho Chehab #define MAX_CHANNELS		(MAX_CH_PER_BRANCH * MAX_BRANCHES)
63fcaf780bSMauro Carvalho Chehab #define MAX_MIR			3
64fcaf780bSMauro Carvalho Chehab 
65fcaf780bSMauro Carvalho Chehab #define to_channel(ch, branch)	((((branch)) << 1) | (ch))
66fcaf780bSMauro Carvalho Chehab 
67fcaf780bSMauro Carvalho Chehab #define to_csrow(slot, ch, branch)					\
68fcaf780bSMauro Carvalho Chehab 		(to_channel(ch, branch) | ((slot) << 2))
69fcaf780bSMauro Carvalho Chehab 
70c3af2eafSMauro Carvalho Chehab /*
71c3af2eafSMauro Carvalho Chehab  * I7300 devices
72fcaf780bSMauro Carvalho Chehab  * All 3 functions of Device 16 (0,1,2) share the SAME DID and
73fcaf780bSMauro Carvalho Chehab  * uses PCI_DEVICE_ID_INTEL_I7300_MCH_ERR for device 16 (0,1,2),
74fcaf780bSMauro Carvalho Chehab  * PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 and PCI_DEVICE_ID_INTEL_I7300_MCH_FB1
75fcaf780bSMauro Carvalho Chehab  * for device 21 (0,1).
76fcaf780bSMauro Carvalho Chehab  */
77fcaf780bSMauro Carvalho Chehab 
78c3af2eafSMauro Carvalho Chehab /****************************************************
79c3af2eafSMauro Carvalho Chehab  * i7300 Register definitions for memory enumberation
80c3af2eafSMauro Carvalho Chehab  ****************************************************/
81c3af2eafSMauro Carvalho Chehab 
82c3af2eafSMauro Carvalho Chehab /*
83c3af2eafSMauro Carvalho Chehab  * Device 16,
84c3af2eafSMauro Carvalho Chehab  * Function 0: System Address (not documented)
85c3af2eafSMauro Carvalho Chehab  * Function 1: Memory Branch Map, Control, Errors Register
86c3af2eafSMauro Carvalho Chehab  */
87c3af2eafSMauro Carvalho Chehab 
88fcaf780bSMauro Carvalho Chehab 	/* OFFSETS for Function 0 */
89fcaf780bSMauro Carvalho Chehab #define AMBASE			0x48 /* AMB Mem Mapped Reg Region Base */
90fcaf780bSMauro Carvalho Chehab #define MAXCH			0x56 /* Max Channel Number */
91fcaf780bSMauro Carvalho Chehab #define MAXDIMMPERCH		0x57 /* Max DIMM PER Channel Number */
92fcaf780bSMauro Carvalho Chehab 
93fcaf780bSMauro Carvalho Chehab 	/* OFFSETS for Function 1 */
94af3d8831SMauro Carvalho Chehab #define MC_SETTINGS		0x40
95d7de2bdbSMauro Carvalho Chehab   #define IS_MIRRORED(mc)		((mc) & (1 << 16))
96d7de2bdbSMauro Carvalho Chehab   #define IS_ECC_ENABLED(mc)		((mc) & (1 << 5))
97d7de2bdbSMauro Carvalho Chehab   #define IS_RETRY_ENABLED(mc)		((mc) & (1 << 31))
98d7de2bdbSMauro Carvalho Chehab   #define IS_SCRBALGO_ENHANCED(mc)	((mc) & (1 << 8))
99d7de2bdbSMauro Carvalho Chehab 
100bb81a216SMauro Carvalho Chehab #define MC_SETTINGS_A		0x58
101bb81a216SMauro Carvalho Chehab   #define IS_SINGLE_MODE(mca)		((mca) & (1 << 14))
102d7de2bdbSMauro Carvalho Chehab 
103fcaf780bSMauro Carvalho Chehab #define TOLM			0x6C
104fcaf780bSMauro Carvalho Chehab #define REDMEMB			0x7C
105fcaf780bSMauro Carvalho Chehab 
106fcaf780bSMauro Carvalho Chehab #define MIR0			0x80
107fcaf780bSMauro Carvalho Chehab #define MIR1			0x84
108fcaf780bSMauro Carvalho Chehab #define MIR2			0x88
109fcaf780bSMauro Carvalho Chehab 
110fcaf780bSMauro Carvalho Chehab /*
111fcaf780bSMauro Carvalho Chehab  * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available
112fcaf780bSMauro Carvalho Chehab  * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it
113fcaf780bSMauro Carvalho Chehab  * seems that we cannot use this information directly for the same usage.
114fcaf780bSMauro Carvalho Chehab  * Each memory slot may have up to 2 AMB interfaces, one for income and another
115fcaf780bSMauro Carvalho Chehab  * for outcome interface to the next slot.
116fcaf780bSMauro Carvalho Chehab  * For now, the driver just stores the AMB present registers, but rely only at
117fcaf780bSMauro Carvalho Chehab  * the MTR info to detect memory.
118fcaf780bSMauro Carvalho Chehab  * Datasheet is also not clear about how to map each AMBPRESENT registers to
119fcaf780bSMauro Carvalho Chehab  * one of the 4 available channels.
120fcaf780bSMauro Carvalho Chehab  */
121fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_0	0x64
122fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_1	0x66
123fcaf780bSMauro Carvalho Chehab 
124fcaf780bSMauro Carvalho Chehab const static u16 mtr_regs [MAX_SLOTS] = {
125fcaf780bSMauro Carvalho Chehab 	0x80, 0x84, 0x88, 0x8c,
126fcaf780bSMauro Carvalho Chehab 	0x82, 0x86, 0x8a, 0x8e
127fcaf780bSMauro Carvalho Chehab };
128fcaf780bSMauro Carvalho Chehab 
129fcaf780bSMauro Carvalho Chehab /* Defines to extract the vaious fields from the
130fcaf780bSMauro Carvalho Chehab  *	MTRx - Memory Technology Registers
131fcaf780bSMauro Carvalho Chehab  */
132fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_PRESENT(mtr)		((mtr) & (1 << 8))
133fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_ETHROTTLE(mtr)	((mtr) & (1 << 7))
134fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_WIDTH(mtr)		(((mtr) & (1 << 6)) ? 8 : 4)
135fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS(mtr)		(((mtr) & (1 << 5)) ? 8 : 4)
136fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_RANKS(mtr)		(((mtr) & (1 << 4)) ? 1 : 0)
137fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS(mtr)		(((mtr) >> 2) & 0x3)
138fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS_ADDR_BITS	2
139fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS_ADDR_BITS(mtr)	(MTR_DIMM_ROWS(mtr) + 13)
140fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
141fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
142fcaf780bSMauro Carvalho Chehab 
143fcaf780bSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG
144fcaf780bSMauro Carvalho Chehab /* MTR NUMROW */
145fcaf780bSMauro Carvalho Chehab static const char *numrow_toString[] = {
146fcaf780bSMauro Carvalho Chehab 	"8,192 - 13 rows",
147fcaf780bSMauro Carvalho Chehab 	"16,384 - 14 rows",
148fcaf780bSMauro Carvalho Chehab 	"32,768 - 15 rows",
149fcaf780bSMauro Carvalho Chehab 	"65,536 - 16 rows"
150fcaf780bSMauro Carvalho Chehab };
151fcaf780bSMauro Carvalho Chehab 
152fcaf780bSMauro Carvalho Chehab /* MTR NUMCOL */
153fcaf780bSMauro Carvalho Chehab static const char *numcol_toString[] = {
154fcaf780bSMauro Carvalho Chehab 	"1,024 - 10 columns",
155fcaf780bSMauro Carvalho Chehab 	"2,048 - 11 columns",
156fcaf780bSMauro Carvalho Chehab 	"4,096 - 12 columns",
157fcaf780bSMauro Carvalho Chehab 	"reserved"
158fcaf780bSMauro Carvalho Chehab };
159fcaf780bSMauro Carvalho Chehab #endif
160fcaf780bSMauro Carvalho Chehab 
161c3af2eafSMauro Carvalho Chehab /************************************************
162c3af2eafSMauro Carvalho Chehab  * i7300 Register definitions for error detection
163c3af2eafSMauro Carvalho Chehab  ************************************************/
16457021918SMauro Carvalho Chehab 
16557021918SMauro Carvalho Chehab /*
16657021918SMauro Carvalho Chehab  * Device 16.1: FBD Error Registers
16757021918SMauro Carvalho Chehab  */
16857021918SMauro Carvalho Chehab #define FERR_FAT_FBD	0x98
16957021918SMauro Carvalho Chehab static const char *ferr_fat_fbd_name[] = {
17057021918SMauro Carvalho Chehab 	[22] = "Non-Redundant Fast Reset Timeout",
17157021918SMauro Carvalho Chehab 	[2]  = ">Tmid Thermal event with intelligent throttling disabled",
17257021918SMauro Carvalho Chehab 	[1]  = "Memory or FBD configuration CRC read error",
17357021918SMauro Carvalho Chehab 	[0]  = "Memory Write error on non-redundant retry or "
17457021918SMauro Carvalho Chehab 	       "FBD configuration Write error on retry",
17557021918SMauro Carvalho Chehab };
17657021918SMauro Carvalho Chehab #define GET_FBD_FAT_IDX(fbderr)	(fbderr & (3 << 28))
17757021918SMauro Carvalho Chehab #define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
17857021918SMauro Carvalho Chehab 
17957021918SMauro Carvalho Chehab #define FERR_NF_FBD	0xa0
18057021918SMauro Carvalho Chehab static const char *ferr_nf_fbd_name[] = {
18157021918SMauro Carvalho Chehab 	[24] = "DIMM-Spare Copy Completed",
18257021918SMauro Carvalho Chehab 	[23] = "DIMM-Spare Copy Initiated",
18357021918SMauro Carvalho Chehab 	[22] = "Redundant Fast Reset Timeout",
18457021918SMauro Carvalho Chehab 	[21] = "Memory Write error on redundant retry",
18557021918SMauro Carvalho Chehab 	[18] = "SPD protocol Error",
18657021918SMauro Carvalho Chehab 	[17] = "FBD Northbound parity error on FBD Sync Status",
18757021918SMauro Carvalho Chehab 	[16] = "Correctable Patrol Data ECC",
18857021918SMauro Carvalho Chehab 	[15] = "Correctable Resilver- or Spare-Copy Data ECC",
18957021918SMauro Carvalho Chehab 	[14] = "Correctable Mirrored Demand Data ECC",
19057021918SMauro Carvalho Chehab 	[13] = "Correctable Non-Mirrored Demand Data ECC",
19157021918SMauro Carvalho Chehab 	[11] = "Memory or FBD configuration CRC read error",
19257021918SMauro Carvalho Chehab 	[10] = "FBD Configuration Write error on first attempt",
19357021918SMauro Carvalho Chehab 	[9]  = "Memory Write error on first attempt",
19457021918SMauro Carvalho Chehab 	[8]  = "Non-Aliased Uncorrectable Patrol Data ECC",
19557021918SMauro Carvalho Chehab 	[7]  = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
19657021918SMauro Carvalho Chehab 	[6]  = "Non-Aliased Uncorrectable Mirrored Demand Data ECC",
19757021918SMauro Carvalho Chehab 	[5]  = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC",
19857021918SMauro Carvalho Chehab 	[4]  = "Aliased Uncorrectable Patrol Data ECC",
19957021918SMauro Carvalho Chehab 	[3]  = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
20057021918SMauro Carvalho Chehab 	[2]  = "Aliased Uncorrectable Mirrored Demand Data ECC",
20157021918SMauro Carvalho Chehab 	[1]  = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
20257021918SMauro Carvalho Chehab 	[0]  = "Uncorrectable Data ECC on Replay",
20357021918SMauro Carvalho Chehab };
20457021918SMauro Carvalho Chehab #define GET_FBD_NF_IDX(fbderr)	(fbderr & (3 << 28))
20557021918SMauro Carvalho Chehab #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
20657021918SMauro Carvalho Chehab 			      (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
20757021918SMauro Carvalho Chehab 			      (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
20857021918SMauro Carvalho Chehab 			      (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
20957021918SMauro Carvalho Chehab 			      (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
21057021918SMauro Carvalho Chehab 			      (1 << 1)  | (1 << 0))
21157021918SMauro Carvalho Chehab 
21257021918SMauro Carvalho Chehab #define EMASK_FBD	0xa8
21357021918SMauro Carvalho Chehab #define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\
21457021918SMauro Carvalho Chehab 			    (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\
21557021918SMauro Carvalho Chehab 			    (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\
21657021918SMauro Carvalho Chehab 			    (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\
21757021918SMauro Carvalho Chehab 			    (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
21857021918SMauro Carvalho Chehab 			    (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
21957021918SMauro Carvalho Chehab 			    (1 << 1)  | (1 << 0))
22057021918SMauro Carvalho Chehab 
221c3af2eafSMauro Carvalho Chehab /*
222c3af2eafSMauro Carvalho Chehab  * Device 16.2: Global Error Registers
223c3af2eafSMauro Carvalho Chehab  */
224c3af2eafSMauro Carvalho Chehab 
2255de6e07eSMauro Carvalho Chehab #define FERR_GLOBAL_HI	0x48
2265de6e07eSMauro Carvalho Chehab static const char *ferr_global_hi_name[] = {
2275de6e07eSMauro Carvalho Chehab 	[3] = "FSB 3 Fatal Error",
2285de6e07eSMauro Carvalho Chehab 	[2] = "FSB 2 Fatal Error",
2295de6e07eSMauro Carvalho Chehab 	[1] = "FSB 1 Fatal Error",
2305de6e07eSMauro Carvalho Chehab 	[0] = "FSB 0 Fatal Error",
2315de6e07eSMauro Carvalho Chehab };
2325de6e07eSMauro Carvalho Chehab #define ferr_global_hi_is_fatal(errno)	1
2335de6e07eSMauro Carvalho Chehab 
234c3af2eafSMauro Carvalho Chehab #define FERR_GLOBAL_LO	0x40
2355de6e07eSMauro Carvalho Chehab static const char *ferr_global_lo_name[] = {
236c3af2eafSMauro Carvalho Chehab 	[31] = "Internal MCH Fatal Error",
237c3af2eafSMauro Carvalho Chehab 	[30] = "Intel QuickData Technology Device Fatal Error",
238c3af2eafSMauro Carvalho Chehab 	[29] = "FSB1 Fatal Error",
239c3af2eafSMauro Carvalho Chehab 	[28] = "FSB0 Fatal Error",
240c3af2eafSMauro Carvalho Chehab 	[27] = "FBD Channel 3 Fatal Error",
241c3af2eafSMauro Carvalho Chehab 	[26] = "FBD Channel 2 Fatal Error",
242c3af2eafSMauro Carvalho Chehab 	[25] = "FBD Channel 1 Fatal Error",
243c3af2eafSMauro Carvalho Chehab 	[24] = "FBD Channel 0 Fatal Error",
244c3af2eafSMauro Carvalho Chehab 	[23] = "PCI Express Device 7Fatal Error",
245c3af2eafSMauro Carvalho Chehab 	[22] = "PCI Express Device 6 Fatal Error",
246c3af2eafSMauro Carvalho Chehab 	[21] = "PCI Express Device 5 Fatal Error",
247c3af2eafSMauro Carvalho Chehab 	[20] = "PCI Express Device 4 Fatal Error",
248c3af2eafSMauro Carvalho Chehab 	[19] = "PCI Express Device 3 Fatal Error",
249c3af2eafSMauro Carvalho Chehab 	[18] = "PCI Express Device 2 Fatal Error",
250c3af2eafSMauro Carvalho Chehab 	[17] = "PCI Express Device 1 Fatal Error",
251c3af2eafSMauro Carvalho Chehab 	[16] = "ESI Fatal Error",
252c3af2eafSMauro Carvalho Chehab 	[15] = "Internal MCH Non-Fatal Error",
253c3af2eafSMauro Carvalho Chehab 	[14] = "Intel QuickData Technology Device Non Fatal Error",
254c3af2eafSMauro Carvalho Chehab 	[13] = "FSB1 Non-Fatal Error",
255c3af2eafSMauro Carvalho Chehab 	[12] = "FSB 0 Non-Fatal Error",
256c3af2eafSMauro Carvalho Chehab 	[11] = "FBD Channel 3 Non-Fatal Error",
257c3af2eafSMauro Carvalho Chehab 	[10] = "FBD Channel 2 Non-Fatal Error",
258c3af2eafSMauro Carvalho Chehab 	[9]  = "FBD Channel 1 Non-Fatal Error",
259c3af2eafSMauro Carvalho Chehab 	[8]  = "FBD Channel 0 Non-Fatal Error",
260c3af2eafSMauro Carvalho Chehab 	[7]  = "PCI Express Device 7 Non-Fatal Error",
261c3af2eafSMauro Carvalho Chehab 	[6]  = "PCI Express Device 6 Non-Fatal Error",
262c3af2eafSMauro Carvalho Chehab 	[5]  = "PCI Express Device 5 Non-Fatal Error",
263c3af2eafSMauro Carvalho Chehab 	[4]  = "PCI Express Device 4 Non-Fatal Error",
264c3af2eafSMauro Carvalho Chehab 	[3]  = "PCI Express Device 3 Non-Fatal Error",
265c3af2eafSMauro Carvalho Chehab 	[2]  = "PCI Express Device 2 Non-Fatal Error",
266c3af2eafSMauro Carvalho Chehab 	[1]  = "PCI Express Device 1 Non-Fatal Error",
267c3af2eafSMauro Carvalho Chehab 	[0]  = "ESI Non-Fatal Error",
268c3af2eafSMauro Carvalho Chehab };
2695de6e07eSMauro Carvalho Chehab #define ferr_global_lo_is_fatal(errno)	((errno < 16) ? 0 : 1)
270fcaf780bSMauro Carvalho Chehab 
271fcaf780bSMauro Carvalho Chehab /* Device name and register DID (Device ID) */
272fcaf780bSMauro Carvalho Chehab struct i7300_dev_info {
273fcaf780bSMauro Carvalho Chehab 	const char *ctl_name;	/* name for this device */
274fcaf780bSMauro Carvalho Chehab 	u16 fsb_mapping_errors;	/* DID for the branchmap,control */
275fcaf780bSMauro Carvalho Chehab };
276fcaf780bSMauro Carvalho Chehab 
277fcaf780bSMauro Carvalho Chehab /* Table of devices attributes supported by this driver */
278fcaf780bSMauro Carvalho Chehab static const struct i7300_dev_info i7300_devs[] = {
279fcaf780bSMauro Carvalho Chehab 	{
280fcaf780bSMauro Carvalho Chehab 		.ctl_name = "I7300",
281fcaf780bSMauro Carvalho Chehab 		.fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
282fcaf780bSMauro Carvalho Chehab 	},
283fcaf780bSMauro Carvalho Chehab };
284fcaf780bSMauro Carvalho Chehab 
285fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info {
286fcaf780bSMauro Carvalho Chehab 	int megabytes;		/* size, 0 means not present  */
287fcaf780bSMauro Carvalho Chehab };
288fcaf780bSMauro Carvalho Chehab 
289fcaf780bSMauro Carvalho Chehab /* driver private data structure */
290fcaf780bSMauro Carvalho Chehab struct i7300_pvt {
2913e57eef6SMauro Carvalho Chehab 	struct pci_dev *pci_dev_16_0_fsb_ctlr;		/* 16.0 */
2923e57eef6SMauro Carvalho Chehab 	struct pci_dev *pci_dev_16_1_fsb_addr_map;	/* 16.1 */
2933e57eef6SMauro Carvalho Chehab 	struct pci_dev *pci_dev_16_2_fsb_err_regs;	/* 16.2 */
2943e57eef6SMauro Carvalho Chehab 	struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES];	/* 21.0  and 22.0 */
295fcaf780bSMauro Carvalho Chehab 
296fcaf780bSMauro Carvalho Chehab 	u16 tolm;				/* top of low memory */
297fcaf780bSMauro Carvalho Chehab 	u64 ambase;				/* AMB BAR */
298fcaf780bSMauro Carvalho Chehab 
299bb81a216SMauro Carvalho Chehab 	u32 mc_settings;			/* Report several settings */
300bb81a216SMauro Carvalho Chehab 	u32 mc_settings_a;
301bb81a216SMauro Carvalho Chehab 
302bb81a216SMauro Carvalho Chehab 	u16 mir[MAX_MIR];			/* Memory Interleave Reg*/
303fcaf780bSMauro Carvalho Chehab 
304fcaf780bSMauro Carvalho Chehab 	u16 mtr[MAX_SLOTS][MAX_BRANCHES];		/* Memory Technlogy Reg */
305fcaf780bSMauro Carvalho Chehab 	u16 ambpresent[MAX_CHANNELS];		/* AMB present regs */
306fcaf780bSMauro Carvalho Chehab 
307fcaf780bSMauro Carvalho Chehab 	/* DIMM information matrix, allocating architecture maximums */
308fcaf780bSMauro Carvalho Chehab 	struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS];
309*85580ea4SMauro Carvalho Chehab 
310*85580ea4SMauro Carvalho Chehab 	/* Temporary buffer for use when preparing error messages */
311*85580ea4SMauro Carvalho Chehab 	char *tmp_prt_buffer;
312fcaf780bSMauro Carvalho Chehab };
313fcaf780bSMauro Carvalho Chehab 
314fcaf780bSMauro Carvalho Chehab /* FIXME: Why do we need to have this static? */
315fcaf780bSMauro Carvalho Chehab static struct edac_pci_ctl_info *i7300_pci;
316fcaf780bSMauro Carvalho Chehab 
3175de6e07eSMauro Carvalho Chehab /********************************************
3185de6e07eSMauro Carvalho Chehab  * i7300 Functions related to error detection
3195de6e07eSMauro Carvalho Chehab  ********************************************/
320fcaf780bSMauro Carvalho Chehab 
3215de6e07eSMauro Carvalho Chehab const char *get_err_from_table(const char *table[], int size, int pos)
322fcaf780bSMauro Carvalho Chehab {
3235de6e07eSMauro Carvalho Chehab 	if (pos >= size)
3245de6e07eSMauro Carvalho Chehab 		return "Reserved";
3255de6e07eSMauro Carvalho Chehab 
3265de6e07eSMauro Carvalho Chehab 	return table[pos];
327fcaf780bSMauro Carvalho Chehab }
3285de6e07eSMauro Carvalho Chehab 
3295de6e07eSMauro Carvalho Chehab #define GET_ERR_FROM_TABLE(table, pos)				\
3305de6e07eSMauro Carvalho Chehab 	get_err_from_table(table, ARRAY_SIZE(table), pos)
331fcaf780bSMauro Carvalho Chehab 
332fcaf780bSMauro Carvalho Chehab /*
3335de6e07eSMauro Carvalho Chehab  *	i7300_process_error_global Retrieve the hardware error information from
3345de6e07eSMauro Carvalho Chehab  *				the hardware and cache it in the 'info'
3355de6e07eSMauro Carvalho Chehab  *				structure
3365de6e07eSMauro Carvalho Chehab  */
337f4277422SMauro Carvalho Chehab static void i7300_process_error_global(struct mem_ctl_info *mci)
3385de6e07eSMauro Carvalho Chehab {
339fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
3405de6e07eSMauro Carvalho Chehab 	u32 errnum, value;
3415de6e07eSMauro Carvalho Chehab 	unsigned long errors;
3425de6e07eSMauro Carvalho Chehab 	const char *specific;
3435de6e07eSMauro Carvalho Chehab 	bool is_fatal;
344fcaf780bSMauro Carvalho Chehab 
345fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
346fcaf780bSMauro Carvalho Chehab 
347fcaf780bSMauro Carvalho Chehab 	/* read in the 1st FATAL error register */
3485de6e07eSMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3495de6e07eSMauro Carvalho Chehab 			      FERR_GLOBAL_HI, &value);
3505de6e07eSMauro Carvalho Chehab 	if (unlikely(value)) {
3515de6e07eSMauro Carvalho Chehab 		errors = value;
3525de6e07eSMauro Carvalho Chehab 		errnum = find_first_bit(&errors,
3535de6e07eSMauro Carvalho Chehab 					ARRAY_SIZE(ferr_global_hi_name));
3545de6e07eSMauro Carvalho Chehab 		specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum);
3555de6e07eSMauro Carvalho Chehab 		is_fatal = ferr_global_hi_is_fatal(errnum);
35686002324SMauro Carvalho Chehab 
35786002324SMauro Carvalho Chehab 		/* Clear the error bit */
35886002324SMauro Carvalho Chehab 		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
35986002324SMauro Carvalho Chehab 				       FERR_GLOBAL_HI, value);
36086002324SMauro Carvalho Chehab 
3615de6e07eSMauro Carvalho Chehab 		goto error_global;
362fcaf780bSMauro Carvalho Chehab 	}
363fcaf780bSMauro Carvalho Chehab 
3645de6e07eSMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
3655de6e07eSMauro Carvalho Chehab 			      FERR_GLOBAL_LO, &value);
3665de6e07eSMauro Carvalho Chehab 	if (unlikely(value)) {
3675de6e07eSMauro Carvalho Chehab 		errors = value;
3685de6e07eSMauro Carvalho Chehab 		errnum = find_first_bit(&errors,
3695de6e07eSMauro Carvalho Chehab 					ARRAY_SIZE(ferr_global_lo_name));
3705de6e07eSMauro Carvalho Chehab 		specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum);
3715de6e07eSMauro Carvalho Chehab 		is_fatal = ferr_global_lo_is_fatal(errnum);
37286002324SMauro Carvalho Chehab 
37386002324SMauro Carvalho Chehab 		/* Clear the error bit */
37486002324SMauro Carvalho Chehab 		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
37586002324SMauro Carvalho Chehab 				       FERR_GLOBAL_LO, value);
37686002324SMauro Carvalho Chehab 
3775de6e07eSMauro Carvalho Chehab 		goto error_global;
378fcaf780bSMauro Carvalho Chehab 	}
379fcaf780bSMauro Carvalho Chehab 	return;
380fcaf780bSMauro Carvalho Chehab 
3815de6e07eSMauro Carvalho Chehab error_global:
3825de6e07eSMauro Carvalho Chehab 	i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n",
3835de6e07eSMauro Carvalho Chehab 			is_fatal ? "Fatal" : "NOT fatal", specific);
384fcaf780bSMauro Carvalho Chehab }
385fcaf780bSMauro Carvalho Chehab 
386fcaf780bSMauro Carvalho Chehab /*
38757021918SMauro Carvalho Chehab  *	i7300_process_fbd_error Retrieve the hardware error information from
38857021918SMauro Carvalho Chehab  *				the hardware and cache it in the 'info'
38957021918SMauro Carvalho Chehab  *				structure
39057021918SMauro Carvalho Chehab  */
391f4277422SMauro Carvalho Chehab static void i7300_process_fbd_error(struct mem_ctl_info *mci)
39257021918SMauro Carvalho Chehab {
39357021918SMauro Carvalho Chehab 	struct i7300_pvt *pvt;
39457021918SMauro Carvalho Chehab 	u32 errnum, value;
39557021918SMauro Carvalho Chehab 	int branch;
39657021918SMauro Carvalho Chehab 	unsigned long errors;
39757021918SMauro Carvalho Chehab 	const char *specific;
39857021918SMauro Carvalho Chehab 	bool is_fatal;
39957021918SMauro Carvalho Chehab 
40057021918SMauro Carvalho Chehab 	pvt = mci->pvt_info;
40157021918SMauro Carvalho Chehab 
40257021918SMauro Carvalho Chehab 	/* read in the 1st FATAL error register */
40357021918SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
40457021918SMauro Carvalho Chehab 			      FERR_FAT_FBD, &value);
40557021918SMauro Carvalho Chehab 	if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) {
40657021918SMauro Carvalho Chehab 		errors = value & FERR_FAT_FBD_ERR_MASK ;
40757021918SMauro Carvalho Chehab 		errnum = find_first_bit(&errors,
40857021918SMauro Carvalho Chehab 					ARRAY_SIZE(ferr_fat_fbd_name));
40957021918SMauro Carvalho Chehab 		specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
41057021918SMauro Carvalho Chehab 		is_fatal = 1;
41157021918SMauro Carvalho Chehab 
41257021918SMauro Carvalho Chehab 		branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
41357021918SMauro Carvalho Chehab 
41457021918SMauro Carvalho Chehab 		goto error_fbd;
41557021918SMauro Carvalho Chehab 	}
41657021918SMauro Carvalho Chehab 
41757021918SMauro Carvalho Chehab 	/* read in the 1st NON-FATAL error register */
41857021918SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
41957021918SMauro Carvalho Chehab 			      FERR_NF_FBD, &value);
42057021918SMauro Carvalho Chehab 	if (unlikely(value & FERR_NF_FBD_ERR_MASK)) {
42157021918SMauro Carvalho Chehab 		errors = value & FERR_NF_FBD_ERR_MASK;
42257021918SMauro Carvalho Chehab 		errnum = find_first_bit(&errors,
42357021918SMauro Carvalho Chehab 					ARRAY_SIZE(ferr_nf_fbd_name));
42457021918SMauro Carvalho Chehab 		specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
42557021918SMauro Carvalho Chehab 		is_fatal = 0;
42657021918SMauro Carvalho Chehab 
42757021918SMauro Carvalho Chehab 		/* Clear the error bit */
42857021918SMauro Carvalho Chehab 		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
42957021918SMauro Carvalho Chehab 				       FERR_GLOBAL_LO, value);
43057021918SMauro Carvalho Chehab 
43157021918SMauro Carvalho Chehab 		goto error_fbd;
43257021918SMauro Carvalho Chehab 	}
43357021918SMauro Carvalho Chehab 	return;
43457021918SMauro Carvalho Chehab 
43557021918SMauro Carvalho Chehab error_fbd:
43657021918SMauro Carvalho Chehab 	i7300_mc_printk(mci, KERN_EMERG, "%s FBD error on branch %d: %s\n",
43757021918SMauro Carvalho Chehab 			is_fatal ? "Fatal" : "NOT fatal", branch, specific);
43857021918SMauro Carvalho Chehab }
43957021918SMauro Carvalho Chehab 
44057021918SMauro Carvalho Chehab /*
441f4277422SMauro Carvalho Chehab  *	i7300_check_error Retrieve the hardware error information from
4425de6e07eSMauro Carvalho Chehab  *				the hardware and cache it in the 'info'
4435de6e07eSMauro Carvalho Chehab  *				structure
444fcaf780bSMauro Carvalho Chehab  */
445f4277422SMauro Carvalho Chehab static void i7300_check_error(struct mem_ctl_info *mci)
4465de6e07eSMauro Carvalho Chehab {
447f4277422SMauro Carvalho Chehab 	i7300_process_error_global(mci);
448f4277422SMauro Carvalho Chehab 	i7300_process_fbd_error(mci);
4495de6e07eSMauro Carvalho Chehab };
450fcaf780bSMauro Carvalho Chehab 
451fcaf780bSMauro Carvalho Chehab /*
452fcaf780bSMauro Carvalho Chehab  *	i7300_clear_error	Retrieve any error from the hardware
453fcaf780bSMauro Carvalho Chehab  *				but do NOT process that error.
454fcaf780bSMauro Carvalho Chehab  *				Used for 'clearing' out of previous errors
455fcaf780bSMauro Carvalho Chehab  *				Called by the Core module.
456fcaf780bSMauro Carvalho Chehab  */
457fcaf780bSMauro Carvalho Chehab static void i7300_clear_error(struct mem_ctl_info *mci)
458fcaf780bSMauro Carvalho Chehab {
459e4327605SMauro Carvalho Chehab 	struct i7300_pvt *pvt = mci->pvt_info;
460e4327605SMauro Carvalho Chehab 	u32 value;
461e4327605SMauro Carvalho Chehab 	/*
462e4327605SMauro Carvalho Chehab 	 * All error values are RWC - we need to read and write 1 to the
463e4327605SMauro Carvalho Chehab 	 * bit that we want to cleanup
464e4327605SMauro Carvalho Chehab 	 */
465fcaf780bSMauro Carvalho Chehab 
466e4327605SMauro Carvalho Chehab 	/* Clear global error registers */
467e4327605SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
468e4327605SMauro Carvalho Chehab 			      FERR_GLOBAL_HI, &value);
469e4327605SMauro Carvalho Chehab 	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
470e4327605SMauro Carvalho Chehab 			      FERR_GLOBAL_HI, value);
471e4327605SMauro Carvalho Chehab 
472e4327605SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
473e4327605SMauro Carvalho Chehab 			      FERR_GLOBAL_LO, &value);
474e4327605SMauro Carvalho Chehab 	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
475e4327605SMauro Carvalho Chehab 			      FERR_GLOBAL_LO, value);
476e4327605SMauro Carvalho Chehab 
477e4327605SMauro Carvalho Chehab 	/* Clear FBD error registers */
478e4327605SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
479e4327605SMauro Carvalho Chehab 			      FERR_FAT_FBD, &value);
480e4327605SMauro Carvalho Chehab 	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
481e4327605SMauro Carvalho Chehab 			      FERR_FAT_FBD, value);
482e4327605SMauro Carvalho Chehab 
483e4327605SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
484e4327605SMauro Carvalho Chehab 			      FERR_NF_FBD, &value);
485e4327605SMauro Carvalho Chehab 	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
486e4327605SMauro Carvalho Chehab 			      FERR_NF_FBD, value);
487fcaf780bSMauro Carvalho Chehab }
488fcaf780bSMauro Carvalho Chehab 
489fcaf780bSMauro Carvalho Chehab /*
490fcaf780bSMauro Carvalho Chehab  *	i7300_enable_error_reporting
491fcaf780bSMauro Carvalho Chehab  *			Turn on the memory reporting features of the hardware
492fcaf780bSMauro Carvalho Chehab  */
493fcaf780bSMauro Carvalho Chehab static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
494fcaf780bSMauro Carvalho Chehab {
49557021918SMauro Carvalho Chehab 	struct i7300_pvt *pvt = mci->pvt_info;
49657021918SMauro Carvalho Chehab 	u32 fbd_error_mask;
49757021918SMauro Carvalho Chehab 
49857021918SMauro Carvalho Chehab 	/* Read the FBD Error Mask Register */
49957021918SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
50057021918SMauro Carvalho Chehab 			      EMASK_FBD, &fbd_error_mask);
50157021918SMauro Carvalho Chehab 
50257021918SMauro Carvalho Chehab 	/* Enable with a '0' */
50357021918SMauro Carvalho Chehab 	fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
50457021918SMauro Carvalho Chehab 
50557021918SMauro Carvalho Chehab 	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
50657021918SMauro Carvalho Chehab 			       EMASK_FBD, fbd_error_mask);
507fcaf780bSMauro Carvalho Chehab }
5085de6e07eSMauro Carvalho Chehab 
5095de6e07eSMauro Carvalho Chehab /************************************************
5105de6e07eSMauro Carvalho Chehab  * i7300 Functions related to memory enumberation
5115de6e07eSMauro Carvalho Chehab  ************************************************/
512fcaf780bSMauro Carvalho Chehab 
513fcaf780bSMauro Carvalho Chehab /*
514fcaf780bSMauro Carvalho Chehab  * determine_mtr(pvt, csrow, channel)
515fcaf780bSMauro Carvalho Chehab  *
516fcaf780bSMauro Carvalho Chehab  * return the proper MTR register as determine by the csrow and desired channel
517fcaf780bSMauro Carvalho Chehab  */
518fcaf780bSMauro Carvalho Chehab static int decode_mtr(struct i7300_pvt *pvt,
519fcaf780bSMauro Carvalho Chehab 		      int slot, int ch, int branch,
520fcaf780bSMauro Carvalho Chehab 		      struct i7300_dimm_info *dinfo,
521fcaf780bSMauro Carvalho Chehab 		      struct csrow_info *p_csrow)
522fcaf780bSMauro Carvalho Chehab {
523fcaf780bSMauro Carvalho Chehab 	int mtr, ans, addrBits, channel;
524fcaf780bSMauro Carvalho Chehab 
525fcaf780bSMauro Carvalho Chehab 	channel = to_channel(ch, branch);
526fcaf780bSMauro Carvalho Chehab 
527fcaf780bSMauro Carvalho Chehab 	mtr = pvt->mtr[slot][branch];
528fcaf780bSMauro Carvalho Chehab 	ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
529fcaf780bSMauro Carvalho Chehab 
530fcaf780bSMauro Carvalho Chehab 	debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n",
531fcaf780bSMauro Carvalho Chehab 		slot, channel,
532fcaf780bSMauro Carvalho Chehab 		ans ? "Present" : "NOT Present");
533fcaf780bSMauro Carvalho Chehab 
534fcaf780bSMauro Carvalho Chehab 	/* Determine if there is a DIMM present in this DIMM slot */
535fcaf780bSMauro Carvalho Chehab 
536fcaf780bSMauro Carvalho Chehab #if 0
537fcaf780bSMauro Carvalho Chehab 	if (!amb_present || !ans)
538fcaf780bSMauro Carvalho Chehab 		return 0;
539fcaf780bSMauro Carvalho Chehab #else
540fcaf780bSMauro Carvalho Chehab 	if (!ans)
541fcaf780bSMauro Carvalho Chehab 		return 0;
542fcaf780bSMauro Carvalho Chehab #endif
543fcaf780bSMauro Carvalho Chehab 
544fcaf780bSMauro Carvalho Chehab 	/* Start with the number of bits for a Bank
545fcaf780bSMauro Carvalho Chehab 	* on the DRAM */
546fcaf780bSMauro Carvalho Chehab 	addrBits = MTR_DRAM_BANKS_ADDR_BITS;
547fcaf780bSMauro Carvalho Chehab 	/* Add thenumber of ROW bits */
548fcaf780bSMauro Carvalho Chehab 	addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
549fcaf780bSMauro Carvalho Chehab 	/* add the number of COLUMN bits */
550fcaf780bSMauro Carvalho Chehab 	addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
551fcaf780bSMauro Carvalho Chehab 	/* add the number of RANK bits */
552fcaf780bSMauro Carvalho Chehab 	addrBits += MTR_DIMM_RANKS(mtr);
553fcaf780bSMauro Carvalho Chehab 
554fcaf780bSMauro Carvalho Chehab 	addrBits += 6;	/* add 64 bits per DIMM */
555fcaf780bSMauro Carvalho Chehab 	addrBits -= 20;	/* divide by 2^^20 */
556fcaf780bSMauro Carvalho Chehab 	addrBits -= 3;	/* 8 bits per bytes */
557fcaf780bSMauro Carvalho Chehab 
558fcaf780bSMauro Carvalho Chehab 	dinfo->megabytes = 1 << addrBits;
559fcaf780bSMauro Carvalho Chehab 
560fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
561fcaf780bSMauro Carvalho Chehab 
562fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tELECTRICAL THROTTLING is %s\n",
563fcaf780bSMauro Carvalho Chehab 		MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
564fcaf780bSMauro Carvalho Chehab 
565fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
566fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single");
567fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
568fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
569fcaf780bSMauro Carvalho Chehab 	debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
570fcaf780bSMauro Carvalho Chehab 
571fcaf780bSMauro Carvalho Chehab 	p_csrow->grain = 8;
572fcaf780bSMauro Carvalho Chehab 	p_csrow->nr_pages = dinfo->megabytes << 8;
573fcaf780bSMauro Carvalho Chehab 	p_csrow->mtype = MEM_FB_DDR2;
574116389edSMauro Carvalho Chehab 
575116389edSMauro Carvalho Chehab 	/*
57615154c57SMauro Carvalho Chehab 	 * The type of error detection actually depends of the
577116389edSMauro Carvalho Chehab 	 * mode of operation. When it is just one single memory chip, at
578116389edSMauro Carvalho Chehab 	 * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code.
57915154c57SMauro Carvalho Chehab 	 * In normal or mirrored mode, it uses Lockstep mode,
580116389edSMauro Carvalho Chehab 	 * with the possibility of using an extended algorithm for x8 memories
581116389edSMauro Carvalho Chehab 	 * See datasheet Sections 7.3.6 to 7.3.8
582116389edSMauro Carvalho Chehab 	 */
58315154c57SMauro Carvalho Chehab 
58415154c57SMauro Carvalho Chehab 	if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
58515154c57SMauro Carvalho Chehab 		p_csrow->edac_mode = EDAC_SECDED;
5863b330f67SMauro Carvalho Chehab 		debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
58715154c57SMauro Carvalho Chehab 	} else {
5883b330f67SMauro Carvalho Chehab 		debugf2("\t\tECC code is on Lockstep mode\n");
58928c2ce7cSMauro Carvalho Chehab 		if (MTR_DRAM_WIDTH(mtr) == 8)
590fcaf780bSMauro Carvalho Chehab 			p_csrow->edac_mode = EDAC_S8ECD8ED;
59115154c57SMauro Carvalho Chehab 		else
59215154c57SMauro Carvalho Chehab 			p_csrow->edac_mode = EDAC_S4ECD4ED;
59315154c57SMauro Carvalho Chehab 	}
594fcaf780bSMauro Carvalho Chehab 
595fcaf780bSMauro Carvalho Chehab 	/* ask what device type on this row */
59628c2ce7cSMauro Carvalho Chehab 	if (MTR_DRAM_WIDTH(mtr) == 8) {
5973b330f67SMauro Carvalho Chehab 		debugf2("\t\tScrub algorithm for x8 is on %s mode\n",
598d7de2bdbSMauro Carvalho Chehab 			IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
599d7de2bdbSMauro Carvalho Chehab 					    "enhanced" : "normal");
600d7de2bdbSMauro Carvalho Chehab 
601fcaf780bSMauro Carvalho Chehab 		p_csrow->dtype = DEV_X8;
602d7de2bdbSMauro Carvalho Chehab 	} else
603fcaf780bSMauro Carvalho Chehab 		p_csrow->dtype = DEV_X4;
604fcaf780bSMauro Carvalho Chehab 
605fcaf780bSMauro Carvalho Chehab 	return mtr;
606fcaf780bSMauro Carvalho Chehab }
607fcaf780bSMauro Carvalho Chehab 
608fcaf780bSMauro Carvalho Chehab /*
609fcaf780bSMauro Carvalho Chehab  *	print_dimm_size
610fcaf780bSMauro Carvalho Chehab  *
611fcaf780bSMauro Carvalho Chehab  *	also will output a DIMM matrix map, if debug is enabled, for viewing
612fcaf780bSMauro Carvalho Chehab  *	how the DIMMs are populated
613fcaf780bSMauro Carvalho Chehab  */
614fcaf780bSMauro Carvalho Chehab static void print_dimm_size(struct i7300_pvt *pvt)
615fcaf780bSMauro Carvalho Chehab {
616fcaf780bSMauro Carvalho Chehab 	struct i7300_dimm_info *dinfo;
617*85580ea4SMauro Carvalho Chehab 	char *p;
618fcaf780bSMauro Carvalho Chehab 	int space, n;
619fcaf780bSMauro Carvalho Chehab 	int channel, slot;
620fcaf780bSMauro Carvalho Chehab 
621fcaf780bSMauro Carvalho Chehab 	space = PAGE_SIZE;
622*85580ea4SMauro Carvalho Chehab 	p = pvt->tmp_prt_buffer;
623fcaf780bSMauro Carvalho Chehab 
624fcaf780bSMauro Carvalho Chehab 	n = snprintf(p, space, "              ");
625fcaf780bSMauro Carvalho Chehab 	p += n;
626fcaf780bSMauro Carvalho Chehab 	space -= n;
627fcaf780bSMauro Carvalho Chehab 	for (channel = 0; channel < MAX_CHANNELS; channel++) {
628fcaf780bSMauro Carvalho Chehab 		n = snprintf(p, space, "channel %d | ", channel);
629fcaf780bSMauro Carvalho Chehab 		p += n;
630fcaf780bSMauro Carvalho Chehab 		space -= n;
631fcaf780bSMauro Carvalho Chehab 	}
632*85580ea4SMauro Carvalho Chehab 	debugf2("%s\n", pvt->tmp_prt_buffer);
633*85580ea4SMauro Carvalho Chehab 	p = pvt->tmp_prt_buffer;
634fcaf780bSMauro Carvalho Chehab 	space = PAGE_SIZE;
635fcaf780bSMauro Carvalho Chehab 	n = snprintf(p, space, "-------------------------------"
636fcaf780bSMauro Carvalho Chehab 		               "------------------------------");
637fcaf780bSMauro Carvalho Chehab 	p += n;
638fcaf780bSMauro Carvalho Chehab 	space -= n;
639*85580ea4SMauro Carvalho Chehab 	debugf2("%s\n", pvt->tmp_prt_buffer);
640*85580ea4SMauro Carvalho Chehab 	p = pvt->tmp_prt_buffer;
641fcaf780bSMauro Carvalho Chehab 	space = PAGE_SIZE;
642fcaf780bSMauro Carvalho Chehab 
643fcaf780bSMauro Carvalho Chehab 	for (slot = 0; slot < MAX_SLOTS; slot++) {
644fcaf780bSMauro Carvalho Chehab 		n = snprintf(p, space, "csrow/SLOT %d  ", slot);
645fcaf780bSMauro Carvalho Chehab 		p += n;
646fcaf780bSMauro Carvalho Chehab 		space -= n;
647fcaf780bSMauro Carvalho Chehab 
648fcaf780bSMauro Carvalho Chehab 		for (channel = 0; channel < MAX_CHANNELS; channel++) {
649fcaf780bSMauro Carvalho Chehab 			dinfo = &pvt->dimm_info[slot][channel];
650fcaf780bSMauro Carvalho Chehab 			n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
651fcaf780bSMauro Carvalho Chehab 			p += n;
652fcaf780bSMauro Carvalho Chehab 			space -= n;
653fcaf780bSMauro Carvalho Chehab 		}
654fcaf780bSMauro Carvalho Chehab 
655*85580ea4SMauro Carvalho Chehab 		debugf2("%s\n", pvt->tmp_prt_buffer);
656*85580ea4SMauro Carvalho Chehab 		p = pvt->tmp_prt_buffer;
657fcaf780bSMauro Carvalho Chehab 		space = PAGE_SIZE;
658fcaf780bSMauro Carvalho Chehab 	}
659fcaf780bSMauro Carvalho Chehab 
660fcaf780bSMauro Carvalho Chehab 	n = snprintf(p, space, "-------------------------------"
661fcaf780bSMauro Carvalho Chehab 		               "------------------------------");
662fcaf780bSMauro Carvalho Chehab 	p += n;
663fcaf780bSMauro Carvalho Chehab 	space -= n;
664*85580ea4SMauro Carvalho Chehab 	debugf2("%s\n", pvt->tmp_prt_buffer);
665*85580ea4SMauro Carvalho Chehab 	p = pvt->tmp_prt_buffer;
666fcaf780bSMauro Carvalho Chehab 	space = PAGE_SIZE;
667fcaf780bSMauro Carvalho Chehab }
668fcaf780bSMauro Carvalho Chehab 
669fcaf780bSMauro Carvalho Chehab /*
670fcaf780bSMauro Carvalho Chehab  *	i7300_init_csrows	Initialize the 'csrows' table within
671fcaf780bSMauro Carvalho Chehab  *				the mci control	structure with the
672fcaf780bSMauro Carvalho Chehab  *				addressing of memory.
673fcaf780bSMauro Carvalho Chehab  *
674fcaf780bSMauro Carvalho Chehab  *	return:
675fcaf780bSMauro Carvalho Chehab  *		0	success
676fcaf780bSMauro Carvalho Chehab  *		1	no actual memory found on this MC
677fcaf780bSMauro Carvalho Chehab  */
678fcaf780bSMauro Carvalho Chehab static int i7300_init_csrows(struct mem_ctl_info *mci)
679fcaf780bSMauro Carvalho Chehab {
680fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
681fcaf780bSMauro Carvalho Chehab 	struct i7300_dimm_info *dinfo;
682fcaf780bSMauro Carvalho Chehab 	struct csrow_info *p_csrow;
683fcaf780bSMauro Carvalho Chehab 	int empty;
684fcaf780bSMauro Carvalho Chehab 	int mtr;
685fcaf780bSMauro Carvalho Chehab 	int ch, branch, slot, channel;
686fcaf780bSMauro Carvalho Chehab 
687fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
688fcaf780bSMauro Carvalho Chehab 
689fcaf780bSMauro Carvalho Chehab 	empty = 1;		/* Assume NO memory */
690fcaf780bSMauro Carvalho Chehab 
691fcaf780bSMauro Carvalho Chehab 	debugf2("Memory Technology Registers:\n");
692fcaf780bSMauro Carvalho Chehab 
693fcaf780bSMauro Carvalho Chehab 	/* Get the AMB present registers for the four channels */
694fcaf780bSMauro Carvalho Chehab 	for (branch = 0; branch < MAX_BRANCHES; branch++) {
695fcaf780bSMauro Carvalho Chehab 		/* Read and dump branch 0's MTRs */
696fcaf780bSMauro Carvalho Chehab 		channel = to_channel(0, branch);
6973e57eef6SMauro Carvalho Chehab 		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], AMBPRESENT_0,
698fcaf780bSMauro Carvalho Chehab 				&pvt->ambpresent[channel]);
699fcaf780bSMauro Carvalho Chehab 		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
700fcaf780bSMauro Carvalho Chehab 			channel, pvt->ambpresent[channel]);
701fcaf780bSMauro Carvalho Chehab 
702fcaf780bSMauro Carvalho Chehab 		channel = to_channel(1, branch);
7033e57eef6SMauro Carvalho Chehab 		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], AMBPRESENT_1,
704fcaf780bSMauro Carvalho Chehab 				&pvt->ambpresent[channel]);
705fcaf780bSMauro Carvalho Chehab 		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
706fcaf780bSMauro Carvalho Chehab 			channel, pvt->ambpresent[channel]);
707fcaf780bSMauro Carvalho Chehab 	}
708fcaf780bSMauro Carvalho Chehab 
709fcaf780bSMauro Carvalho Chehab 	/* Get the set of MTR[0-7] regs by each branch */
710fcaf780bSMauro Carvalho Chehab 	for (slot = 0; slot < MAX_SLOTS; slot++) {
711fcaf780bSMauro Carvalho Chehab 		int where = mtr_regs[slot];
712fcaf780bSMauro Carvalho Chehab 		for (branch = 0; branch < MAX_BRANCHES; branch++) {
7133e57eef6SMauro Carvalho Chehab 			pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
714fcaf780bSMauro Carvalho Chehab 					where,
715fcaf780bSMauro Carvalho Chehab 					&pvt->mtr[slot][branch]);
716fcaf780bSMauro Carvalho Chehab 			for (ch = 0; ch < MAX_BRANCHES; ch++) {
717fcaf780bSMauro Carvalho Chehab 				int channel = to_channel(ch, branch);
718fcaf780bSMauro Carvalho Chehab 
719fcaf780bSMauro Carvalho Chehab 				dinfo = &pvt->dimm_info[slot][channel];
720fcaf780bSMauro Carvalho Chehab 				p_csrow = &mci->csrows[slot];
721fcaf780bSMauro Carvalho Chehab 
722fcaf780bSMauro Carvalho Chehab 				mtr = decode_mtr(pvt, slot, ch, branch,
723fcaf780bSMauro Carvalho Chehab 							dinfo, p_csrow);
724fcaf780bSMauro Carvalho Chehab 				/* if no DIMMS on this row, continue */
725fcaf780bSMauro Carvalho Chehab 				if (!MTR_DIMMS_PRESENT(mtr))
726fcaf780bSMauro Carvalho Chehab 					continue;
727fcaf780bSMauro Carvalho Chehab 
728fcaf780bSMauro Carvalho Chehab 				p_csrow->csrow_idx = slot;
729fcaf780bSMauro Carvalho Chehab 
730fcaf780bSMauro Carvalho Chehab 				/* FAKE OUT VALUES, FIXME */
731fcaf780bSMauro Carvalho Chehab 				p_csrow->first_page = 0 + slot * 20;
732fcaf780bSMauro Carvalho Chehab 				p_csrow->last_page = 9 + slot * 20;
733fcaf780bSMauro Carvalho Chehab 				p_csrow->page_mask = 0xfff;
734fcaf780bSMauro Carvalho Chehab 
735fcaf780bSMauro Carvalho Chehab 				empty = 0;
736fcaf780bSMauro Carvalho Chehab 			}
737fcaf780bSMauro Carvalho Chehab 		}
738fcaf780bSMauro Carvalho Chehab 	}
739fcaf780bSMauro Carvalho Chehab 
740fcaf780bSMauro Carvalho Chehab 	return empty;
741fcaf780bSMauro Carvalho Chehab }
742fcaf780bSMauro Carvalho Chehab 
743fcaf780bSMauro Carvalho Chehab static void decode_mir(int mir_no, u16 mir[MAX_MIR])
744fcaf780bSMauro Carvalho Chehab {
745fcaf780bSMauro Carvalho Chehab 	if (mir[mir_no] & 3)
746fcaf780bSMauro Carvalho Chehab 		debugf2("MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n",
747fcaf780bSMauro Carvalho Chehab 			mir_no,
748fcaf780bSMauro Carvalho Chehab 			(mir[mir_no] >> 4) & 0xfff,
749fcaf780bSMauro Carvalho Chehab 			(mir[mir_no] & 1) ? "B0" : "",
750fcaf780bSMauro Carvalho Chehab 			(mir[mir_no] & 2) ? "B1": "");
751fcaf780bSMauro Carvalho Chehab }
752fcaf780bSMauro Carvalho Chehab 
753fcaf780bSMauro Carvalho Chehab /*
754fcaf780bSMauro Carvalho Chehab  *	i7300_get_mc_regs	read in the necessary registers and
755fcaf780bSMauro Carvalho Chehab  *				cache locally
756fcaf780bSMauro Carvalho Chehab  *
757fcaf780bSMauro Carvalho Chehab  *			Fills in the private data members
758fcaf780bSMauro Carvalho Chehab  */
759fcaf780bSMauro Carvalho Chehab static int i7300_get_mc_regs(struct mem_ctl_info *mci)
760fcaf780bSMauro Carvalho Chehab {
761fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
762fcaf780bSMauro Carvalho Chehab 	u32 actual_tolm;
763fcaf780bSMauro Carvalho Chehab 	int i, rc;
764fcaf780bSMauro Carvalho Chehab 
765fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
766fcaf780bSMauro Carvalho Chehab 
7673e57eef6SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
768fcaf780bSMauro Carvalho Chehab 			(u32 *) &pvt->ambase);
769fcaf780bSMauro Carvalho Chehab 
770fcaf780bSMauro Carvalho Chehab 	debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
771fcaf780bSMauro Carvalho Chehab 
772fcaf780bSMauro Carvalho Chehab 	/* Get the Branch Map regs */
7733e57eef6SMauro Carvalho Chehab 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
774fcaf780bSMauro Carvalho Chehab 	pvt->tolm >>= 12;
775fcaf780bSMauro Carvalho Chehab 	debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
776fcaf780bSMauro Carvalho Chehab 		pvt->tolm);
777fcaf780bSMauro Carvalho Chehab 
778fcaf780bSMauro Carvalho Chehab 	actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
779fcaf780bSMauro Carvalho Chehab 	debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
780fcaf780bSMauro Carvalho Chehab 		actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
781fcaf780bSMauro Carvalho Chehab 
782af3d8831SMauro Carvalho Chehab 	/* Get memory controller settings */
7833e57eef6SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
784af3d8831SMauro Carvalho Chehab 			     &pvt->mc_settings);
785bb81a216SMauro Carvalho Chehab 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A,
786bb81a216SMauro Carvalho Chehab 			     &pvt->mc_settings_a);
787d7de2bdbSMauro Carvalho Chehab 
788bb81a216SMauro Carvalho Chehab 	if (IS_SINGLE_MODE(pvt->mc_settings_a))
789bb81a216SMauro Carvalho Chehab 		debugf0("Memory controller operating on single mode\n");
790bb81a216SMauro Carvalho Chehab 	else
791af3d8831SMauro Carvalho Chehab 		debugf0("Memory controller operating on %s mode\n",
792d7de2bdbSMauro Carvalho Chehab 		IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored");
793bb81a216SMauro Carvalho Chehab 
794af3d8831SMauro Carvalho Chehab 	debugf0("Error detection is %s\n",
795d7de2bdbSMauro Carvalho Chehab 		IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
796d7de2bdbSMauro Carvalho Chehab 	debugf0("Retry is %s\n",
797d7de2bdbSMauro Carvalho Chehab 		IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
798af3d8831SMauro Carvalho Chehab 
799af3d8831SMauro Carvalho Chehab 	/* Get Memory Interleave Range registers */
8003e57eef6SMauro Carvalho Chehab 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0, &pvt->mir[0]);
8013e57eef6SMauro Carvalho Chehab 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1, &pvt->mir[1]);
8023e57eef6SMauro Carvalho Chehab 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2, &pvt->mir[2]);
803fcaf780bSMauro Carvalho Chehab 
804fcaf780bSMauro Carvalho Chehab 	/* Decode the MIR regs */
805fcaf780bSMauro Carvalho Chehab 	for (i = 0; i < MAX_MIR; i++)
806fcaf780bSMauro Carvalho Chehab 		decode_mir(i, pvt->mir);
807fcaf780bSMauro Carvalho Chehab 
808fcaf780bSMauro Carvalho Chehab 	rc = i7300_init_csrows(mci);
809fcaf780bSMauro Carvalho Chehab 	if (rc < 0)
810fcaf780bSMauro Carvalho Chehab 		return rc;
811fcaf780bSMauro Carvalho Chehab 
812fcaf780bSMauro Carvalho Chehab 	/* Go and determine the size of each DIMM and place in an
813fcaf780bSMauro Carvalho Chehab 	 * orderly matrix */
814fcaf780bSMauro Carvalho Chehab 	print_dimm_size(pvt);
815fcaf780bSMauro Carvalho Chehab 
816fcaf780bSMauro Carvalho Chehab 	return 0;
817fcaf780bSMauro Carvalho Chehab }
818fcaf780bSMauro Carvalho Chehab 
8195de6e07eSMauro Carvalho Chehab /*************************************************
8205de6e07eSMauro Carvalho Chehab  * i7300 Functions related to device probe/release
8215de6e07eSMauro Carvalho Chehab  *************************************************/
8225de6e07eSMauro Carvalho Chehab 
823fcaf780bSMauro Carvalho Chehab /*
824fcaf780bSMauro Carvalho Chehab  *	i7300_put_devices	'put' all the devices that we have
825fcaf780bSMauro Carvalho Chehab  *				reserved via 'get'
826fcaf780bSMauro Carvalho Chehab  */
827fcaf780bSMauro Carvalho Chehab static void i7300_put_devices(struct mem_ctl_info *mci)
828fcaf780bSMauro Carvalho Chehab {
829fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
830fcaf780bSMauro Carvalho Chehab 	int branch;
831fcaf780bSMauro Carvalho Chehab 
832fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
833fcaf780bSMauro Carvalho Chehab 
834fcaf780bSMauro Carvalho Chehab 	/* Decrement usage count for devices */
835fcaf780bSMauro Carvalho Chehab 	for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++)
8363e57eef6SMauro Carvalho Chehab 		pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]);
8373e57eef6SMauro Carvalho Chehab 	pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs);
8383e57eef6SMauro Carvalho Chehab 	pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map);
839fcaf780bSMauro Carvalho Chehab }
840fcaf780bSMauro Carvalho Chehab 
841fcaf780bSMauro Carvalho Chehab /*
842fcaf780bSMauro Carvalho Chehab  *	i7300_get_devices	Find and perform 'get' operation on the MCH's
843fcaf780bSMauro Carvalho Chehab  *			device/functions we want to reference for this driver
844fcaf780bSMauro Carvalho Chehab  *
845fcaf780bSMauro Carvalho Chehab  *			Need to 'get' device 16 func 1 and func 2
846fcaf780bSMauro Carvalho Chehab  */
847fcaf780bSMauro Carvalho Chehab static int i7300_get_devices(struct mem_ctl_info *mci, int dev_idx)
848fcaf780bSMauro Carvalho Chehab {
849fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
850fcaf780bSMauro Carvalho Chehab 	struct pci_dev *pdev;
851fcaf780bSMauro Carvalho Chehab 
852fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
853fcaf780bSMauro Carvalho Chehab 
854fcaf780bSMauro Carvalho Chehab 	/* Attempt to 'get' the MCH register we want */
855fcaf780bSMauro Carvalho Chehab 	pdev = NULL;
8563e57eef6SMauro Carvalho Chehab 	while (!pvt->pci_dev_16_1_fsb_addr_map || !pvt->pci_dev_16_2_fsb_err_regs) {
857fcaf780bSMauro Carvalho Chehab 		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
858fcaf780bSMauro Carvalho Chehab 				      PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
859fcaf780bSMauro Carvalho Chehab 		if (!pdev) {
860fcaf780bSMauro Carvalho Chehab 			/* End of list, leave */
861fcaf780bSMauro Carvalho Chehab 			i7300_printk(KERN_ERR,
862fcaf780bSMauro Carvalho Chehab 				"'system address,Process Bus' "
863fcaf780bSMauro Carvalho Chehab 				"device not found:"
864fcaf780bSMauro Carvalho Chehab 				"vendor 0x%x device 0x%x ERR funcs "
865fcaf780bSMauro Carvalho Chehab 				"(broken BIOS?)\n",
866fcaf780bSMauro Carvalho Chehab 				PCI_VENDOR_ID_INTEL,
867fcaf780bSMauro Carvalho Chehab 				PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
868fcaf780bSMauro Carvalho Chehab 			goto error;
869fcaf780bSMauro Carvalho Chehab 		}
870fcaf780bSMauro Carvalho Chehab 
871fcaf780bSMauro Carvalho Chehab 		/* Store device 16 funcs 1 and 2 */
872fcaf780bSMauro Carvalho Chehab 		switch (PCI_FUNC(pdev->devfn)) {
873fcaf780bSMauro Carvalho Chehab 		case 1:
8743e57eef6SMauro Carvalho Chehab 			pvt->pci_dev_16_1_fsb_addr_map = pdev;
875fcaf780bSMauro Carvalho Chehab 			break;
876fcaf780bSMauro Carvalho Chehab 		case 2:
8773e57eef6SMauro Carvalho Chehab 			pvt->pci_dev_16_2_fsb_err_regs = pdev;
878fcaf780bSMauro Carvalho Chehab 			break;
879fcaf780bSMauro Carvalho Chehab 		}
880fcaf780bSMauro Carvalho Chehab 	}
881fcaf780bSMauro Carvalho Chehab 
882fcaf780bSMauro Carvalho Chehab 	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
8833e57eef6SMauro Carvalho Chehab 		pci_name(pvt->pci_dev_16_0_fsb_ctlr),
8843e57eef6SMauro Carvalho Chehab 		pvt->pci_dev_16_0_fsb_ctlr->vendor, pvt->pci_dev_16_0_fsb_ctlr->device);
885fcaf780bSMauro Carvalho Chehab 	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
8863e57eef6SMauro Carvalho Chehab 		pci_name(pvt->pci_dev_16_1_fsb_addr_map),
8873e57eef6SMauro Carvalho Chehab 		pvt->pci_dev_16_1_fsb_addr_map->vendor, pvt->pci_dev_16_1_fsb_addr_map->device);
888fcaf780bSMauro Carvalho Chehab 	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
8893e57eef6SMauro Carvalho Chehab 		pci_name(pvt->pci_dev_16_2_fsb_err_regs),
8903e57eef6SMauro Carvalho Chehab 		pvt->pci_dev_16_2_fsb_err_regs->vendor, pvt->pci_dev_16_2_fsb_err_regs->device);
891fcaf780bSMauro Carvalho Chehab 
8923e57eef6SMauro Carvalho Chehab 	pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
893fcaf780bSMauro Carvalho Chehab 				            PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
894fcaf780bSMauro Carvalho Chehab 					    NULL);
8953e57eef6SMauro Carvalho Chehab 	if (!pvt->pci_dev_2x_0_fbd_branch[0]) {
896fcaf780bSMauro Carvalho Chehab 		i7300_printk(KERN_ERR,
897fcaf780bSMauro Carvalho Chehab 			"MC: 'BRANCH 0' device not found:"
898fcaf780bSMauro Carvalho Chehab 			"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
899fcaf780bSMauro Carvalho Chehab 			PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0);
900fcaf780bSMauro Carvalho Chehab 		goto error;
901fcaf780bSMauro Carvalho Chehab 	}
902fcaf780bSMauro Carvalho Chehab 
9033e57eef6SMauro Carvalho Chehab 	pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL,
904fcaf780bSMauro Carvalho Chehab 					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB1,
905fcaf780bSMauro Carvalho Chehab 					    NULL);
9063e57eef6SMauro Carvalho Chehab 	if (!pvt->pci_dev_2x_0_fbd_branch[1]) {
907fcaf780bSMauro Carvalho Chehab 		i7300_printk(KERN_ERR,
908fcaf780bSMauro Carvalho Chehab 			"MC: 'BRANCH 1' device not found:"
909fcaf780bSMauro Carvalho Chehab 			"vendor 0x%x device 0x%x Func 0 "
910fcaf780bSMauro Carvalho Chehab 			"(broken BIOS?)\n",
911fcaf780bSMauro Carvalho Chehab 			PCI_VENDOR_ID_INTEL,
912fcaf780bSMauro Carvalho Chehab 			PCI_DEVICE_ID_INTEL_I7300_MCH_FB1);
913fcaf780bSMauro Carvalho Chehab 		goto error;
914fcaf780bSMauro Carvalho Chehab 	}
915fcaf780bSMauro Carvalho Chehab 
916fcaf780bSMauro Carvalho Chehab 	return 0;
917fcaf780bSMauro Carvalho Chehab 
918fcaf780bSMauro Carvalho Chehab error:
919fcaf780bSMauro Carvalho Chehab 	i7300_put_devices(mci);
920fcaf780bSMauro Carvalho Chehab 	return -ENODEV;
921fcaf780bSMauro Carvalho Chehab }
922fcaf780bSMauro Carvalho Chehab 
923fcaf780bSMauro Carvalho Chehab /*
924fcaf780bSMauro Carvalho Chehab  *	i7300_probe1	Probe for ONE instance of device to see if it is
925fcaf780bSMauro Carvalho Chehab  *			present.
926fcaf780bSMauro Carvalho Chehab  *	return:
927fcaf780bSMauro Carvalho Chehab  *		0 for FOUND a device
928fcaf780bSMauro Carvalho Chehab  *		< 0 for error code
929fcaf780bSMauro Carvalho Chehab  */
930fcaf780bSMauro Carvalho Chehab static int i7300_probe1(struct pci_dev *pdev, int dev_idx)
931fcaf780bSMauro Carvalho Chehab {
932fcaf780bSMauro Carvalho Chehab 	struct mem_ctl_info *mci;
933fcaf780bSMauro Carvalho Chehab 	struct i7300_pvt *pvt;
934fcaf780bSMauro Carvalho Chehab 	int num_channels;
935fcaf780bSMauro Carvalho Chehab 	int num_dimms_per_channel;
936fcaf780bSMauro Carvalho Chehab 	int num_csrows;
937fcaf780bSMauro Carvalho Chehab 
938fcaf780bSMauro Carvalho Chehab 	if (dev_idx >= ARRAY_SIZE(i7300_devs))
939fcaf780bSMauro Carvalho Chehab 		return -EINVAL;
940fcaf780bSMauro Carvalho Chehab 
941fcaf780bSMauro Carvalho Chehab 	debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
942fcaf780bSMauro Carvalho Chehab 		__func__,
943fcaf780bSMauro Carvalho Chehab 		pdev->bus->number,
944fcaf780bSMauro Carvalho Chehab 		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
945fcaf780bSMauro Carvalho Chehab 
946fcaf780bSMauro Carvalho Chehab 	/* We only are looking for func 0 of the set */
947fcaf780bSMauro Carvalho Chehab 	if (PCI_FUNC(pdev->devfn) != 0)
948fcaf780bSMauro Carvalho Chehab 		return -ENODEV;
949fcaf780bSMauro Carvalho Chehab 
950fcaf780bSMauro Carvalho Chehab 	/* As we don't have a motherboard identification routine to determine
951fcaf780bSMauro Carvalho Chehab 	 * actual number of slots/dimms per channel, we thus utilize the
952fcaf780bSMauro Carvalho Chehab 	 * resource as specified by the chipset. Thus, we might have
953fcaf780bSMauro Carvalho Chehab 	 * have more DIMMs per channel than actually on the mobo, but this
954fcaf780bSMauro Carvalho Chehab 	 * allows the driver to support upto the chipset max, without
955fcaf780bSMauro Carvalho Chehab 	 * some fancy mobo determination.
956fcaf780bSMauro Carvalho Chehab 	 */
957fcaf780bSMauro Carvalho Chehab 	num_dimms_per_channel = MAX_SLOTS;
958fcaf780bSMauro Carvalho Chehab 	num_channels = MAX_CHANNELS;
959fcaf780bSMauro Carvalho Chehab 	num_csrows = MAX_SLOTS * MAX_CHANNELS;
960fcaf780bSMauro Carvalho Chehab 
961fcaf780bSMauro Carvalho Chehab 	debugf0("MC: %s(): Number of - Channels= %d  DIMMS= %d  CSROWS= %d\n",
962fcaf780bSMauro Carvalho Chehab 		__func__, num_channels, num_dimms_per_channel, num_csrows);
963fcaf780bSMauro Carvalho Chehab 
964fcaf780bSMauro Carvalho Chehab 	/* allocate a new MC control structure */
965fcaf780bSMauro Carvalho Chehab 	mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
966fcaf780bSMauro Carvalho Chehab 
967fcaf780bSMauro Carvalho Chehab 	if (mci == NULL)
968fcaf780bSMauro Carvalho Chehab 		return -ENOMEM;
969fcaf780bSMauro Carvalho Chehab 
970fcaf780bSMauro Carvalho Chehab 	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
971fcaf780bSMauro Carvalho Chehab 
972fcaf780bSMauro Carvalho Chehab 	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
973fcaf780bSMauro Carvalho Chehab 
974fcaf780bSMauro Carvalho Chehab 	pvt = mci->pvt_info;
9753e57eef6SMauro Carvalho Chehab 	pvt->pci_dev_16_0_fsb_ctlr = pdev;	/* Record this device in our private */
976fcaf780bSMauro Carvalho Chehab 
977*85580ea4SMauro Carvalho Chehab 	pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
978*85580ea4SMauro Carvalho Chehab 	if (!pvt->tmp_prt_buffer) {
979*85580ea4SMauro Carvalho Chehab 		edac_mc_free(mci);
980*85580ea4SMauro Carvalho Chehab 		return -ENOMEM;
981*85580ea4SMauro Carvalho Chehab 	}
982*85580ea4SMauro Carvalho Chehab 
983fcaf780bSMauro Carvalho Chehab 	/* 'get' the pci devices we want to reserve for our use */
984fcaf780bSMauro Carvalho Chehab 	if (i7300_get_devices(mci, dev_idx))
985fcaf780bSMauro Carvalho Chehab 		goto fail0;
986fcaf780bSMauro Carvalho Chehab 
987fcaf780bSMauro Carvalho Chehab 	mci->mc_idx = 0;
988fcaf780bSMauro Carvalho Chehab 	mci->mtype_cap = MEM_FLAG_FB_DDR2;
989fcaf780bSMauro Carvalho Chehab 	mci->edac_ctl_cap = EDAC_FLAG_NONE;
990fcaf780bSMauro Carvalho Chehab 	mci->edac_cap = EDAC_FLAG_NONE;
991fcaf780bSMauro Carvalho Chehab 	mci->mod_name = "i7300_edac.c";
992fcaf780bSMauro Carvalho Chehab 	mci->mod_ver = I7300_REVISION;
993fcaf780bSMauro Carvalho Chehab 	mci->ctl_name = i7300_devs[dev_idx].ctl_name;
994fcaf780bSMauro Carvalho Chehab 	mci->dev_name = pci_name(pdev);
995fcaf780bSMauro Carvalho Chehab 	mci->ctl_page_to_phys = NULL;
996fcaf780bSMauro Carvalho Chehab 
997fcaf780bSMauro Carvalho Chehab 	/* Set the function pointer to an actual operation function */
998fcaf780bSMauro Carvalho Chehab 	mci->edac_check = i7300_check_error;
999fcaf780bSMauro Carvalho Chehab 
1000fcaf780bSMauro Carvalho Chehab 	/* initialize the MC control structure 'csrows' table
1001fcaf780bSMauro Carvalho Chehab 	 * with the mapping and control information */
1002fcaf780bSMauro Carvalho Chehab 	if (i7300_get_mc_regs(mci)) {
1003fcaf780bSMauro Carvalho Chehab 		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
1004fcaf780bSMauro Carvalho Chehab 			"    because i7300_init_csrows() returned nonzero "
1005fcaf780bSMauro Carvalho Chehab 			"value\n");
1006fcaf780bSMauro Carvalho Chehab 		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
1007fcaf780bSMauro Carvalho Chehab 	} else {
1008fcaf780bSMauro Carvalho Chehab 		debugf1("MC: Enable error reporting now\n");
1009fcaf780bSMauro Carvalho Chehab 		i7300_enable_error_reporting(mci);
1010fcaf780bSMauro Carvalho Chehab 	}
1011fcaf780bSMauro Carvalho Chehab 
1012fcaf780bSMauro Carvalho Chehab 	/* add this new MC control structure to EDAC's list of MCs */
1013fcaf780bSMauro Carvalho Chehab 	if (edac_mc_add_mc(mci)) {
1014fcaf780bSMauro Carvalho Chehab 		debugf0("MC: " __FILE__
1015fcaf780bSMauro Carvalho Chehab 			": %s(): failed edac_mc_add_mc()\n", __func__);
1016fcaf780bSMauro Carvalho Chehab 		/* FIXME: perhaps some code should go here that disables error
1017fcaf780bSMauro Carvalho Chehab 		 * reporting if we just enabled it
1018fcaf780bSMauro Carvalho Chehab 		 */
1019fcaf780bSMauro Carvalho Chehab 		goto fail1;
1020fcaf780bSMauro Carvalho Chehab 	}
1021fcaf780bSMauro Carvalho Chehab 
1022fcaf780bSMauro Carvalho Chehab 	i7300_clear_error(mci);
1023fcaf780bSMauro Carvalho Chehab 
1024fcaf780bSMauro Carvalho Chehab 	/* allocating generic PCI control info */
1025fcaf780bSMauro Carvalho Chehab 	i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1026fcaf780bSMauro Carvalho Chehab 	if (!i7300_pci) {
1027fcaf780bSMauro Carvalho Chehab 		printk(KERN_WARNING
1028fcaf780bSMauro Carvalho Chehab 			"%s(): Unable to create PCI control\n",
1029fcaf780bSMauro Carvalho Chehab 			__func__);
1030fcaf780bSMauro Carvalho Chehab 		printk(KERN_WARNING
1031fcaf780bSMauro Carvalho Chehab 			"%s(): PCI error report via EDAC not setup\n",
1032fcaf780bSMauro Carvalho Chehab 			__func__);
1033fcaf780bSMauro Carvalho Chehab 	}
1034fcaf780bSMauro Carvalho Chehab 
1035fcaf780bSMauro Carvalho Chehab 	return 0;
1036fcaf780bSMauro Carvalho Chehab 
1037fcaf780bSMauro Carvalho Chehab 	/* Error exit unwinding stack */
1038fcaf780bSMauro Carvalho Chehab fail1:
1039fcaf780bSMauro Carvalho Chehab 
1040fcaf780bSMauro Carvalho Chehab 	i7300_put_devices(mci);
1041fcaf780bSMauro Carvalho Chehab 
1042fcaf780bSMauro Carvalho Chehab fail0:
1043*85580ea4SMauro Carvalho Chehab 	kfree(pvt->tmp_prt_buffer);
1044fcaf780bSMauro Carvalho Chehab 	edac_mc_free(mci);
1045fcaf780bSMauro Carvalho Chehab 	return -ENODEV;
1046fcaf780bSMauro Carvalho Chehab }
1047fcaf780bSMauro Carvalho Chehab 
1048fcaf780bSMauro Carvalho Chehab /*
1049fcaf780bSMauro Carvalho Chehab  *	i7300_init_one	constructor for one instance of device
1050fcaf780bSMauro Carvalho Chehab  *
1051fcaf780bSMauro Carvalho Chehab  * 	returns:
1052fcaf780bSMauro Carvalho Chehab  *		negative on error
1053fcaf780bSMauro Carvalho Chehab  *		count (>= 0)
1054fcaf780bSMauro Carvalho Chehab  */
1055fcaf780bSMauro Carvalho Chehab static int __devinit i7300_init_one(struct pci_dev *pdev,
1056fcaf780bSMauro Carvalho Chehab 				const struct pci_device_id *id)
1057fcaf780bSMauro Carvalho Chehab {
1058fcaf780bSMauro Carvalho Chehab 	int rc;
1059fcaf780bSMauro Carvalho Chehab 
1060fcaf780bSMauro Carvalho Chehab 	debugf0("MC: " __FILE__ ": %s()\n", __func__);
1061fcaf780bSMauro Carvalho Chehab 
1062fcaf780bSMauro Carvalho Chehab 	/* wake up device */
1063fcaf780bSMauro Carvalho Chehab 	rc = pci_enable_device(pdev);
1064fcaf780bSMauro Carvalho Chehab 	if (rc == -EIO)
1065fcaf780bSMauro Carvalho Chehab 		return rc;
1066fcaf780bSMauro Carvalho Chehab 
1067fcaf780bSMauro Carvalho Chehab 	/* now probe and enable the device */
1068fcaf780bSMauro Carvalho Chehab 	return i7300_probe1(pdev, id->driver_data);
1069fcaf780bSMauro Carvalho Chehab }
1070fcaf780bSMauro Carvalho Chehab 
1071fcaf780bSMauro Carvalho Chehab /*
1072fcaf780bSMauro Carvalho Chehab  *	i7300_remove_one	destructor for one instance of device
1073fcaf780bSMauro Carvalho Chehab  *
1074fcaf780bSMauro Carvalho Chehab  */
1075fcaf780bSMauro Carvalho Chehab static void __devexit i7300_remove_one(struct pci_dev *pdev)
1076fcaf780bSMauro Carvalho Chehab {
1077fcaf780bSMauro Carvalho Chehab 	struct mem_ctl_info *mci;
1078*85580ea4SMauro Carvalho Chehab 	char *tmp;
1079fcaf780bSMauro Carvalho Chehab 
1080fcaf780bSMauro Carvalho Chehab 	debugf0(__FILE__ ": %s()\n", __func__);
1081fcaf780bSMauro Carvalho Chehab 
1082fcaf780bSMauro Carvalho Chehab 	if (i7300_pci)
1083fcaf780bSMauro Carvalho Chehab 		edac_pci_release_generic_ctl(i7300_pci);
1084fcaf780bSMauro Carvalho Chehab 
1085fcaf780bSMauro Carvalho Chehab 	mci = edac_mc_del_mc(&pdev->dev);
1086fcaf780bSMauro Carvalho Chehab 	if (!mci)
1087fcaf780bSMauro Carvalho Chehab 		return;
1088fcaf780bSMauro Carvalho Chehab 
1089*85580ea4SMauro Carvalho Chehab 	tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer;
1090*85580ea4SMauro Carvalho Chehab 
1091fcaf780bSMauro Carvalho Chehab 	/* retrieve references to resources, and free those resources */
1092fcaf780bSMauro Carvalho Chehab 	i7300_put_devices(mci);
1093fcaf780bSMauro Carvalho Chehab 
1094*85580ea4SMauro Carvalho Chehab 	kfree(tmp);
1095fcaf780bSMauro Carvalho Chehab 	edac_mc_free(mci);
1096fcaf780bSMauro Carvalho Chehab }
1097fcaf780bSMauro Carvalho Chehab 
1098fcaf780bSMauro Carvalho Chehab /*
1099fcaf780bSMauro Carvalho Chehab  *	pci_device_id	table for which devices we are looking for
1100fcaf780bSMauro Carvalho Chehab  *
1101fcaf780bSMauro Carvalho Chehab  *	The "E500P" device is the first device supported.
1102fcaf780bSMauro Carvalho Chehab  */
1103fcaf780bSMauro Carvalho Chehab static const struct pci_device_id i7300_pci_tbl[] __devinitdata = {
1104fcaf780bSMauro Carvalho Chehab 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
1105fcaf780bSMauro Carvalho Chehab 	{0,}			/* 0 terminated list. */
1106fcaf780bSMauro Carvalho Chehab };
1107fcaf780bSMauro Carvalho Chehab 
1108fcaf780bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, i7300_pci_tbl);
1109fcaf780bSMauro Carvalho Chehab 
1110fcaf780bSMauro Carvalho Chehab /*
1111fcaf780bSMauro Carvalho Chehab  *	i7300_driver	pci_driver structure for this module
1112fcaf780bSMauro Carvalho Chehab  *
1113fcaf780bSMauro Carvalho Chehab  */
1114fcaf780bSMauro Carvalho Chehab static struct pci_driver i7300_driver = {
1115fcaf780bSMauro Carvalho Chehab 	.name = "i7300_edac",
1116fcaf780bSMauro Carvalho Chehab 	.probe = i7300_init_one,
1117fcaf780bSMauro Carvalho Chehab 	.remove = __devexit_p(i7300_remove_one),
1118fcaf780bSMauro Carvalho Chehab 	.id_table = i7300_pci_tbl,
1119fcaf780bSMauro Carvalho Chehab };
1120fcaf780bSMauro Carvalho Chehab 
1121fcaf780bSMauro Carvalho Chehab /*
1122fcaf780bSMauro Carvalho Chehab  *	i7300_init		Module entry function
1123fcaf780bSMauro Carvalho Chehab  *			Try to initialize this module for its devices
1124fcaf780bSMauro Carvalho Chehab  */
1125fcaf780bSMauro Carvalho Chehab static int __init i7300_init(void)
1126fcaf780bSMauro Carvalho Chehab {
1127fcaf780bSMauro Carvalho Chehab 	int pci_rc;
1128fcaf780bSMauro Carvalho Chehab 
1129fcaf780bSMauro Carvalho Chehab 	debugf2("MC: " __FILE__ ": %s()\n", __func__);
1130fcaf780bSMauro Carvalho Chehab 
1131fcaf780bSMauro Carvalho Chehab 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
1132fcaf780bSMauro Carvalho Chehab 	opstate_init();
1133fcaf780bSMauro Carvalho Chehab 
1134fcaf780bSMauro Carvalho Chehab 	pci_rc = pci_register_driver(&i7300_driver);
1135fcaf780bSMauro Carvalho Chehab 
1136fcaf780bSMauro Carvalho Chehab 	return (pci_rc < 0) ? pci_rc : 0;
1137fcaf780bSMauro Carvalho Chehab }
1138fcaf780bSMauro Carvalho Chehab 
1139fcaf780bSMauro Carvalho Chehab /*
1140fcaf780bSMauro Carvalho Chehab  *	i7300_exit()	Module exit function
1141fcaf780bSMauro Carvalho Chehab  *			Unregister the driver
1142fcaf780bSMauro Carvalho Chehab  */
1143fcaf780bSMauro Carvalho Chehab static void __exit i7300_exit(void)
1144fcaf780bSMauro Carvalho Chehab {
1145fcaf780bSMauro Carvalho Chehab 	debugf2("MC: " __FILE__ ": %s()\n", __func__);
1146fcaf780bSMauro Carvalho Chehab 	pci_unregister_driver(&i7300_driver);
1147fcaf780bSMauro Carvalho Chehab }
1148fcaf780bSMauro Carvalho Chehab 
1149fcaf780bSMauro Carvalho Chehab module_init(i7300_init);
1150fcaf780bSMauro Carvalho Chehab module_exit(i7300_exit);
1151fcaf780bSMauro Carvalho Chehab 
1152fcaf780bSMauro Carvalho Chehab MODULE_LICENSE("GPL");
1153fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
1154fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
1155fcaf780bSMauro Carvalho Chehab MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
1156fcaf780bSMauro Carvalho Chehab 		   I7300_REVISION);
1157fcaf780bSMauro Carvalho Chehab 
1158fcaf780bSMauro Carvalho Chehab module_param(edac_op_state, int, 0444);
1159fcaf780bSMauro Carvalho Chehab MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
1160