lkml.org 
[lkml]   [2009]   [Jan]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH 2.6.28 2/3] EDAC: Use 'overflow' device for binding i82875 EDAC driver
Bind i82875 EDAC driver to the 'overflow' device.
Depends on 'Unhide MCH5/6 memory controller configuration device' patch
to work in some cases.

This is rebased against 2.6.28 vanilla kernel.

Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>

--- orig/drivers/edac/i82875p_edac.c 2008-12-07 01:15:51.000000000 +0100
+++ tmp/drivers/edac/i82875p_edac.c 2008-12-07 13:02:32.000000000 +0100
@@ -30,10 +30,6 @@
#define i82875p_mc_printk(mci, level, fmt, arg...) \
edac_mc_chipset_printk(mci, level, "i82875p", fmt, ##arg)

-#ifndef PCI_DEVICE_ID_INTEL_82875_0
-#define PCI_DEVICE_ID_INTEL_82875_0 0x2578
-#endif /* PCI_DEVICE_ID_INTEL_82875_0 */
-
#ifndef PCI_DEVICE_ID_INTEL_82875_6
#define PCI_DEVICE_ID_INTEL_82875_6 0x257e
#endif /* PCI_DEVICE_ID_INTEL_82875_6 */
@@ -157,7 +153,7 @@
};

struct i82875p_pvt {
- struct pci_dev *ovrfl_pdev;
+ struct pci_dev *mci_pdev;
void __iomem *ovrfl_window;
};

@@ -178,18 +174,13 @@
.ctl_name = "i82875p"},
};

-static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
- * already registered driver
- */
-
static struct edac_pci_ctl_info *i82875p_pci;

static void i82875p_get_error_info(struct mem_ctl_info *mci,
struct i82875p_error_info *info)
{
- struct pci_dev *pdev;
-
- pdev = to_pci_dev(mci->dev);
+ struct i82875p_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev = pvt->mci_pdev;

/*
* This is a mess because there is no atomic way to read all the
@@ -262,78 +253,6 @@
i82875p_process_error_info(mci, &info, 1);
}

-/* Return 0 on success or 1 on failure. */
-static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
- struct pci_dev **ovrfl_pdev,
- void __iomem **ovrfl_window)
-{
- struct pci_dev *dev;
- void __iomem *window;
- int err;
-
- *ovrfl_pdev = NULL;
- *ovrfl_window = NULL;
- dev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
-
- if (dev == NULL) {
- /* Intel tells BIOS developers to hide device 6 which
- * configures the overflow device access containing
- * the DRBs - this is where we expose device 6.
- * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
- */
- pci_write_bits8(pdev, 0xf4, 0x2, 0x2);
- dev = pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
-
- if (dev == NULL)
- return 1;
-
- err = pci_bus_add_device(dev);
- if (err) {
- i82875p_printk(KERN_ERR,
- "%s(): pci_bus_add_device() Failed\n",
- __func__);
- }
- pci_bus_assign_resources(dev->bus);
- }
-
- *ovrfl_pdev = dev;
-
- if (pci_enable_device(dev)) {
- i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
- "device\n", __func__);
- return 1;
- }
-
- if (pci_request_regions(dev, pci_name(dev))) {
-#ifdef CORRECT_BIOS
- goto fail0;
-#endif
- }
-
- /* cache is irrelevant for PCI bus reads/writes */
- window = ioremap_nocache(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
-
- if (window == NULL) {
- i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
- __func__);
- goto fail1;
- }
-
- *ovrfl_window = window;
- return 0;
-
-fail1:
- pci_release_regions(dev);
-
-#ifdef CORRECT_BIOS
-fail0:
- pci_disable_device(dev);
-#endif
- /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
- return 1;
-}
-
/* Return 1 if dual channel mode is active. Else return 0. */
static inline int dual_channel_active(u32 drc)
{
@@ -341,7 +260,6 @@
}

static void i82875p_init_csrows(struct mem_ctl_info *mci,
- struct pci_dev *pdev,
void __iomem * ovrfl_window, u32 drc)
{
struct csrow_info *csrow;
@@ -381,12 +299,12 @@
}
}

-static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
+static int i82875p_probe_edac(struct pci_dev *mci_pdev,
+ struct pci_dev *ovrfl_pdev, int dev_idx)
{
int rc = -ENODEV;
struct mem_ctl_info *mci;
struct i82875p_pvt *pvt;
- struct pci_dev *ovrfl_pdev;
void __iomem *ovrfl_window;
u32 drc;
u32 nr_chans;
@@ -394,10 +312,12 @@

debugf0("%s()\n", __func__);

- ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
+ /* cache is irrelevant for PCI bus reads/writes */
+ ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
+ pci_resource_len(ovrfl_pdev, 0));
+ if (!ovrfl_window)
+ return -EBUSY;

- if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
- return -ENODEV;
drc = readl(ovrfl_window + I82875P_DRC);
nr_chans = dual_channel_active(drc) + 1;
mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
@@ -412,21 +332,23 @@
kobject_get(&mci->edac_mci_kobj);

