From 4ba7d0f0eb68cf7731ead4ca20e540d0266cfa8e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Nov 2008 09:08:28 +0100 Subject: drivers/pci/hotplug: Add missing pci_dev_get pci_get_slot does a pci_dev_get, so pci_dev_put needs to be called in an error case. An alterative would be to move the test_and_set_bit before the call to pci_get_slot. The problem was fixed using the following semantic patch. (http://www.emn.fr/x-info/coccinelle/) // @@ local idexpression *n; statement S1,S2; expression E,E1; expression *ptr != NULL; type T,T1; @@ ( if (!(n = pci_get_slot(...))) S1 | n = pci_get_slot(...) ) <... when != pci_dev_put(n) when != if (...) { <+... pci_dev_put(n) ...+> } when != true !n || ... when != n = (T)E when != E = n if (!n || ...) S2 ...> ( return \(0\|<+...n...+>\|ptr\); | + pci_dev_put(n); return ...; | pci_dev_put(n); | n = (T1)E1 | E1 = n ) // Signed-off-by: Julia Lawall Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/fakephp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/hotplug/fakephp.c') diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 3a2637a00934..b0e7de9e536d 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -324,6 +324,7 @@ static int disable_slot(struct hotplug_slot *slot) if (test_and_set_bit(0, &dslot->removed)) { dbg("Slot already scheduled for removal\n"); + pci_dev_put(dev); return -ENODEV; } -- cgit v1.2.3 From bf4162bcf82ebc3258d6bc0ddd6453132abde72d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 25 Nov 2008 13:51:44 -0800 Subject: PCI hotplug: fakephp: Allocate PCI resources before adding the device For PCI devices, pci_bus_assign_resources() must be called to set up the pci_device->resource array before pci_bus_add_devices() can be called, else attempts to load drivers results in BAR collision errors where there are none. This is not done in fakephp, so devices can be "unplugged" but scanning the parent bus won't bring the devices back due to resource unallocation. Move the pci_bus_add_device-calling logic into pci_rescan_bus and preface it with a call to pci_bus_assign_resources so that we only have to (re)allocate resources once per bus where a new device is found. Signed-off-by: Darrick J. Wong Acked-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/fakephp.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) (limited to 'drivers/pci/hotplug/fakephp.c') diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index b0e7de9e536d..d8649e127298 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -195,13 +195,13 @@ static void remove_slot_worker(struct work_struct *work) * Tries hard not to re-enable already existing devices; * also handles scanning of subfunctions. */ -static void pci_rescan_slot(struct pci_dev *temp) +static int pci_rescan_slot(struct pci_dev *temp) { struct pci_bus *bus = temp->bus; struct pci_dev *dev; int func; - int retval; u8 hdr_type; + int count = 0; if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { temp->hdr_type = hdr_type & 0x7f; @@ -213,17 +213,12 @@ static void pci_rescan_slot(struct pci_dev *temp) dbg("New device on %s function %x:%x\n", bus->name, temp->devfn >> 3, temp->devfn & 7); - retval = pci_bus_add_device(dev); - if (retval) - dev_err(&dev->dev, "error adding " - "device, continuing.\n"); - else - add_slot(dev); + count++; } } /* multifunction device? */ if (!(hdr_type & 0x80)) - return; + return count; /* continue scanning for other functions */ for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) { @@ -239,16 +234,13 @@ static void pci_rescan_slot(struct pci_dev *temp) dbg("New device on %s function %x:%x\n", bus->name, temp->devfn >> 3, temp->devfn & 7); - retval = pci_bus_add_device(dev); - if (retval) - dev_err(&dev->dev, "error adding " - "device, continuing.\n"); - else - add_slot(dev); + count++; } } } } + + return count; } @@ -262,6 +254,8 @@ static void pci_rescan_bus(const struct pci_bus *bus) { unsigned int devfn; struct pci_dev *dev; + int retval; + int found = 0; dev = alloc_pci_dev(); if (!dev) return; @@ -270,7 +264,23 @@ static void pci_rescan_bus(const struct pci_bus *bus) dev->sysdata = bus->sysdata; for (devfn = 0; devfn < 0x100; devfn += 8) { dev->devfn = devfn; - pci_rescan_slot(dev); + found += pci_rescan_slot(dev); + } + + if (found) { + pci_bus_assign_resources(bus); + list_for_each_entry(dev, &bus->devices, bus_list) { + /* Skip already-added devices */ + if (dev->is_added) + continue; + retval = pci_bus_add_device(dev); + if (retval) + dev_err(&dev->dev, + "Error adding device, continuing\n"); + else + add_slot(dev); + } + pci_bus_add_devices(bus); } kfree(dev); } -- cgit v1.2.3