Blame view

drivers/edac/i7core_edac.c 61.5 KB
122375508   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
52707f918   Mauro Carvalho Chehab   i7core_edac: Bett...
2
3
  /* Intel i7 core/Nehalem Memory Controller kernel module
   *
e7bf068aa   David Sterba   i7core_edac: fix ...
4
   * This driver supports the memory controllers found on the Intel
52707f918   Mauro Carvalho Chehab   i7core_edac: Bett...
5
6
7
   * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx,
   * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield
   * and Westmere-EP.
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
8
   *
52707f918   Mauro Carvalho Chehab   i7core_edac: Bett...
9
   * Copyright (c) 2009-2010 by:
37e59f876   Mauro Carvalho Chehab   [media, edac] Cha...
10
   *	 Mauro Carvalho Chehab
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
11
   *
7d4c1ea2b   Alexander A. Klimov   EDAC: Replace HTT...
12
   * Red Hat Inc. https://www.redhat.com
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * Forked and adapted from the i5400_edac driver
   *
   * Based on the following public Intel datasheets:
   * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
   * Datasheet, Volume 2:
   *	http://download.intel.com/design/processor/datashts/320835.pdf
   * Intel Xeon Processor 5500 Series Datasheet Volume 2
   *	http://www.intel.com/Assets/PDF/datasheet/321322.pdf
   * also available at:
   * 	http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
   */
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
25
26
27
28
29
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/pci.h>
  #include <linux/pci_ids.h>
  #include <linux/slab.h>
3b918c12d   Randy Dunlap   edac: fix i7core ...
30
  #include <linux/delay.h>
535e9c78e   Nils Carlson   i7core_edac: scru...
31
  #include <linux/dmi.h>
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
32
33
  #include <linux/edac.h>
  #include <linux/mmzone.h>
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
34
  #include <linux/smp.h>
4140c5426   Borislav Petkov   i7core_edac: Drop...
35
  #include <asm/mce.h>
14d2c0834   Mauro Carvalho Chehab   i7core: Use regis...
36
  #include <asm/processor.h>
4fad8098b   Sedat Dilek   i7core_edac: Fix ...
37
  #include <asm/div64.h>
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
38

78d88e8a3   Mauro Carvalho Chehab   edac: rename edac...
39
  #include "edac_module.h"
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
40

18c29002f   Mauro Carvalho Chehab   i7core_edac: move...
41
42
43
44
  /* Static vars */
  static LIST_HEAD(i7core_edac_list);
  static DEFINE_MUTEX(i7core_edac_lock);
  static int probed;
54a08ab15   Mauro Carvalho Chehab   i7core_edac: Don'...
45
46
47
  static int use_pci_fixup;
  module_param(use_pci_fixup, int, 0444);
  MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
48
  /*
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
49
50
51
52
53
54
55
56
57
   * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
   * registers start at bus 255, and are not reported by BIOS.
   * We currently find devices with only 2 sockets. In order to support more QPI
   * Quick Path Interconnect, just increment this number.
   */
  #define MAX_SOCKET_BUSES	2
  
  
  /*
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
58
59
   * Alter this version for the module when modifications are made
   */
152ba3942   Michal Marek   edac: Drop __DATE...
60
  #define I7CORE_REVISION    " Ver: 1.0.0"
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
61
  #define EDAC_MOD_STR      "i7core_edac"
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
62
63
64
65
66
67
68
69
70
71
72
73
  /*
   * Debug macros
   */
  #define i7core_printk(level, fmt, arg...)			\
  	edac_printk(level, "i7core", fmt, ##arg)
  
  #define i7core_mc_printk(mci, level, fmt, arg...)		\
  	edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
  
  /*
   * i7core Memory Controller Registers
   */
e9bd2e737   Mauro Carvalho Chehab   i7core_edac: Adds...
74
75
76
  	/* OFFSETS for Device 0 Function 0 */
  
  #define MC_CFG_CONTROL	0x90
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
77
78
    #define MC_CFG_UNLOCK		0x02
    #define MC_CFG_LOCK		0x00
e9bd2e737   Mauro Carvalho Chehab   i7core_edac: Adds...
79

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
80
81
82
83
84
  	/* OFFSETS for Device 3 Function 0 */
  
  #define MC_CONTROL	0x48
  #define MC_STATUS	0x4c
  #define MC_MAX_DOD	0x64
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
85
  /*
15ed103a9   David Mackey   edac: Fix spellin...
86
   * OFFSETS for Device 3 Function 4, as indicated on Xeon 5500 datasheet:
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
87
88
89
90
91
92
93
94
95
   * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
   */
  
  #define MC_TEST_ERR_RCV1	0x60
    #define DIMM2_COR_ERR(r)			((r) & 0x7fff)
  
  #define MC_TEST_ERR_RCV0	0x64
    #define DIMM1_COR_ERR(r)			(((r) >> 16) & 0x7fff)
    #define DIMM0_COR_ERR(r)			((r) & 0x7fff)
15ed103a9   David Mackey   edac: Fix spellin...
96
  /* OFFSETS for Device 3 Function 2, as indicated on Xeon 5500 datasheet */
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
97
98
99
100
101
102
103
  #define MC_SSRCONTROL		0x48
    #define SSR_MODE_DISABLE	0x00
    #define SSR_MODE_ENABLE	0x01
    #define SSR_MODE_MASK		0x03
  
  #define MC_SCRUB_CONTROL	0x4c
    #define STARTSCRUB		(1 << 24)
535e9c78e   Nils Carlson   i7core_edac: scru...
104
    #define SCRUBINTERVAL_MASK    0xffffff
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
105

b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
106
107
108
109
110
111
112
113
114
  #define MC_COR_ECC_CNT_0	0x80
  #define MC_COR_ECC_CNT_1	0x84
  #define MC_COR_ECC_CNT_2	0x88
  #define MC_COR_ECC_CNT_3	0x8c
  #define MC_COR_ECC_CNT_4	0x90
  #define MC_COR_ECC_CNT_5	0x94
  
  #define DIMM_TOP_COR_ERR(r)			(((r) >> 16) & 0x7fff)
  #define DIMM_BOT_COR_ERR(r)			((r) & 0x7fff)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
115
  	/* OFFSETS for Devices 4,5 and 6 Function 0 */
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
116
117
118
119
120
  #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
    #define THREE_DIMMS_PRESENT		(1 << 24)
    #define SINGLE_QUAD_RANK_PRESENT	(1 << 23)
    #define QUAD_RANK_PRESENT		(1 << 22)
    #define REGISTERED_DIMM		(1 << 15)
f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
121
122
123
  #define MC_CHANNEL_MAPPER	0x60
    #define RDLCH(r, ch)		((((r) >> (3 + (ch * 6))) & 0x07) - 1)
    #define WRLCH(r, ch)		((((r) >> (ch * 6)) & 0x07) - 1)
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
124
125
  #define MC_CHANNEL_RANK_PRESENT 0x7c
    #define RANK_PRESENT_MASK		0xffff
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
126
  #define MC_CHANNEL_ADDR_MATCH	0xf0
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
127
128
129
130
131
132
133
134
135
136
  #define MC_CHANNEL_ERROR_MASK	0xf8
  #define MC_CHANNEL_ERROR_INJECT	0xfc
    #define INJECT_ADDR_PARITY	0x10
    #define INJECT_ECC		0x08
    #define MASK_CACHELINE	0x06
    #define MASK_FULL_CACHELINE	0x06
    #define MASK_MSB32_CACHELINE	0x04
    #define MASK_LSB32_CACHELINE	0x02
    #define NO_MASK_CACHELINE	0x00
    #define REPEAT_EN		0x01
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
137

0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
138
  	/* OFFSETS for Devices 4,5 and 6 Function 1 */
b990538a7   Mauro Carvalho Chehab   i7core_edac: Codi...
139

0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
140
141
142
143
144
145
146
  #define MC_DOD_CH_DIMM0		0x48
  #define MC_DOD_CH_DIMM1		0x4c
  #define MC_DOD_CH_DIMM2		0x50
    #define RANKOFFSET_MASK	((1 << 12) | (1 << 11) | (1 << 10))
    #define RANKOFFSET(x)		((x & RANKOFFSET_MASK) >> 10)
    #define DIMM_PRESENT_MASK	(1 << 9)
    #define DIMM_PRESENT(x)	(((x) & DIMM_PRESENT_MASK) >> 9)
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
147
148
149
150
    #define MC_DOD_NUMBANK_MASK		((1 << 8) | (1 << 7))
    #define MC_DOD_NUMBANK(x)		(((x) & MC_DOD_NUMBANK_MASK) >> 7)
    #define MC_DOD_NUMRANK_MASK		((1 << 6) | (1 << 5))
    #define MC_DOD_NUMRANK(x)		(((x) & MC_DOD_NUMRANK_MASK) >> 5)
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
151
    #define MC_DOD_NUMROW_MASK		((1 << 4) | (1 << 3) | (1 << 2))
5566cb7c9   Mauro Carvalho Chehab   i7core_edac: Memo...
152
    #define MC_DOD_NUMROW(x)		(((x) & MC_DOD_NUMROW_MASK) >> 2)
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
153
154
    #define MC_DOD_NUMCOL_MASK		3
    #define MC_DOD_NUMCOL(x)		((x) & MC_DOD_NUMCOL_MASK)
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
155

f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
156
  #define MC_RANK_PRESENT		0x7c
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  #define MC_SAG_CH_0	0x80
  #define MC_SAG_CH_1	0x84
  #define MC_SAG_CH_2	0x88
  #define MC_SAG_CH_3	0x8c
  #define MC_SAG_CH_4	0x90
  #define MC_SAG_CH_5	0x94
  #define MC_SAG_CH_6	0x98
  #define MC_SAG_CH_7	0x9c
  
  #define MC_RIR_LIMIT_CH_0	0x40
  #define MC_RIR_LIMIT_CH_1	0x44
  #define MC_RIR_LIMIT_CH_2	0x48
  #define MC_RIR_LIMIT_CH_3	0x4C
  #define MC_RIR_LIMIT_CH_4	0x50
  #define MC_RIR_LIMIT_CH_5	0x54
  #define MC_RIR_LIMIT_CH_6	0x58
  #define MC_RIR_LIMIT_CH_7	0x5C
  #define MC_RIR_LIMIT_MASK	((1 << 10) - 1)
  
  #define MC_RIR_WAY_CH		0x80
    #define MC_RIR_WAY_OFFSET_MASK	(((1 << 14) - 1) & ~0x7)
    #define MC_RIR_WAY_RANK_MASK		0x7
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
179
180
181
182
183
  /*
   * i7core structs
   */
  
  #define NUM_CHANS 3
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
184
185
186
  #define MAX_DIMMS 3		/* Max DIMMS per channel */
  #define MAX_MCR_FUNC  4
  #define MAX_CHAN_FUNC 3
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
187
188
189
190
191
  
  struct i7core_info {
  	u32	mc_control;
  	u32	mc_status;
  	u32	max_dod;
f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
192
  	u32	ch_map;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
193
  };
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
194
195
196
197
198
199
200
201
202
203
204
  
  struct i7core_inject {
  	int	enable;
  
  	u32	section;
  	u32	type;
  	u32	eccmask;
  
  	/* Error address mask */
  	int channel, dimm, rank, bank, page, col;
  };
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
205
  struct i7core_channel {
0bf09e829   Mauro Carvalho Chehab   i7core: fix ranks...
206
207
208
  	bool		is_3dimms_present;
  	bool		is_single_4rank;
  	bool		has_4rank;
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
209
  	u32		dimms;
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
210
  };
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
211
  struct pci_id_descr {
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
212
213
214
  	int			dev;
  	int			func;
  	int 			dev_id;
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
215
  	int			optional;
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
216
  };
bd9e19ca4   Vernon Mauery   Add support for W...
217
  struct pci_id_table {
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
218
219
  	const struct pci_id_descr	*descr;
  	int				n_devs;
bd9e19ca4   Vernon Mauery   Add support for W...
220
  };
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
221
222
223
224
  struct i7core_dev {
  	struct list_head	list;
  	u8			socket;
  	struct pci_dev		**pdev;
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
225
  	int			n_devs;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
226
227
  	struct mem_ctl_info	*mci;
  };
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
228
  struct i7core_pvt {
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
229
  	struct device *addrmatch_dev, *chancounts_dev;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
230

f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
231
232
233
234
235
  	struct pci_dev	*pci_noncore;
  	struct pci_dev	*pci_mcr[MAX_MCR_FUNC + 1];
  	struct pci_dev	*pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
  
  	struct i7core_dev *i7core_dev;
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
236

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
237
  	struct i7core_info	info;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
238
  	struct i7core_inject	inject;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
239
  	struct i7core_channel	channel[NUM_CHANS];
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
240

f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
241
  	int		ce_count_available;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
242
243
  
  			/* ECC corrected errors counts per udimm */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
244
245
  	unsigned long	udimm_ce_count[MAX_DIMMS];
  	int		udimm_last_ce_count[MAX_DIMMS];
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
246
  			/* ECC corrected errors counts per rdimm */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
247
248
  	unsigned long	rdimm_ce_count[NUM_CHANS][MAX_DIMMS];
  	int		rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS];
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
249

27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
250
  	bool		is_registered, enable_scrub;
14d2c0834   Mauro Carvalho Chehab   i7core: Use regis...
251

535e9c78e   Nils Carlson   i7core_edac: scru...
252
253
  	/* DCLK Frequency used for computing scrub rate */
  	int			dclk_freq;
939747bd6   Mauro Carvalho Chehab   i7core_edac: Be s...
254
255
  	/* Struct to control EDAC polling */
  	struct edac_pci_ctl_info *i7core_pci;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
256
  };
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
257
258
259
260
  #define PCI_DESCR(device, function, device_id)	\
  	.dev = (device),			\
  	.func = (function),			\
  	.dev_id = (device_id)
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
261
  static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
