aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-08-08 16:09:55 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-08-14 17:20:37 -0400
commit090a3c5322e900f468b3205b76d0837003ad57b2 (patch)
tree8363cd8326137b871778fac3e2f2c32bb0a13f31 /drivers/pci/pci.c
parent77cb985ad4acbe66a92ead1bb826deffa47dd33f (diff)
PCI: Add pci_reset_slot() and pci_reset_bus()
Sometimes pci_reset_function() is not sufficient. We have cases where devices do not support any kind of reset, but there might be multiple functions on the bus preventing pci_reset_function() from doing a secondary bus reset. We also have cases where a device will advertise that it supports a PM reset, but really does nothing on D3hot->D0 (graphics cards are notorious for this). These devices often also have more than one function, so even blacklisting PM reset for them wouldn't allow a secondary bus reset through pci_reset_function(). If a driver supports multiple devices it should have the ability to induce a bus reset when it needs to. This patch provides that ability through pci_reset_slot() and pci_reset_bus(). It's the caller's responsibility when using these interfaces to understand that all of the devices in or below the slot (or on or below the bus) will be reset and therefore should be under control of the caller. PCI state of all the affected devices is saved and restored around these resets, but internal state of all of the affected devices is reset (which should be the intention). Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d48d9febc241..12fccc24925c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3460,6 +3460,215 @@ int pci_reset_function(struct pci_dev *dev)
3460} 3460}
3461EXPORT_SYMBOL_GPL(pci_reset_function); 3461EXPORT_SYMBOL_GPL(pci_reset_function);
3462 3462
3463/* Lock devices from the top of the tree down */
3464static void pci_bus_lock(struct pci_bus *bus)
3465{
3466 struct pci_dev *dev;
3467
3468 list_for_each_entry(dev, &bus->devices, bus_list) {
3469 pci_dev_lock(dev);
3470 if (dev->subordinate)
3471 pci_bus_lock(dev->subordinate);
3472 }
3473}
3474
3475/* Unlock devices from the bottom of the tree up */
3476static void pci_bus_unlock(struct pci_bus *bus)
3477{
3478 struct pci_dev *dev;
3479
3480 list_for_each_entry(dev, &bus->devices, bus_list) {
3481 if (dev->subordinate)
3482 pci_bus_unlock(dev->subordinate);
3483 pci_dev_unlock(dev);
3484 }
3485}
3486
3487/* Lock devices from the top of the tree down */
3488static void pci_slot_lock(struct pci_slot *slot)
3489{
3490 struct pci_dev *dev;
3491
3492 list_for_each_entry(dev, &slot->bus->devices, bus_list) {
3493 if (!dev->slot || dev->slot != slot)
3494 continue;
3495 pci_dev_lock(dev);
3496 if (dev->subordinate)
3497 pci_bus_lock(dev->subordinate);
3498 }
3499}
3500
3501/* Unlock devices from the bottom of the tree up */
3502static void pci_slot_unlock(struct pci_slot *slot)
3503{
3504 struct pci_dev *dev;
3505
3506 list_for_each_entry(dev, &slot->bus->devices, bus_list) {
3507 if (!dev->slot || dev->slot != slot)
3508 continue;
3509 if (dev->subordinate)
3510 pci_bus_unlock(dev->subordinate);
3511 pci_dev_unlock(dev);
3512 }
3513}
3514
3515/* Save and disable devices from the top of the tree down */
3516static void pci_bus_save_and_disable(struct pci_bus *bus)
3517{
3518 struct pci_dev *dev;
3519
3520 list_for_each_entry(dev, &bus->devices, bus_list) {
3521 pci_dev_save_and_disable(dev);
3522 if (dev->subordinate)
3523 pci_bus_save_and_disable(dev->subordinate);
3524 }
3525}
3526
3527/*
3528 * Restore devices from top of the tree down - parent bridges need to be
3529 * restored before we can get to subordinate devices.
3530 */
3531static void pci_bus_restore(struct pci_bus *bus)
3532{
3533 struct pci_dev *dev;
3534
3535 list_for_each_entry(dev, &bus->devices, bus_list) {
3536 pci_dev_restore(dev);
3537 if (dev->subordinate)
3538 pci_bus_restore(dev->subordinate);
3539 }
3540}
3541
3542/* Save and disable devices from the top of the tree down */
3543static void pci_slot_save_and_disable(struct pci_slot *slot)
3544{
3545 struct pci_dev *dev;
3546
3547 list_for_each_entry(dev, &slot->bus->devices, bus_list) {
3548 if (!dev->slot || dev->slot != slot)
3549 continue;
3550 pci_dev_save_and_disable(dev);
3551 if (dev->subordinate)
3552 pci_bus_save_and_disable(dev->subordinate);
3553 }
3554}
3555
3556/*
3557 * Restore devices from top of the tree down - parent bridges need to be
3558 * restored before we can get to subordinate devices.
3559 */
3560static void pci_slot_restore(struct pci_slot *slot)
3561{
3562 struct pci_dev *dev;
3563
3564 list_for_each_entry(dev, &slot->bus->devices, bus_list) {
3565 if (!dev->slot || dev->slot != slot)
3566 continue;
3567 pci_dev_restore(dev);
3568 if (dev->subordinate)
3569 pci_bus_restore(dev->subordinate);
3570 }
3571}
3572
3573static int pci_slot_reset(struct pci_slot *slot, int probe)
3574{
3575 int rc;
3576
3577 if (!slot)
3578 return -ENOTTY;
3579
3580 if (!probe)
3581 pci_slot_lock(slot);
3582
3583 might_sleep();
3584
3585 rc = pci_reset_hotplug_slot(slot->hotplug, probe);
3586
3587 if (!probe)
3588 pci_slot_unlock(slot);
3589
3590 return rc;
3591}
3592
3593/**
3594 * pci_reset_slot - reset a PCI slot
3595 * @slot: PCI slot to reset
3596 *
3597 * A PCI bus may host multiple slots, each slot may support a reset mechanism
3598 * independent of other slots. For instance, some slots may support slot power
3599 * control. In the case of a 1:1 bus to slot architecture, this function may
3600 * wrap the bus reset to avoid spurious slot related events such as hotplug.
3601 * Generally a slot reset should be attempted before a bus reset. All of the
3602 * function of the slot and any subordinate buses behind the slot are reset
3603 * through this function. PCI config space of all devices in the slot and
3604 * behind the slot is saved before and restored after reset.
3605 *
3606 * Return 0 on success, non-zero on error.
3607 */
3608int pci_reset_slot(struct pci_slot *slot)
3609{
3610 int rc;
3611
3612 rc = pci_slot_reset(slot, 1);
3613 if (rc)
3614 return rc;
3615
3616 pci_slot_save_and_disable(slot);
3617
3618 rc = pci_slot_reset(slot, 0);
3619
3620 pci_slot_restore(slot);
3621
3622 return rc;
3623}
3624EXPORT_SYMBOL_GPL(pci_reset_slot);
3625
3626static int pci_bus_reset(struct pci_bus *bus, int probe)
3627{
3628 if (!bus->self)
3629 return -ENOTTY;
3630
3631 if (probe)
3632 return 0;
3633
3634 pci_bus_lock(bus);
3635
3636 might_sleep();
3637
3638 pci_reset_bridge_secondary_bus(bus->self);
3639
3640 pci_bus_unlock(bus);
3641
3642 return 0;
3643}
3644
3645/**
3646 * pci_reset_bus - reset a PCI bus
3647 * @bus: top level PCI bus to reset
3648 *
3649 * Do a bus reset on the given bus and any subordinate buses, saving
3650 * and restoring state of all devices.
3651 *
3652 * Return 0 on success, non-zero on error.
3653 */
3654int pci_reset_bus(struct pci_bus *bus)
3655{
3656 int rc;
3657
3658 rc = pci_bus_reset(bus, 1);
3659 if (rc)
3660 return rc;
3661
3662 pci_bus_save_and_disable(bus);
3663
3664 rc = pci_bus_reset(bus, 0);
3665
3666 pci_bus_restore(bus);
3667
3668 return rc;
3669}
3670EXPORT_SYMBOL_GPL(pci_reset_bus);
3671
3463/** 3672/**
3464 * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count 3673 * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
3465 * @dev: PCI device to query 3674 * @dev: PCI device to query