Blame view

drivers/edac/i82443bxgx_edac.c 13.7 KB
5a2c675c8   Tim Small   drivers/edac: new...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
   * module (C) 2006 Tim Small
   *
   * This file may be distributed under the terms of the GNU General
   * Public License.
   *
   * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
   * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
   * others.
   *
   * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
   *
   * Written with reference to 82443BX Host Bridge Datasheet:
631dd1a88   Justin P. Mattock   Update broken web...
15
   * http://download.intel.com/design/chipsets/datashts/29063301.pdf 
5a2c675c8   Tim Small   drivers/edac: new...
16
17
18
19
20
21
22
23
24
25
26
27
28
   * references to this document given in [].
   *
   * This module doesn't support the 440LX, but it may be possible to
   * make it do so (the 440LX's register definitions are different, but
   * not completely so - I haven't studied them in enough detail to know
   * how easy this would be).
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  
  #include <linux/pci.h>
  #include <linux/pci_ids.h>
5a2c675c8   Tim Small   drivers/edac: new...
29

c3c52bce6   Hitoshi Mitake   edac: fix module ...
30
  #include <linux/edac.h>
20bcb7a81   Douglas Thompson   drivers/edac: mod...
31
  #include "edac_core.h"
5a2c675c8   Tim Small   drivers/edac: new...
32
33
34
35
  
  #define I82443_REVISION	"0.1"
  
  #define EDAC_MOD_STR    "i82443bxgx_edac"
5a2c675c8   Tim Small   drivers/edac: new...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  /* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
   * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
   * rows" "The 82443BX supports multiple-bit error detection and
   * single-bit error correction when ECC mode is enabled and
   * single/multi-bit error detection when correction is disabled.
   * During writes to the DRAM, the 82443BX generates ECC for the data
   * on a QWord basis. Partial QWord writes require a read-modify-write
   * cycle when ECC is enabled."
  */
  
  /* "Additionally, the 82443BX ensures that the data is corrected in
   * main memory so that accumulation of errors is prevented. Another
   * error within the same QWord would result in a double-bit error
   * which is unrecoverable. This is known as hardware scrubbing since
   * it requires no software intervention to correct the data in memory."
   */
  
  /* [Also see page 100 (section 4.3), "DRAM Interface"]
   * [Also see page 112 (section 4.6.1.4), ECC]
   */
  
  #define I82443BXGX_NR_CSROWS 8
  #define I82443BXGX_NR_CHANS  1
  #define I82443BXGX_NR_DIMMS  4
5a2c675c8   Tim Small   drivers/edac: new...
60
  /* 82443 PCI Device 0 */
111166010   Douglas Thompson   drivers/edac: Lin...
61
62
63
64
65
66
67
68
69
70
71
  #define I82443BXGX_NBXCFG 0x50	/* 32bit register starting at this PCI
  				 * config space offset */
  #define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24	/* Array of bits, zero if
  						 * row is non-ECC */
  #define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12	/* 2 bits,00=100MHz,10=66 MHz */
  
  #define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7	/* 2 bits:       */
  #define I82443BXGX_NBXCFG_INTEGRITY_NONE   0x0	/* 00 = Non-ECC */
  #define I82443BXGX_NBXCFG_INTEGRITY_EC     0x1	/* 01 = EC (only) */
  #define I82443BXGX_NBXCFG_INTEGRITY_ECC    0x2	/* 10 = ECC */
  #define I82443BXGX_NBXCFG_INTEGRITY_SCRUB  0x3	/* 11 = ECC + HW Scrub */
5a2c675c8   Tim Small   drivers/edac: new...
72
73
  
  #define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE  6
5a2c675c8   Tim Small   drivers/edac: new...
74
  /* 82443 PCI Device 0 */
111166010   Douglas Thompson   drivers/edac: Lin...
75
76
77
78
79
80
81
82
  #define I82443BXGX_EAP   0x80	/* 32bit register starting at this PCI
  				 * config space offset, Error Address
  				 * Pointer Register */
  #define I82443BXGX_EAP_OFFSET_EAP  12	/* High 20 bits of error address */
  #define I82443BXGX_EAP_OFFSET_MBE  BIT(1)	/* Err at EAP was multi-bit (W1TC) */
  #define I82443BXGX_EAP_OFFSET_SBE  BIT(0)	/* Err at EAP was single-bit (W1TC) */
  
  #define I82443BXGX_ERRCMD  0x90	/* 8bit register starting at this PCI
