OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [edac/] [i82443bxgx_edac.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
3
 * module (C) 2006 Tim Small
4
 *
5
 * This file may be distributed under the terms of the GNU General
6
 * Public License.
7
 *
8
 * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
9
 * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
10
 * others.
11
 *
12
 * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
13
 *
14
 * Written with reference to 82443BX Host Bridge Datasheet:
15
 * http://www.intel.com/design/chipsets/440/documentation.htm
16
 * references to this document given in [].
17
 *
18
 * This module doesn't support the 440LX, but it may be possible to
19
 * make it do so (the 440LX's register definitions are different, but
20
 * not completely so - I haven't studied them in enough detail to know
21
 * how easy this would be).
22
 */
23
 
24
#include <linux/module.h>
25
#include <linux/init.h>
26
 
27
#include <linux/pci.h>
28
#include <linux/pci_ids.h>
29
 
30
#include <linux/slab.h>
31
 
32
#include "edac_core.h"
33
 
34
#define I82443_REVISION "0.1"
35
 
36
#define EDAC_MOD_STR    "i82443bxgx_edac"
37
 
38
/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
39
 * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
40
 * rows" "The 82443BX supports multiple-bit error detection and
41
 * single-bit error correction when ECC mode is enabled and
42
 * single/multi-bit error detection when correction is disabled.
43
 * During writes to the DRAM, the 82443BX generates ECC for the data
44
 * on a QWord basis. Partial QWord writes require a read-modify-write
45
 * cycle when ECC is enabled."
46
*/
47
 
48
/* "Additionally, the 82443BX ensures that the data is corrected in
49
 * main memory so that accumulation of errors is prevented. Another
50
 * error within the same QWord would result in a double-bit error
51
 * which is unrecoverable. This is known as hardware scrubbing since
52
 * it requires no software intervention to correct the data in memory."
53
 */
54
 
55
/* [Also see page 100 (section 4.3), "DRAM Interface"]
56
 * [Also see page 112 (section 4.6.1.4), ECC]
57
 */
58
 
59
#define I82443BXGX_NR_CSROWS 8
60
#define I82443BXGX_NR_CHANS  1
61
#define I82443BXGX_NR_DIMMS  4
62
 
63
/* 82443 PCI Device 0 */
64
#define I82443BXGX_NBXCFG 0x50  /* 32bit register starting at this PCI
65
                                 * config space offset */
66
#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24  /* Array of bits, zero if
67
                                                 * row is non-ECC */
68
#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12   /* 2 bits,00=100MHz,10=66 MHz */
69
 
70
#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7       /* 2 bits:       */
71
#define I82443BXGX_NBXCFG_INTEGRITY_NONE   0x0  /* 00 = Non-ECC */
72
#define I82443BXGX_NBXCFG_INTEGRITY_EC     0x1  /* 01 = EC (only) */
73
#define I82443BXGX_NBXCFG_INTEGRITY_ECC    0x2  /* 10 = ECC */
74
#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB  0x3  /* 11 = ECC + HW Scrub */
75
 
76
#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE  6
77
 
78
/* 82443 PCI Device 0 */
79
#define I82443BXGX_EAP   0x80   /* 32bit register starting at this PCI
80
                                 * config space offset, Error Address
81
                                 * Pointer Register */
82
#define I82443BXGX_EAP_OFFSET_EAP  12   /* High 20 bits of error address */
83
#define I82443BXGX_EAP_OFFSET_MBE  BIT(1)       /* Err at EAP was multi-bit (W1TC) */
84
#define I82443BXGX_EAP_OFFSET_SBE  BIT(0)       /* Err at EAP was single-bit (W1TC) */
85
 
86
#define I82443BXGX_ERRCMD  0x90 /* 8bit register starting at this PCI
87
                                 * config space offset. */
88
#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1)     /* 1 = enable */
89
#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0)     /* 1 = enable */
90
 
91
#define I82443BXGX_ERRSTS  0x91 /* 16bit register starting at this PCI
92
                                 * config space offset. */
93
#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5        /* 3 bits - first err row multibit */
94
#define I82443BXGX_ERRSTS_OFFSET_MEF   BIT(4)   /* 1 = MBE occurred */
95
#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1        /* 3 bits - first err row singlebit */
96
#define I82443BXGX_ERRSTS_OFFSET_SEF   BIT(0)   /* 1 = SBE occurred */
97
 
98
#define I82443BXGX_DRAMC 0x57   /* 8bit register starting at this PCI
99
                                 * config space offset. */
100
#define I82443BXGX_DRAMC_OFFSET_DT 3    /* 2 bits, DRAM Type */
101
#define I82443BXGX_DRAMC_DRAM_IS_EDO 0  /* 00 = EDO */
102
#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1        /* 01 = SDRAM */
103
#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2       /* 10 = Registered SDRAM */
104
 
105
#define I82443BXGX_DRB 0x60     /* 8x 8bit registers starting at this PCI
106
                                 * config space offset. */
107
 
108
/* FIXME - don't poll when ECC disabled? */
109
 
110
struct i82443bxgx_edacmc_error_info {
111
        u32 eap;
112
};
113
 
114
static struct edac_pci_ctl_info *i82443bxgx_pci;
115
 
116
static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
117
                                struct i82443bxgx_edacmc_error_info
118
                                *info)
