/* * The bandwidth is based on experimentation, feel free to refine it. */ static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth) { struct i5100_priv *priv = mci->pvt_info; u32 dw; pci_read_config_dword(priv->mc, I5100_MC, &dw); if (*bandwidth) { priv->scrub_enable = 1; dw |= I5100_MC_SCRBEN_MASK; schedule_delayed_work(&(priv->i5100_scrubbing), I5100_SCRUB_REFRESH_RATE); } else { priv->scrub_enable = 0; dw &= ~I5100_MC_SCRBEN_MASK; cancel_delayed_work(&(priv->i5100_scrubbing)); } pci_write_config_dword(priv->mc, I5100_MC, dw); pci_read_config_dword(priv->mc, I5100_MC, &dw); *bandwidth = 5900000 * i5100_mc_scrben(dw); return 0; }
static int i5100_get_scrub_rate(struct mem_ctl_info *mci) { struct i5100_priv *priv = mci->pvt_info; u32 dw; pci_read_config_dword(priv->mc, I5100_MC, &dw); return 5900000 * i5100_mc_scrben(dw); }
static int __devinit i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { int rc; struct mem_ctl_info *mci; struct i5100_priv *priv; struct pci_dev *ch0mm, *ch1mm; 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; } mci = edac_mc_alloc(sizeof(*priv), ranksperch * 2, 1, 0); if (!mci) { ret = -ENOMEM; goto bail_disable_ch1; } mci->dev = &pdev->dev; priv = mci->pvt_info; priv->ranksperchan = ranksperch; priv->mc = pdev; priv->ch0mm = ch0mm; priv->ch1mm = ch1mm; 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->mod_ver = "not versioned"; 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; 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; } return ret; bail_scrub: priv->scrub_enable = 0; cancel_delayed_work_sync(&(priv->i5100_scrubbing)); 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; }