debugf3("%s(): init mci\n", __func__);
- mci->dev = &pdev->dev;
+ mci->dev = &ovrfl_pdev->dev;
mci->mtype_cap = MEM_FLAG_DDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
mci->edac_cap = EDAC_FLAG_UNKNOWN;
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82875P_REVISION;
mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
- mci->dev_name = pci_name(pdev);
+ mci->dev_name = pci_name(mci_pdev);
mci->edac_check = i82875p_check;
mci->ctl_page_to_phys = NULL;
+
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct i82875p_pvt *)mci->pvt_info;
- pvt->ovrfl_pdev = ovrfl_pdev;
+ pvt = mci->pvt_info;
+ pvt->mci_pdev = mci_pdev;
pvt->ovrfl_window = ovrfl_window;
- i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
+
+ i82875p_init_csrows(mci, ovrfl_window, drc);
i82875p_get_error_info(mci, &discard); /* clear counters */

/* Here we assume that we will never see multiple instances of this
@@ -438,7 +360,7 @@
}

/* allocating generic PCI control info */
- i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ i82875p_pci = edac_pci_create_generic_ctl(&mci_pdev->dev, EDAC_MOD_STR);
if (!i82875p_pci) {
printk(KERN_WARNING
"%s(): Unable to create PCI control\n",
@@ -458,10 +380,6 @@

fail0:
iounmap(ovrfl_window);
- pci_release_regions(ovrfl_pdev);
-
- pci_disable_device(ovrfl_pdev);
- /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
return rc;
}

@@ -469,26 +387,52 @@
static int __devinit i82875p_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ int mci_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+ struct pci_dev *mci_pdev;
int rc;

debugf0("%s()\n", __func__);
i82875p_printk(KERN_INFO, "i82875p init one\n");

- if (pci_enable_device(pdev) < 0)
- return -EIO;
+ mci_pdev = pci_get_slot(pdev->bus, mci_devfn);
+ if (!mci_pdev)
+ return -ENODEV;
+
+ rc = pci_enable_device(mci_pdev);
+ if (rc < 0)
+ goto err_out_put1;
+
+ /* XXX looks like something is clearing this bit after early
+ * quirk phase */
+ pci_write_bits8(pdev, 0xf4, 0x2, 0x2);

- rc = i82875p_probe1(pdev, ent->driver_data);
+ rc = pci_enable_device(pdev);
+ if (rc < 0)
+ goto err_out_put1;

- if (mci_pdev == NULL)
- mci_pdev = pci_dev_get(pdev);
+ rc = pci_request_regions(pdev, pci_name(pdev));
+ if (rc < 0)
+ goto err_out_noreg;

+ rc = i82875p_probe_edac(mci_pdev, pdev, ent->driver_data);
+
+ if (!rc)
+ return 0;
+
+ pci_release_regions(pdev);
+err_out_noreg:
+ pci_disable_device(pdev);
+err_out_put1:
+ pci_dev_put(mci_pdev);
return rc;
}

static void __devexit i82875p_remove_one(struct pci_dev *pdev)
{
+ int mci_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+ struct pci_dev *mci_pdev;
struct mem_ctl_info *mci;
- struct i82875p_pvt *pvt = NULL;
+ struct i82875p_pvt *pvt;

debugf0("%s()\n", __func__);

@@ -498,29 +442,19 @@
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;

- pvt = (struct i82875p_pvt *)mci->pvt_info;
+ pvt = mci->pvt_info;
+ iounmap(pvt->ovrfl_window);

- if (pvt->ovrfl_window)
- iounmap(pvt->ovrfl_window);
-
- if (pvt->ovrfl_pdev) {
-#ifdef CORRECT_BIOS
- pci_release_regions(pvt->ovrfl_pdev);
-#endif /*CORRECT_BIOS */
- pci_disable_device(pvt->ovrfl_pdev);
- pci_dev_put(pvt->ovrfl_pdev);
- }
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_dev_put(pvt->mci_pdev);

edac_mc_free(mci);
}

-static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
- {
- PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- I82875P},
- {
- 0,
- } /* 0 terminated list. */
+static DEFINE_PCI_DEVICE_TABLE(i82875p_pci_tbl) = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82875_6), I82875P },
+ { 0, } /* 0 terminated list. */
};

MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
@@ -534,58 +468,19 @@

static int __init i82875p_init(void)
{
- int pci_rc;
-
debugf3("%s()\n", __func__);

- /* Ensure that the OPSTATE is set correctly for POLL or NMI */
- opstate_init();
-
- pci_rc = pci_register_driver(&i82875p_driver);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();

- if (pci_rc < 0)
- goto fail0;
-
- if (mci_pdev == NULL) {
- mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82875_0, NULL);
-
- if (!mci_pdev) {
- debugf0("875p pci_get_device fail\n");
- pci_rc = -ENODEV;
- goto fail1;
- }
-
- pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl);
-
- if (pci_rc < 0) {
- debugf0("875p init fail\n");
- pci_rc = -ENODEV;
- goto fail1;
- }
- }
-
- return 0;
-
-fail1:
- pci_unregister_driver(&i82875p_driver);
-
-fail0:
- if (mci_pdev != NULL)
- pci_dev_put(mci_pdev);
-
- return pci_rc;
+ return pci_register_driver(&i82875p_driver);
}

static void __exit i82875p_exit(void)
{
debugf3("%s()\n", __func__);

- i82875p_remove_one(mci_pdev);
- pci_dev_put(mci_pdev);
-
pci_unregister_driver(&i82875p_driver);
-
}

module_init(i82875p_init);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2009-01-01 20:07    [W:0.063 / U:0.692 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site