aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-14 14:03:14 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-01-14 14:14:25 -0500
commitc4ec84c7db0e4b01ed40cc2388f16ae5c6513cc0 (patch)
treeb280cdcdbf714b6709e8d87a0d157f4979cb73d7 /drivers/pci
parent5ef68e8867ca9d979644d05c6045b2c79d8989de (diff)
PCI: hotplug: Use global PCI rescan-remove locking
Multiple race conditions are possible between PCI hotplug and the generic PCI bus rescan and device removal that can be triggered via sysfs. To avoid those race conditions make PCI hotplug use global PCI rescan-remove locking. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c14
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c8
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c13
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c17
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c19
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c4
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c4
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c5
-rw-r--r--drivers/pci/hotplug/shpchp_pci.c18
9 files changed, 83 insertions, 19 deletions
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index d3add9819f63..8c1464851768 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -254,9 +254,12 @@ int __ref cpci_configure_slot(struct slot *slot)
254{ 254{
255 struct pci_dev *dev; 255 struct pci_dev *dev;
256 struct pci_bus *parent; 256 struct pci_bus *parent;
257 int ret = 0;
257 258
258 dbg("%s - enter", __func__); 259 dbg("%s - enter", __func__);
259 260
261 pci_lock_rescan_remove();
262
260 if (slot->dev == NULL) { 263 if (slot->dev == NULL) {
261 dbg("pci_dev null, finding %02x:%02x:%x", 264 dbg("pci_dev null, finding %02x:%02x:%x",
262 slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); 265 slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
@@ -277,7 +280,8 @@ int __ref cpci_configure_slot(struct slot *slot)
277 slot->dev = pci_get_slot(slot->bus, slot->devfn); 280 slot->dev = pci_get_slot(slot->bus, slot->devfn);
278 if (slot->dev == NULL) { 281 if (slot->dev == NULL) {
279 err("Could not find PCI device for slot %02x", slot->number); 282 err("Could not find PCI device for slot %02x", slot->number);
280 return -ENODEV; 283 ret = -ENODEV;
284 goto out;
281 } 285 }
282 } 286 }
283 parent = slot->dev->bus; 287 parent = slot->dev->bus;
@@ -294,8 +298,10 @@ int __ref cpci_configure_slot(struct slot *slot)
294 298
295 pci_bus_add_devices(parent); 299 pci_bus_add_devices(parent);
296 300
301 out:
302 pci_unlock_rescan_remove();
297 dbg("%s - exit", __func__); 303 dbg("%s - exit", __func__);
298 return 0; 304 return ret;
299} 305}
300 306
301int cpci_unconfigure_slot(struct slot* slot) 307int cpci_unconfigure_slot(struct slot* slot)
@@ -308,6 +314,8 @@ int cpci_unconfigure_slot(struct slot* slot)
308 return -ENODEV; 314 return -ENODEV;
309 } 315 }
310 316
317 pci_lock_rescan_remove();
318
311 list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) { 319 list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
312 if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) 320 if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
313 continue; 321 continue;
@@ -318,6 +326,8 @@ int cpci_unconfigure_slot(struct slot* slot)
318 pci_dev_put(slot->dev); 326 pci_dev_put(slot->dev);
319 slot->dev = NULL; 327 slot->dev = NULL;
320 328
329 pci_unlock_rescan_remove();
330
321 dbg("%s - exit", __func__); 331 dbg("%s - exit", __func__);
322 return 0; 332 return 0;
323} 333}
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 6e4a12c91adb..a3e3c2002b58 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -86,6 +86,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
86 struct pci_bus *child; 86 struct pci_bus *child;
87 int num; 87 int num;
88 88
89 pci_lock_rescan_remove();
90
89 if (func->pci_dev == NULL) 91 if (func->pci_dev == NULL)
90 func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); 92 func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function));
91 93
@@ -100,7 +102,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
100 func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); 102 func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
101 if (func->pci_dev == NULL) { 103 if (func->pci_dev == NULL) {
102 dbg("ERROR: pci_dev still null\n"); 104 dbg("ERROR: pci_dev still null\n");
103 return 0; 105 goto out;
104 } 106 }
105 } 107 }
106 108
@@ -113,6 +115,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
113 115
114 pci_dev_put(func->pci_dev); 116 pci_dev_put(func->pci_dev);
115 117
118 out:
119 pci_unlock_rescan_remove();
116 return 0; 120 return 0;
117} 121}
118 122
@@ -123,6 +127,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
123 127
124 dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); 128 dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function);
125 129
130 pci_lock_rescan_remove();
126 for (j=0; j<8 ; j++) { 131 for (j=0; j<8 ; j++) {
127 struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); 132 struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
128 if (temp) { 133 if (temp) {
@@ -130,6 +135,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
130 pci_stop_and_remove_bus_device(temp); 135 pci_stop_and_remove_bus_device(temp);
131 } 136 }
132 } 137 }
138 pci_unlock_rescan_remove();
133 return 0; 139 return 0;
134} 140}
135 141
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index efdc13adbe41..cf3ac1e4b099 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -718,6 +718,8 @@ static void ibm_unconfigure_device(struct pci_func *func)
718 func->device, func->function); 718 func->device, func->function);
719 debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); 719 debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0);
720 720
721 pci_lock_rescan_remove();
722
721 for (j = 0; j < 0x08; j++) { 723 for (j = 0; j < 0x08; j++) {
722 temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); 724 temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
723 if (temp) { 725 if (temp) {
@@ -725,7 +727,10 @@ static void ibm_unconfigure_device(struct pci_func *func)
725 pci_dev_put(temp); 727 pci_dev_put(temp);
726 } 728 }
727 } 729 }
730
728 pci_dev_put(func->dev); 731 pci_dev_put(func->dev);
732
733 pci_unlock_rescan_remove();
729} 734}
730 735
731/* 736/*
@@ -780,6 +785,8 @@ static int ibm_configure_device(struct pci_func *func)
780 int flag = 0; /* this is to make sure we don't double scan the bus, 785 int flag = 0; /* this is to make sure we don't double scan the bus,
781 for bridged devices primarily */ 786 for bridged devices primarily */
782 787
788 pci_lock_rescan_remove();
789
783 if (!(bus_structure_fixup(func->busno))) 790 if (!(bus_structure_fixup(func->busno)))
784 flag = 1; 791 flag = 1;
785 if (func->dev == NULL) 792 if (func->dev == NULL)
@@ -789,7 +796,7 @@ static int ibm_configure_device(struct pci_func *func)
789 if (func->dev == NULL) { 796 if (func->dev == NULL) {
790 struct pci_bus *bus = pci_find_bus(0, func->busno); 797 struct pci_bus *bus = pci_find_bus(0, func->busno);
791 if (!bus) 798 if (!bus)
792 return 0; 799 goto out;
793 800
794 num = pci_scan_slot(bus, 801 num = pci_scan_slot(bus,
795 PCI_DEVFN(func->device, func->function)); 802 PCI_DEVFN(func->device, func->function));
@@ -800,7 +807,7 @@ static int ibm_configure_device(struct pci_func *func)
800 PCI_DEVFN(func->device, func->function)); 807 PCI_DEVFN(func->device, func->function));
801 if (func->dev == NULL) { 808 if (func->dev == NULL) {
802 err("ERROR... : pci_dev still NULL\n"); 809 err("ERROR... : pci_dev still NULL\n");
803 return 0; 810 goto out;
804 } 811 }
805 } 812 }
806 if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { 813 if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
@@ -810,6 +817,8 @@ static int ibm_configure_device(struct pci_func *func)
810 pci_bus_add_devices(child); 817 pci_bus_add_devices(child);
811 } 818 }
812 819
820 out:
821 pci_unlock_rescan_remove();
813 return 0; 822 return 0;
814} 823}
815 824
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 198355112ee7..b07d7cc2d697 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -39,22 +39,26 @@ int pciehp_configure_device(struct slot *p_slot)
39 struct pci_dev *dev; 39 struct pci_dev *dev;
40 struct pci_dev *bridge = p_slot->ctrl->pcie->port; 40 struct pci_dev *bridge = p_slot->ctrl->pcie->port;
41 struct pci_bus *parent = bridge->subordinate; 41 struct pci_bus *parent = bridge->subordinate;
42 int num; 42 int num, ret = 0;
43 struct controller *ctrl = p_slot->ctrl; 43 struct controller *ctrl = p_slot->ctrl;
44 44
45 pci_lock_rescan_remove();
46
45 dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); 47 dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
46 if (dev) { 48 if (dev) {
47 ctrl_err(ctrl, "Device %s already exists " 49 ctrl_err(ctrl, "Device %s already exists "
48 "at %04x:%02x:00, cannot hot-add\n", pci_name(dev), 50 "at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
49 pci_domain_nr(parent), parent->number); 51 pci_domain_nr(parent), parent->number);
50 pci_dev_put(dev); 52 pci_dev_put(dev);
51 return -EINVAL; 53 ret = -EINVAL;
54 goto out;
52 } 55 }
53 56
54 num = pci_scan_slot(parent, PCI_DEVFN(0, 0)); 57 num = pci_scan_slot(parent, PCI_DEVFN(0, 0));
55 if (num == 0) { 58 if (num == 0) {
56 ctrl_err(ctrl, "No new device found\n"); 59 ctrl_err(ctrl, "No new device found\n");
57 return -ENODEV; 60 ret = -ENODEV;
61 goto out;
58 } 62 }
59 63
60 list_for_each_entry(dev, &parent->devices, bus_list) 64 list_for_each_entry(dev, &parent->devices, bus_list)
@@ -73,7 +77,9 @@ int pciehp_configure_device(struct slot *p_slot)
73 77
74 pci_bus_add_devices(parent); 78 pci_bus_add_devices(parent);
75 79
76 return 0; 80 out:
81 pci_unlock_rescan_remove();
82 return ret;
77} 83}
78 84
79int pciehp_unconfigure_device(struct slot *p_slot) 85int pciehp_unconfigure_device(struct slot *p_slot)
@@ -90,6 +96,8 @@ int pciehp_unconfigure_device(struct slot *p_slot)
90 __func__, pci_domain_nr(parent), parent->number); 96 __func__, pci_domain_nr(parent), parent->number);
91 pciehp_get_adapter_status(p_slot, &presence); 97 pciehp_get_adapter_status(p_slot, &presence);
92 98
99 pci_lock_rescan_remove();
100
93 /* 101 /*
94 * Stopping an SR-IOV PF device removes all the associated VFs, 102 * Stopping an SR-IOV PF device removes all the associated VFs,
95 * which will update the bus->devices list and confuse the 103 * which will update the bus->devices list and confuse the
@@ -124,5 +132,6 @@ int pciehp_unconfigure_device(struct slot *p_slot)
124 pci_dev_put(dev); 132 pci_dev_put(dev);
125 } 133 }
126 134
135 pci_unlock_rescan_remove();
127 return rc; 136 return rc;
128} 137}
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index e9c044d15add..4fcdeedda31b 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -354,10 +354,15 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
354{ 354{
355 struct pci_bus *bus; 355 struct pci_bus *bus;
356 struct slot *slot; 356 struct slot *slot;
357 int ret = 0;
358
359 pci_lock_rescan_remove();
357 360
358 bus = pcibios_find_pci_bus(dn); 361 bus = pcibios_find_pci_bus(dn);
359 if (!bus) 362 if (!bus) {
360 return -EINVAL; 363 ret = -EINVAL;
364 goto out;
365 }
361 366
362 pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", 367 pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
363 bus->self ? pci_name(bus->self) : "<!PHB!>"); 368 bus->self ? pci_name(bus->self) : "<!PHB!>");
@@ -371,7 +376,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
371 printk(KERN_ERR 376 printk(KERN_ERR
372 "%s: unable to remove hotplug slot %s\n", 377 "%s: unable to remove hotplug slot %s\n",
373 __func__, drc_name); 378 __func__, drc_name);
374 return -EIO; 379 ret = -EIO;
380 goto out;
375 } 381 }
376 } 382 }
377 383
@@ -382,7 +388,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
382 if (pcibios_unmap_io_space(bus)) { 388 if (pcibios_unmap_io_space(bus)) {
383 printk(KERN_ERR "%s: failed to unmap bus range\n", 389 printk(KERN_ERR "%s: failed to unmap bus range\n",
384 __func__); 390 __func__);
385 return -ERANGE; 391 ret = -ERANGE;
392 goto out;
386 } 393 }
387 394
388 /* Remove the EADS bridge device itself */ 395 /* Remove the EADS bridge device itself */
@@ -390,7 +397,9 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
390 pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); 397 pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
391 pci_stop_and_remove_bus_device(bus->self); 398 pci_stop_and_remove_bus_device(bus->self);
392 399
393 return 0; 400 out:
401 pci_unlock_rescan_remove();
402 return ret;
394} 403}
395 404
396/** 405/**
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index b7fc5c9255a5..4796c15fba94 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -398,7 +398,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
398 return retval; 398 return retval;
399 399
400 if (state == PRESENT) { 400 if (state == PRESENT) {
401 pci_lock_rescan_remove();
401 pcibios_add_pci_devices(slot->bus); 402 pcibios_add_pci_devices(slot->bus);
403 pci_unlock_rescan_remove();
402 slot->state = CONFIGURED; 404 slot->state = CONFIGURED;
403 } else if (state == EMPTY) { 405 } else if (state == EMPTY) {
404 slot->state = EMPTY; 406 slot->state = EMPTY;
@@ -418,7 +420,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
418 if (slot->state == NOT_CONFIGURED) 420 if (slot->state == NOT_CONFIGURED)
419 return -EINVAL; 421 return -EINVAL;
420 422
423 pci_lock_rescan_remove();
421 pcibios_remove_pci_devices(slot->bus); 424 pcibios_remove_pci_devices(slot->bus);
425 pci_unlock_rescan_remove();
422 vm_unmap_aliases(); 426 vm_unmap_aliases();
423 427
424 slot->state = NOT_CONFIGURED; 428 slot->state = NOT_CONFIGURED;
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index 3c7eb5dd91c6..8d2ce22151eb 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -80,7 +80,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
80 goto out_deconfigure; 80 goto out_deconfigure;
81 81
82 pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); 82 pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
83 pci_lock_rescan_remove();
83 pci_bus_add_devices(slot->zdev->bus); 84 pci_bus_add_devices(slot->zdev->bus);
85 pci_unlock_rescan_remove();
84 86
85 return rc; 87 return rc;
86 88
@@ -98,7 +100,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
98 return -EIO; 100 return -EIO;
99 101
100 if (slot->zdev->pdev) 102 if (slot->zdev->pdev)
101 pci_stop_and_remove_bus_device(slot->zdev->pdev); 103 pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
102 104
103 rc = zpci_disable_device(slot->zdev); 105 rc = zpci_disable_device(slot->zdev);
104 if (rc) 106 if (rc)
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5b05a68cca6c..613043f7576f 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -459,12 +459,15 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
459 acpi_scan_lock_release(); 459 acpi_scan_lock_release();
460 } 460 }
461 461
462 pci_lock_rescan_remove();
463
462 /* Call the driver for the new device */ 464 /* Call the driver for the new device */
463 pci_bus_add_devices(slot->pci_bus); 465 pci_bus_add_devices(slot->pci_bus);
464 /* Call the drivers for the new devices subordinate to PPB */ 466 /* Call the drivers for the new devices subordinate to PPB */
465 if (new_ppb) 467 if (new_ppb)
466 pci_bus_add_devices(new_bus); 468 pci_bus_add_devices(new_bus);
467 469
470 pci_unlock_rescan_remove();
468 mutex_unlock(&sn_hotplug_mutex); 471 mutex_unlock(&sn_hotplug_mutex);
469 472
470 if (rc == 0) 473 if (rc == 0)
@@ -540,6 +543,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
540 acpi_scan_lock_release(); 543 acpi_scan_lock_release();
541 } 544 }
542 545
546 pci_lock_rescan_remove();
543 /* Free the SN resources assigned to the Linux device.*/ 547 /* Free the SN resources assigned to the Linux device.*/
544 list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) { 548 list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
545 if (PCI_SLOT(dev->devfn) != slot->device_num + 1) 549 if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
@@ -550,6 +554,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
550 pci_stop_and_remove_bus_device(dev); 554 pci_stop_and_remove_bus_device(dev);
551 pci_dev_put(dev); 555 pci_dev_put(dev);
552 } 556 }
557 pci_unlock_rescan_remove();
553 558
554 /* Remove the SSDT for the slot from the ACPI namespace */ 559 /* Remove the SSDT for the slot from the ACPI namespace */
555 if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { 560 if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index b0e83132542e..2bf69fe1926c 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -40,7 +40,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
40 struct controller *ctrl = p_slot->ctrl; 40 struct controller *ctrl = p_slot->ctrl;
41 struct pci_dev *bridge = ctrl->pci_dev; 41 struct pci_dev *bridge = ctrl->pci_dev;
42 struct pci_bus *parent = bridge->subordinate; 42 struct pci_bus *parent = bridge->subordinate;
43 int num; 43 int num, ret = 0;
44
45 pci_lock_rescan_remove();
44 46
45 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); 47 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
46 if (dev) { 48 if (dev) {
@@ -48,13 +50,15 @@ int __ref shpchp_configure_device(struct slot *p_slot)
48 "at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev), 50 "at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev),
49 pci_domain_nr(parent), p_slot->bus, p_slot->device); 51 pci_domain_nr(parent), p_slot->bus, p_slot->device);
50 pci_dev_put(dev); 52 pci_dev_put(dev);
51 return -EINVAL; 53 ret = -EINVAL;
54 goto out;
52 } 55 }
53 56
54 num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); 57 num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
55 if (num == 0) { 58 if (num == 0) {
56 ctrl_err(ctrl, "No new device found\n"); 59 ctrl_err(ctrl, "No new device found\n");
57 return -ENODEV; 60 ret = -ENODEV;
61 goto out;
58 } 62 }
59 63
60 list_for_each_entry(dev, &parent->devices, bus_list) { 64 list_for_each_entry(dev, &parent->devices, bus_list) {
@@ -75,7 +79,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
75 79
76 pci_bus_add_devices(parent); 80 pci_bus_add_devices(parent);
77 81
78 return 0; 82 out:
83 pci_unlock_rescan_remove();
84 return ret;
79} 85}
80 86
81int shpchp_unconfigure_device(struct slot *p_slot) 87int shpchp_unconfigure_device(struct slot *p_slot)
@@ -89,6 +95,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
89 ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", 95 ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
90 __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); 96 __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
91 97
98 pci_lock_rescan_remove();
99
92 list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { 100 list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
93 if (PCI_SLOT(dev->devfn) != p_slot->device) 101 if (PCI_SLOT(dev->devfn) != p_slot->device)
94 continue; 102 continue;
@@ -108,6 +116,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
108 pci_stop_and_remove_bus_device(dev); 116 pci_stop_and_remove_bus_device(dev);
109 pci_dev_put(dev); 117 pci_dev_put(dev);
110 } 118 }
119
120 pci_unlock_rescan_remove();
111 return rc; 121 return rc;
112} 122}
113 123