262
263
264
  		/* Memory controller */
  	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR)     },
  	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD)  },
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
265
  			/* Exists only for RDIMM */
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
266
  	{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1  },
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  	{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
  
  		/* Channel 0 */
  	{ PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) },
  	{ PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) },
  	{ PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) },
  	{ PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC)   },
  
  		/* Channel 1 */
  	{ PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) },
  	{ PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) },
  	{ PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) },
  	{ PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC)   },
  
  		/* Channel 2 */
  	{ PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) },
  	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
  	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
  	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC)   },
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
286
287
288
289
290
291
292
293
294
  
  		/* Generic Non-core registers */
  	/*
  	 * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
  	 * On Xeon 55xx, however, it has a different id (8086:2c40). So,
  	 * the probing code needs to test for the other address in case of
  	 * failure of this one
  	 */
  	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE)  },
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
295
  };
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
296

1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
297
  static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
52a2e4fc3   Mauro Carvalho Chehab   i7core_edac: Add ...
298
299
300
301
302
303
304
305
  	{ PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR)         },
  	{ PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD)      },
  	{ PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST)     },
  
  	{ PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL) },
  	{ PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR) },
  	{ PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) },
  	{ PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC)   },
508fa179f   Mauro Carvalho Chehab   i7core_edac: Fix ...
306
307
308
309
  	{ PCI_DESCR( 5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) },
  	{ PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
  	{ PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
  	{ PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC)   },
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
310
311
312
313
314
315
  
  	/*
  	 * This is the PCI device has an alternate address on some
  	 * processors like Core i7 860
  	 */
  	{ PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)     },
52a2e4fc3   Mauro Carvalho Chehab   i7core_edac: Add ...
316
  };
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
317
  static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
bd9e19ca4   Vernon Mauery   Add support for W...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  		/* Memory controller */
  	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2)     },
  	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2)  },
  			/* Exists only for RDIMM */
  	{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2), .optional = 1  },
  	{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2) },
  
  		/* Channel 0 */
  	{ PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2) },
  	{ PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2) },
  	{ PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2) },
  	{ PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2)   },
  
  		/* Channel 1 */
  	{ PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2) },
  	{ PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2) },
  	{ PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2) },
  	{ PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2)   },
  
  		/* Channel 2 */
  	{ PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2) },
  	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
  	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
  	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2)   },
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
342
343
344
  
  		/* Generic Non-core registers */
  	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2)  },
bd9e19ca4   Vernon Mauery   Add support for W...
345
  };
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
346
347
  #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
  static const struct pci_id_table pci_dev_table[] = {
bd9e19ca4   Vernon Mauery   Add support for W...
348
349
350
  	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
  	PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
  	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
3c52cc57c   Mauro Carvalho Chehab   i7core_edac: prop...
351
  	{0,}			/* 0 terminated list. */
bd9e19ca4   Vernon Mauery   Add support for W...
352
  };
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
353
354
  /*
   *	pci_device_id	table for which devices we are looking for
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
355
   */
ba935f409   Jingoo Han   EDAC: Remove DEFI...
356
  static const struct pci_device_id i7core_pci_tbl[] = {
d1fd4fb69   Mauro Carvalho Chehab   i7core_edac: Add ...
357
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
f05da2f78   Mauro Carvalho Chehab   i7core: add suppo...
358
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
359
360
  	{0,}			/* 0 terminated list. */
  };
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
361
  /****************************************************************************
15ed103a9   David Mackey   edac: Fix spellin...
362
  			Ancillary status routines
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
363
364
365
   ****************************************************************************/
  
  	/* MC_CONTROL bits */
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
366
367
  #define CH_ACTIVE(pvt, ch)	((pvt)->info.mc_control & (1 << (8 + ch)))
  #define ECCx8(pvt)		((pvt)->info.mc_control & (1 << 1))
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
368
369
  
  	/* MC_STATUS bits */
61053fded   Keith Mannthey   i7core_edac: Fix ...
370
  #define ECC_ENABLED(pvt)	((pvt)->info.mc_status & (1 << 4))
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
371
  #define CH_DISABLED(pvt, ch)	((pvt)->info.mc_status & (1 << ch))
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
372
373
  
  	/* MC_MAX_DOD read functions */
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
374
  static inline int numdimms(u32 dimms)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
375
  {
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
376
  	return (dimms & 0x3) + 1;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
377
  }
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
378
  static inline int numrank(u32 rank)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
379
  {
c31d34fe9   Niklas Söderlund   i7core_edac: fix ...
380
  	static const int ranks[] = { 1, 2, 4, -EINVAL };
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
381

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
382
  	return ranks[rank & 0x3];
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
383
  }
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
384
  static inline int numbank(u32 bank)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
385
  {
c31d34fe9   Niklas Söderlund   i7core_edac: fix ...
386
  	static const int banks[] = { 4, 8, 16, -EINVAL };
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
387

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
388
  	return banks[bank & 0x3];
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
389
  }
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
390
  static inline int numrow(u32 row)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
391
  {
c31d34fe9   Niklas Söderlund   i7core_edac: fix ...
392
  	static const int rows[] = {
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
393
394
395
  		1 << 12, 1 << 13, 1 << 14, 1 << 15,
  		1 << 16, -EINVAL, -EINVAL, -EINVAL,
  	};
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
396
  	return rows[row & 0x7];
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
397
  }
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
398
  static inline int numcol(u32 col)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
399
  {
c31d34fe9   Niklas Söderlund   i7core_edac: fix ...
400
  	static const int cols[] = {
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
401
402
  		1 << 10, 1 << 11, 1 << 12, -EINVAL,
  	};
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
403
  	return cols[col & 0x3];
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
404
  }
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
405
  static struct i7core_dev *get_i7core_dev(u8 socket)
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
406
407
408
409
410
411
412
413
414
415
  {
  	struct i7core_dev *i7core_dev;
  
  	list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
  		if (i7core_dev->socket == socket)
  			return i7core_dev;
  	}
  
  	return NULL;
  }
848b2f7ed   Hidetoshi Seto   i7core_edac: Intr...
416
417
418
419
420
421
422
423
  static struct i7core_dev *alloc_i7core_dev(u8 socket,
  					   const struct pci_id_table *table)
  {
  	struct i7core_dev *i7core_dev;
  
  	i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
  	if (!i7core_dev)
  		return NULL;
6396bb221   Kees Cook   treewide: kzalloc...
424
  	i7core_dev->pdev = kcalloc(table->n_devs, sizeof(*i7core_dev->pdev),
848b2f7ed   Hidetoshi Seto   i7core_edac: Intr...
425
426
427
428
429
430
431
432
433
434
435
436
  				   GFP_KERNEL);
  	if (!i7core_dev->pdev) {
  		kfree(i7core_dev);
  		return NULL;
  	}
  
  	i7core_dev->socket = socket;
  	i7core_dev->n_devs = table->n_devs;
  	list_add_tail(&i7core_dev->list, &i7core_edac_list);
  
  	return i7core_dev;
  }
2aa9be448   Hidetoshi Seto   i7core_edac: Intr...
437
438
439
440
441
442
  static void free_i7core_dev(struct i7core_dev *i7core_dev)
  {
  	list_del(&i7core_dev->list);
  	kfree(i7core_dev->pdev);
  	kfree(i7core_dev);
  }
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
443
444
445
  /****************************************************************************
  			Memory check routines
   ****************************************************************************/
eb94fc402   Mauro Carvalho Chehab   i7core_edac: fill...
446

084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
447
  static int get_dimm_config(struct mem_ctl_info *mci)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
448
449
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
450
  	struct pci_dev *pdev;
ba6c5c62e   Mauro Carvalho Chehab   i7core_edac: maps...
451
  	int i, j;
1c6fed808   Mauro Carvalho Chehab   i7core_edac: Prop...
452
  	enum edac_type mode;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
453
  	enum mem_type mtype;
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
454
  	struct dimm_info *dimm;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
455

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
456
  	/* Get data from the MC register, function 0 */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
457
  	pdev = pvt->pci_mcr[0];
7dd6953c5   Mauro Carvalho Chehab   i7core_edac: Add ...
458
  	if (!pdev)
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
459
  		return -ENODEV;
f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
460
  	/* Device 3 function 0 reads */
7dd6953c5   Mauro Carvalho Chehab   i7core_edac: Add ...
461
462
463
464
  	pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control);
  	pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status);
  	pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
  	pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
465

