diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2009-02-20 23:16:07 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-03-20 13:47:33 -0400 |
commit | ae40582e9959cdb7bfe4b918be8e3d19f9511798 (patch) | |
tree | bb46eb3c3ba364b219fa1138011c98e82237604b /drivers/pci | |
parent | 10a0ef39fbd1d484c2bbc1ffd83d57ecef209140 (diff) |
PCI: pcie_portdriver: fix pcie_port_device_remove
pcie_port_device_remove currently calls the remove method of port
drivers twice. Ouch!
We are calling device_for_each_child multiple times for no apparent
reason.
So make it simple. Place put_device and device_unregister into
remove_iter, and throw out the rest. Only call device_for_each_child
once.
The code is simpler and actually works!
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 23 |
1 files changed, 3 insertions, 20 deletions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 3aea92a92928..569af0015fce 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -456,16 +456,9 @@ int pcie_port_device_resume(struct pci_dev *dev) | |||
456 | 456 | ||
457 | static int remove_iter(struct device *dev, void *data) | 457 | static int remove_iter(struct device *dev, void *data) |
458 | { | 458 | { |
459 | struct pcie_port_service_driver *service_driver; | ||
460 | |||
461 | if (dev->bus == &pcie_port_bus_type) { | 459 | if (dev->bus == &pcie_port_bus_type) { |
462 | if (dev->driver) { | 460 | put_device(dev); |
463 | service_driver = to_service_driver(dev->driver); | 461 | device_unregister(dev); |
464 | if (service_driver->remove) | ||
465 | service_driver->remove(to_pcie_device(dev)); | ||
466 | } | ||
467 | *(unsigned long*)data = (unsigned long)dev; | ||
468 | return 1; | ||
469 | } | 462 | } |
470 | return 0; | 463 | return 0; |
471 | } | 464 | } |
@@ -480,18 +473,8 @@ static int remove_iter(struct device *dev, void *data) | |||
480 | void pcie_port_device_remove(struct pci_dev *dev) | 473 | void pcie_port_device_remove(struct pci_dev *dev) |
481 | { | 474 | { |
482 | struct pcie_port_data *port_data = pci_get_drvdata(dev); | 475 | struct pcie_port_data *port_data = pci_get_drvdata(dev); |
483 | int status; | ||
484 | |||
485 | do { | ||
486 | unsigned long device_addr; | ||
487 | 476 | ||
488 | status = device_for_each_child(&dev->dev, &device_addr, remove_iter); | 477 | device_for_each_child(&dev->dev, NULL, remove_iter); |
489 | if (status) { | ||
490 | struct device *device = (struct device*)device_addr; | ||
491 | put_device(device); | ||
492 | device_unregister(device); | ||
493 | } | ||
494 | } while (status); | ||
495 | 478 | ||
496 | switch (port_data->port_irq_mode) { | 479 | switch (port_data->port_irq_mode) { |
497 | case PCIE_PORT_MSIX_MODE: | 480 | case PCIE_PORT_MSIX_MODE: |