Merge branch 'pci/locking' into next
* pci/locking: PCI: Check parent kobject in pci_destroy_dev() xen/pcifront: Use global PCI rescan-remove locking powerpc/eeh: Use global PCI rescan-remove locking MPT / PCI: Use pci_stop_and_remove_bus_device_locked() platform / x86: Use global PCI rescan-remove locking PCI: hotplug: Use global PCI rescan-remove locking pcmcia: Use global PCI rescan-remove locking ACPI / hotplug / PCI: Use global PCI rescan-remove locking ACPI / PCI: Use global PCI rescan-remove locking in PCI root hotplug PCI: Add global pci_lock_rescan_remove()
This commit is contained in:
commit
4030461846
|
@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, void *userdata)
|
|||
edev->mode |= EEH_DEV_DISCONNECTED;
|
||||
(*removed)++;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
|
|||
* into pcibios_add_pci_devices().
|
||||
*/
|
||||
eeh_pe_state_mark(pe, EEH_PE_KEEP);
|
||||
if (bus)
|
||||
if (bus) {
|
||||
pci_lock_rescan_remove();
|
||||
pcibios_remove_pci_devices(bus);
|
||||
else if (frozen_bus)
|
||||
pci_unlock_rescan_remove();
|
||||
} else if (frozen_bus) {
|
||||
eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
|
||||
}
|
||||
|
||||
/* Reset the pci controller. (Asserts RST#; resets config space).
|
||||
* Reconfigure bridges and devices. Don't try to bring the system
|
||||
|
@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
/* Restore PE */
|
||||
eeh_ops->configure_bridge(pe);
|
||||
eeh_pe_restore_bars(pe);
|
||||
|
@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
|
|||
pe->tstamp = tstamp;
|
||||
pe->freeze_count = cnt;
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -618,8 +626,11 @@ perm_error:
|
|||
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
|
||||
|
||||
/* Shut down the device drivers for good. */
|
||||
if (frozen_bus)
|
||||
if (frozen_bus) {
|
||||
pci_lock_rescan_remove();
|
||||
pcibios_remove_pci_devices(frozen_bus);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
}
|
||||
|
||||
static void eeh_handle_special_event(void)
|
||||
|
@ -692,6 +703,7 @@ static void eeh_handle_special_event(void)
|
|||
if (rc == 2 || rc == 1)
|
||||
eeh_handle_normal_event(pe);
|
||||
else {
|
||||
pci_lock_rescan_remove();
|
||||
list_for_each_entry_safe(hose, tmp,
|
||||
&hose_list, list_node) {
|
||||
phb_pe = eeh_phb_pe_get(hose);
|
||||
|
@ -703,6 +715,7 @@ static void eeh_handle_special_event(void)
|
|||
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
|
||||
pcibios_remove_pci_devices(bus);
|
||||
}
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -596,7 +596,9 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
|||
pci_assign_unassigned_root_bus_resources(root->bus);
|
||||
}
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pci_bus_add_devices(root->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
return 1;
|
||||
|
||||
end:
|
||||
|
@ -608,6 +610,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
|
|||
{
|
||||
struct acpi_pci_root *root = acpi_driver_data(device);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
pci_stop_root_bus(root->bus);
|
||||
|
||||
device_set_run_wake(root->bus->bridge, false);
|
||||
|
@ -615,6 +619,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
|
|||
|
||||
pci_remove_root_bus(root->bus);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
kfree(root);
|
||||
}
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ static int mpt_remove_dead_ioc_func(void *arg)
|
|||
if ((pdev == NULL))
|
||||
return -1;
|
||||
|
||||
pci_stop_and_remove_bus_device(pdev);
|
||||
pci_stop_and_remove_bus_device_locked(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ struct acpiphp_bridge {
|
|||
|
||||
/* PCI-to-PCI bridge device */
|
||||
struct pci_dev *pci_dev;
|
||||
|
||||
bool is_going_away;
|
||||
};
|
||||
|
||||
|
||||
|
@ -150,6 +152,7 @@ struct acpiphp_attention_info
|
|||
/* slot flags */
|
||||
|
||||
#define SLOT_ENABLED (0x00000001)
|
||||
#define SLOT_IS_GOING_AWAY (0x00000002)
|
||||
|
||||
/* function flags */
|
||||
|
||||
|
@ -169,7 +172,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
|
|||
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
|
||||
|
||||
int acpiphp_enable_slot(struct acpiphp_slot *slot);
|
||||
int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
|
||||
int acpiphp_disable_slot(struct acpiphp_slot *slot);
|
||||
u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
|
||||
u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
|
||||
u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
|
||||
|
|
|
@ -156,7 +156,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
|||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
/* disable the specified slot */
|
||||
return acpiphp_disable_and_eject_slot(slot->acpi_slot);
|
||||
return acpiphp_disable_slot(slot->acpi_slot);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -430,6 +430,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
|
|||
pr_err("failed to remove notify handler\n");
|
||||
}
|
||||
}
|
||||
slot->flags |= SLOT_IS_GOING_AWAY;
|
||||
if (slot->slot)
|
||||
acpiphp_unregister_hotplug_slot(slot);
|
||||
}
|
||||
|
@ -437,6 +438,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
|
|||
mutex_lock(&bridge_mutex);
|
||||
list_del(&bridge->list);
|
||||
mutex_unlock(&bridge_mutex);
|
||||
|
||||
bridge->is_going_away = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -736,6 +739,10 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
|
|||
{
|
||||
struct acpiphp_slot *slot;
|
||||
|
||||
/* Bail out if the bridge is going away. */
|
||||
if (bridge->is_going_away)
|
||||
return;
|
||||
|
||||
list_for_each_entry(slot, &bridge->slots, node) {
|
||||
struct pci_bus *bus = slot->bus;
|
||||
struct pci_dev *dev, *tmp;
|
||||
|
@ -805,6 +812,8 @@ void acpiphp_check_host_bridge(acpi_handle handle)
|
|||
}
|
||||
}
|
||||
|
||||
static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
|
||||
|
||||
static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
struct acpiphp_context *context = data;
|
||||
|
@ -834,6 +843,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
|||
} else {
|
||||
struct acpiphp_slot *slot = func->slot;
|
||||
|
||||
if (slot->flags & SLOT_IS_GOING_AWAY)
|
||||
break;
|
||||
|
||||
mutex_lock(&slot->crit_sect);
|
||||
enable_slot(slot);
|
||||
mutex_unlock(&slot->crit_sect);
|
||||
|
@ -849,6 +861,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
|||
struct acpiphp_slot *slot = func->slot;
|
||||
int ret;
|
||||
|
||||
if (slot->flags & SLOT_IS_GOING_AWAY)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Check if anything has changed in the slot and rescan
|
||||
* from the parent if that's the case.
|
||||
|
@ -878,9 +893,11 @@ static void hotplug_event_work(void *data, u32 type)
|
|||
acpi_handle handle = context->handle;
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
hotplug_event(handle, type, context);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
acpi_scan_lock_release();
|
||||
acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
|
||||
put_bridge(context->func.parent);
|
||||
|
@ -1048,12 +1065,19 @@ void acpiphp_remove_slots(struct pci_bus *bus)
|
|||
*/
|
||||
int acpiphp_enable_slot(struct acpiphp_slot *slot)
|
||||
{
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (slot->flags & SLOT_IS_GOING_AWAY)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&slot->crit_sect);
|
||||
/* configure all functions */
|
||||
if (!(slot->flags & SLOT_ENABLED))
|
||||
enable_slot(slot);
|
||||
|
||||
mutex_unlock(&slot->crit_sect);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1061,10 +1085,12 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
|
|||
* acpiphp_disable_and_eject_slot - power off and eject slot
|
||||
* @slot: ACPI PHP slot
|
||||
*/
|
||||
int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
|
||||
static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
|
||||
{
|
||||
struct acpiphp_func *func;
|
||||
int retval = 0;
|
||||
|
||||
if (slot->flags & SLOT_IS_GOING_AWAY)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&slot->crit_sect);
|
||||
|
||||
|
@ -1082,9 +1108,18 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
|
|||
}
|
||||
|
||||
mutex_unlock(&slot->crit_sect);
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpiphp_disable_slot(struct acpiphp_slot *slot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
ret = acpiphp_disable_and_eject_slot(slot);
|
||||
pci_unlock_rescan_remove();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* slot enabled: 1
|
||||
|
@ -1095,7 +1130,6 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
|
|||
return (slot->flags & SLOT_ENABLED);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* latch open: 1
|
||||
* latch closed: 0
|
||||
|
@ -1105,7 +1139,6 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
|
|||
return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* adapter presence : 1
|
||||
* absence : 0
|
||||
|
|
|
@ -254,9 +254,12 @@ int __ref cpci_configure_slot(struct slot *slot)
|
|||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *parent;
|
||||
int ret = 0;
|
||||
|
||||
dbg("%s - enter", __func__);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (slot->dev == NULL) {
|
||||
dbg("pci_dev null, finding %02x:%02x:%x",
|
||||
slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
|
||||
|
@ -277,7 +280,8 @@ int __ref cpci_configure_slot(struct slot *slot)
|
|||
slot->dev = pci_get_slot(slot->bus, slot->devfn);
|
||||
if (slot->dev == NULL) {
|
||||
err("Could not find PCI device for slot %02x", slot->number);
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
parent = slot->dev->bus;
|
||||
|
@ -294,8 +298,10 @@ int __ref cpci_configure_slot(struct slot *slot)
|
|||
|
||||
pci_bus_add_devices(parent);
|
||||
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
dbg("%s - exit", __func__);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpci_unconfigure_slot(struct slot* slot)
|
||||
|
@ -308,6 +314,8 @@ int cpci_unconfigure_slot(struct slot* slot)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
|
||||
continue;
|
||||
|
@ -318,6 +326,8 @@ int cpci_unconfigure_slot(struct slot* slot)
|
|||
pci_dev_put(slot->dev);
|
||||
slot->dev = NULL;
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
dbg("%s - exit", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
|
|||
struct pci_bus *child;
|
||||
int num;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (func->pci_dev == NULL)
|
||||
func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function));
|
||||
|
||||
|
@ -100,7 +102,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
|
|||
func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
|
||||
if (func->pci_dev == NULL) {
|
||||
dbg("ERROR: pci_dev still null\n");
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +115,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
|
|||
|
||||
pci_dev_put(func->pci_dev);
|
||||
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -123,6 +127,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
|
|||
|
||||
dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
for (j=0; j<8 ; j++) {
|
||||
struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
|
||||
if (temp) {
|
||||
|
@ -130,6 +135,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
|
|||
pci_stop_and_remove_bus_device(temp);
|
||||
}
|
||||
}
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -718,6 +718,8 @@ static void ibm_unconfigure_device(struct pci_func *func)
|
|||
func->device, func->function);
|
||||
debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
for (j = 0; j < 0x08; j++) {
|
||||
temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
|
||||
if (temp) {
|
||||
|
@ -725,7 +727,10 @@ static void ibm_unconfigure_device(struct pci_func *func)
|
|||
pci_dev_put(temp);
|
||||
}
|
||||
}
|
||||
|
||||
pci_dev_put(func->dev);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -780,6 +785,8 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
int flag = 0; /* this is to make sure we don't double scan the bus,
|
||||
for bridged devices primarily */
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (!(bus_structure_fixup(func->busno)))
|
||||
flag = 1;
|
||||
if (func->dev == NULL)
|
||||
|
@ -789,7 +796,7 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
if (func->dev == NULL) {
|
||||
struct pci_bus *bus = pci_find_bus(0, func->busno);
|
||||
if (!bus)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
num = pci_scan_slot(bus,
|
||||
PCI_DEVFN(func->device, func->function));
|
||||
|
@ -800,7 +807,7 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
PCI_DEVFN(func->device, func->function));
|
||||
if (func->dev == NULL) {
|
||||
err("ERROR... : pci_dev still NULL\n");
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
|
||||
|
@ -810,6 +817,8 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
pci_bus_add_devices(child);
|
||||
}
|
||||
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,22 +39,26 @@ int pciehp_configure_device(struct slot *p_slot)
|
|||
struct pci_dev *dev;
|
||||
struct pci_dev *bridge = p_slot->ctrl->pcie->port;
|
||||
struct pci_bus *parent = bridge->subordinate;
|
||||
int num;
|
||||
int num, ret = 0;
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
|
||||
if (dev) {
|
||||
ctrl_err(ctrl, "Device %s already exists "
|
||||
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
|
||||
pci_domain_nr(parent), parent->number);
|
||||
pci_dev_put(dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = pci_scan_slot(parent, PCI_DEVFN(0, 0));
|
||||
if (num == 0) {
|
||||
ctrl_err(ctrl, "No new device found\n");
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||
|
@ -73,7 +77,9 @@ int pciehp_configure_device(struct slot *p_slot)
|
|||
|
||||
pci_bus_add_devices(parent);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pciehp_unconfigure_device(struct slot *p_slot)
|
||||
|
@ -90,6 +96,8 @@ int pciehp_unconfigure_device(struct slot *p_slot)
|
|||
__func__, pci_domain_nr(parent), parent->number);
|
||||
pciehp_get_adapter_status(p_slot, &presence);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
/*
|
||||
* Stopping an SR-IOV PF device removes all the associated VFs,
|
||||
* which will update the bus->devices list and confuse the
|
||||
|
@ -124,5 +132,6 @@ int pciehp_unconfigure_device(struct slot *p_slot)
|
|||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -354,10 +354,15 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
|
|||
{
|
||||
struct pci_bus *bus;
|
||||
struct slot *slot;
|
||||
int ret = 0;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
bus = pcibios_find_pci_bus(dn);
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!bus) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
|
||||
bus->self ? pci_name(bus->self) : "<!PHB!>");
|
||||
|
@ -371,7 +376,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
|
|||
printk(KERN_ERR
|
||||
"%s: unable to remove hotplug slot %s\n",
|
||||
__func__, drc_name);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,7 +388,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
|
|||
if (pcibios_unmap_io_space(bus)) {
|
||||
printk(KERN_ERR "%s: failed to unmap bus range\n",
|
||||
__func__);
|
||||
return -ERANGE;
|
||||
ret = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Remove the EADS bridge device itself */
|
||||
|
@ -390,7 +397,9 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
|
|||
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
|
||||
pci_stop_and_remove_bus_device(bus->self);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -398,7 +398,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
|
|||
return retval;
|
||||
|
||||
if (state == PRESENT) {
|
||||
pci_lock_rescan_remove();
|
||||
pcibios_add_pci_devices(slot->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
slot->state = CONFIGURED;
|
||||
} else if (state == EMPTY) {
|
||||
slot->state = EMPTY;
|
||||
|
@ -418,7 +420,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
|||
if (slot->state == NOT_CONFIGURED)
|
||||
return -EINVAL;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pcibios_remove_pci_devices(slot->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
vm_unmap_aliases();
|
||||
|
||||
slot->state = NOT_CONFIGURED;
|
||||
|
|
|
@ -80,7 +80,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
|
|||
goto out_deconfigure;
|
||||
|
||||
pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
|
||||
pci_lock_rescan_remove();
|
||||
pci_bus_add_devices(slot->zdev->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
return rc;
|
||||
|
||||
|
@ -98,7 +100,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
|||
return -EIO;
|
||||
|
||||
if (slot->zdev->pdev)
|
||||
pci_stop_and_remove_bus_device(slot->zdev->pdev);
|
||||
pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
|
||||
|
||||
rc = zpci_disable_device(slot->zdev);
|
||||
if (rc)
|
||||
|
|
|
@ -459,12 +459,15 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
|
|||
acpi_scan_lock_release();
|
||||
}
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
/* Call the driver for the new device */
|
||||
pci_bus_add_devices(slot->pci_bus);
|
||||
/* Call the drivers for the new devices subordinate to PPB */
|
||||
if (new_ppb)
|
||||
pci_bus_add_devices(new_bus);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
mutex_unlock(&sn_hotplug_mutex);
|
||||
|
||||
if (rc == 0)
|
||||
|
@ -540,6 +543,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
|
|||
acpi_scan_lock_release();
|
||||
}
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
/* Free the SN resources assigned to the Linux device.*/
|
||||
list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
|
||||
|
@ -550,6 +554,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
|
|||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
/* Remove the SSDT for the slot from the ACPI namespace */
|
||||
if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
|
||||
|
|
|
@ -40,7 +40,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
|
|||
struct controller *ctrl = p_slot->ctrl;
|
||||
struct pci_dev *bridge = ctrl->pci_dev;
|
||||
struct pci_bus *parent = bridge->subordinate;
|
||||
int num;
|
||||
int num, ret = 0;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
|
||||
if (dev) {
|
||||
|
@ -48,13 +50,15 @@ int __ref shpchp_configure_device(struct slot *p_slot)
|
|||
"at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev),
|
||||
pci_domain_nr(parent), p_slot->bus, p_slot->device);
|
||||
pci_dev_put(dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
|
||||
if (num == 0) {
|
||||
ctrl_err(ctrl, "No new device found\n");
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
||||
|
@ -75,7 +79,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
|
|||
|
||||
pci_bus_add_devices(parent);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pci_unlock_rescan_remove();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int shpchp_unconfigure_device(struct slot *p_slot)
|
||||
|
@ -89,6 +95,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
|
|||
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
|
||||
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != p_slot->device)
|
||||
continue;
|
||||
|
@ -108,6 +116,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
|
|||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,6 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
|
|||
}
|
||||
static DEVICE_ATTR_RW(msi_bus);
|
||||
|
||||
static DEFINE_MUTEX(pci_remove_rescan_mutex);
|
||||
static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
|
@ -308,10 +307,10 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
|
|||
return -EINVAL;
|
||||
|
||||
if (val) {
|
||||
mutex_lock(&pci_remove_rescan_mutex);
|
||||
pci_lock_rescan_remove();
|
||||
while ((b = pci_find_next_bus(b)) != NULL)
|
||||
pci_rescan_bus(b);
|
||||
mutex_unlock(&pci_remove_rescan_mutex);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -342,9 +341,9 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
|
|||
return -EINVAL;
|
||||
|
||||
if (val) {
|
||||
mutex_lock(&pci_remove_rescan_mutex);
|
||||
pci_lock_rescan_remove();
|
||||
pci_rescan_bus(pdev->bus);
|
||||
mutex_unlock(&pci_remove_rescan_mutex);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -354,11 +353,7 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan,
|
|||
|
||||
static void remove_callback(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
mutex_lock(&pci_remove_rescan_mutex);
|
||||
pci_stop_and_remove_bus_device(pdev);
|
||||
mutex_unlock(&pci_remove_rescan_mutex);
|
||||
pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
@ -395,12 +390,12 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
|
|||
return -EINVAL;
|
||||
|
||||
if (val) {
|
||||
mutex_lock(&pci_remove_rescan_mutex);
|
||||
pci_lock_rescan_remove();
|
||||
if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
|
||||
pci_rescan_bus_bridge_resize(bus->self);
|
||||
else
|
||||
pci_rescan_bus(bus);
|
||||
mutex_unlock(&pci_remove_rescan_mutex);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -2024,6 +2024,24 @@ EXPORT_SYMBOL(pci_scan_slot);
|
|||
EXPORT_SYMBOL(pci_scan_bridge);
|
||||
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
|
||||
|
||||
/*
|
||||
* pci_rescan_bus(), pci_rescan_bus_bridge_resize() and PCI device removal
|
||||
* routines should always be executed under this mutex.
|
||||
*/
|
||||
static DEFINE_MUTEX(pci_rescan_remove_lock);
|
||||
|
||||
void pci_lock_rescan_remove(void)
|
||||
{
|
||||
mutex_lock(&pci_rescan_remove_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_lock_rescan_remove);
|
||||
|
||||
void pci_unlock_rescan_remove(void)
|
||||
{
|
||||
mutex_unlock(&pci_rescan_remove_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_unlock_rescan_remove);
|
||||
|
||||
static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b)
|
||||
{
|
||||
const struct pci_dev *a = to_pci_dev(d_a);
|
||||
|
|
|
@ -20,6 +20,9 @@ static void pci_stop_dev(struct pci_dev *dev)
|
|||
|
||||
static void pci_destroy_dev(struct pci_dev *dev)
|
||||
{
|
||||
if (!dev->dev.kobj.parent)
|
||||
return;
|
||||
|
||||
device_del(&dev->dev);
|
||||
|
||||
put_device(&dev->dev);
|
||||
|
@ -95,6 +98,14 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
|
||||
|
||||
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev)
|
||||
{
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
|
||||
|
||||
void pci_stop_root_bus(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *child, *tmp;
|
||||
|
|
|
@ -471,12 +471,15 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
|
|||
}
|
||||
pcifront_init_sd(sd, domain, bus, pdev);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
|
||||
&pcifront_bus_ops, sd);
|
||||
if (!b) {
|
||||
dev_err(&pdev->xdev->dev,
|
||||
"Error creating PCI Frontend Bus!\n");
|
||||
err = -ENOMEM;
|
||||
pci_unlock_rescan_remove();
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
@ -494,6 +497,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
|
|||
/* Create SysFS and notify udev of the devices. Aka: "going live" */
|
||||
pci_bus_add_devices(b);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return err;
|
||||
|
||||
err_out:
|
||||
|
@ -556,6 +560,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
|
|||
|
||||
dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
|
||||
list_del(&bus_entry->list);
|
||||
|
||||
|
@ -568,6 +573,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
|
|||
|
||||
kfree(bus_entry);
|
||||
}
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
static pci_ers_result_t pcifront_common_process(int cmd,
|
||||
|
@ -1043,8 +1049,10 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
|
|||
domain, bus, slot, func);
|
||||
continue;
|
||||
}
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_and_remove_bus_device(pci_dev);
|
||||
pci_dev_put(pci_dev);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
dev_dbg(&pdev->xdev->dev,
|
||||
"PCI device %04x:%02x:%02x.%d removed.\n",
|
||||
|
|
|
@ -70,6 +70,8 @@ int __ref cb_alloc(struct pcmcia_socket *s)
|
|||
struct pci_dev *dev;
|
||||
unsigned int max, pass;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
|
||||
pci_fixup_cardbus(bus);
|
||||
|
||||
|
@ -93,6 +95,7 @@ int __ref cb_alloc(struct pcmcia_socket *s)
|
|||
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -115,6 +118,10 @@ void cb_free(struct pcmcia_socket *s)
|
|||
if (!bus)
|
||||
return;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list)
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
|
|
@ -606,6 +606,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
|
|||
mutex_unlock(&asus->wmi_lock);
|
||||
|
||||
mutex_lock(&asus->hotplug_lock);
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (asus->wlan.rfkill)
|
||||
rfkill_set_sw_state(asus->wlan.rfkill, blocked);
|
||||
|
@ -656,6 +657,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
|
|||
}
|
||||
|
||||
out_unlock:
|
||||
pci_unlock_rescan_remove();
|
||||
mutex_unlock(&asus->hotplug_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -592,6 +592,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
|
|||
rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
|
||||
|
||||
mutex_lock(&eeepc->hotplug_lock);
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (eeepc->hotplug_slot) {
|
||||
port = acpi_get_pci_dev(handle);
|
||||
|
@ -649,6 +650,7 @@ out_put_dev:
|
|||
}
|
||||
|
||||
out_unlock:
|
||||
pci_unlock_rescan_remove();
|
||||
mutex_unlock(&eeepc->hotplug_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ static int mpt2sas_remove_dead_ioc_func(void *arg)
|
|||
pdev = ioc->pdev;
|
||||
if ((pdev == NULL))
|
||||
return -1;
|
||||
pci_stop_and_remove_bus_device(pdev);
|
||||
pci_stop_and_remove_bus_device_locked(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
|
|||
pdev = ioc->pdev;
|
||||
if ((pdev == NULL))
|
||||
return -1;
|
||||
pci_stop_and_remove_bus_device(pdev);
|
||||
pci_stop_and_remove_bus_device_locked(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -775,6 +775,7 @@ struct pci_dev *pci_dev_get(struct pci_dev *dev);
|
|||
void pci_dev_put(struct pci_dev *dev);
|
||||
void pci_remove_bus(struct pci_bus *b);
|
||||
void pci_stop_and_remove_bus_device(struct pci_dev *dev);
|
||||
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev);
|
||||
void pci_stop_root_bus(struct pci_bus *bus);
|
||||
void pci_remove_root_bus(struct pci_bus *bus);
|
||||
void pci_setup_cardbus(struct pci_bus *bus);
|
||||
|
@ -1011,6 +1012,8 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev);
|
|||
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
|
||||
unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
|
||||
unsigned int pci_rescan_bus(struct pci_bus *bus);
|
||||
void pci_lock_rescan_remove(void);
|
||||
void pci_unlock_rescan_remove(void);
|
||||
|
||||
/* Vital product data routines */
|
||||
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
|
||||
|
|
Loading…
Reference in New Issue