956b9ba15   Joe Perches   edac: Convert deb...
466
467
468
469
  	edac_dbg(0, "QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x
  ",
  		 pvt->i7core_dev->socket, pvt->info.mc_control,
  		 pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
470

1c6fed808   Mauro Carvalho Chehab   i7core_edac: Prop...
471
  	if (ECC_ENABLED(pvt)) {
956b9ba15   Joe Perches   edac: Convert deb...
472
473
  		edac_dbg(0, "ECC enabled with x%d SDCC
  ", ECCx8(pvt) ? 8 : 4);
1c6fed808   Mauro Carvalho Chehab   i7core_edac: Prop...
474
475
476
477
478
  		if (ECCx8(pvt))
  			mode = EDAC_S8ECD8ED;
  		else
  			mode = EDAC_S4ECD4ED;
  	} else {
956b9ba15   Joe Perches   edac: Convert deb...
479
480
  		edac_dbg(0, "ECC disabled
  ");
1c6fed808   Mauro Carvalho Chehab   i7core_edac: Prop...
481
482
  		mode = EDAC_NONE;
  	}
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
483
484
  
  	/* FIXME: need to handle the error codes */
956b9ba15   Joe Perches   edac: Convert deb...
485
486
487
488
489
490
491
  	edac_dbg(0, "DOD Max limits: DIMMS: %d, %d-ranked, %d-banked x%x x 0x%x
  ",
  		 numdimms(pvt->info.max_dod),
  		 numrank(pvt->info.max_dod >> 2),
  		 numbank(pvt->info.max_dod >> 4),
  		 numrow(pvt->info.max_dod >> 6),
  		 numcol(pvt->info.max_dod >> 9));
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
492

0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
493
  	for (i = 0; i < NUM_CHANS; i++) {
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
494
  		u32 data, dimm_dod[3], value[8];
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
495

52a2e4fc3   Mauro Carvalho Chehab   i7core_edac: Add ...
496
497
  		if (!pvt->pci_ch[i][0])
  			continue;
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
498
  		if (!CH_ACTIVE(pvt, i)) {
956b9ba15   Joe Perches   edac: Convert deb...
499
500
  			edac_dbg(0, "Channel %i is not active
  ", i);
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
501
502
503
  			continue;
  		}
  		if (CH_DISABLED(pvt, i)) {
956b9ba15   Joe Perches   edac: Convert deb...
504
505
  			edac_dbg(0, "Channel %i is disabled
  ", i);
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
506
507
  			continue;
  		}
f122a8922   Mauro Carvalho Chehab   i7core_edac: Show...
508
  		/* Devices 4-6 function 0 */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
509
  		pci_read_config_dword(pvt->pci_ch[i][0],
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
510
  				MC_CHANNEL_DIMM_INIT_PARAMS, &data);
0bf09e829   Mauro Carvalho Chehab   i7core: fix ranks...
511
512
513
514
515
516
517
518
519
  
  		if (data & THREE_DIMMS_PRESENT)
  			pvt->channel[i].is_3dimms_present = true;
  
  		if (data & SINGLE_QUAD_RANK_PRESENT)
  			pvt->channel[i].is_single_4rank = true;
  
  		if (data & QUAD_RANK_PRESENT)
  			pvt->channel[i].has_4rank = true;
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
520

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
521
522
  		if (data & REGISTERED_DIMM)
  			mtype = MEM_RDDR3;
14d2c0834   Mauro Carvalho Chehab   i7core: Use regis...
523
  		else
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
524
  			mtype = MEM_DDR3;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
525
526
  
  		/* Devices 4-6 function 1 */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
527
  		pci_read_config_dword(pvt->pci_ch[i][1],
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
528
  				MC_DOD_CH_DIMM0, &dimm_dod[0]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
529
  		pci_read_config_dword(pvt->pci_ch[i][1],
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
530
  				MC_DOD_CH_DIMM1, &dimm_dod[1]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
531
  		pci_read_config_dword(pvt->pci_ch[i][1],
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
532
  				MC_DOD_CH_DIMM2, &dimm_dod[2]);
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
533

956b9ba15   Joe Perches   edac: Convert deb...
534
535
536
537
538
539
540
541
542
  		edac_dbg(0, "Ch%d phy rd%d, wr%d (0x%08x): %s%s%s%cDIMMs
  ",
  			 i,
  			 RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
  			 data,
  			 pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
  			 pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
  			 pvt->channel[i].has_4rank ? "HAS_4R " : "",
  			 (data & REGISTERED_DIMM) ? 'R' : 'U');
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
543
544
545
  
  		for (j = 0; j < 3; j++) {
  			u32 banks, ranks, rows, cols;
5566cb7c9   Mauro Carvalho Chehab   i7core_edac: Memo...
546
  			u32 size, npages;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
547
548
549
  
  			if (!DIMM_PRESENT(dimm_dod[j]))
  				continue;
bc9ad9e40   Robert Richter   EDAC: Replace EDA...
550
  			dimm = edac_get_dimm(mci, i, j, 0);
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
551
552
553
554
  			banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
  			ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
  			rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
  			cols = numcol(MC_DOD_NUMCOL(dimm_dod[j]));
5566cb7c9   Mauro Carvalho Chehab   i7core_edac: Memo...
555
556
  			/* DDR3 has 8 I/O banks */
  			size = (rows * cols * banks * ranks) >> (20 - 3);
6f6da1360   Qiuxu Zhuo   EDAC: Correct DIM...
557
558
  			edac_dbg(0, "\tdimm %d %d MiB offset: %x, bank: %d, rank: %d, row: %#x, col: %#x
  ",
956b9ba15   Joe Perches   edac: Convert deb...
559
560
561
  				 j, size,
  				 RANKOFFSET(dimm_dod[j]),
  				 banks, ranks, rows, cols);
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
562

e9144601d   Mauro Carvalho Chehab   i7core_edac: move...
563
  			npages = MiB_TO_PAGES(size);
5566cb7c9   Mauro Carvalho Chehab   i7core_edac: Memo...
564

a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
565
  			dimm->nr_pages = npages;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
566

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
567
568
  			switch (banks) {
  			case 4:
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
569
  				dimm->dtype = DEV_X4;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
570
571
  				break;
  			case 8:
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
572
  				dimm->dtype = DEV_X8;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
573
574
  				break;
  			case 16:
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
575
  				dimm->dtype = DEV_X16;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
576
577
  				break;
  			default:
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
578
  				dimm->dtype = DEV_UNKNOWN;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
579
  			}
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
580
581
582
583
584
585
  			snprintf(dimm->label, sizeof(dimm->label),
  				 "CPU#%uChannel#%u_DIMM#%u",
  				 pvt->i7core_dev->socket, i, j);
  			dimm->grain = 8;
  			dimm->edac_mode = mode;
  			dimm->mtype = mtype;
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
586
  		}
1c6fed808   Mauro Carvalho Chehab   i7core_edac: Prop...
587

854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
588
589
590
591
592
593
594
595
  		pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
  		pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
  		pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
  		pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
  		pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
  		pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
  		pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
  		pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
956b9ba15   Joe Perches   edac: Convert deb...
596
597
  		edac_dbg(1, "\t[%i] DIVBY3\tREMOVED\tOFFSET
  ", i);
854d33499   Mauro Carvalho Chehab   i7core_edac: Get ...
598
  		for (j = 0; j < 8; j++)
956b9ba15   Joe Perches   edac: Convert deb...
599
600
601
602
603
  			edac_dbg(1, "\t\t%#x\t%#x\t%#x
  ",
  				 (value[j] >> 27) & 0x1,
  				 (value[j] >> 24) & 0x7,
  				 (value[j] & ((1 << 24) - 1)));
0b2b7b7ec   Mauro Carvalho Chehab   i7core_edac: Add ...
604
  	}
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
605
606
607
608
  	return 0;
  }
  
  /****************************************************************************
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
609
610
  			Error insertion routines
   ****************************************************************************/
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
611
  #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
612
613
614
615
616
617
618
  /* The i7core has independent error injection features per channel.
     However, to have a simpler code, we don't allow enabling error injection
     on more than one channel.
     Also, since a change at an inject parameter will be applied only at enable,
     we're disabling error injection on all write calls to the sysfs nodes that
     controls the error code injection.
   */
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
619
  static int disable_inject(const struct mem_ctl_info *mci)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
620
621
622
623
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  
  	pvt->inject.enable = 0;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
624
  	if (!pvt->pci_ch[pvt->inject.channel][0])
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
625
  		return -ENODEV;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
626
  	pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
4157d9f55   Mauro Carvalho Chehab   i7core_edac: fix ...
627
  				MC_CHANNEL_ERROR_INJECT, 0);
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
628
629
  
  	return 0;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
630
631
632
633
634
635
636
637
638
  }
  
  /*
   * i7core inject inject.section
   *
   *	accept and store error injection inject.section value
   *	bit 0 - refers to the lower 32-byte half cacheline
   *	bit 1 - refers to the upper 32-byte half cacheline
   */
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
639
640
  static ssize_t i7core_inject_section_store(struct device *dev,
  					   struct device_attribute *mattr,
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
641
642
  					   const char *data, size_t count)
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
643
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
644
645
646
647
648
  	struct i7core_pvt *pvt = mci->pvt_info;
  	unsigned long value;
  	int rc;
  
  	if (pvt->inject.enable)
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
649
  		disable_inject(mci);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
650

c7f62fc87   Jingoo Han   EDAC: Replace str...
651
  	rc = kstrtoul(data, 10, &value);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
652
  	if ((rc < 0) || (value > 3))
2068def56   Mauro Carvalho Chehab   i7core_edac: fix ...
653
  		return -EIO;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
654
655
656
657
  
  	pvt->inject.section = (u32) value;
  	return count;
  }
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
658
659
660
  static ssize_t i7core_inject_section_show(struct device *dev,
  					  struct device_attribute *mattr,
  					  char *data)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
661
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
662
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
663
664
665
666
667
668
669
670
671
672
673
674
675
  	struct i7core_pvt *pvt = mci->pvt_info;
  	return sprintf(data, "0x%08x
  ", pvt->inject.section);
  }
  
  /*
   * i7core inject.type
   *
   *	accept and store error injection inject.section value
   *	bit 0 - repeat enable - Enable error repetition
   *	bit 1 - inject ECC error
   *	bit 2 - inject parity error
   */
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
676
677
  static ssize_t i7core_inject_type_store(struct device *dev,
  					struct device_attribute *mattr,
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
678
679
  					const char *data, size_t count)
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
680
  	struct mem_ctl_info *mci = to_mci(dev);
1722bc0e8   Colin Ian King   EDAC: Fix indenta...
681
  	struct i7core_pvt *pvt = mci->pvt_info;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
682
683
684
685
  	unsigned long value;
  	int rc;
  
  	if (pvt->inject.enable)
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
686
  		disable_inject(mci);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
687

c7f62fc87   Jingoo Han   EDAC: Replace str...
688
  	rc = kstrtoul(data, 10, &value);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
689
  	if ((rc < 0) || (value > 7))
2068def56   Mauro Carvalho Chehab   i7core_edac: fix ...
690
  		return -EIO;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
691
692
693
694
  
  	pvt->inject.type = (u32) value;
  	return count;
  }
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
695
696
697
  static ssize_t i7core_inject_type_show(struct device *dev,
  				       struct device_attribute *mattr,
  				       char *data)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
698
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
699
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
700
  	struct i7core_pvt *pvt = mci->pvt_info;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
701

194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
702
703
704
705
706
707
708
709
710
711
712
713
714
715
  	return sprintf(data, "0x%08x
  ", pvt->inject.type);
  }
  
  /*
   * i7core_inject_inject.eccmask_store
   *
   * The type of error (UE/CE) will depend on the inject.eccmask value:
   *   Any bits set to a 1 will flip the corresponding ECC bit
   *   Correctable errors can be injected by flipping 1 bit or the bits within
   *   a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
   *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
   *   uncorrectable error to be injected.
   */
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
716
717
718
  static ssize_t i7core_inject_eccmask_store(struct device *dev,
  					   struct device_attribute *mattr,
  					   const char *data, size_t count)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
719
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
720
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
721
722
723
724
725
  	struct i7core_pvt *pvt = mci->pvt_info;
  	unsigned long value;
  	int rc;
  
  	if (pvt->inject.enable)
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
726
  		disable_inject(mci);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
727

c7f62fc87   Jingoo Han   EDAC: Replace str...
728
  	rc = kstrtoul(data, 10, &value);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
729
  	if (rc < 0)
2068def56   Mauro Carvalho Chehab   i7core_edac: fix ...
730
  		return -EIO;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
731
732
733
734
  
  	pvt->inject.eccmask = (u32) value;
  	return count;
  }
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
735
736
737
  static ssize_t i7core_inject_eccmask_show(struct device *dev,
  					  struct device_attribute *mattr,
  					  char *data)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
738
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
739
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
740
  	struct i7core_pvt *pvt = mci->pvt_info;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
741

194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  	return sprintf(data, "0x%08x
  ", pvt->inject.eccmask);
  }
  
  /*
   * i7core_addrmatch
   *
   * The type of error (UE/CE) will depend on the inject.eccmask value:
   *   Any bits set to a 1 will flip the corresponding ECC bit
   *   Correctable errors can be injected by flipping 1 bit or the bits within
   *   a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
   *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
   *   uncorrectable error to be injected.
   */
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
756

a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
757
758
  #define DECLARE_ADDR_MATCH(param, limit)			\
  static ssize_t i7core_inject_store_##param(			\
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
759
760
761
  	struct device *dev,					\
  	struct device_attribute *mattr,				\
  	const char *data, size_t count)				\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
762
  {								\
42709efb3   Prarit Bhargava   i7core_edac: fix ...
763
  	struct mem_ctl_info *mci = dev_get_drvdata(dev);	\
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
764
  	struct i7core_pvt *pvt;					\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
765
766
767
  	long value;						\
  	int rc;							\
  								\
956b9ba15   Joe Perches   edac: Convert deb...
768
769
  	edac_dbg(1, "
  ");					\
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
770
771
  	pvt = mci->pvt_info;					\
  								\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
772
773
774
  	if (pvt->inject.enable)					\
  		disable_inject(mci);				\
  								\
4f87fad1d   Mauro Carvalho Chehab   i7core_edac: Bett...
775
776
  	if (!strcasecmp(data, "any") || !strcasecmp(data, "any
  "))\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
777
778
  		value = -1;					\
  	else {							\
c7f62fc87   Jingoo Han   EDAC: Replace str...
779
  		rc = kstrtoul(data, 10, &value);		\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
780
781
782
783
784
785
786
787
788
789
  		if ((rc < 0) || (value >= limit))		\
  			return -EIO;				\
  	}							\
  								\
  	pvt->inject.param = value;				\
  								\
  	return count;						\
  }								\
  								\
  static ssize_t i7core_inject_show_##param(			\
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
790
791
792
  	struct device *dev,					\
  	struct device_attribute *mattr,				\
  	char *data)						\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
793
  {								\
42709efb3   Prarit Bhargava   i7core_edac: fix ...
794
  	struct mem_ctl_info *mci = dev_get_drvdata(dev);	\
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
795
796
797
  	struct i7core_pvt *pvt;					\
  								\
  	pvt = mci->pvt_info;					\
956b9ba15   Joe Perches   edac: Convert deb...
798
799
  	edac_dbg(1, "pvt=%p
  ", pvt);				\
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
800
801
802
803
804
805
  	if (pvt->inject.param < 0)				\
  		return sprintf(data, "any
  ");			\
  	else							\
  		return sprintf(data, "%d
  ", pvt->inject.param);\
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
806
  }
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
807
  #define ATTR_ADDR_MATCH(param)					\
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
808
809
810
  	static DEVICE_ATTR(param, S_IRUGO | S_IWUSR,		\
  		    i7core_inject_show_##param,			\
  		    i7core_inject_store_##param)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
811

a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
812
813
814
815
816
817
  DECLARE_ADDR_MATCH(channel, 3);
  DECLARE_ADDR_MATCH(dimm, 3);
  DECLARE_ADDR_MATCH(rank, 4);
  DECLARE_ADDR_MATCH(bank, 32);
  DECLARE_ADDR_MATCH(page, 0x10000);
  DECLARE_ADDR_MATCH(col, 0x4000);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
818

5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
819
820
821
822
823
824
  ATTR_ADDR_MATCH(channel);
  ATTR_ADDR_MATCH(dimm);
  ATTR_ADDR_MATCH(rank);
  ATTR_ADDR_MATCH(bank);
  ATTR_ADDR_MATCH(page);
  ATTR_ADDR_MATCH(col);
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
825
  static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
826
827
828
  {
  	u32 read;
  	int count;
956b9ba15   Joe Perches   edac: Convert deb...
829
830
831
832
  	edac_dbg(0, "setting pci %02x:%02x.%x reg=%02x value=%08x
  ",
  		 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
  		 where, val);
4157d9f55   Mauro Carvalho Chehab   i7core_edac: fix ...
833

276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
834
835
  	for (count = 0; count < 10; count++) {
  		if (count)
b990538a7   Mauro Carvalho Chehab   i7core_edac: Codi...
836
  			msleep(100);
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
837
838
839
840
841
842
  		pci_write_config_dword(dev, where, val);
  		pci_read_config_dword(dev, where, &read);
  
  		if (read == val)
  			return 0;
  	}
4157d9f55   Mauro Carvalho Chehab   i7core_edac: fix ...
843
844
845
846
847
  	i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x "
  		"write=%08x. Read=%08x
  ",
  		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
  		where, val, read);
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
848
849
850
  
  	return -EINVAL;
  }
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  /*
   * This routine prepares the Memory Controller for error injection.
   * The error will be injected when some process tries to write to the
   * memory that matches the given criteria.
   * The criteria can be set in terms of a mask where dimm, rank, bank, page
   * and col can be specified.
   * A -1 value for any of the mask items will make the MCU to ignore
   * that matching criteria for error injection.
   *
   * It should be noticed that the error will only happen after a write operation
   * on a memory that matches the condition. if REPEAT_EN is not enabled at
   * inject mask, then it will produce just one error. Otherwise, it will repeat
   * until the injectmask would be cleaned.
   *
   * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
   *    is reliable enough to check if the MC is using the
   *    three channels. However, this is not clear at the datasheet.
   */
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
869
870
871
  static ssize_t i7core_inject_enable_store(struct device *dev,
  					  struct device_attribute *mattr,
  					  const char *data, size_t count)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
872
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
873
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
874
875
876
877
878
  	struct i7core_pvt *pvt = mci->pvt_info;
  	u32 injectmask;
  	u64 mask = 0;
  	int  rc;
  	long enable;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
879
  	if (!pvt->pci_ch[pvt->inject.channel][0])
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
880
  		return 0;
c7f62fc87   Jingoo Han   EDAC: Replace str...
881
  	rc = kstrtoul(data, 10, &enable);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
882
883
884
885
886
887
888
889
890
891
892
893
  	if ((rc < 0))
  		return 0;
  
  	if (enable) {
  		pvt->inject.enable = 1;
  	} else {
  		disable_inject(mci);
  		return count;
  	}
  
  	/* Sets pvt->inject.dimm mask */
  	if (pvt->inject.dimm < 0)
486dd09f1   Alan Cox   edac: i7core_edac...
894
  		mask |= 1LL << 41;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
895
  	else {
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
896
  		if (pvt->channel[pvt->inject.channel].dimms > 2)
486dd09f1   Alan Cox   edac: i7core_edac...
897
  			mask |= (pvt->inject.dimm & 0x3LL) << 35;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
898
  		else
486dd09f1   Alan Cox   edac: i7core_edac...
899
  			mask |= (pvt->inject.dimm & 0x1LL) << 36;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
900
901
902
903
  	}
  
  	/* Sets pvt->inject.rank mask */
  	if (pvt->inject.rank < 0)
486dd09f1   Alan Cox   edac: i7core_edac...
904
  		mask |= 1LL << 40;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
905
  	else {
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
906
  		if (pvt->channel[pvt->inject.channel].dimms > 2)
486dd09f1   Alan Cox   edac: i7core_edac...
907
  			mask |= (pvt->inject.rank & 0x1LL) << 34;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
908
  		else
486dd09f1   Alan Cox   edac: i7core_edac...
909
  			mask |= (pvt->inject.rank & 0x3LL) << 34;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
910
911
912
913
  	}
  
  	/* Sets pvt->inject.bank mask */
  	if (pvt->inject.bank < 0)
486dd09f1   Alan Cox   edac: i7core_edac...
914
  		mask |= 1LL << 39;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
915
  	else
486dd09f1   Alan Cox   edac: i7core_edac...
916
  		mask |= (pvt->inject.bank & 0x15LL) << 30;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
917
918
919
  
  	/* Sets pvt->inject.page mask */
  	if (pvt->inject.page < 0)
486dd09f1   Alan Cox   edac: i7core_edac...
920
  		mask |= 1LL << 38;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
921
  	else
486dd09f1   Alan Cox   edac: i7core_edac...
922
  		mask |= (pvt->inject.page & 0xffff) << 14;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
923
924
925
  
  	/* Sets pvt->inject.column mask */
  	if (pvt->inject.col < 0)
486dd09f1   Alan Cox   edac: i7core_edac...
926
  		mask |= 1LL << 37;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
927
  	else
486dd09f1   Alan Cox   edac: i7core_edac...
928
  		mask |= (pvt->inject.col & 0x3fff);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
929

276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
930
931
932
933
934
935
936
937
938
939
940
941
  	/*
  	 * bit    0: REPEAT_EN
  	 * bits 1-2: MASK_HALF_CACHELINE
  	 * bit    3: INJECT_ECC
  	 * bit    4: INJECT_ADDR_PARITY
  	 */
  
  	injectmask = (pvt->inject.type & 1) |
  		     (pvt->inject.section & 0x3) << 1 |
  		     (pvt->inject.type & 0x6) << (3 - 1);
  
  	/* Unlock writes to registers - this register is write only */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
942
  	pci_write_config_dword(pvt->pci_noncore,
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
943
  			       MC_CFG_CONTROL, 0x2);
e9bd2e737   Mauro Carvalho Chehab   i7core_edac: Adds...
944

f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
945
  	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
946
  			       MC_CHANNEL_ADDR_MATCH, mask);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
947
  	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
948
  			       MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L);
7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
949

f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
950
  	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
951
  			       MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
952
  	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
4157d9f55   Mauro Carvalho Chehab   i7core_edac: fix ...
953
  			       MC_CHANNEL_ERROR_INJECT, injectmask);
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
954

194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
955
  	/*
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
956
957
958
  	 * This is something undocumented, based on my tests
  	 * Without writing 8 to this register, errors aren't injected. Not sure
  	 * why.
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
959
  	 */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
960
  	pci_write_config_dword(pvt->pci_noncore,
276b824c3   Mauro Carvalho Chehab   i7core_edac: some...
961
  			       MC_CFG_CONTROL, 8);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
962

956b9ba15   Joe Perches   edac: Convert deb...
963
964
965
  	edac_dbg(0, "Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x
  ",
  		 mask, pvt->inject.eccmask, injectmask);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
966

7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
967

194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
968
969
  	return count;
  }
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
970
971
972
  static ssize_t i7core_inject_enable_show(struct device *dev,
  					 struct device_attribute *mattr,
  					 char *data)
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
973
  {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
974
  	struct mem_ctl_info *mci = to_mci(dev);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
975
  	struct i7core_pvt *pvt = mci->pvt_info;
7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
976
  	u32 injectmask;
52a2e4fc3   Mauro Carvalho Chehab   i7core_edac: Add ...
977
978
  	if (!pvt->pci_ch[pvt->inject.channel][0])
  		return 0;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
979
  	pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
4157d9f55   Mauro Carvalho Chehab   i7core_edac: fix ...
980
  			       MC_CHANNEL_ERROR_INJECT, &injectmask);
7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
981

956b9ba15   Joe Perches   edac: Convert deb...
982
983
  	edac_dbg(0, "Inject error read: 0x%018x
  ", injectmask);
7b029d03c   Mauro Carvalho Chehab   i7core_edac: A fe...
984
985
986
  
  	if (injectmask & 0x0c)
  		pvt->inject.enable = 1;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
987
988
989
  	return sprintf(data, "%d
  ", pvt->inject.enable);
  }
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
990
991
  #define DECLARE_COUNTER(param)					\
  static ssize_t i7core_show_counter_##param(			\
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
992
993
994
  	struct device *dev,					\
  	struct device_attribute *mattr,				\
  	char *data)						\
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
995
  {								\
42709efb3   Prarit Bhargava   i7core_edac: fix ...
996
  	struct mem_ctl_info *mci = dev_get_drvdata(dev);	\
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
997
998
  	struct i7core_pvt *pvt = mci->pvt_info;			\
  								\
956b9ba15   Joe Perches   edac: Convert deb...
999
1000
  	edac_dbg(1, "
  ");					\
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
1001
1002
1003
1004
1005
1006
1007
  	if (!pvt->ce_count_available || (pvt->is_registered))	\
  		return sprintf(data, "data unavailable
  ");	\
  	return sprintf(data, "%lu
  ",				\
  			pvt->udimm_ce_count[param]);		\
  }
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1008

f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
1009
  #define ATTR_COUNTER(param)					\
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1010
1011
1012
  	static DEVICE_ATTR(udimm##param, S_IRUGO | S_IWUSR,	\
  		    i7core_show_counter_##param,		\
  		    NULL)
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1013

f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
1014
1015
1016
  DECLARE_COUNTER(0);
  DECLARE_COUNTER(1);
  DECLARE_COUNTER(2);
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1017

5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1018
1019
1020
  ATTR_COUNTER(0);
  ATTR_COUNTER(1);
  ATTR_COUNTER(2);
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
1021
  /*
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1022
   * inject_addrmatch device sysfs struct
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
1023
   */
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
1024

5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1025
1026
1027
1028
1029
1030
1031
1032
  static struct attribute *i7core_addrmatch_attrs[] = {
  	&dev_attr_channel.attr,
  	&dev_attr_dimm.attr,
  	&dev_attr_rank.attr,
  	&dev_attr_bank.attr,
  	&dev_attr_page.attr,
  	&dev_attr_col.attr,
  	NULL
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
1033
  };
1c18be5a4   Arvind Yadav   EDAC: Constify at...
1034
  static const struct attribute_group addrmatch_grp = {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1035
  	.attrs	= i7core_addrmatch_attrs,
a5538e531   Mauro Carvalho Chehab   i7core_edac: Add ...
1036
  };
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1037
1038
1039
  static const struct attribute_group *addrmatch_groups[] = {
  	&addrmatch_grp,
  	NULL
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
1040
  };
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1041
1042
  static void addrmatch_release(struct device *device)
  {
956b9ba15   Joe Perches   edac: Convert deb...
1043
1044
  	edac_dbg(1, "Releasing device %s
  ", dev_name(device));
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1045
  	kfree(device);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1046
  }
b2b3e7362   Bhumika Goyal   EDAC: Make device...
1047
  static const struct device_type addrmatch_type = {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1048
1049
  	.groups		= addrmatch_groups,
  	.release	= addrmatch_release,
f338d7369   Mauro Carvalho Chehab   i7core_edac: Conv...
1050
  };
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1051
1052
1053
1054
1055
1056
1057
1058
1059
  /*
   * all_channel_counts sysfs struct
   */
  
  static struct attribute *i7core_udimm_counters_attrs[] = {
  	&dev_attr_udimm0.attr,
  	&dev_attr_udimm1.attr,
  	&dev_attr_udimm2.attr,
  	NULL
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
1060
  };
1c18be5a4   Arvind Yadav   EDAC: Constify at...
1061
  static const struct attribute_group all_channel_counts_grp = {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1062
  	.attrs	= i7core_udimm_counters_attrs,
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
1063
  };
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1064
1065
1066
  static const struct attribute_group *all_channel_counts_groups[] = {
  	&all_channel_counts_grp,
  	NULL
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
1067
  };
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1068
1069
  static void all_channel_counts_release(struct device *device)
  {
956b9ba15   Joe Perches   edac: Convert deb...
1070
1071
  	edac_dbg(1, "Releasing device %s
  ", dev_name(device));
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1072
  	kfree(device);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1073
  }
b2b3e7362   Bhumika Goyal   EDAC: Make device...
1074
  static const struct device_type all_channel_counts_type = {
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
  	.groups		= all_channel_counts_groups,
  	.release	= all_channel_counts_release,
  };
  
  /*
   * inject sysfs attributes
   */
  
  static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
  		   i7core_inject_section_show, i7core_inject_section_store);
  
  static DEVICE_ATTR(inject_type, S_IRUGO | S_IWUSR,
  		   i7core_inject_type_show, i7core_inject_type_store);
  
  
  static DEVICE_ATTR(inject_eccmask, S_IRUGO | S_IWUSR,
  		   i7core_inject_eccmask_show, i7core_inject_eccmask_store);
  
  static DEVICE_ATTR(inject_enable, S_IRUGO | S_IWUSR,
  		   i7core_inject_enable_show, i7core_inject_enable_store);
2eace188f   Takashi Iwai   EDAC: i7core: Use...
1095
1096
1097
1098
1099
1100
1101
1102
1103
  static struct attribute *i7core_dev_attrs[] = {
  	&dev_attr_inject_section.attr,
  	&dev_attr_inject_type.attr,
  	&dev_attr_inject_eccmask.attr,
  	&dev_attr_inject_enable.attr,
  	NULL
  };
  
  ATTRIBUTE_GROUPS(i7core_dev);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1104
1105
1106
1107
  static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	int rc;
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1108
1109
  	pvt->addrmatch_dev = kzalloc(sizeof(*pvt->addrmatch_dev), GFP_KERNEL);
  	if (!pvt->addrmatch_dev)
e97d7e381   Takashi Iwai   EDAC: i7core: Ret...
1110
  		return -ENOMEM;
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1111
1112
1113
1114
1115
1116
1117
  
  	pvt->addrmatch_dev->type = &addrmatch_type;
  	pvt->addrmatch_dev->bus = mci->dev.bus;
  	device_initialize(pvt->addrmatch_dev);
  	pvt->addrmatch_dev->parent = &mci->dev;
  	dev_set_name(pvt->addrmatch_dev, "inject_addrmatch");
  	dev_set_drvdata(pvt->addrmatch_dev, mci);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1118

956b9ba15   Joe Perches   edac: Convert deb...
1119
1120
  	edac_dbg(1, "creating %s
  ", dev_name(pvt->addrmatch_dev));
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1121

356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1122
  	rc = device_add(pvt->addrmatch_dev);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1123
  	if (rc < 0)
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1124
  		goto err_put_addrmatch;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1125
1126
  
  	if (!pvt->is_registered) {
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1127
1128
1129
  		pvt->chancounts_dev = kzalloc(sizeof(*pvt->chancounts_dev),
  					      GFP_KERNEL);
  		if (!pvt->chancounts_dev) {
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1130
1131
  			rc = -ENOMEM;
  			goto err_del_addrmatch;
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1132
1133
1134
1135
1136
1137
1138
1139
  		}
  
  		pvt->chancounts_dev->type = &all_channel_counts_type;
  		pvt->chancounts_dev->bus = mci->dev.bus;
  		device_initialize(pvt->chancounts_dev);
  		pvt->chancounts_dev->parent = &mci->dev;
  		dev_set_name(pvt->chancounts_dev, "all_channel_counts");
  		dev_set_drvdata(pvt->chancounts_dev, mci);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1140

956b9ba15   Joe Perches   edac: Convert deb...
1141
1142
  		edac_dbg(1, "creating %s
  ", dev_name(pvt->chancounts_dev));
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1143

356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1144
  		rc = device_add(pvt->chancounts_dev);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1145
  		if (rc < 0)
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1146
  			goto err_put_chancounts;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1147
1148
  	}
  	return 0;
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1149
1150
1151
1152
1153
1154
1155
1156
1157
  
  err_put_chancounts:
  	put_device(pvt->chancounts_dev);
  err_del_addrmatch:
  	device_del(pvt->addrmatch_dev);
  err_put_addrmatch:
  	put_device(pvt->addrmatch_dev);
  
  	return rc;
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1158
1159
1160
1161
1162
  }
  
  static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
956b9ba15   Joe Perches   edac: Convert deb...
1163
1164
  	edac_dbg(1, "
  ");
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1165

5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1166
  	if (!pvt->is_registered) {
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1167
  		device_del(pvt->chancounts_dev);
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1168
  		put_device(pvt->chancounts_dev);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1169
  	}
356f0a308   Mauro Carvalho Chehab   i7core_edac: chan...
1170
  	device_del(pvt->addrmatch_dev);
6c974d4df   Johan Hovold   EDAC, i7core: Fix...
1171
  	put_device(pvt->addrmatch_dev);
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
1172
  }
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
1173
  /****************************************************************************
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1174
1175
1176
1177
  	Device initialization routines: put/get, init/exit
   ****************************************************************************/
  
  /*
64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
1178
   *	i7core_put_all_devices	'put' all the devices that we have
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1179
1180
   *				reserved via 'get'
   */
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1181
  static void i7core_put_devices(struct i7core_dev *i7core_dev)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1182
  {
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1183
  	int i;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1184

956b9ba15   Joe Perches   edac: Convert deb...
1185
1186
  	edac_dbg(0, "
  ");
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1187
  	for (i = 0; i < i7core_dev->n_devs; i++) {
22e6bcbdc   Mauro Carvalho Chehab   i7core_edac: chan...
1188
1189
1190
  		struct pci_dev *pdev = i7core_dev->pdev[i];
  		if (!pdev)
  			continue;
956b9ba15   Joe Perches   edac: Convert deb...
1191
1192
1193
1194
  		edac_dbg(0, "Removing dev %02x:%02x.%d
  ",
  			 pdev->bus->number,
  			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
22e6bcbdc   Mauro Carvalho Chehab   i7core_edac: chan...
1195
1196
  		pci_dev_put(pdev);
  	}
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1197
  }
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1198

13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1199
1200
  static void i7core_put_all_devices(void)
  {
425386803   Mauro Carvalho Chehab   i7core_edac: We n...
1201
  	struct i7core_dev *i7core_dev, *tmp;
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1202

39300e714   Mauro Carvalho Chehab   i7core_edac: expl...
1203
  	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
1204
  		i7core_put_devices(i7core_dev);
2aa9be448   Hidetoshi Seto   i7core_edac: Intr...
1205
  		free_i7core_dev(i7core_dev);
39300e714   Mauro Carvalho Chehab   i7core_edac: expl...
1206
  	}
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1207
  }
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
1208
  static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table)
bc2d7245f   Keith Mannthey   i7core_edac: Prob...
1209
1210
1211
  {
  	struct pci_dev *pdev = NULL;
  	int i;
54a08ab15   Mauro Carvalho Chehab   i7core_edac: Don'...
1212

bc2d7245f   Keith Mannthey   i7core_edac: Prob...
1213
  	/*
e7bf068aa   David Sterba   i7core_edac: fix ...
1214
  	 * On Xeon 55xx, the Intel Quick Path Arch Generic Non-core pci buses
bc2d7245f   Keith Mannthey   i7core_edac: Prob...
1215
1216
1217
  	 * aren't announced by acpi. So, we need to use a legacy scan probing
  	 * to detect them
  	 */
bd9e19ca4   Vernon Mauery   Add support for W...
1218
1219
1220
1221
1222
1223
  	while (table && table->descr) {
  		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, table->descr[0].dev_id, NULL);
  		if (unlikely(!pdev)) {
  			for (i = 0; i < MAX_SOCKET_BUSES; i++)
  				pcibios_scan_specific_bus(255-i);
  		}
bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1224
  		pci_dev_put(pdev);
bd9e19ca4   Vernon Mauery   Add support for W...
1225
  		table++;
bc2d7245f   Keith Mannthey   i7core_edac: Prob...
1226
1227
  	}
  }
bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1228
1229
1230
1231
1232
1233
1234
  static unsigned i7core_pci_lastbus(void)
  {
  	int last_bus = 0, bus;
  	struct pci_bus *b = NULL;
  
  	while ((b = pci_find_next_bus(b)) != NULL) {
  		bus = b->number;
956b9ba15   Joe Perches   edac: Convert deb...
1235
1236
  		edac_dbg(0, "Found bus %d
  ", bus);
bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1237
1238
1239
  		if (bus > last_bus)
  			last_bus = bus;
  	}
956b9ba15   Joe Perches   edac: Convert deb...
1240
1241
  	edac_dbg(0, "Last bus %d
  ", last_bus);
bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1242
1243
1244
  
  	return last_bus;
  }
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1245
  /*
64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
1246
   *	i7core_get_all_devices	Find and perform 'get' operation on the MCH's
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1247
1248
1249
1250
   *			device/functions we want to reference for this driver
   *
   *			Need to 'get' device 16 func 1 and func 2
   */
b197cba07   Hidetoshi Seto   i7core_edac: Redu...
1251
1252
1253
1254
  static int i7core_get_onedevice(struct pci_dev **prev,
  				const struct pci_id_table *table,
  				const unsigned devno,
  				const unsigned last_bus)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1255
  {
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1256
  	struct i7core_dev *i7core_dev;
b197cba07   Hidetoshi Seto   i7core_edac: Redu...
1257
  	const struct pci_id_descr *dev_descr = &table->descr[devno];
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1258

8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
1259
  	struct pci_dev *pdev = NULL;
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
1260
1261
  	u8 bus = 0;
  	u8 socket = 0;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1262

c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1263
  	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1264
  			      dev_descr->dev_id, *prev);
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1265

224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1266
  	/*
15ed103a9   David Mackey   edac: Fix spellin...
1267
  	 * On Xeon 55xx, the Intel QuickPath Arch Generic Non-core regs
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1268
1269
1270
  	 * is at addr 8086:2c40, instead of 8086:2c41. So, we need
  	 * to probe for the alternate address in case of failure
  	 */
c0f5eeed0   Jean Delvare   i7core_edac: Fix ...
1271
1272
  	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
  		pci_dev_get(*prev);	/* pci_get_device will put it */
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1273
1274
  		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
  				      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
c0f5eeed0   Jean Delvare   i7core_edac: Fix ...
1275
  	}
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1276

c0f5eeed0   Jean Delvare   i7core_edac: Fix ...
1277
1278
1279
  	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
  	    !pdev) {
  		pci_dev_get(*prev);	/* pci_get_device will put it */
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1280
1281
1282
  		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
  				      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
  				      *prev);
c0f5eeed0   Jean Delvare   i7core_edac: Fix ...
1283
  	}
224e871f3   Mauro Carvalho Chehab   i7core_edac: Fix ...
1284

c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1285
1286
1287
1288
  	if (!pdev) {
  		if (*prev) {
  			*prev = pdev;
  			return 0;
d1fd4fb69   Mauro Carvalho Chehab   i7core_edac: Add ...
1289
  		}
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1290
  		if (dev_descr->optional)
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1291
  			return 0;
310cbb728   Mauro Carvalho Chehab   i7core: fix probi...
1292

bd9e19ca4   Vernon Mauery   Add support for W...
1293
1294
  		if (devno == 0)
  			return -ENODEV;
ab0893740   Daniel J Blueman   quiesce EDAC init...
1295
  		i7core_printk(KERN_INFO,
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1296
1297
  			"Device not found: dev %02x.%d PCI ID %04x:%04x
  ",
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1298
1299
  			dev_descr->dev, dev_descr->func,
  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
1300

c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1301
1302
1303
1304
  		/* End of list, leave */
  		return -ENODEV;
  	}
  	bus = pdev->bus->number;
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
1305

bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1306
  	socket = last_bus - bus;
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1307

66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1308
1309
  	i7core_dev = get_i7core_dev(socket);
  	if (!i7core_dev) {
848b2f7ed   Hidetoshi Seto   i7core_edac: Intr...
1310
  		i7core_dev = alloc_i7core_dev(socket, table);
2896637b8   Hidetoshi Seto   i7core_edac: Call...
1311
1312
  		if (!i7core_dev) {
  			pci_dev_put(pdev);
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1313
  			return -ENOMEM;
2896637b8   Hidetoshi Seto   i7core_edac: Call...
1314
  		}
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1315
  	}
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
1316

66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1317
  	if (i7core_dev->pdev[devno]) {
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1318
1319
1320
1321
  		i7core_printk(KERN_ERR,
  			"Duplicated device for "
  			"dev %02x:%02x.%d PCI ID %04x:%04x
  ",
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1322
1323
  			bus, dev_descr->dev, dev_descr->func,
  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1324
1325
1326
  		pci_dev_put(pdev);
  		return -ENODEV;
  	}
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
1327

66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1328
  	i7core_dev->pdev[devno] = pdev;
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1329
1330
  
  	/* Sanity check */
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1331
1332
  	if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
  			PCI_FUNC(pdev->devfn) != dev_descr->func)) {
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1333
1334
1335
1336
  		i7core_printk(KERN_ERR,
  			"Device PCI ID %04x:%04x "
  			"has dev %02x:%02x.%d instead of dev %02x:%02x.%d
  ",
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1337
  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1338
  			bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1339
  			bus, dev_descr->dev, dev_descr->func);
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1340
1341
  		return -ENODEV;
  	}
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1342

c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1343
1344
1345
1346
1347
1348
  	/* Be sure that the device is enabled */
  	if (unlikely(pci_enable_device(pdev) < 0)) {
  		i7core_printk(KERN_ERR,
  			"Couldn't enable "
  			"dev %02x:%02x.%d PCI ID %04x:%04x
  ",
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1349
1350
  			bus, dev_descr->dev, dev_descr->func,
  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1351
1352
  		return -ENODEV;
  	}
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1353

956b9ba15   Joe Perches   edac: Convert deb...
1354
1355
1356
1357
1358
  	edac_dbg(0, "Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x
  ",
  		 socket, bus, dev_descr->dev,
  		 dev_descr->func,
  		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
1359

a3e154163   Mauro Carvalho Chehab   i7core_edac: Avoi...
1360
1361
1362
1363
1364
1365
  	/*
  	 * As stated on drivers/pci/search.c, the reference count for
  	 * @from is always decremented if it is not %NULL. So, as we need
  	 * to get all devices up to null, we need to do a get for the device
  	 */
  	pci_dev_get(pdev);
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1366
  	*prev = pdev;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1367

c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1368
1369
  	return 0;
  }
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1370

64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
1371
  static int i7core_get_all_devices(void)
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1372
  {
3c52cc57c   Mauro Carvalho Chehab   i7core_edac: prop...
1373
  	int i, rc, last_bus;
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1374
  	struct pci_dev *pdev = NULL;
3c52cc57c   Mauro Carvalho Chehab   i7core_edac: prop...
1375
  	const struct pci_id_table *table = pci_dev_table;
bd9e19ca4   Vernon Mauery   Add support for W...
1376

bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1377
  	last_bus = i7core_pci_lastbus();
3c52cc57c   Mauro Carvalho Chehab   i7core_edac: prop...
1378
  	while (table && table->descr) {
bd9e19ca4   Vernon Mauery   Add support for W...
1379
1380
1381
  		for (i = 0; i < table->n_devs; i++) {
  			pdev = NULL;
  			do {
b197cba07   Hidetoshi Seto   i7core_edac: Redu...
1382
  				rc = i7core_get_onedevice(&pdev, table, i,
bda142890   Mauro Carvalho Chehab   i7core_edac: Prop...
1383
  							  last_bus);
bd9e19ca4   Vernon Mauery   Add support for W...
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  				if (rc < 0) {
  					if (i == 0) {
  						i = table->n_devs;
  						break;
  					}
  					i7core_put_all_devices();
  					return -ENODEV;
  				}
  			} while (pdev);
  		}
3c52cc57c   Mauro Carvalho Chehab   i7core_edac: prop...
1394
  		table++;
c77720b95   Mauro Carvalho Chehab   i7core: fix get_d...
1395
  	}
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1396

ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1397
  	return 0;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1398
  }
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1399
1400
  static int mci_bind_devs(struct mem_ctl_info *mci,
  			 struct i7core_dev *i7core_dev)
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1401
1402
1403
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	struct pci_dev *pdev;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1404
  	int i, func, slot;
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1405
  	char *family;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1406

27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1407
1408
  	pvt->is_registered = false;
  	pvt->enable_scrub  = false;
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
1409
  	for (i = 0; i < i7core_dev->n_devs; i++) {
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1410
1411
  		pdev = i7core_dev->pdev[i];
  		if (!pdev)
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
1412
  			continue;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1413
1414
1415
1416
1417
1418
1419
1420
  		func = PCI_FUNC(pdev->devfn);
  		slot = PCI_SLOT(pdev->devfn);
  		if (slot == 3) {
  			if (unlikely(func > MAX_MCR_FUNC))
  				goto error;
  			pvt->pci_mcr[func] = pdev;
  		} else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) {
  			if (unlikely(func > MAX_CHAN_FUNC))
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1421
  				goto error;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1422
  			pvt->pci_ch[slot - 4][func] = pdev;
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1423
  		} else if (!slot && !func) {
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1424
  			pvt->pci_noncore = pdev;
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
  
  			/* Detect the processor family */
  			switch (pdev->device) {
  			case PCI_DEVICE_ID_INTEL_I7_NONCORE:
  				family = "Xeon 35xx/ i7core";
  				pvt->enable_scrub = false;
  				break;
  			case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT:
  				family = "i7-800/i5-700";
  				pvt->enable_scrub = false;
  				break;
  			case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE:
  				family = "Xeon 34xx";
  				pvt->enable_scrub = false;
  				break;
  			case PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT:
  				family = "Xeon 55xx";
  				pvt->enable_scrub = true;
  				break;
  			case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2:
  				family = "Xeon 56xx / i7-900";
  				pvt->enable_scrub = true;
  				break;
  			default:
  				family = "unknown";
  				pvt->enable_scrub = false;
  			}
956b9ba15   Joe Perches   edac: Convert deb...
1452
1453
  			edac_dbg(0, "Detected a processor type %s
  ", family);
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1454
  		} else
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1455
  			goto error;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1456

956b9ba15   Joe Perches   edac: Convert deb...
1457
1458
1459
1460
  		edac_dbg(0, "Associated fn %d.%d, dev = %p, socket %d
  ",
  			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
  			 pdev, i7core_dev->socket);
14d2c0834   Mauro Carvalho Chehab   i7core: Use regis...
1461

f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1462
1463
  		if (PCI_SLOT(pdev->devfn) == 3 &&
  			PCI_FUNC(pdev->devfn) == 2)
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
1464
  			pvt->is_registered = true;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1465
  	}
e9bd2e737   Mauro Carvalho Chehab   i7core_edac: Adds...
1466

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1467
  	return 0;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
1468
1469
1470
1471
1472
1473
1474
  
  error:
  	i7core_printk(KERN_ERR, "Device %d, function %d "
  		      "is out of the expected range
  ",
  		      slot, func);
  	return -EINVAL;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1475
  }
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1476
1477
1478
  /****************************************************************************
  			Error check routines
   ****************************************************************************/
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1479
1480
  
  static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
1481
1482
1483
1484
  					 const int chan,
  					 const int new0,
  					 const int new1,
  					 const int new2)
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1485
1486
1487
1488
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	int add0 = 0, add1 = 0, add2 = 0;
  	/* Updates CE counters if it is not the first time here */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1489
  	if (pvt->ce_count_available) {
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1490
  		/* Updates CE counters */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1491
1492
1493
  		add2 = new2 - pvt->rdimm_last_ce_count[chan][2];
  		add1 = new1 - pvt->rdimm_last_ce_count[chan][1];
  		add0 = new0 - pvt->rdimm_last_ce_count[chan][0];
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1494
1495
1496
  
  		if (add2 < 0)
  			add2 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1497
  		pvt->rdimm_ce_count[chan][2] += add2;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1498
1499
1500
  
  		if (add1 < 0)
  			add1 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1501
  		pvt->rdimm_ce_count[chan][1] += add1;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1502
1503
1504
  
  		if (add0 < 0)
  			add0 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1505
  		pvt->rdimm_ce_count[chan][0] += add0;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1506
  	} else
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1507
  		pvt->ce_count_available = 1;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1508
1509
  
  	/* Store the new values */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1510
1511
1512
  	pvt->rdimm_last_ce_count[chan][2] = new2;
  	pvt->rdimm_last_ce_count[chan][1] = new1;
  	pvt->rdimm_last_ce_count[chan][0] = new0;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1513
1514
1515
  
  	/*updated the edac core */
  	if (add0 != 0)
00d183392   Mauro Carvalho Chehab   i7core_edac: prop...
1516
1517
1518
  		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add0,
  				     0, 0, 0,
  				     chan, 0, -1, "error", "");
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1519
  	if (add1 != 0)
00d183392   Mauro Carvalho Chehab   i7core_edac: prop...
1520
1521
1522
  		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add1,
  				     0, 0, 0,
  				     chan, 1, -1, "error", "");
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1523
  	if (add2 != 0)
00d183392   Mauro Carvalho Chehab   i7core_edac: prop...
1524
1525
1526
  		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add2,
  				     0, 0, 0,
  				     chan, 2, -1, "error", "");
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1527
  }
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1528
  static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1529
