diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 427991741cf3..5a14b73cf3a1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -612,30 +612,51 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) | |||
612 | } | 612 | } |
613 | 613 | ||
614 | /** | 614 | /** |
615 | * pci_enable_device - Initialize device before it's used by a driver. | 615 | * __pci_enable_device - Initialize device before it's used by a driver. |
616 | * @dev: PCI device to be initialized | 616 | * @dev: PCI device to be initialized |
617 | * | 617 | * |
618 | * Initialize device before it's used by a driver. Ask low-level code | 618 | * Initialize device before it's used by a driver. Ask low-level code |
619 | * to enable I/O and memory. Wake up the device if it was suspended. | 619 | * to enable I/O and memory. Wake up the device if it was suspended. |
620 | * Beware, this function can fail. | 620 | * Beware, this function can fail. |
621 | * | ||
622 | * Note this function is a backend and is not supposed to be called by | ||
623 | * normal code, use pci_enable_device() instead. | ||
621 | */ | 624 | */ |
622 | int | 625 | int |
623 | pci_enable_device(struct pci_dev *dev) | 626 | __pci_enable_device(struct pci_dev *dev) |
624 | { | 627 | { |
625 | int err; | 628 | int err; |
626 | 629 | ||
627 | if (dev->is_enabled) | ||
628 | return 0; | ||
629 | |||
630 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 630 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); |
631 | if (err) | 631 | if (err) |
632 | return err; | 632 | return err; |
633 | pci_fixup_device(pci_fixup_enable, dev); | 633 | pci_fixup_device(pci_fixup_enable, dev); |
634 | dev->is_enabled = 1; | ||
635 | return 0; | 634 | return 0; |
636 | } | 635 | } |
637 | 636 | ||
638 | /** | 637 | /** |
638 | * pci_enable_device - Initialize device before it's used by a driver. | ||
639 | * @dev: PCI device to be initialized | ||
640 | * | ||
641 | * Initialize device before it's used by a driver. Ask low-level code | ||
642 | * to enable I/O and memory. Wake up the device if it was suspended. | ||
643 | * Beware, this function can fail. | ||
644 | * | ||
645 | * Note we don't actually enable the device many times if we call | ||
646 | * this function repeatedly (we just increment the count). | ||
647 | */ | ||
648 | int pci_enable_device(struct pci_dev *dev) | ||
649 | { | ||
650 | int result; | ||
651 | if (atomic_add_return(1, &dev->enable_cnt) > 1) | ||
652 | return 0; /* already enabled */ | ||
653 | result = __pci_enable_device(dev); | ||
654 | if (result < 0) | ||
655 | atomic_dec(&dev->enable_cnt); | ||
656 | return result; | ||
657 | } | ||
658 | |||
659 | /** | ||
639 | * pcibios_disable_device - disable arch specific PCI resources for device dev | 660 | * pcibios_disable_device - disable arch specific PCI resources for device dev |
640 | * @dev: the PCI device to disable | 661 | * @dev: the PCI device to disable |
641 | * | 662 | * |
@@ -651,12 +672,18 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} | |||
651 | * | 672 | * |
652 | * Signal to the system that the PCI device is not in use by the system | 673 | * Signal to the system that the PCI device is not in use by the system |
653 | * anymore. This only involves disabling PCI bus-mastering, if active. | 674 | * anymore. This only involves disabling PCI bus-mastering, if active. |
675 | * | ||
676 | * Note we don't actually disable the device until all callers of | ||
677 | * pci_device_enable() have called pci_device_disable(). | ||
654 | */ | 678 | */ |
655 | void | 679 | void |
656 | pci_disable_device(struct pci_dev *dev) | 680 | pci_disable_device(struct pci_dev *dev) |
657 | { | 681 | { |
658 | u16 pci_command; | 682 | u16 pci_command; |
659 | 683 | ||
684 | if (atomic_sub_return(1, &dev->enable_cnt) != 0) | ||
685 | return; | ||
686 | |||
660 | if (dev->msi_enabled) | 687 | if (dev->msi_enabled) |
661 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | 688 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), |
662 | PCI_CAP_ID_MSI); | 689 | PCI_CAP_ID_MSI); |
@@ -672,7 +699,6 @@ pci_disable_device(struct pci_dev *dev) | |||
672 | dev->is_busmaster = 0; | 699 | dev->is_busmaster = 0; |
673 | 700 | ||
674 | pcibios_disable_device(dev); | 701 | pcibios_disable_device(dev); |
675 | dev->is_enabled = 0; | ||
676 | } | 702 | } |
677 | 703 | ||
678 | /** | 704 | /** |