5a2c675c8   Tim Small   drivers/edac: new...
83
  				 * config space offset. */
111166010   Douglas Thompson   drivers/edac: Lin...
84
85
  #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1)	/* 1 = enable */
  #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0)	/* 1 = enable */
5a2c675c8   Tim Small   drivers/edac: new...
86

111166010   Douglas Thompson   drivers/edac: Lin...
87
  #define I82443BXGX_ERRSTS  0x91	/* 16bit register starting at this PCI
5a2c675c8   Tim Small   drivers/edac: new...
88
  				 * config space offset. */
111166010   Douglas Thompson   drivers/edac: Lin...
89
90
91
92
  #define I82443BXGX_ERRSTS_OFFSET_MBFRE 5	/* 3 bits - first err row multibit */
  #define I82443BXGX_ERRSTS_OFFSET_MEF   BIT(4)	/* 1 = MBE occurred */
  #define I82443BXGX_ERRSTS_OFFSET_SBFRE 1	/* 3 bits - first err row singlebit */
  #define I82443BXGX_ERRSTS_OFFSET_SEF   BIT(0)	/* 1 = SBE occurred */
5a2c675c8   Tim Small   drivers/edac: new...
93

111166010   Douglas Thompson   drivers/edac: Lin...
94
95
96
97
  #define I82443BXGX_DRAMC 0x57	/* 8bit register starting at this PCI
  				 * config space offset. */
  #define I82443BXGX_DRAMC_OFFSET_DT 3	/* 2 bits, DRAM Type */
  #define I82443BXGX_DRAMC_DRAM_IS_EDO 0	/* 00 = EDO */
5a2c675c8   Tim Small   drivers/edac: new...
98
  #define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1	/* 01 = SDRAM */
111166010   Douglas Thompson   drivers/edac: Lin...
99
  #define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2	/* 10 = Registered SDRAM */
5a2c675c8   Tim Small   drivers/edac: new...
100

111166010   Douglas Thompson   drivers/edac: Lin...
101
102
  #define I82443BXGX_DRB 0x60	/* 8x 8bit registers starting at this PCI
  				 * config space offset. */
5a2c675c8   Tim Small   drivers/edac: new...
103
104
  
  /* FIXME - don't poll when ECC disabled? */
5a2c675c8   Tim Small   drivers/edac: new...
105
106
107
  struct i82443bxgx_edacmc_error_info {
  	u32 eap;
  };
456a2f955   Dave Jiang   drivers/edac: dri...
108
  static struct edac_pci_ctl_info *i82443bxgx_pci;
53a2fe580   Vladislav Bogdanov   edac: make i82443...
109
110
111
112
113
  static struct pci_dev *mci_pdev;	/* init dev: in case that AGP code has
  					 * already registered driver
  					 */
  
  static int i82443bxgx_registered = 1;
111166010   Douglas Thompson   drivers/edac: Lin...
114
  static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
052dfb45c   Douglas Thompson   drivers/edac: cle...
115
116
  				struct i82443bxgx_edacmc_error_info
  				*info)
5a2c675c8   Tim Small   drivers/edac: new...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  {
  	struct pci_dev *pdev;
  	pdev = to_pci_dev(mci->dev);
  	pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
  	if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
  		/* Clear error to allow next error to be reported [p.61] */
  		pci_write_bits32(pdev, I82443BXGX_EAP,
  				 I82443BXGX_EAP_OFFSET_SBE,
  				 I82443BXGX_EAP_OFFSET_SBE);
  
  	if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
  		/* Clear error to allow next error to be reported [p.61] */
  		pci_write_bits32(pdev, I82443BXGX_EAP,
  				 I82443BXGX_EAP_OFFSET_MBE,
  				 I82443BXGX_EAP_OFFSET_MBE);
  }
