aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c127
1 files changed, 126 insertions, 1 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 84c757ba0664..8b44cff2c176 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -744,6 +744,104 @@ int pci_enable_device(struct pci_dev *dev)
744 return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); 744 return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
745} 745}
746 746
747/*
748 * Managed PCI resources. This manages device on/off, intx/msi/msix
749 * on/off and BAR regions. pci_dev itself records msi/msix status, so
750 * there's no need to track it separately. pci_devres is initialized
751 * when a device is enabled using managed PCI device enable interface.
752 */
753struct pci_devres {
754 unsigned int disable:1;
755 unsigned int orig_intx:1;
756 unsigned int restore_intx:1;
757 u32 region_mask;
758};
759
760static void pcim_release(struct device *gendev, void *res)
761{
762 struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
763 struct pci_devres *this = res;
764 int i;
765
766 if (dev->msi_enabled)
767 pci_disable_msi(dev);
768 if (dev->msix_enabled)
769 pci_disable_msix(dev);
770
771 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
772 if (this->region_mask & (1 << i))
773 pci_release_region(dev, i);
774
775 if (this->restore_intx)
776 pci_intx(dev, this->orig_intx);
777
778 if (this->disable)
779 pci_disable_device(dev);
780}
781
782static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
783{
784 struct pci_devres *dr, *new_dr;
785
786 dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
787 if (dr)
788 return dr;
789
790 new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
791 if (!new_dr)
792 return NULL;
793 return devres_get(&pdev->dev, new_dr, NULL, NULL);
794}
795
796static struct pci_devres * find_pci_dr(struct pci_dev *pdev)
797{
798 if (pci_is_managed(pdev))
799 return devres_find(&pdev->dev, pcim_release, NULL, NULL);
800 return NULL;
801}
802
803/**
804 * pcim_enable_device - Managed pci_enable_device()
805 * @pdev: PCI device to be initialized
806 *
807 * Managed pci_enable_device().
808 */
809int pcim_enable_device(struct pci_dev *pdev)
810{
811 struct pci_devres *dr;
812 int rc;
813
814 dr = get_pci_dr(pdev);
815 if (unlikely(!dr))
816 return -ENOMEM;
817 WARN_ON(!!dr->disable);
818
819 rc = pci_enable_device(pdev);
820 if (!rc) {
821 pdev->is_managed = 1;
822 dr->disable = 1;
823 }
824 return rc;
825}
826
827/**
828 * pcim_pin_device - Pin managed PCI device
829 * @pdev: PCI device to pin
830 *
831 * Pin managed PCI device @pdev. Pinned device won't be disabled on
832 * driver detach. @pdev must have been enabled with
833 * pcim_enable_device().
834 */
835void pcim_pin_device(struct pci_dev *pdev)
836{
837 struct pci_devres *dr;
838
839 dr = find_pci_dr(pdev);
840 WARN_ON(!dr || !dr->disable);
841 if (dr)
842 dr->disable = 0;
843}
844
747/** 845/**
748 * pcibios_disable_device - disable arch specific PCI resources for device dev 846 * pcibios_disable_device - disable arch specific PCI resources for device dev
749 * @dev: the PCI device to disable 847 * @dev: the PCI device to disable
@@ -767,8 +865,13 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
767void 865void
768pci_disable_device(struct pci_dev *dev) 866pci_disable_device(struct pci_dev *dev)
769{ 867{
868 struct pci_devres *dr;
770 u16 pci_command; 869 u16 pci_command;
771 870
871 dr = find_pci_dr(dev);
872 if (dr)
873 dr->disable = 0;
874
772 if (atomic_sub_return(1, &dev->enable_cnt) != 0) 875 if (atomic_sub_return(1, &dev->enable_cnt) != 0)
773 return; 876 return;
774 877
@@ -867,6 +970,8 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
867 */ 970 */
868void pci_release_region(struct pci_dev *pdev, int bar) 971void pci_release_region(struct pci_dev *pdev, int bar)
869{ 972{
973 struct pci_devres *dr;
974
870 if (pci_resource_len(pdev, bar) == 0) 975 if (pci_resource_len(pdev, bar) == 0)
871 return; 976 return;
872 if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) 977 if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
@@ -875,6 +980,10 @@ void pci_release_region(struct pci_dev *pdev, int bar)
875 else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) 980 else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
876 release_mem_region(pci_resource_start(pdev, bar), 981 release_mem_region(pci_resource_start(pdev, bar),
877 pci_resource_len(pdev, bar)); 982 pci_resource_len(pdev, bar));
983
984 dr = find_pci_dr(pdev);
985 if (dr)
986 dr->region_mask &= ~(1 << bar);
878} 987}
879 988
880/** 989/**
@@ -893,6 +1002,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
893 */ 1002 */
894int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) 1003int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
895{ 1004{
1005 struct pci_devres *dr;
1006
896 if (pci_resource_len(pdev, bar) == 0) 1007 if (pci_resource_len(pdev, bar) == 0)
897 return 0; 1008 return 0;
898 1009
@@ -906,7 +1017,11 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
906 pci_resource_len(pdev, bar), res_name)) 1017 pci_resource_len(pdev, bar), res_name))
907 goto err_out; 1018 goto err_out;
908 } 1019 }
909 1020
1021 dr = find_pci_dr(pdev);
1022 if (dr)
1023 dr->region_mask |= 1 << bar;
1024
910 return 0; 1025 return 0;
911 1026
912err_out: 1027err_out:
@@ -1144,7 +1259,15 @@ pci_intx(struct pci_dev *pdev, int enable)
1144 } 1259 }
1145 1260
1146 if (new != pci_command) { 1261 if (new != pci_command) {
1262 struct pci_devres *dr;
1263
1147 pci_write_config_word(pdev, PCI_COMMAND, new); 1264 pci_write_config_word(pdev, PCI_COMMAND, new);
1265
1266 dr = find_pci_dr(pdev);
1267 if (dr && !dr->restore_intx) {
1268 dr->restore_intx = 1;
1269 dr->orig_intx = !enable;
1270 }
1148 } 1271 }
1149} 1272}
1150 1273
@@ -1226,6 +1349,8 @@ device_initcall(pci_init);
1226EXPORT_SYMBOL_GPL(pci_restore_bars); 1349EXPORT_SYMBOL_GPL(pci_restore_bars);
1227EXPORT_SYMBOL(pci_enable_device_bars); 1350EXPORT_SYMBOL(pci_enable_device_bars);
1228EXPORT_SYMBOL(pci_enable_device); 1351EXPORT_SYMBOL(pci_enable_device);
1352EXPORT_SYMBOL(pcim_enable_device);
1353EXPORT_SYMBOL(pcim_pin_device);
1229EXPORT_SYMBOL(pci_disable_device); 1354EXPORT_SYMBOL(pci_disable_device);
1230EXPORT_SYMBOL(pci_find_capability); 1355EXPORT_SYMBOL(pci_find_capability);
1231EXPORT_SYMBOL(pci_bus_find_capability); 1356EXPORT_SYMBOL(pci_bus_find_capability);