119
{
120
        struct pci_dev *pdev;
121
        pdev = to_pci_dev(mci->dev);
122
        pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
123
        if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
124
                /* Clear error to allow next error to be reported [p.61] */
125
                pci_write_bits32(pdev, I82443BXGX_EAP,
126
                                 I82443BXGX_EAP_OFFSET_SBE,
127
                                 I82443BXGX_EAP_OFFSET_SBE);
128
 
129
        if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
130
                /* Clear error to allow next error to be reported [p.61] */
131
                pci_write_bits32(pdev, I82443BXGX_EAP,
132
                                 I82443BXGX_EAP_OFFSET_MBE,
133
                                 I82443BXGX_EAP_OFFSET_MBE);
134
}
135
 
136
static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
137
                                                struct
138
                                                i82443bxgx_edacmc_error_info
139
                                                *info, int handle_errors)
140
{
141
        int error_found = 0;
142
        u32 eapaddr, page, pageoffset;
143
 
144
        /* bits 30:12 hold the 4kb block in which the error occurred
145
         * [p.61] */
146
        eapaddr = (info->eap & 0xfffff000);
147
        page = eapaddr >> PAGE_SHIFT;
148
        pageoffset = eapaddr - (page << PAGE_SHIFT);
149
 
150
        if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
151
                error_found = 1;
152
                if (handle_errors)
153
                        edac_mc_handle_ce(mci, page, pageoffset,
154
                                /* 440BX/GX don't make syndrome information
155
                                 * available */
156
                                0, edac_mc_find_csrow_by_page(mci, page), 0,
157
                                mci->ctl_name);
158
        }
159
 
160
        if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
161
                error_found = 1;
162
                if (handle_errors)
163
                        edac_mc_handle_ue(mci, page, pageoffset,
164
                                        edac_mc_find_csrow_by_page(mci, page),
165
                                        mci->ctl_name);
166
        }
167
 
168
        return error_found;
169
}
170
 
171
static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
172
{
173
        struct i82443bxgx_edacmc_error_info info;
174
 
175
        debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
176
        i82443bxgx_edacmc_get_error_info(mci, &info);
177
        i82443bxgx_edacmc_process_error_info(mci, &info, 1);
178
}
179
 
180
static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
181
                                struct pci_dev *pdev,
182
                                enum edac_type edac_mode,
183
                                enum mem_type mtype)
184
{
185
        struct csrow_info *csrow;
186
        int index;
187
        u8 drbar, dramc;
188
        u32 row_base, row_high_limit, row_high_limit_last;
189
 
190
        pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
191
        row_high_limit_last = 0;
192
        for (index = 0; index < mci->nr_csrows; index++) {
193
                csrow = &mci->csrows[index];
194
                pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
195
                debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
196
                        mci->mc_idx, __func__, index, drbar);
197
                row_high_limit = ((u32) drbar << 23);
198
                /* find the DRAM Chip Select Base address and mask */
199
                debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
200
                        "Boundry Address=%#0x, Last = %#0x \n",
201
                        mci->mc_idx, __func__, index, row_high_limit,
202
                        row_high_limit_last);
203
 
204
                /* 440GX goes to 2GB, represented with a DRB of 0. */
205
                if (row_high_limit_last && !row_high_limit)
206
                        row_high_limit = 1UL << 31;
207
 
208
                /* This row is empty [p.49] */
209
                if (row_high_limit == row_high_limit_last)
210
                        continue;
211
                row_base = row_high_limit_last;
212
                csrow->first_page = row_base >> PAGE_SHIFT;
213
                csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
214
                csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
215
                /* EAP reports in 4kilobyte granularity [61] */
216
                csrow->grain = 1 << 12;
217
                csrow->mtype = mtype;
218
                /* I don't think 440BX can tell you device type? FIXME? */
219
                csrow->dtype = DEV_UNKNOWN;
220
                /* Mode is global to all rows on 440BX */
221
                csrow->edac_mode = edac_mode;
222
                row_high_limit_last = row_high_limit;
223
        }
224
}
225
 