1530
1531
1532
1533
1534
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	u32 rcv[3][2];
  	int i, new0, new1, new2;
  
  	/*Read DEV 3: FUN 2:  MC_COR_ECC_CNT regs directly*/
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1535
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1536
  								&rcv[0][0]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1537
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1538
  								&rcv[0][1]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1539
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1540
  								&rcv[1][0]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1541
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1542
  								&rcv[1][1]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1543
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1544
  								&rcv[2][0]);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1545
  	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1546
1547
  								&rcv[2][1]);
  	for (i = 0 ; i < 3; i++) {
956b9ba15   Joe Perches   edac: Convert deb...
1548
1549
1550
  		edac_dbg(3, "MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x
  ",
  			 (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1551
  		/*if the channel has 3 dimms*/
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1552
  		if (pvt->channel[i].dimms > 2) {
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  			new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
  			new1 = DIMM_TOP_COR_ERR(rcv[i][0]);
  			new2 = DIMM_BOT_COR_ERR(rcv[i][1]);
  		} else {
  			new0 = DIMM_TOP_COR_ERR(rcv[i][0]) +
  					DIMM_BOT_COR_ERR(rcv[i][0]);
  			new1 = DIMM_TOP_COR_ERR(rcv[i][1]) +
  					DIMM_BOT_COR_ERR(rcv[i][1]);
  			new2 = 0;
  		}
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1563
  		i7core_rdimm_update_ce_count(mci, i, new0, new1, new2);
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1564
1565
  	}
  }
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1566
1567
1568
1569
1570
1571
1572
  
  /* This function is based on the device 3 function 4 registers as described on:
   * Intel Xeon Processor 5500 Series Datasheet Volume 2
   *	http://www.intel.com/Assets/PDF/datasheet/321322.pdf
   * also available at:
   * 	http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
   */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1573
  static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1574
1575
1576
1577
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	u32 rcv1, rcv0;
  	int new0, new1, new2;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1578
  	if (!pvt->pci_mcr[4]) {
956b9ba15   Joe Perches   edac: Convert deb...
1579
1580
  		edac_dbg(0, "MCR registers not found
  ");
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1581
1582
  		return;
  	}
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1583
  	/* Corrected test errors */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1584
1585
  	pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1);
  	pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0);
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1586
1587
1588
1589
1590
  
  	/* Store the new values */
  	new2 = DIMM2_COR_ERR(rcv1);
  	new1 = DIMM1_COR_ERR(rcv0);
  	new0 = DIMM0_COR_ERR(rcv0);
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1591
  	/* Updates CE counters if it is not the first time here */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1592
  	if (pvt->ce_count_available) {
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1593
1594
  		/* Updates CE counters */
  		int add0, add1, add2;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1595
1596
1597
  		add2 = new2 - pvt->udimm_last_ce_count[2];
  		add1 = new1 - pvt->udimm_last_ce_count[1];
  		add0 = new0 - pvt->udimm_last_ce_count[0];
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1598
1599
1600
  
  		if (add2 < 0)
  			add2 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1601
  		pvt->udimm_ce_count[2] += add2;
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1602
1603
1604
  
  		if (add1 < 0)
  			add1 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1605
  		pvt->udimm_ce_count[1] += add1;
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1606
1607
1608
  
  		if (add0 < 0)
  			add0 += 0x7fff;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1609
  		pvt->udimm_ce_count[0] += add0;
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1610
1611
1612
1613
1614
1615
  
  		if (add0 | add1 | add2)
  			i7core_printk(KERN_ERR, "New Corrected error(s): "
  				      "dimm0: +%d, dimm1: +%d, dimm2 +%d
  ",
  				      add0, add1, add2);
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1616
  	} else
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1617
  		pvt->ce_count_available = 1;
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1618
1619
  
  	/* Store the new values */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1620