111166010   Douglas Thompson   drivers/edac: Lin...
133
134
135
136
  static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
  						struct
  						i82443bxgx_edacmc_error_info
  						*info, int handle_errors)
5a2c675c8   Tim Small   drivers/edac: new...
137
138
139
140
141
142
143
144
145
  {
  	int error_found = 0;
  	u32 eapaddr, page, pageoffset;
  
  	/* bits 30:12 hold the 4kb block in which the error occurred
  	 * [p.61] */
  	eapaddr = (info->eap & 0xfffff000);
  	page = eapaddr >> PAGE_SHIFT;
  	pageoffset = eapaddr - (page << PAGE_SHIFT);
111166010   Douglas Thompson   drivers/edac: Lin...
146
  	if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
5a2c675c8   Tim Small   drivers/edac: new...
147
148
  		error_found = 1;
  		if (handle_errors)
111166010   Douglas Thompson   drivers/edac: Lin...
149
  			edac_mc_handle_ce(mci, page, pageoffset,
052dfb45c   Douglas Thompson   drivers/edac: cle...
150
151
152
153
  				/* 440BX/GX don't make syndrome information
  				 * available */
  				0, edac_mc_find_csrow_by_page(mci, page), 0,
  				mci->ctl_name);
5a2c675c8   Tim Small   drivers/edac: new...
154
  	}
111166010   Douglas Thompson   drivers/edac: Lin...
155
  	if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
5a2c675c8   Tim Small   drivers/edac: new...
156
157
  		error_found = 1;
  		if (handle_errors)
111166010   Douglas Thompson   drivers/edac: Lin...
158
  			edac_mc_handle_ue(mci, page, pageoffset,
052dfb45c   Douglas Thompson   drivers/edac: cle...
159
160
  					edac_mc_find_csrow_by_page(mci, page),
  					mci->ctl_name);
5a2c675c8   Tim Small   drivers/edac: new...
161
162
163
164
  	}
  
  	return error_found;
  }
5a2c675c8   Tim Small   drivers/edac: new...
165
166
167
  static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
  {
  	struct i82443bxgx_edacmc_error_info info;
63ae96be9   Joe Perches   drivers/edac: con...
168
169
  	debugf1("MC%d: %s: %s()
  ", mci->mc_idx, __FILE__, __func__);
5a2c675c8   Tim Small   drivers/edac: new...
170
171
172
  	i82443bxgx_edacmc_get_error_info(mci, &info);
  	i82443bxgx_edacmc_process_error_info(mci, &info, 1);
  }
5a2c675c8   Tim Small   drivers/edac: new...
173
  static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
052dfb45c   Douglas Thompson   drivers/edac: cle...
174
175
176
  				struct pci_dev *pdev,
  				enum edac_type edac_mode,
  				enum mem_type mtype)
5a2c675c8   Tim Small   drivers/edac: new...
177
178
179
180
181
182
183
184
185
186
187
  {
  	struct csrow_info *csrow;
  	int index;
  	u8 drbar, dramc;
  	u32 row_base, row_high_limit, row_high_limit_last;
  
  	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
  	row_high_limit_last = 0;
  	for (index = 0; index < mci->nr_csrows; index++) {
  		csrow = &mci->csrows[index];
  		pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
63ae96be9   Joe Perches   drivers/edac: con...
188
189
190
  		debugf1("MC%d: %s: %s() Row=%d DRB = %#0x
  ",
  			mci->mc_idx, __FILE__, __func__, index, drbar);
5a2c675c8   Tim Small   drivers/edac: new...
191
192
  		row_high_limit = ((u32) drbar << 23);
  		/* find the DRAM Chip Select Base address and mask */
63ae96be9   Joe Perches   drivers/edac: con...
193
  		debugf1("MC%d: %s: %s() Row=%d, "
25985edce   Lucas De Marchi   Fix common misspe...
194
195
  			"Boundary Address=%#0x, Last = %#0x
  ",
63ae96be9   Joe Perches   drivers/edac: con...
196
  			mci->mc_idx, __FILE__, __func__, index, row_high_limit,
5a2c675c8   Tim Small   drivers/edac: new...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  			row_high_limit_last);
  
  		/* 440GX goes to 2GB, represented with a DRB of 0. */
  		if (row_high_limit_last && !row_high_limit)
  			row_high_limit = 1UL << 31;
  
  		/* This row is empty [p.49] */
  		if (row_high_limit == row_high_limit_last)
  			continue;
  		row_base = row_high_limit_last;
  		csrow->first_page = row_base >> PAGE_SHIFT;
  		csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
  		csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
  		/* EAP reports in 4kilobyte granularity [61] */
  		csrow->grain = 1 << 12;
  		csrow->mtype = mtype;
  		/* I don't think 440BX can tell you device type? FIXME? */
  		csrow->dtype = DEV_UNKNOWN;
  		/* Mode is global to all rows on 440BX */
  		csrow->edac_mode = edac_mode;
  		row_high_limit_last = row_high_limit;
  	}
  }
