Skip to content

Commit

Permalink
Merge branch 'pci/locking' into next
Browse files Browse the repository at this point in the history
* 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()
  • Loading branch information
Bjorn Helgaas committed Jan 15, 2014
2 parents 1255dfb + 8a4c5c3 commit 4030461
Show file tree
Hide file tree
Showing 25 changed files with 209 additions and 44 deletions.
19 changes: 16 additions & 3 deletions arch/powerpc/kernel/eeh_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -618,8 +626,11 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
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)
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}
}

Expand Down
6 changes: 6 additions & 0 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -608,13 +610,17 @@ 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);
pci_acpi_remove_bus_pm_notifier(device);

pci_remove_root_bus(root->bus);

pci_unlock_rescan_remove();

kfree(root);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/message/fusion/mptbase.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
5 changes: 4 additions & 1 deletion drivers/pci/hotplug/acpiphp.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ struct acpiphp_bridge {

/* PCI-to-PCI bridge device */
struct pci_dev *pci_dev;

bool is_going_away;
};


Expand Down Expand Up @@ -150,6 +152,7 @@ struct acpiphp_attention_info
/* slot flags */

#define SLOT_ENABLED (0x00000001)
#define SLOT_IS_GOING_AWAY (0x00000002)

/* function flags */

Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/hotplug/acpiphp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down
43 changes: 38 additions & 5 deletions drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,16 @@ 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);
}

mutex_lock(&bridge_mutex);
list_del(&bridge->list);
mutex_unlock(&bridge_mutex);

bridge->is_going_away = true;
}

/**
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1048,23 +1065,32 @@ 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;
}

/**
* 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);

Expand All @@ -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
Expand All @@ -1095,7 +1130,6 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
return (slot->flags & SLOT_ENABLED);
}


/*
* latch open: 1
* latch closed: 0
Expand All @@ -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
Expand Down
14 changes: 12 additions & 2 deletions drivers/pci/hotplug/cpci_hotplug_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
8 changes: 7 additions & 1 deletion drivers/pci/hotplug/cpqphp_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -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;
}
}

Expand All @@ -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;
}

Expand All @@ -123,13 +127,15 @@ 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) {
pci_dev_put(temp);
pci_stop_and_remove_bus_device(temp);
}
}
pci_unlock_rescan_remove();
return 0;
}

Expand Down
Loading

0 comments on commit 4030461

Please sign in to comment.