1621
1622
  	pvt->udimm_last_ce_count[2] = new2;
  	pvt->udimm_last_ce_count[1] = new1;
  	pvt->udimm_last_ce_count[0] = new0;
442305b15   Mauro Carvalho Chehab   i7core_edac: Add ...
1623
  }
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1624
1625
1626
  /*
   * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32
   * Architectures Software Developer’s Manual Volume 3B.
f237fcf2b   Mauro Carvalho Chehab   i7core_edac: some...
1627
1628
1629
   * Nehalem are defined as family 0x06, model 0x1a
   *
   * The MCA registers used here are the following ones:
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1630
   *     struct mce field	MCA Register
f237fcf2b   Mauro Carvalho Chehab   i7core_edac: some...
1631
1632
1633
   *     m->status	MSR_IA32_MC8_STATUS
   *     m->addr		MSR_IA32_MC8_ADDR
   *     m->misc		MSR_IA32_MC8_MISC
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1634
1635
1636
   * In the case of Nehalem, the error information is masked at .status and .misc
   * fields
   */
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1637
  static void i7core_mce_output_error(struct mem_ctl_info *mci,
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
1638
  				    const struct mce *m)
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1639
  {
b4e8f0b6e   Mauro Carvalho Chehab   i7core_edac: Use ...
1640
  	struct i7core_pvt *pvt = mci->pvt_info;
f118920ba   Jean Delvare   i7core_edac: Drop...
1641
  	char *optype, *err;
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1642
  	enum hw_event_mc_err_type tp_event;
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1643
  	unsigned long error = m->status & 0x1ff0000l;
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1644
1645
  	bool uncorrected_error = m->mcgstatus & 1ll << 61;
  	bool ripv = m->mcgstatus & 1;
a639539fa   Mauro Carvalho Chehab   i7core: enrich er...
1646
  	u32 optypenum = (m->status >> 4) & 0x07;
8cf2d2399   Mathias Krause   i7core_edac: fixe...
1647
  	u32 core_err_cnt = (m->status >> 38) & 0x7fff;
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1648
1649
1650
1651
  	u32 dimm = (m->misc >> 16) & 0x3;
  	u32 channel = (m->misc >> 18) & 0x3;
  	u32 syndrome = m->misc >> 32;
  	u32 errnum = find_first_bit(&error, 32);
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1652
  	if (uncorrected_error) {
432de7fd7   Tony Luck   EDAC, {i7core,sb,...
1653
  		core_err_cnt = 1;
f118920ba   Jean Delvare   i7core_edac: Drop...
1654
  		if (ripv)
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1655
  			tp_event = HW_EVENT_ERR_UNCORRECTED;
45bc6098a   Tony Luck   EDAC/{i7core,sb,p...
1656
1657
  		else
  			tp_event = HW_EVENT_ERR_FATAL;
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1658
  	} else {
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1659
1660
  		tp_event = HW_EVENT_ERR_CORRECTED;
  	}
c5d345286   Mauro Carvalho Chehab   i7core: check if ...
1661

a639539fa   Mauro Carvalho Chehab   i7core: enrich er...
1662
  	switch (optypenum) {
b990538a7   Mauro Carvalho Chehab   i7core_edac: Codi...
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
  	case 0:
  		optype = "generic undef request";
  		break;
  	case 1:
  		optype = "read error";
  		break;
  	case 2:
  		optype = "write error";
  		break;
  	case 3:
  		optype = "addr/cmd error";
  		break;
  	case 4:
  		optype = "scrubbing error";
  		break;
  	default:
  		optype = "reserved";
  		break;
a639539fa   Mauro Carvalho Chehab   i7core: enrich er...
1681
  	}
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
  	switch (errnum) {
  	case 16:
  		err = "read ECC error";
  		break;
  	case 17:
  		err = "RAS ECC error";
  		break;
  	case 18:
  		err = "write parity error";
  		break;
  	case 19:
83e548bea   Colin Ian King   EDAC, i7core: Fix...
1693
  		err = "redundancy loss";
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
  		break;
  	case 20:
  		err = "reserved";
  		break;
  	case 21:
  		err = "memory range error";
  		break;
  	case 22:
  		err = "RTID out of range";
  		break;
  	case 23:
  		err = "address parity error";
  		break;
  	case 24:
  		err = "byte enable parity error";
  		break;
  	default:
  		err = "unknown";
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1712
  	}
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1713

0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1714
1715
1716
1717
1718
1719
  	/*
  	 * Call the helper to output message
  	 * FIXME: what to do if core_err_cnt > 1? Currently, it generates
  	 * only one event
  	 */
  	if (uncorrected_error || !pvt->is_registered)
00d183392   Mauro Carvalho Chehab   i7core_edac: prop...
1720
  		edac_mc_handle_error(tp_event, mci, core_err_cnt,
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
1721
1722
1723
1724
  				     m->addr >> PAGE_SHIFT,
  				     m->addr & ~PAGE_MASK,
  				     syndrome,
  				     channel, dimm, -1,
00d183392   Mauro Carvalho Chehab   i7core_edac: prop...
1725
  				     err, optype);
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1726
  }
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
1727
  /*
87d1d272b   Mauro Carvalho Chehab   i7core_edac: need...
1728
1729
1730
   *	i7core_check_error	Retrieve and process errors reported by the
   *				hardware. Called by the Core module.
   */
535953450   Tony Luck   EDAC, i7core: Rem...
1731
  static void i7core_check_error(struct mem_ctl_info *mci, struct mce *m)
87d1d272b   Mauro Carvalho Chehab   i7core_edac: need...
1732
  {
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1733
  	struct i7core_pvt *pvt = mci->pvt_info;
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1734

535953450   Tony Luck   EDAC, i7core: Rem...
1735
  	i7core_mce_output_error(mci, m);
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1736

ca9c90ba0   Mauro Carvalho Chehab   i7core_edac: Use ...
1737
1738
1739
  	/*
  	 * Now, let's increment CE error counts
  	 */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
1740
1741
1742
1743
  	if (!pvt->is_registered)
  		i7core_udimm_check_mc_ecc_err(mci);
  	else
  		i7core_rdimm_check_mc_ecc_err(mci);
87d1d272b   Mauro Carvalho Chehab   i7core_edac: need...
1744
1745
1746
  }
  
  /*
535953450   Tony Luck   EDAC, i7core: Rem...
1747
1748
   * Check that logging is enabled and that this is the right type
   * of error for us to handle.
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1749
   */
4140c5426   Borislav Petkov   i7core_edac: Drop...
1750
1751
  static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val,
  				  void *data)
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1752
  {
4140c5426   Borislav Petkov   i7core_edac: Drop...
1753
1754
1755
  	struct mce *mce = (struct mce *)data;
  	struct i7core_dev *i7_dev;
  	struct mem_ctl_info *mci;
4140c5426   Borislav Petkov   i7core_edac: Drop...
1756
1757
  
  	i7_dev = get_i7core_dev(mce->socketid);
23ba710a0   Tony Luck   x86/mce: Fix all ...
1758
  	if (!i7_dev || (mce->kflags & MCE_HANDLED_CEC))
c4fc1956f   Tony Luck   EDAC: i7core, sb_...
1759
  		return NOTIFY_DONE;
4140c5426   Borislav Petkov   i7core_edac: Drop...
1760
1761
  
  	mci = i7_dev->mci;
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1762

8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1763
1764
1765
1766
1767
  	/*
  	 * Just let mcelog handle it if the error is
  	 * outside the memory controller
  	 */
  	if (((mce->status & 0xffff) >> 7) != 1)
4140c5426   Borislav Petkov   i7core_edac: Drop...
1768
  		return NOTIFY_DONE;
8a2f118e3   Mauro Carvalho Chehab   i7core_edac: deco...
1769

f237fcf2b   Mauro Carvalho Chehab   i7core_edac: some...
1770
1771
  	/* Bank 8 registers are the only ones that we know how to handle */
  	if (mce->bank != 8)
4140c5426   Borislav Petkov   i7core_edac: Drop...
1772
  		return NOTIFY_DONE;
f237fcf2b   Mauro Carvalho Chehab   i7core_edac: some...
1773

535953450   Tony Luck   EDAC, i7core: Rem...
1774
  	i7core_check_error(mci, mce);
c5d345286   Mauro Carvalho Chehab   i7core: check if ...
1775

e7bf068aa   David Sterba   i7core_edac: fix ...
1776
  	/* Advise mcelog that the errors were handled */
23ba710a0   Tony Luck   x86/mce: Fix all ...
1777
1778
  	mce->kflags |= MCE_HANDLED_EDAC;
  	return NOTIFY_OK;
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
1779
  }
4140c5426   Borislav Petkov   i7core_edac: Drop...
1780
1781
  static struct notifier_block i7_mce_dec = {
  	.notifier_call	= i7core_mce_check_error,
9026cc82b   Borislav Petkov   x86/ras, EDAC, ac...
1782
  	.priority	= MCE_PRIO_EDAC,
4140c5426   Borislav Petkov   i7core_edac: Drop...
1783
  };
535e9c78e   Nils Carlson   i7core_edac: scru...
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
  struct memdev_dmi_entry {
  	u8 type;
  	u8 length;
  	u16 handle;
  	u16 phys_mem_array_handle;
  	u16 mem_err_info_handle;
  	u16 total_width;
  	u16 data_width;
  	u16 size;
  	u8 form;
  	u8 device_set;
  	u8 device_locator;
  	u8 bank_locator;
  	u8 memory_type;
  	u16 type_detail;
  	u16 speed;
  	u8 manufacturer;
  	u8 serial_number;
  	u8 asset_tag;
  	u8 part_number;
  	u8 attributes;
  	u32 extended_size;
  	u16 conf_mem_clk_speed;
  } __attribute__((__packed__));
  
  
  /*
   * Decode the DRAM Clock Frequency, be paranoid, make sure that all
   * memory devices show the same speed, and if they don't then consider
   * all speeds to be invalid.
   */
  static void decode_dclk(const struct dmi_header *dh, void *_dclk_freq)
  {
  	int *dclk_freq = _dclk_freq;
  	u16 dmi_mem_clk_speed;
  
  	if (*dclk_freq == -1)
  		return;
  
  	if (dh->type == DMI_ENTRY_MEM_DEVICE) {
  		struct memdev_dmi_entry *memdev_dmi_entry =
  			(struct memdev_dmi_entry *)dh;
  		unsigned long conf_mem_clk_speed_offset =
  			(unsigned long)&memdev_dmi_entry->conf_mem_clk_speed -
  			(unsigned long)&memdev_dmi_entry->type;
  		unsigned long speed_offset =
  			(unsigned long)&memdev_dmi_entry->speed -
  			(unsigned long)&memdev_dmi_entry->type;
  
  		/* Check that a DIMM is present */
  		if (memdev_dmi_entry->size == 0)
  			return;
  
  		/*
  		 * Pick the configured speed if it's available, otherwise
  		 * pick the DIMM speed, or we don't have a speed.
  		 */
  		if (memdev_dmi_entry->length > conf_mem_clk_speed_offset) {
  			dmi_mem_clk_speed =
  				memdev_dmi_entry->conf_mem_clk_speed;
  		} else if (memdev_dmi_entry->length > speed_offset) {
  			dmi_mem_clk_speed = memdev_dmi_entry->speed;
  		} else {
  			*dclk_freq = -1;
  			return;
  		}
  
  		if (*dclk_freq == 0) {
  			/* First pass, speed was 0 */
  			if (dmi_mem_clk_speed > 0) {
  				/* Set speed if a valid speed is read */
  				*dclk_freq = dmi_mem_clk_speed;
  			} else {
  				/* Otherwise we don't have a valid speed */
  				*dclk_freq = -1;
  			}
  		} else if (*dclk_freq > 0 &&
  			   *dclk_freq != dmi_mem_clk_speed) {
  			/*
  			 * If we have a speed, check that all DIMMS are the same
  			 * speed, otherwise set the speed as invalid.
  			 */
  			*dclk_freq = -1;
  		}
  	}
  }
  
  /*
   * The default DCLK frequency is used as a fallback if we
   * fail to find anything reliable in the DMI. The value
   * is taken straight from the datasheet.
   */
  #define DEFAULT_DCLK_FREQ 800
  
  static int get_dclk_freq(void)
  {
  	int dclk_freq = 0;
  
  	dmi_walk(decode_dclk, (void *)&dclk_freq);
  
  	if (dclk_freq < 1)
  		return DEFAULT_DCLK_FREQ;
  
  	return dclk_freq;
  }
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1889
1890
1891
1892
1893
1894
1895
1896
1897
  /*
   * set_sdram_scrub_rate		This routine sets byte/sec bandwidth scrub rate
   *				to hardware according to SCRUBINTERVAL formula
   *				found in datasheet.
   */
  static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	struct pci_dev *pdev;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
  	u32 dw_scrub;
  	u32 dw_ssr;
  
  	/* Get data from the MC register, function 2 */
  	pdev = pvt->pci_mcr[2];
  	if (!pdev)
  		return -ENODEV;
  
  	pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &dw_scrub);
  
  	if (new_bw == 0) {
  		/* Prepare to disable petrol scrub */
  		dw_scrub &= ~STARTSCRUB;
  		/* Stop the patrol scrub engine */
535e9c78e   Nils Carlson   i7core_edac: scru...
1912
1913
  		write_and_test(pdev, MC_SCRUB_CONTROL,
  			       dw_scrub & ~SCRUBINTERVAL_MASK);
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1914
1915
1916
1917
1918
1919
  
  		/* Get current status of scrub rate and set bit to disable */
  		pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
  		dw_ssr &= ~SSR_MODE_MASK;
  		dw_ssr |= SSR_MODE_DISABLE;
  	} else {
535e9c78e   Nils Carlson   i7core_edac: scru...
1920
1921
1922
  		const int cache_line_size = 64;
  		const u32 freq_dclk_mhz = pvt->dclk_freq;
  		unsigned long long scrub_interval;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1923
1924
  		/*
  		 * Translate the desired scrub rate to a register value and
535e9c78e   Nils Carlson   i7core_edac: scru...
1925
  		 * program the corresponding register value.
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1926
  		 */
535e9c78e   Nils Carlson   i7core_edac: scru...
1927
  		scrub_interval = (unsigned long long)freq_dclk_mhz *
4fad8098b   Sedat Dilek   i7core_edac: Fix ...
1928
1929
  			cache_line_size * 1000000;
  		do_div(scrub_interval, new_bw);
535e9c78e   Nils Carlson   i7core_edac: scru...
1930
1931
1932
1933
1934
  
  		if (!scrub_interval || scrub_interval > SCRUBINTERVAL_MASK)
  			return -EINVAL;
  
  		dw_scrub = SCRUBINTERVAL_MASK & scrub_interval;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
  
  		/* Start the patrol scrub engine */
  		pci_write_config_dword(pdev, MC_SCRUB_CONTROL,
  				       STARTSCRUB | dw_scrub);
  
  		/* Get current status of scrub rate and set bit to enable */
  		pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
  		dw_ssr &= ~SSR_MODE_MASK;
  		dw_ssr |= SSR_MODE_ENABLE;
  	}
  	/* Disable or enable scrubbing */
  	pci_write_config_dword(pdev, MC_SSRCONTROL, dw_ssr);
  
  	return new_bw;
  }
  
  /*
   * get_sdram_scrub_rate		This routine convert current scrub rate value
15ed103a9   David Mackey   edac: Fix spellin...
1953
   *				into byte/sec bandwidth according to
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1954
1955
1956
1957
1958
1959
1960
   *				SCRUBINTERVAL formula found in datasheet.
   */
  static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	struct pci_dev *pdev;
  	const u32 cache_line_size = 64;
