0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h>
0043 #include <linux/init.h>
0044 #include <linux/pci.h>
0045 #include <linux/pci_ids.h>
0046 #include <linux/edac.h>
0047
0048 #include <linux/io-64-nonatomic-lo-hi.h>
0049 #include "edac_module.h"
0050
0051 #define EDAC_MOD_STR "ie31200_edac"
0052
0053 #define ie31200_printk(level, fmt, arg...) \
0054 edac_printk(level, "ie31200", fmt, ##arg)
0055
0056 #define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108
0057 #define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c
0058 #define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150
0059 #define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158
0060 #define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
0061 #define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
0062 #define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
0063 #define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
0064 #define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918
0065
0066
0067 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00
0068 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1 0x3e0f
0069 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2 0x3e18
0070 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3 0x3e1f
0071 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4 0x3e30
0072 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5 0x3e31
0073 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6 0x3e32
0074 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7 0x3e33
0075 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8 0x3ec2
0076 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9 0x3ec6
0077 #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca
0078
0079
0080 #define DEVICE_ID_SKYLAKE_OR_LATER(did) \
0081 (((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_8) || \
0082 ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \
0083 (((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \
0084 PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK))
0085
0086 #define IE31200_DIMMS 4
0087 #define IE31200_RANKS 8
0088 #define IE31200_RANKS_PER_CHANNEL 4
0089 #define IE31200_DIMMS_PER_CHANNEL 2
0090 #define IE31200_CHANNELS 2
0091
0092
0093 #define IE31200_MCHBAR_LOW 0x48
0094 #define IE31200_MCHBAR_HIGH 0x4c
0095 #define IE31200_MCHBAR_MASK GENMASK_ULL(38, 15)
0096 #define IE31200_MMR_WINDOW_SIZE BIT(15)
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117 #define IE31200_ERRSTS 0xc8
0118 #define IE31200_ERRSTS_UE BIT(1)
0119 #define IE31200_ERRSTS_CE BIT(0)
0120 #define IE31200_ERRSTS_BITS (IE31200_ERRSTS_UE | IE31200_ERRSTS_CE)
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 #define IE31200_C0ECCERRLOG 0x40c8
0137 #define IE31200_C1ECCERRLOG 0x44c8
0138 #define IE31200_C0ECCERRLOG_SKL 0x4048
0139 #define IE31200_C1ECCERRLOG_SKL 0x4448
0140 #define IE31200_ECCERRLOG_CE BIT(0)
0141 #define IE31200_ECCERRLOG_UE BIT(1)
0142 #define IE31200_ECCERRLOG_RANK_BITS GENMASK_ULL(28, 27)
0143 #define IE31200_ECCERRLOG_RANK_SHIFT 27
0144 #define IE31200_ECCERRLOG_SYNDROME_BITS GENMASK_ULL(23, 16)
0145 #define IE31200_ECCERRLOG_SYNDROME_SHIFT 16
0146
0147 #define IE31200_ECCERRLOG_SYNDROME(log) \
0148 ((log & IE31200_ECCERRLOG_SYNDROME_BITS) >> \
0149 IE31200_ECCERRLOG_SYNDROME_SHIFT)
0150
0151 #define IE31200_CAPID0 0xe4
0152 #define IE31200_CAPID0_PDCD BIT(4)
0153 #define IE31200_CAPID0_DDPCD BIT(6)
0154 #define IE31200_CAPID0_ECC BIT(1)
0155
0156 #define IE31200_MAD_DIMM_0_OFFSET 0x5004
0157 #define IE31200_MAD_DIMM_0_OFFSET_SKL 0x500C
0158 #define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0)
0159 #define IE31200_MAD_DIMM_A_RANK BIT(17)
0160 #define IE31200_MAD_DIMM_A_RANK_SHIFT 17
0161 #define IE31200_MAD_DIMM_A_RANK_SKL BIT(10)
0162 #define IE31200_MAD_DIMM_A_RANK_SKL_SHIFT 10
0163 #define IE31200_MAD_DIMM_A_WIDTH BIT(19)
0164 #define IE31200_MAD_DIMM_A_WIDTH_SHIFT 19
0165 #define IE31200_MAD_DIMM_A_WIDTH_SKL GENMASK_ULL(9, 8)
0166 #define IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT 8
0167
0168
0169 #define IE31200_PAGES(n, skl) \
0170 (n << (28 + (2 * skl) - PAGE_SHIFT))
0171
0172 static int nr_channels;
0173 static struct pci_dev *mci_pdev;
0174 static int ie31200_registered = 1;
0175
0176 struct ie31200_priv {
0177 void __iomem *window;
0178 void __iomem *c0errlog;
0179 void __iomem *c1errlog;
0180 };
0181
0182 enum ie31200_chips {
0183 IE31200 = 0,
0184 };
0185
0186 struct ie31200_dev_info {
0187 const char *ctl_name;
0188 };
0189
0190 struct ie31200_error_info {
0191 u16 errsts;
0192 u16 errsts2;
0193 u64 eccerrlog[IE31200_CHANNELS];
0194 };
0195
0196 static const struct ie31200_dev_info ie31200_devs[] = {
0197 [IE31200] = {
0198 .ctl_name = "IE31200"
0199 },
0200 };
0201
0202 struct dimm_data {
0203 u8 size;
0204 u8 dual_rank : 1,
0205 x16_width : 2;
0206 };
0207
0208 static int how_many_channels(struct pci_dev *pdev)
0209 {
0210 int n_channels;
0211 unsigned char capid0_2b;
0212
0213 pci_read_config_byte(pdev, IE31200_CAPID0 + 1, &capid0_2b);
0214
0215
0216 if (capid0_2b & IE31200_CAPID0_PDCD) {
0217 edac_dbg(0, "In single channel mode\n");
0218 n_channels = 1;
0219 } else {
0220 edac_dbg(0, "In dual channel mode\n");
0221 n_channels = 2;
0222 }
0223
0224
0225 if (capid0_2b & IE31200_CAPID0_DDPCD)
0226 edac_dbg(0, "2 DIMMS per channel disabled\n");
0227 else
0228 edac_dbg(0, "2 DIMMS per channel enabled\n");
0229
0230 return n_channels;
0231 }
0232
0233 static bool ecc_capable(struct pci_dev *pdev)
0234 {
0235 unsigned char capid0_4b;
0236
0237 pci_read_config_byte(pdev, IE31200_CAPID0 + 3, &capid0_4b);
0238 if (capid0_4b & IE31200_CAPID0_ECC)
0239 return false;
0240 return true;
0241 }
0242
0243 static int eccerrlog_row(u64 log)
0244 {
0245 return ((log & IE31200_ECCERRLOG_RANK_BITS) >>
0246 IE31200_ECCERRLOG_RANK_SHIFT);
0247 }
0248
0249 static void ie31200_clear_error_info(struct mem_ctl_info *mci)
0250 {
0251
0252
0253
0254
0255 pci_write_bits16(to_pci_dev(mci->pdev), IE31200_ERRSTS,
0256 IE31200_ERRSTS_BITS, IE31200_ERRSTS_BITS);
0257 }
0258
0259 static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci,
0260 struct ie31200_error_info *info)
0261 {
0262 struct pci_dev *pdev;
0263 struct ie31200_priv *priv = mci->pvt_info;
0264
0265 pdev = to_pci_dev(mci->pdev);
0266
0267
0268
0269
0270
0271
0272 pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts);
0273 if (!(info->errsts & IE31200_ERRSTS_BITS))
0274 return;
0275
0276 info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
0277 if (nr_channels == 2)
0278 info->eccerrlog[1] = lo_hi_readq(priv->c1errlog);
0279
0280 pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2);
0281
0282
0283
0284
0285
0286
0287
0288 if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
0289 info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
0290 if (nr_channels == 2)
0291 info->eccerrlog[1] =
0292 lo_hi_readq(priv->c1errlog);
0293 }
0294
0295 ie31200_clear_error_info(mci);
0296 }
0297
0298 static void ie31200_process_error_info(struct mem_ctl_info *mci,
0299 struct ie31200_error_info *info)
0300 {
0301 int channel;
0302 u64 log;
0303
0304 if (!(info->errsts & IE31200_ERRSTS_BITS))
0305 return;
0306
0307 if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
0308 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
0309 -1, -1, -1, "UE overwrote CE", "");
0310 info->errsts = info->errsts2;
0311 }
0312
0313 for (channel = 0; channel < nr_channels; channel++) {
0314 log = info->eccerrlog[channel];
0315 if (log & IE31200_ECCERRLOG_UE) {
0316 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
0317 0, 0, 0,
0318 eccerrlog_row(log),
0319 channel, -1,
0320 "ie31200 UE", "");
0321 } else if (log & IE31200_ECCERRLOG_CE) {
0322 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
0323 0, 0,
0324 IE31200_ECCERRLOG_SYNDROME(log),
0325 eccerrlog_row(log),
0326 channel, -1,
0327 "ie31200 CE", "");
0328 }
0329 }
0330 }
0331
0332 static void ie31200_check(struct mem_ctl_info *mci)
0333 {
0334 struct ie31200_error_info info;
0335
0336 ie31200_get_and_clear_error_info(mci, &info);
0337 ie31200_process_error_info(mci, &info);
0338 }
0339
0340 static void __iomem *ie31200_map_mchbar(struct pci_dev *pdev)
0341 {
0342 union {
0343 u64 mchbar;
0344 struct {
0345 u32 mchbar_low;
0346 u32 mchbar_high;
0347 };
0348 } u;
0349 void __iomem *window;
0350
0351 pci_read_config_dword(pdev, IE31200_MCHBAR_LOW, &u.mchbar_low);
0352 pci_read_config_dword(pdev, IE31200_MCHBAR_HIGH, &u.mchbar_high);
0353 u.mchbar &= IE31200_MCHBAR_MASK;
0354
0355 if (u.mchbar != (resource_size_t)u.mchbar) {
0356 ie31200_printk(KERN_ERR, "mmio space beyond accessible range (0x%llx)\n",
0357 (unsigned long long)u.mchbar);
0358 return NULL;
0359 }
0360
0361 window = ioremap(u.mchbar, IE31200_MMR_WINDOW_SIZE);
0362 if (!window)
0363 ie31200_printk(KERN_ERR, "Cannot map mmio space at 0x%llx\n",
0364 (unsigned long long)u.mchbar);
0365
0366 return window;
0367 }
0368
0369 static void __skl_populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
0370 int chan)
0371 {
0372 dd->size = (addr_decode >> (chan << 4)) & IE31200_MAD_DIMM_SIZE;
0373 dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK_SKL << (chan << 4))) ? 1 : 0;
0374 dd->x16_width = ((addr_decode & (IE31200_MAD_DIMM_A_WIDTH_SKL << (chan << 4))) >>
0375 (IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT + (chan << 4)));
0376 }
0377
0378 static void __populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
0379 int chan)
0380 {
0381 dd->size = (addr_decode >> (chan << 3)) & IE31200_MAD_DIMM_SIZE;
0382 dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK << chan)) ? 1 : 0;
0383 dd->x16_width = (addr_decode & (IE31200_MAD_DIMM_A_WIDTH << chan)) ? 1 : 0;
0384 }
0385
0386 static void populate_dimm_info(struct dimm_data *dd, u32 addr_decode, int chan,
0387 bool skl)
0388 {
0389 if (skl)
0390 __skl_populate_dimm_info(dd, addr_decode, chan);
0391 else
0392 __populate_dimm_info(dd, addr_decode, chan);
0393 }
0394
0395
0396 static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
0397 {
0398 int i, j, ret;
0399 struct mem_ctl_info *mci = NULL;
0400 struct edac_mc_layer layers[2];
0401 struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
0402 void __iomem *window;
0403 struct ie31200_priv *priv;
0404 u32 addr_decode, mad_offset;
0405
0406
0407
0408
0409
0410 bool skl = DEVICE_ID_SKYLAKE_OR_LATER(pdev->device);
0411
0412 edac_dbg(0, "MC:\n");
0413
0414 if (!ecc_capable(pdev)) {
0415 ie31200_printk(KERN_INFO, "No ECC support\n");
0416 return -ENODEV;
0417 }
0418
0419 nr_channels = how_many_channels(pdev);
0420 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
0421 layers[0].size = IE31200_DIMMS;
0422 layers[0].is_virt_csrow = true;
0423 layers[1].type = EDAC_MC_LAYER_CHANNEL;
0424 layers[1].size = nr_channels;
0425 layers[1].is_virt_csrow = false;
0426 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
0427 sizeof(struct ie31200_priv));
0428 if (!mci)
0429 return -ENOMEM;
0430
0431 window = ie31200_map_mchbar(pdev);
0432 if (!window) {
0433 ret = -ENODEV;
0434 goto fail_free;
0435 }
0436
0437 edac_dbg(3, "MC: init mci\n");
0438 mci->pdev = &pdev->dev;
0439 if (skl)
0440 mci->mtype_cap = MEM_FLAG_DDR4;
0441 else
0442 mci->mtype_cap = MEM_FLAG_DDR3;
0443 mci->edac_ctl_cap = EDAC_FLAG_SECDED;
0444 mci->edac_cap = EDAC_FLAG_SECDED;
0445 mci->mod_name = EDAC_MOD_STR;
0446 mci->ctl_name = ie31200_devs[dev_idx].ctl_name;
0447 mci->dev_name = pci_name(pdev);
0448 mci->edac_check = ie31200_check;
0449 mci->ctl_page_to_phys = NULL;
0450 priv = mci->pvt_info;
0451 priv->window = window;
0452 if (skl) {
0453 priv->c0errlog = window + IE31200_C0ECCERRLOG_SKL;
0454 priv->c1errlog = window + IE31200_C1ECCERRLOG_SKL;
0455 mad_offset = IE31200_MAD_DIMM_0_OFFSET_SKL;
0456 } else {
0457 priv->c0errlog = window + IE31200_C0ECCERRLOG;
0458 priv->c1errlog = window + IE31200_C1ECCERRLOG;
0459 mad_offset = IE31200_MAD_DIMM_0_OFFSET;
0460 }
0461
0462
0463 for (i = 0; i < IE31200_CHANNELS; i++) {
0464 addr_decode = readl(window + mad_offset +
0465 (i * 4));
0466 edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
0467 for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
0468 populate_dimm_info(&dimm_info[i][j], addr_decode, j,
0469 skl);
0470 edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
0471 dimm_info[i][j].size,
0472 dimm_info[i][j].dual_rank,
0473 dimm_info[i][j].x16_width);
0474 }
0475 }
0476
0477
0478
0479
0480
0481
0482
0483 for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) {
0484 for (j = 0; j < IE31200_CHANNELS; j++) {
0485 struct dimm_info *dimm;
0486 unsigned long nr_pages;
0487
0488 nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl);
0489 if (nr_pages == 0)
0490 continue;
0491
0492 if (dimm_info[j][i].dual_rank) {
0493 nr_pages = nr_pages / 2;
0494 dimm = edac_get_dimm(mci, (i * 2) + 1, j, 0);
0495 dimm->nr_pages = nr_pages;
0496 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
0497 dimm->grain = 8;
0498 if (skl)
0499 dimm->mtype = MEM_DDR4;
0500 else
0501 dimm->mtype = MEM_DDR3;
0502 dimm->dtype = DEV_UNKNOWN;
0503 dimm->edac_mode = EDAC_UNKNOWN;
0504 }
0505 dimm = edac_get_dimm(mci, i * 2, j, 0);
0506 dimm->nr_pages = nr_pages;
0507 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
0508 dimm->grain = 8;
0509 if (skl)
0510 dimm->mtype = MEM_DDR4;
0511 else
0512 dimm->mtype = MEM_DDR3;
0513 dimm->dtype = DEV_UNKNOWN;
0514 dimm->edac_mode = EDAC_UNKNOWN;
0515 }
0516 }
0517
0518 ie31200_clear_error_info(mci);
0519
0520 if (edac_mc_add_mc(mci)) {
0521 edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
0522 ret = -ENODEV;
0523 goto fail_unmap;
0524 }
0525
0526
0527 edac_dbg(3, "MC: success\n");
0528 return 0;
0529
0530 fail_unmap:
0531 iounmap(window);
0532
0533 fail_free:
0534 edac_mc_free(mci);
0535
0536 return ret;
0537 }
0538
0539 static int ie31200_init_one(struct pci_dev *pdev,
0540 const struct pci_device_id *ent)
0541 {
0542 int rc;
0543
0544 edac_dbg(0, "MC:\n");
0545 if (pci_enable_device(pdev) < 0)
0546 return -EIO;
0547 rc = ie31200_probe1(pdev, ent->driver_data);
0548 if (rc == 0 && !mci_pdev)
0549 mci_pdev = pci_dev_get(pdev);
0550
0551 return rc;
0552 }
0553
0554 static void ie31200_remove_one(struct pci_dev *pdev)
0555 {
0556 struct mem_ctl_info *mci;
0557 struct ie31200_priv *priv;
0558
0559 edac_dbg(0, "\n");
0560 pci_dev_put(mci_pdev);
0561 mci_pdev = NULL;
0562 mci = edac_mc_del_mc(&pdev->dev);
0563 if (!mci)
0564 return;
0565 priv = mci->pvt_info;
0566 iounmap(priv->window);
0567 edac_mc_free(mci);
0568 }
0569
0570 static const struct pci_device_id ie31200_pci_tbl[] = {
0571 { PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0572 { PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0573 { PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0574 { PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0575 { PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0576 { PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0577 { PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0578 { PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0579 { PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0580 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0581 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0582 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0583 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0584 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0585 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0586 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0587 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0588 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0589 { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
0590 { 0, }
0591 };
0592 MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
0593
0594 static struct pci_driver ie31200_driver = {
0595 .name = EDAC_MOD_STR,
0596 .probe = ie31200_init_one,
0597 .remove = ie31200_remove_one,
0598 .id_table = ie31200_pci_tbl,
0599 };
0600
0601 static int __init ie31200_init(void)
0602 {
0603 int pci_rc, i;
0604
0605 edac_dbg(3, "MC:\n");
0606
0607 opstate_init();
0608
0609 pci_rc = pci_register_driver(&ie31200_driver);
0610 if (pci_rc < 0)
0611 goto fail0;
0612
0613 if (!mci_pdev) {
0614 ie31200_registered = 0;
0615 for (i = 0; ie31200_pci_tbl[i].vendor != 0; i++) {
0616 mci_pdev = pci_get_device(ie31200_pci_tbl[i].vendor,
0617 ie31200_pci_tbl[i].device,
0618 NULL);
0619 if (mci_pdev)
0620 break;
0621 }
0622 if (!mci_pdev) {
0623 edac_dbg(0, "ie31200 pci_get_device fail\n");
0624 pci_rc = -ENODEV;
0625 goto fail1;
0626 }
0627 pci_rc = ie31200_init_one(mci_pdev, &ie31200_pci_tbl[i]);
0628 if (pci_rc < 0) {
0629 edac_dbg(0, "ie31200 init fail\n");
0630 pci_rc = -ENODEV;
0631 goto fail1;
0632 }
0633 }
0634 return 0;
0635
0636 fail1:
0637 pci_unregister_driver(&ie31200_driver);
0638 fail0:
0639 pci_dev_put(mci_pdev);
0640
0641 return pci_rc;
0642 }
0643
0644 static void __exit ie31200_exit(void)
0645 {
0646 edac_dbg(3, "MC:\n");
0647 pci_unregister_driver(&ie31200_driver);
0648 if (!ie31200_registered)
0649 ie31200_remove_one(mci_pdev);
0650 }
0651
0652 module_init(ie31200_init);
0653 module_exit(ie31200_exit);
0654
0655 MODULE_LICENSE("GPL");
0656 MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
0657 MODULE_DESCRIPTION("MC support for Intel Processor E31200 memory hub controllers");