in i5100_edac.c [980:1163]
static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
int rc;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct i5100_priv *priv;
struct pci_dev *ch0mm, *ch1mm, *einj;
int ret = 0;
u32 dw;
int ranksperch;
if (PCI_FUNC(pdev->devfn) != 1)
return -ENODEV;
rc = pci_enable_device(pdev);
if (rc < 0) {
ret = rc;
goto bail;
}
/* ECC enabled? */
pci_read_config_dword(pdev, I5100_MC, &dw);
if (!i5100_mc_errdeten(dw)) {
printk(KERN_INFO "i5100_edac: ECC not enabled.\n");
ret = -ENODEV;
goto bail_pdev;
}
/* figure out how many ranks, from strapped state of 48GB_Mode input */
pci_read_config_dword(pdev, I5100_MS, &dw);
ranksperch = !!(dw & (1 << 8)) * 2 + 4;
/* enable error reporting... */
pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw);
dw &= ~I5100_FERR_NF_MEM_ANY_MASK;
pci_write_config_dword(pdev, I5100_EMASK_MEM, dw);
/* device 21, func 0, Channel 0 Memory Map, Error Flag/Mask, etc... */
ch0mm = pci_get_device_func(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5100_21, 0);
if (!ch0mm) {
ret = -ENODEV;
goto bail_pdev;
}
rc = pci_enable_device(ch0mm);
if (rc < 0) {
ret = rc;
goto bail_ch0;
}
/* device 22, func 0, Channel 1 Memory Map, Error Flag/Mask, etc... */
ch1mm = pci_get_device_func(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5100_22, 0);
if (!ch1mm) {
ret = -ENODEV;
goto bail_disable_ch0;
}
rc = pci_enable_device(ch1mm);
if (rc < 0) {
ret = rc;
goto bail_ch1;
}
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = 2;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_SLOT;
layers[1].size = ranksperch;
layers[1].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
sizeof(*priv));
if (!mci) {
ret = -ENOMEM;
goto bail_disable_ch1;
}
/* device 19, func 0, Error injection */
einj = pci_get_device_func(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5100_19, 0);
if (!einj) {
ret = -ENODEV;
goto bail_mc_free;
}
rc = pci_enable_device(einj);
if (rc < 0) {
ret = rc;
goto bail_einj;
}
mci->pdev = &pdev->dev;
priv = mci->pvt_info;
priv->ranksperchan = ranksperch;
priv->mc = pdev;
priv->ch0mm = ch0mm;
priv->ch1mm = ch1mm;
priv->einj = einj;
INIT_DELAYED_WORK(&(priv->i5100_scrubbing), i5100_refresh_scrubbing);
/* If scrubbing was already enabled by the bios, start maintaining it */
pci_read_config_dword(pdev, I5100_MC, &dw);
if (i5100_mc_scrben(dw)) {
priv->scrub_enable = 1;
schedule_delayed_work(&(priv->i5100_scrubbing),
I5100_SCRUB_REFRESH_RATE);
}
i5100_init_dimm_layout(pdev, mci);
i5100_init_interleaving(pdev, mci);
mci->mtype_cap = MEM_FLAG_FB_DDR2;
mci->edac_ctl_cap = EDAC_FLAG_SECDED;
mci->edac_cap = EDAC_FLAG_SECDED;
mci->mod_name = "i5100_edac.c";
mci->ctl_name = "i5100";
mci->dev_name = pci_name(pdev);
mci->ctl_page_to_phys = NULL;
mci->edac_check = i5100_check_error;
mci->set_sdram_scrub_rate = i5100_set_scrub_rate;
mci->get_sdram_scrub_rate = i5100_get_scrub_rate;
priv->inject_channel = 0;
priv->inject_hlinesel = 0;
priv->inject_deviceptr1 = 0;
priv->inject_deviceptr2 = 0;
priv->inject_eccmask1 = 0;
priv->inject_eccmask2 = 0;
i5100_init_csrows(mci);
/* this strange construction seems to be in every driver, dunno why */
switch (edac_op_state) {
case EDAC_OPSTATE_POLL:
case EDAC_OPSTATE_NMI:
break;
default:
edac_op_state = EDAC_OPSTATE_POLL;
break;
}
if (edac_mc_add_mc(mci)) {
ret = -ENODEV;
goto bail_scrub;
}
i5100_setup_debugfs(mci);
return ret;
bail_scrub:
priv->scrub_enable = 0;
cancel_delayed_work_sync(&(priv->i5100_scrubbing));
pci_disable_device(einj);
bail_einj:
pci_dev_put(einj);
bail_mc_free:
edac_mc_free(mci);
bail_disable_ch1:
pci_disable_device(ch1mm);
bail_ch1:
pci_dev_put(ch1mm);
bail_disable_ch0:
pci_disable_device(ch0mm);
bail_ch0:
pci_dev_put(ch0mm);
bail_pdev:
pci_disable_device(pdev);
bail:
return ret;
}