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