226
static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
227
{
228
        struct mem_ctl_info *mci;
229
        u8 dramc;
230
        u32 nbxcfg, ecc_mode;
231
        enum mem_type mtype;
232
        enum edac_type edac_mode;
233
 
234
        debugf0("MC: " __FILE__ ": %s()\n", __func__);
235
 
236
        /* Something is really hosed if PCI config space reads from
237
         * the MC aren't working.
238
         */
239
        if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
240
                return -EIO;
241
 
242
        mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
243
 
244
        if (mci == NULL)
245
                return -ENOMEM;
246
 
247
        debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
248
        mci->dev = &pdev->dev;
249
        mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
250
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
251
        pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
252
        switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
253
        case I82443BXGX_DRAMC_DRAM_IS_EDO:
254
                mtype = MEM_EDO;
255
                break;
256
        case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
257
                mtype = MEM_SDR;
258
                break;
259
        case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
260
                mtype = MEM_RDR;
261
                break;
262
        default:
263
                debugf0("Unknown/reserved DRAM type value "
264
                        "in DRAMC register!\n");
265
                mtype = -MEM_UNKNOWN;
266
        }
267
 
268
        if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
269
                mci->edac_cap = mci->edac_ctl_cap;
270
        else
271
                mci->edac_cap = EDAC_FLAG_NONE;
272
 
273
        mci->scrub_cap = SCRUB_FLAG_HW_SRC;
274
        pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
275
        ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
276
                (BIT(0) | BIT(1)));
277
 
278
        mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
279
                ? SCRUB_HW_SRC : SCRUB_NONE;
280
 
281
        switch (ecc_mode) {
282
        case I82443BXGX_NBXCFG_INTEGRITY_NONE:
283
                edac_mode = EDAC_NONE;
284
                break;
285
        case I82443BXGX_NBXCFG_INTEGRITY_EC:
286
                edac_mode = EDAC_EC;
287
                break;
288
        case I82443BXGX_NBXCFG_INTEGRITY_ECC:
289
        case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
290
                edac_mode = EDAC_SECDED;
291
                break;
292
        default:
293
                debugf0("%s(): Unknown/reserved ECC state "
294
                        "in NBXCFG register!\n", __func__);
295
                edac_mode = EDAC_UNKNOWN;
296
                break;
297
        }
298
 
299
        i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
300
 
301
        /* Many BIOSes don't clear error flags on boot, so do this
302
         * here, or we get "phantom" errors occuring at module-load
303
         * time. */
304
        pci_write_bits32(pdev, I82443BXGX_EAP,
305
                        (I82443BXGX_EAP_OFFSET_SBE |
306
                                I82443BXGX_EAP_OFFSET_MBE),
307
                        (I82443BXGX_EAP_OFFSET_SBE |
308
                                I82443BXGX_EAP_OFFSET_MBE));
309
 
310
        mci->mod_name = EDAC_MOD_STR;
311
        mci->mod_ver = I82443_REVISION;
312
        mci->ctl_name = "I82443BXGX";
313
        mci->dev_name = pci_name(pdev);
314
        mci->edac_check = i82443bxgx_edacmc_check;
315
        mci->ctl_page_to_phys = NULL;
316
 
317
        if (edac_mc_add_mc(mci)) {
318
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
319
                goto fail;
320
        }
321
 
322
        /* allocating generic PCI control info */
323
        i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
324
        if (!i82443bxgx_pci) {
325
                printk(KERN_WARNING
326
                        "%s(): Unable to create PCI control\n",
327
                        __func__);
328
                printk(KERN_WARNING
329
                        "%s(): PCI error report via EDAC not setup\n",
330
                        __func__);
331
        }
332
 
333
        debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
334
        return 0;
335
 
336
fail:
337
        edac_mc_free(mci);
338
        return -ENODEV;
339
}
340
 
341
EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
342
 
343
/* returns count (>= 0), or negative on error */
344
static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
345
                                                const struct pci_device_id *ent)
346
{
347
        debugf0("MC: " __FILE__ ": %s()\n", __func__);
348
 
349
        /* don't need to call pci_device_enable() */
350
        return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
351
}
352
 
353
static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
354
{
355
        struct mem_ctl_info *mci;
356
 
357
        debugf0(__FILE__ ": %s()\n", __func__);
358
 
359
        if (i82443bxgx_pci)
360
                edac_pci_release_generic_ctl(i82443bxgx_pci);
361
 
362
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
363
                return;
364
 
365
        edac_mc_free(mci);
366
}
367
 
368
EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
369
 
370
static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
371
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
372
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
373
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
374
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
375
        {0,}                     /* 0 terminated list. */
376
};
377
 
378
MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
379
 
380
static struct pci_driver i82443bxgx_edacmc_driver = {
381
        .name = EDAC_MOD_STR,
382
        .probe = i82443bxgx_edacmc_init_one,
383
        .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
384
        .id_table = i82443bxgx_pci_tbl,
385
};
386
 
387
static int __init i82443bxgx_edacmc_init(void)
388
{
389
        return pci_register_driver(&i82443bxgx_edacmc_driver);
390
}
391
 
392
static void __exit i82443bxgx_edacmc_exit(void)
393
{
394
        pci_unregister_driver(&i82443bxgx_edacmc_driver);
395
}
396
 
397
module_init(i82443bxgx_edacmc_init);
398
module_exit(i82443bxgx_edacmc_exit);
399
 
400
MODULE_LICENSE("GPL");
401
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
402
MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.