535e9c78e   Nils Carlson   i7core_edac: scru...
1961
1962
  	const u32 freq_dclk_mhz = pvt->dclk_freq;
  	unsigned long long scrub_rate;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
  	u32 scrubval;
  
  	/* Get data from the MC register, function 2 */
  	pdev = pvt->pci_mcr[2];
  	if (!pdev)
  		return -ENODEV;
  
  	/* Get current scrub control data */
  	pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &scrubval);
  
  	/* Mask highest 8-bits to 0 */
535e9c78e   Nils Carlson   i7core_edac: scru...
1974
  	scrubval &=  SCRUBINTERVAL_MASK;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1975
1976
1977
1978
  	if (!scrubval)
  		return 0;
  
  	/* Calculate scrub rate value into byte/sec bandwidth */
535e9c78e   Nils Carlson   i7core_edac: scru...
1979
  	scrub_rate =  (unsigned long long)freq_dclk_mhz *
4fad8098b   Sedat Dilek   i7core_edac: Fix ...
1980
1981
  		1000000 * cache_line_size;
  	do_div(scrub_rate, scrubval);
535e9c78e   Nils Carlson   i7core_edac: scru...
1982
  	return (int)scrub_rate;
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
  }
  
  static void enable_sdram_scrub_setting(struct mem_ctl_info *mci)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	u32 pci_lock;
  
  	/* Unlock writes to pci registers */
  	pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
  	pci_lock &= ~0x3;
  	pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
  			       pci_lock | MC_CFG_UNLOCK);
  
  	mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
  	mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
  }
  
  static void disable_sdram_scrub_setting(struct mem_ctl_info *mci)
  {
  	struct i7core_pvt *pvt = mci->pvt_info;
  	u32 pci_lock;
  
  	/* Lock writes to pci registers */
  	pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
  	pci_lock &= ~0x3;
  	pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
  			       pci_lock | MC_CFG_LOCK);
  }