111166010   Douglas Thompson   drivers/edac: Lin...
220
  static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
5a2c675c8   Tim Small   drivers/edac: new...
221
222
223
224
225
226
  {
  	struct mem_ctl_info *mci;
  	u8 dramc;
  	u32 nbxcfg, ecc_mode;
  	enum mem_type mtype;
  	enum edac_type edac_mode;
63ae96be9   Joe Perches   drivers/edac: con...
227
228
  	debugf0("MC: %s: %s()
  ", __FILE__, __func__);
5a2c675c8   Tim Small   drivers/edac: new...
229
230
  
  	/* Something is really hosed if PCI config space reads from
052dfb45c   Douglas Thompson   drivers/edac: cle...
231
232
  	 * the MC aren't working.
  	 */
5a2c675c8   Tim Small   drivers/edac: new...
233
234
  	if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
  		return -EIO;
b8f6f9755   Doug Thompson   drivers/edac: fix...
235
  	mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
5a2c675c8   Tim Small   drivers/edac: new...
236
237
238
  
  	if (mci == NULL)
  		return -ENOMEM;
63ae96be9   Joe Perches   drivers/edac: con...
239
240
  	debugf0("MC: %s: %s(): mci = %p
  ", __FILE__, __func__, mci);
5a2c675c8   Tim Small   drivers/edac: new...
241
242
243
244
245
  	mci->dev = &pdev->dev;
  	mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
  	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
  	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
  	switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
111166010   Douglas Thompson   drivers/edac: Lin...
246
  	case I82443BXGX_DRAMC_DRAM_IS_EDO:
5a2c675c8   Tim Small   drivers/edac: new...
247
248
249
250
251
252
253
254
255
  		mtype = MEM_EDO;
  		break;
  	case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
  		mtype = MEM_SDR;
  		break;
  	case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
  		mtype = MEM_RDR;
  		break;
  	default:
052dfb45c   Douglas Thompson   drivers/edac: cle...
256
257
258
  		debugf0("Unknown/reserved DRAM type value "
  			"in DRAMC register!
  ");
5a2c675c8   Tim Small   drivers/edac: new...
259
260
261
262
263
264
265
266
267
268
269
  		mtype = -MEM_UNKNOWN;
  	}
  
  	if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
  		mci->edac_cap = mci->edac_ctl_cap;
  	else
  		mci->edac_cap = EDAC_FLAG_NONE;
  
  	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
  	pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
  	ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
052dfb45c   Douglas Thompson   drivers/edac: cle...
270
  		(BIT(0) | BIT(1)));
5a2c675c8   Tim Small   drivers/edac: new...
271
272
  
  	mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
052dfb45c   Douglas Thompson   drivers/edac: cle...
273
  		? SCRUB_HW_SRC : SCRUB_NONE;
5a2c675c8   Tim Small   drivers/edac: new...
274

111166010   Douglas Thompson   drivers/edac: Lin...
275
  	switch (ecc_mode) {
5a2c675c8   Tim Small   drivers/edac: new...
276
277
278
279
280
281
282
283
284
285
286
  	case I82443BXGX_NBXCFG_INTEGRITY_NONE:
  		edac_mode = EDAC_NONE;
  		break;
  	case I82443BXGX_NBXCFG_INTEGRITY_EC:
  		edac_mode = EDAC_EC;
  		break;
  	case I82443BXGX_NBXCFG_INTEGRITY_ECC:
  	case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
  		edac_mode = EDAC_SECDED;
  		break;
  	default:
052dfb45c   Douglas Thompson   drivers/edac: cle...
287
288
289
  		debugf0("%s(): Unknown/reserved ECC state "
  			"in NBXCFG register!
  ", __func__);
5a2c675c8   Tim Small   drivers/edac: new...
290
291
292
293
294
295
296
  		edac_mode = EDAC_UNKNOWN;
  		break;
  	}
  
  	i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
  
  	/* Many BIOSes don't clear error flags on boot, so do this
25985edce   Lucas De Marchi   Fix common misspe...
297
  	 * here, or we get "phantom" errors occurring at module-load
5a2c675c8   Tim Small   drivers/edac: new...
298
299
  	 * time. */
  	pci_write_bits32(pdev, I82443BXGX_EAP,
052dfb45c   Douglas Thompson   drivers/edac: cle...
300
301
302
303
  			(I82443BXGX_EAP_OFFSET_SBE |
  				I82443BXGX_EAP_OFFSET_MBE),
  			(I82443BXGX_EAP_OFFSET_SBE |
  				I82443BXGX_EAP_OFFSET_MBE));
5a2c675c8   Tim Small   drivers/edac: new...
304
305
306
307
  
  	mci->mod_name = EDAC_MOD_STR;
  	mci->mod_ver = I82443_REVISION;
  	mci->ctl_name = "I82443BXGX";
c4192705f   Dave Jiang   drivers/edac: add...
308
  	mci->dev_name = pci_name(pdev);
5a2c675c8   Tim Small   drivers/edac: new...
309
310
  	mci->edac_check = i82443bxgx_edacmc_check;
  	mci->ctl_page_to_phys = NULL;
b8f6f9755   Doug Thompson   drivers/edac: fix...
311
  	if (edac_mc_add_mc(mci)) {
5a2c675c8   Tim Small   drivers/edac: new...
312
313
314
315
  		debugf3("%s(): failed edac_mc_add_mc()
  ", __func__);
  		goto fail;
  	}
456a2f955   Dave Jiang   drivers/edac: dri...
316
317
318
319
320
321
322
323
324
325
326
327
  	/* allocating generic PCI control info */
  	i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
  	if (!i82443bxgx_pci) {
  		printk(KERN_WARNING
  			"%s(): Unable to create PCI control
  ",
  			__func__);
  		printk(KERN_WARNING
  			"%s(): PCI error report via EDAC not setup
  ",
  			__func__);
  	}
63ae96be9   Joe Perches   drivers/edac: con...
328
329
  	debugf3("MC: %s: %s(): success
  ", __FILE__, __func__);
5a2c675c8   Tim Small   drivers/edac: new...
330
  	return 0;
052dfb45c   Douglas Thompson   drivers/edac: cle...
331
  fail:
5a2c675c8   Tim Small   drivers/edac: new...
332
333
334
  	edac_mc_free(mci);
  	return -ENODEV;
  }
111166010   Douglas Thompson   drivers/edac: Lin...
335

5a2c675c8   Tim Small   drivers/edac: new...
336
337
338
339
  EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
  
  /* returns count (>= 0), or negative on error */
  static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
111166010   Douglas Thompson   drivers/edac: Lin...
340
  						const struct pci_device_id *ent)
5a2c675c8   Tim Small   drivers/edac: new...
341
  {
53a2fe580   Vladislav Bogdanov   edac: make i82443...
342
  	int rc;
63ae96be9   Joe Perches   drivers/edac: con...
343
344
  	debugf0("MC: %s: %s()
  ", __FILE__, __func__);
5a2c675c8   Tim Small   drivers/edac: new...
345

ee6583f6e   Roman Fietze   PCI: fix typos pc...
346
  	/* don't need to call pci_enable_device() */
53a2fe580   Vladislav Bogdanov   edac: make i82443...
347
348
349
350
351
352
  	rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
  
  	if (mci_pdev == NULL)
  		mci_pdev = pci_dev_get(pdev);
  
  	return rc;
5a2c675c8   Tim Small   drivers/edac: new...
353
  }
5a2c675c8   Tim Small   drivers/edac: new...
354
355
356
  static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
  {
  	struct mem_ctl_info *mci;
63ae96be9   Joe Perches   drivers/edac: con...
357
358
  	debugf0("%s: %s()
  ", __FILE__, __func__);
5a2c675c8   Tim Small   drivers/edac: new...
359

456a2f955   Dave Jiang   drivers/edac: dri...
360
361
  	if (i82443bxgx_pci)
  		edac_pci_release_generic_ctl(i82443bxgx_pci);
111166010   Douglas Thompson   drivers/edac: Lin...
362
  	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
5a2c675c8   Tim Small   drivers/edac: new...
363
364
365
366
  		return;
  
  	edac_mc_free(mci);
  }
5a2c675c8   Tim Small   drivers/edac: new...
367

111166010   Douglas Thompson   drivers/edac: Lin...
368
  EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
5a2c675c8   Tim Small   drivers/edac: new...
369
370
371
372
373
374
375
376
377
378
  
  static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
  	{0,}			/* 0 terminated list. */
  };
  
  MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
5a2c675c8   Tim Small   drivers/edac: new...
379
380
381
382
383
384
  static struct pci_driver i82443bxgx_edacmc_driver = {
  	.name = EDAC_MOD_STR,
  	.probe = i82443bxgx_edacmc_init_one,
  	.remove = __devexit_p(i82443bxgx_edacmc_remove_one),
  	.id_table = i82443bxgx_pci_tbl,
  };
5a2c675c8   Tim Small   drivers/edac: new...
385
386
  static int __init i82443bxgx_edacmc_init(void)
  {
53a2fe580   Vladislav Bogdanov   edac: make i82443...
387
  	int pci_rc;
c3c52bce6   Hitoshi Mitake   edac: fix module ...
388
389
         /* Ensure that the OPSTATE is set correctly for POLL or NMI */
         opstate_init();
53a2fe580   Vladislav Bogdanov   edac: make i82443...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  	pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
  	if (pci_rc < 0)
  		goto fail0;
  
  	if (mci_pdev == NULL) {
  		const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
  		int i = 0;
  		i82443bxgx_registered = 0;
  
  		while (mci_pdev == NULL && id->vendor != 0) {
  			mci_pdev = pci_get_device(id->vendor,
  					id->device, NULL);
  			i++;
  			id = &i82443bxgx_pci_tbl[i];
  		}
  		if (!mci_pdev) {
  			debugf0("i82443bxgx pci_get_device fail
  ");
  			pci_rc = -ENODEV;
  			goto fail1;
  		}
  
  		pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
  
  		if (pci_rc < 0) {
  			debugf0("i82443bxgx init fail
  ");
  			pci_rc = -ENODEV;
  			goto fail1;
  		}
  	}
  
  	return 0;
  
  fail1:
  	pci_unregister_driver(&i82443bxgx_edacmc_driver);
  
  fail0:
  	if (mci_pdev != NULL)
  		pci_dev_put(mci_pdev);
  
  	return pci_rc;
5a2c675c8   Tim Small   drivers/edac: new...
432
  }
5a2c675c8   Tim Small   drivers/edac: new...
433
434
435
  static void __exit i82443bxgx_edacmc_exit(void)
  {
  	pci_unregister_driver(&i82443bxgx_edacmc_driver);
53a2fe580   Vladislav Bogdanov   edac: make i82443...
436
437
438
439
440
441
  
  	if (!i82443bxgx_registered)
  		i82443bxgx_edacmc_remove_one(mci_pdev);
  
  	if (mci_pdev)
  		pci_dev_put(mci_pdev);
5a2c675c8   Tim Small   drivers/edac: new...
442
  }
5a2c675c8   Tim Small   drivers/edac: new...
443
444
  module_init(i82443bxgx_edacmc_init);
  module_exit(i82443bxgx_edacmc_exit);
5a2c675c8   Tim Small   drivers/edac: new...
445
446
447
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
  MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
c3c52bce6   Hitoshi Mitake   edac: fix module ...
448
449
450
  
  module_param(edac_op_state, int, 0444);
  MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");