{
int i;
- for (i = 0; i < N_DEVS; i++)
- pci_dev_put(i7core_dev->pdev[i]);
-
- list_del(&i7core_dev->list);
+ debugf0(__FILE__ ": %s()\n", __func__);
+ for (i = 0; i < N_DEVS; i++) {
+ struct pci_dev *pdev = i7core_dev->pdev[i];
+ if (!pdev)
+ continue;
+ debugf0("Removing dev %02x:%02x.%d\n",
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ pci_dev_put(pdev);
+ }
kfree(i7core_dev->pdev);
+ list_del(&i7core_dev->list);
kfree(i7core_dev);
}
static void __devexit i7core_remove(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
- struct i7core_pvt *pvt;
- struct i7core_dev *i7core_dev;
+ struct i7core_dev *i7core_dev, *tmp;
debugf0(__FILE__ ": %s()\n", __func__);
if (i7core_pci)
edac_pci_release_generic_ctl(i7core_pci);
+ /*
+ * we have a trouble here: pdev value for removal will be wrong, since
+ * it will point to the X58 register used to detect that the machine
+ * is a Nehalem or upper design. However, due to the way several PCI
+ * devices are grouped together to provide MC functionality, we need
+ * to use a different method for releasing the devices
+ */
- mci = edac_mc_del_mc(&pdev->dev);
- if (!mci)
- return;
-
- /* Unregisters on edac_mce in order to receive memory errors */
- pvt = mci->pvt_info;
- i7core_dev = pvt->i7core_dev;
- edac_mce_unregister(&pvt->edac_mce);
-
- /* retrieve references to resources, and free those resources */
mutex_lock(&i7core_edac_lock);
- i7core_put_devices(i7core_dev);
+ list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
+ mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
+ if (mci) {
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ i7core_dev = pvt->i7core_dev;
+ edac_mce_unregister(&pvt->edac_mce);
+ kfree(mci->ctl_name);
+ edac_mc_free(mci);
+ i7core_put_devices(i7core_dev);
+ } else {
+ i7core_printk(KERN_ERR,
+ "Couldn't find mci for socket %d\n",
+ i7core_dev->socket);
+ }
+ }
mutex_unlock(&i7core_edac_lock);
-
- kfree(mci->ctl_name);
- edac_mc_free(mci);
}
MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);