a3aa0a4ab   Hidetoshi Seto   i7core_edac: Intr...
2011
2012
2013
2014
2015
2016
  static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
  {
  	pvt->i7core_pci = edac_pci_create_generic_ctl(
  						&pvt->i7core_dev->pdev[0]->dev,
  						EDAC_MOD_STR);
  	if (unlikely(!pvt->i7core_pci))
f9902f24f   Mauro Carvalho Chehab   i7core_edac: use ...
2017
2018
2019
  		i7core_printk(KERN_WARNING,
  			      "Unable to setup PCI error report via EDAC
  ");
a3aa0a4ab   Hidetoshi Seto   i7core_edac: Intr...
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
  }
  
  static void i7core_pci_ctl_release(struct i7core_pvt *pvt)
  {
  	if (likely(pvt->i7core_pci))
  		edac_pci_release_generic_ctl(pvt->i7core_pci);
  	else
  		i7core_printk(KERN_ERR,
  				"Couldn't find mem_ctl_info for socket %d
  ",
  				pvt->i7core_dev->socket);
  	pvt->i7core_pci = NULL;
  }
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2033
2034
2035
2036
2037
2038
  static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
  {
  	struct mem_ctl_info *mci = i7core_dev->mci;
  	struct i7core_pvt *pvt;
  
  	if (unlikely(!mci || !mci->pvt_info)) {
956b9ba15   Joe Perches   edac: Convert deb...
2039
2040
  		edac_dbg(0, "MC: dev = %p
  ", &i7core_dev->pdev[0]->dev);
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2041
2042
2043
2044
2045
2046
2047
  
  		i7core_printk(KERN_ERR, "Couldn't find mci handler
  ");
  		return;
  	}
  
  	pvt = mci->pvt_info;
956b9ba15   Joe Perches   edac: Convert deb...
2048
2049
  	edac_dbg(0, "MC: mci = %p, dev = %p
  ", mci, &i7core_dev->pdev[0]->dev);
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2050

e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
2051
  	/* Disable scrubrate setting */
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
2052
2053
  	if (pvt->enable_scrub)
  		disable_sdram_scrub_setting(mci);
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
2054

1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2055
2056
2057
2058
  	/* Disable EDAC polling */
  	i7core_pci_ctl_release(pvt);
  
  	/* Remove MC sysfs nodes */
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
2059
  	i7core_delete_sysfs_devices(mci);
fd687502d   Mauro Carvalho Chehab   edac: Rename the ...
2060
  	edac_mc_del_mc(mci->pdev);
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2061

956b9ba15   Joe Perches   edac: Convert deb...
2062
2063
  	edac_dbg(1, "%s: free mci struct
  ", mci->ctl_name);
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2064
2065
2066
2067
  	kfree(mci->ctl_name);
  	edac_mc_free(mci);
  	i7core_dev->mci = NULL;
  }
aace42831   Hidetoshi Seto   i7core_edac: Redu...
2068
  static int i7core_register_mci(struct i7core_dev *i7core_dev)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2069
2070
2071
  {
  	struct mem_ctl_info *mci;
  	struct i7core_pvt *pvt;
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
2072
2073
  	int rc;
  	struct edac_mc_layer layers[2];
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2074

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2075
  	/* allocate a new MC control structure */
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
2076
2077
2078
2079
2080
2081
2082
  
  	layers[0].type = EDAC_MC_LAYER_CHANNEL;
  	layers[0].size = NUM_CHANS;
  	layers[0].is_virt_csrow = false;
  	layers[1].type = EDAC_MC_LAYER_SLOT;
  	layers[1].size = MAX_DIMMS;
  	layers[1].is_virt_csrow = true;
ca0907b9e   Mauro Carvalho Chehab   edac: Remove the ...
2083
  	mci = edac_mc_alloc(i7core_dev->socket, ARRAY_SIZE(layers), layers,
0975c16f4   Mauro Carvalho Chehab   i7core_edac: conv...
2084
  			    sizeof(*pvt));
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2085
2086
  	if (unlikely(!mci))
  		return -ENOMEM;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2087

956b9ba15   Joe Perches   edac: Convert deb...
2088
2089
  	edac_dbg(0, "MC: mci = %p, dev = %p
  ", mci, &i7core_dev->pdev[0]->dev);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2090

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2091
  	pvt = mci->pvt_info;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2092
  	memset(pvt, 0, sizeof(*pvt));
67166af4a   Mauro Carvalho Chehab   i7core_edac: add ...
2093

6d37d240f   Mauro Carvalho Chehab   i7core_edac: Fix ...
2094
2095
2096
  	/* Associates i7core_dev and mci for future usage */
  	pvt->i7core_dev = i7core_dev;
  	i7core_dev->mci = mci;
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
2097
2098
2099
2100
2101
2102
  	/*
  	 * FIXME: how to handle RDDR3 at MCI level? It is possible to have
  	 * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
  	 * memory channels
  	 */
  	mci->mtype_cap = MEM_FLAG_DDR3;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2103
2104
2105
  	mci->edac_ctl_cap = EDAC_FLAG_NONE;
  	mci->edac_cap = EDAC_FLAG_NONE;
  	mci->mod_name = "i7core_edac.c";
75f029c3a   Arvind Yadav   EDAC: Handle retu...
2106
2107
2108
2109
2110
2111
  
  	mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d", i7core_dev->socket);
  	if (!mci->ctl_name) {
  		rc = -ENOMEM;
  		goto fail1;
  	}
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2112
  	mci->dev_name = pci_name(i7core_dev->pdev[0]);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2113
  	mci->ctl_page_to_phys = NULL;
1288c18f4   Mauro Carvalho Chehab   i7core_edac: Prop...
2114

ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2115
  	/* Store pci devices at mci for faster access */
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2116
  	rc = mci_bind_devs(mci, i7core_dev);
41fcb7fee   Mauro Carvalho Chehab   i7core_edac: Codi...
2117
  	if (unlikely(rc < 0))
628c5ddfb   Hidetoshi Seto   i7core_edac: Fix ...
2118
  		goto fail0;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2119

5939813b9   Hidetoshi Seto   i7core_edac: Fix ...
2120

ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2121
  	/* Get dimm basic config */
2e5185f7f   Hidetoshi Seto   i7core_edac: Remo...
2122
  	get_dimm_config(mci);
5939813b9   Hidetoshi Seto   i7core_edac: Fix ...
2123
  	/* record ptr to the generic device */
fd687502d   Mauro Carvalho Chehab   edac: Rename the ...
2124
  	mci->pdev = &i7core_dev->pdev[0]->dev;
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2125

e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
2126
  	/* Enable scrubrate setting */
27100db0e   Mauro Carvalho Chehab   i7core_edac: Don'...
2127
2128
  	if (pvt->enable_scrub)
  		enable_sdram_scrub_setting(mci);
e8b6a1271   Samuel Gabrielsson   i7core_edac: Add ...
2129

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2130
  	/* add this new MC control structure to EDAC's list of MCs */
2eace188f   Takashi Iwai   EDAC: i7core: Use...
2131
  	if (unlikely(edac_mc_add_mc_with_groups(mci, i7core_dev_groups))) {
956b9ba15   Joe Perches   edac: Convert deb...
2132
2133
  		edac_dbg(0, "MC: failed edac_mc_add_mc()
  ");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2134
2135
2136
  		/* FIXME: perhaps some code should go here that disables error
  		 * reporting if we just enabled it
  		 */
b7c761512   Mauro Carvalho Chehab   i7core_edac: Impr...
2137
2138
  
  		rc = -EINVAL;
628c5ddfb   Hidetoshi Seto   i7core_edac: Fix ...
2139
  		goto fail0;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2140
  	}
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
2141
  	if (i7core_create_sysfs_devices(mci)) {
956b9ba15   Joe Perches   edac: Convert deb...
2142
2143
  		edac_dbg(0, "MC: failed to create sysfs nodes
  ");
5c4cdb5ae   Mauro Carvalho Chehab   i7core_edac: conv...
2144
2145
2146
2147
  		edac_mc_del_mc(mci->pdev);
  		rc = -EINVAL;
  		goto fail0;
  	}
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2148

194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
2149
  	/* Default error mask is any memory */
ef708b53b   Mauro Carvalho Chehab   i7core_edac: Add ...
2150
  	pvt->inject.channel = 0;
194a40fea   Mauro Carvalho Chehab   i7core_edac: Add ...
2151
2152
2153
2154
2155
  	pvt->inject.dimm = -1;
  	pvt->inject.rank = -1;
  	pvt->inject.bank = -1;
  	pvt->inject.page = -1;
  	pvt->inject.col = -1;
a3aa0a4ab   Hidetoshi Seto   i7core_edac: Intr...
2156
2157
  	/* allocating generic PCI control info */
  	i7core_pci_ctl_create(pvt);
535e9c78e   Nils Carlson   i7core_edac: scru...
2158
2159
  	/* DCLK for scrub rate setting */
  	pvt->dclk_freq = get_dclk_freq();
628c5ddfb   Hidetoshi Seto   i7core_edac: Fix ...
2160
  	return 0;
628c5ddfb   Hidetoshi Seto   i7core_edac: Fix ...
2161
2162
  fail0:
  	kfree(mci->ctl_name);
75f029c3a   Arvind Yadav   EDAC: Handle retu...
2163
2164
  
  fail1:
628c5ddfb   Hidetoshi Seto   i7core_edac: Fix ...
2165
  	edac_mc_free(mci);
1c6edbbe2   Hidetoshi Seto   i7core_edac: Intr...
2166
  	i7core_dev->mci = NULL;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
  	return rc;
  }
  
  /*
   *	i7core_probe	Probe for ONE instance of device to see if it is
   *			present.
   *	return:
   *		0 for FOUND a device
   *		< 0 for error code
   */
2d95d8158   Mauro Carvalho Chehab   i7core_edac: Avoi...
2177

9b3c6e85c   Greg Kroah-Hartman   Drivers: edac: re...
2178
  static int i7core_probe(struct pci_dev *pdev, const struct pci_device_id *id)
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2179
  {
405575914   Mauro Carvalho Chehab   i7core_edac: retu...
2180
  	int rc, count = 0;
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2181
  	struct i7core_dev *i7core_dev;
2d95d8158   Mauro Carvalho Chehab   i7core_edac: Avoi...
2182
2183
  	/* get the pci devices we want to reserve for our use */
  	mutex_lock(&i7core_edac_lock);
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2184
  	/*
d4c277957   Mauro Carvalho Chehab   i7core_edac: a fe...
2185
  	 * All memory controllers are allocated at the first pass.
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2186
  	 */
2d95d8158   Mauro Carvalho Chehab   i7core_edac: Avoi...
2187
2188
  	if (unlikely(probed >= 1)) {
  		mutex_unlock(&i7core_edac_lock);
76a7bd811   Mauro Carvalho Chehab   i7core_edac: retu...
2189
  		return -ENODEV;
2d95d8158   Mauro Carvalho Chehab   i7core_edac: Avoi...
2190
2191
  	}
  	probed++;
de06eeef5   Mauro Carvalho Chehab   i7core_edac: Use ...
2192

64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
2193
  	rc = i7core_get_all_devices();
f47429494   Mauro Carvalho Chehab   i7core_edac: crea...
2194
2195
2196
2197
  	if (unlikely(rc < 0))
  		goto fail0;
  
  	list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
405575914   Mauro Carvalho Chehab   i7core_edac: retu...
2198
  		count++;
aace42831   Hidetoshi Seto   i7core_edac: Redu...
2199
  		rc = i7core_register_mci(i7core_dev);
d4c277957   Mauro Carvalho Chehab   i7core_edac: a fe...
2200
2201
  		if (unlikely(rc < 0))
  			goto fail1;
d5381642a   Mauro Carvalho Chehab   i7core_edac: Add ...
2202
  	}
405575914   Mauro Carvalho Chehab   i7core_edac: retu...
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
  	/*
  	 * Nehalem-EX uses a different memory controller. However, as the
  	 * memory controller is not visible on some Nehalem/Nehalem-EP, we
  	 * need to indirectly probe via a X58 PCI device. The same devices
  	 * are found on (some) Nehalem-EX. So, on those machines, the
  	 * probe routine needs to return -ENODEV, as the actual Memory
  	 * Controller registers won't be detected.
  	 */
  	if (!count) {
  		rc = -ENODEV;
  		goto fail1;
  	}
  
  	i7core_printk(KERN_INFO,
  		      "Driver loaded, %d memory controller(s) found.
  ",
  		      count);
8f3319075   Mauro Carvalho Chehab   i7core_edac: Regi...
2220

66607706c   Mauro Carvalho Chehab   Dynamically alloc...
2221
  	mutex_unlock(&i7core_edac_lock);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2222
  	return 0;
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
2223
  fail1:
88ef5ea97   Mauro Carvalho Chehab   i7core_edac: it i...
2224
2225
  	list_for_each_entry(i7core_dev, &i7core_edac_list, list)
  		i7core_unregister_mci(i7core_dev);
13d6e9b65   Mauro Carvalho Chehab   i7core_edac: at r...
2226
  	i7core_put_all_devices();
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
2227
2228
  fail0:
  	mutex_unlock(&i7core_edac_lock);
b7c761512   Mauro Carvalho Chehab   i7core_edac: Impr...
2229
  	return rc;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2230
2231
2232
2233
2234
2235
  }
  
  /*
   *	i7core_remove	destructor for one instance of device
   *
   */
9b3c6e85c   Greg Kroah-Hartman   Drivers: edac: re...
2236
  static void i7core_remove(struct pci_dev *pdev)
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2237
  {
64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
2238
  	struct i7core_dev *i7core_dev;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2239

956b9ba15   Joe Perches   edac: Convert deb...
2240
2241
  	edac_dbg(0, "
  ");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2242

22e6bcbdc   Mauro Carvalho Chehab   i7core_edac: chan...
2243
2244
2245
2246
2247
2248
2249
  	/*
  	 * we have a trouble here: pdev value for removal will be wrong, since
  	 * it will point to the X58 register used to detect that the machine
  	 * is a Nehalem or upper design. However, due to the way several PCI
  	 * devices are grouped together to provide MC functionality, we need
  	 * to use a different method for releasing the devices
  	 */
87d1d272b   Mauro Carvalho Chehab   i7core_edac: need...
2250

66607706c   Mauro Carvalho Chehab   Dynamically alloc...
2251
  	mutex_lock(&i7core_edac_lock);
71fe01706   Hidetoshi Seto   i7core_edac: Chec...
2252
2253
2254
2255
2256
  
  	if (unlikely(!probed)) {
  		mutex_unlock(&i7core_edac_lock);
  		return;
  	}
88ef5ea97   Mauro Carvalho Chehab   i7core_edac: it i...
2257
2258
  	list_for_each_entry(i7core_dev, &i7core_edac_list, list)
  		i7core_unregister_mci(i7core_dev);
64c10f6e0   Hidetoshi Seto   i7core_edac: Alwa...
2259
2260
2261
  
  	/* Release PCI resources */
  	i7core_put_all_devices();
2d95d8158   Mauro Carvalho Chehab   i7core_edac: Avoi...
2262
  	probed--;
66607706c   Mauro Carvalho Chehab   Dynamically alloc...
2263
  	mutex_unlock(&i7core_edac_lock);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2264
  }
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2265
2266
2267
2268
2269
2270
2271
2272
2273
  MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
  
  /*
   *	i7core_driver	pci_driver structure for this module
   *
   */
  static struct pci_driver i7core_driver = {
  	.name     = "i7core_edac",
  	.probe    = i7core_probe,
9b3c6e85c   Greg Kroah-Hartman   Drivers: edac: re...
2274
  	.remove   = i7core_remove,
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
  	.id_table = i7core_pci_tbl,
  };
  
  /*
   *	i7core_init		Module entry function
   *			Try to initialize this module for its devices
   */
  static int __init i7core_init(void)
  {
  	int pci_rc;
956b9ba15   Joe Perches   edac: Convert deb...
2285
2286
  	edac_dbg(2, "
  ");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2287
2288
2289
  
  	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
  	opstate_init();
54a08ab15   Mauro Carvalho Chehab   i7core_edac: Don'...
2290
2291
  	if (use_pci_fixup)
  		i7core_xeon_pci_fixup(pci_dev_table);
bc2d7245f   Keith Mannthey   i7core_edac: Prob...
2292

a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2293
  	pci_rc = pci_register_driver(&i7core_driver);
e35fca479   Chen Gong   edac: avoid mce d...
2294
2295
  	if (pci_rc >= 0) {
  		mce_register_decode_chain(&i7_mce_dec);
3ef288a98   Mauro Carvalho Chehab   i7core_edac: Prin...
2296
  		return 0;
e35fca479   Chen Gong   edac: avoid mce d...
2297
  	}
3ef288a98   Mauro Carvalho Chehab   i7core_edac: Prin...
2298
2299
2300
2301
2302
2303
  
  	i7core_printk(KERN_ERR, "Failed to register device with error %d.
  ",
  		      pci_rc);
  
  	return pci_rc;
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2304
2305
2306
2307
2308
2309
2310
2311
  }
  
  /*
   *	i7core_exit()	Module exit function
   *			Unregister the driver
   */
  static void __exit i7core_exit(void)
  {
956b9ba15   Joe Perches   edac: Convert deb...
2312
2313
  	edac_dbg(2, "
  ");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2314
  	pci_unregister_driver(&i7core_driver);
e35fca479   Chen Gong   edac: avoid mce d...
2315
  	mce_unregister_decode_chain(&i7_mce_dec);
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2316
2317
2318
2319
2320
2321
  }
  
  module_init(i7core_init);
  module_exit(i7core_exit);
  
  MODULE_LICENSE("GPL");
37e59f876   Mauro Carvalho Chehab   [media, edac] Cha...
2322
  MODULE_AUTHOR("Mauro Carvalho Chehab");
7d4c1ea2b   Alexander A. Klimov   EDAC: Replace HTT...
2323
  MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
a0c36a1f0   Mauro Carvalho Chehab   i7core_edac: Add ...
2324
2325
2326
2327
2328
  MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
  		   I7CORE_REVISION);
  
  module_param(edac_op_state, int, 0444);
  MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");