diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-16 10:49:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-16 10:49:54 -0400 |
commit | 4406c56d0a4da7a37b9180abeaece6cd00bcc874 (patch) | |
tree | 65a85fa73a25d24cbed6d163fdcf8df1b934a0be /drivers/pci/pci-driver.c | |
parent | 6b7b352f2102e21f9d8f38e932f01d9c5705c073 (diff) | |
parent | 5e3573db2bd5db6925159279d99576a4635bdb66 (diff) |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (75 commits)
PCI hotplug: clean up acpi_run_hpp()
PCI hotplug: acpiphp: use generic pci_configure_slot()
PCI hotplug: shpchp: use generic pci_configure_slot()
PCI hotplug: pciehp: use generic pci_configure_slot()
PCI hotplug: add pci_configure_slot()
PCI hotplug: clean up acpi_get_hp_params_from_firmware() interface
PCI hotplug: acpiphp: don't cache hotplug_params in acpiphp_bridge
PCI hotplug: acpiphp: remove superfluous _HPP/_HPX evaluation
PCI: Clear saved_state after the state has been restored
PCI PM: Return error codes from pci_pm_resume()
PCI: use dev_printk in quirk messages
PCI / PCIe portdrv: Fix pcie_portdrv_slot_reset()
PCI Hotplug: convert acpi_pci_detect_ejectable() to take an acpi_handle
PCI Hotplug: acpiphp: find bridges the easy way
PCI: pcie portdrv: remove unused variable
PCI / ACPI PM: Propagate wake-up enable for devices w/o ACPI support
ACPI PM: Replace wakeup.prepared with reference counter
PCI PM: Introduce device flag wakeup_prepared
PCI / ACPI PM: Rework some debug messages
PCI PM: Simplify PCI wake-up code
...
Fixed up conflict in arch/powerpc/kernel/pci_64.c due to OF device tree
scanning having been moved and merged for the 32- and 64-bit cases. The
'needs_freset' initialization added in 6e19314cc ("PCI/powerpc: support
PCIe fundamental reset") is now in arch/powerpc/kernel/pci_of_scan.c.
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 132 |
1 files changed, 77 insertions, 55 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index a7eb7277b106..e5d47be3c6d7 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -19,37 +19,98 @@ | |||
19 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
20 | #include "pci.h" | 20 | #include "pci.h" |
21 | 21 | ||
22 | /* | ||
23 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG | ||
24 | */ | ||
25 | |||
26 | struct pci_dynid { | 22 | struct pci_dynid { |
27 | struct list_head node; | 23 | struct list_head node; |
28 | struct pci_device_id id; | 24 | struct pci_device_id id; |
29 | }; | 25 | }; |
30 | 26 | ||
31 | #ifdef CONFIG_HOTPLUG | 27 | /** |
28 | * pci_add_dynid - add a new PCI device ID to this driver and re-probe devices | ||
29 | * @drv: target pci driver | ||
30 | * @vendor: PCI vendor ID | ||
31 | * @device: PCI device ID | ||
32 | * @subvendor: PCI subvendor ID | ||
33 | * @subdevice: PCI subdevice ID | ||
34 | * @class: PCI class | ||
35 | * @class_mask: PCI class mask | ||
36 | * @driver_data: private driver data | ||
37 | * | ||
38 | * Adds a new dynamic pci device ID to this driver and causes the | ||
39 | * driver to probe for all devices again. @drv must have been | ||
40 | * registered prior to calling this function. | ||
41 | * | ||
42 | * CONTEXT: | ||
43 | * Does GFP_KERNEL allocation. | ||
44 | * | ||
45 | * RETURNS: | ||
46 | * 0 on success, -errno on failure. | ||
47 | */ | ||
48 | int pci_add_dynid(struct pci_driver *drv, | ||
49 | unsigned int vendor, unsigned int device, | ||
50 | unsigned int subvendor, unsigned int subdevice, | ||
51 | unsigned int class, unsigned int class_mask, | ||
52 | unsigned long driver_data) | ||
53 | { | ||
54 | struct pci_dynid *dynid; | ||
55 | int retval; | ||
56 | |||
57 | dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | ||
58 | if (!dynid) | ||
59 | return -ENOMEM; | ||
60 | |||
61 | dynid->id.vendor = vendor; | ||
62 | dynid->id.device = device; | ||
63 | dynid->id.subvendor = subvendor; | ||
64 | dynid->id.subdevice = subdevice; | ||
65 | dynid->id.class = class; | ||
66 | dynid->id.class_mask = class_mask; | ||
67 | dynid->id.driver_data = driver_data; | ||
68 | |||
69 | spin_lock(&drv->dynids.lock); | ||
70 | list_add_tail(&dynid->node, &drv->dynids.list); | ||
71 | spin_unlock(&drv->dynids.lock); | ||
72 | |||
73 | get_driver(&drv->driver); | ||
74 | retval = driver_attach(&drv->driver); | ||
75 | put_driver(&drv->driver); | ||
76 | |||
77 | return retval; | ||
78 | } | ||
79 | |||
80 | static void pci_free_dynids(struct pci_driver *drv) | ||
81 | { | ||
82 | struct pci_dynid *dynid, *n; | ||
32 | 83 | ||
84 | spin_lock(&drv->dynids.lock); | ||
85 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { | ||
86 | list_del(&dynid->node); | ||
87 | kfree(dynid); | ||
88 | } | ||
89 | spin_unlock(&drv->dynids.lock); | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Dynamic device ID manipulation via sysfs is disabled for !CONFIG_HOTPLUG | ||
94 | */ | ||
95 | #ifdef CONFIG_HOTPLUG | ||
33 | /** | 96 | /** |
34 | * store_new_id - add a new PCI device ID to this driver and re-probe devices | 97 | * store_new_id - sysfs frontend to pci_add_dynid() |
35 | * @driver: target device driver | 98 | * @driver: target device driver |
36 | * @buf: buffer for scanning device ID data | 99 | * @buf: buffer for scanning device ID data |
37 | * @count: input size | 100 | * @count: input size |
38 | * | 101 | * |
39 | * Adds a new dynamic pci device ID to this driver, | 102 | * Allow PCI IDs to be added to an existing driver via sysfs. |
40 | * and causes the driver to probe for all devices again. | ||
41 | */ | 103 | */ |
42 | static ssize_t | 104 | static ssize_t |
43 | store_new_id(struct device_driver *driver, const char *buf, size_t count) | 105 | store_new_id(struct device_driver *driver, const char *buf, size_t count) |
44 | { | 106 | { |
45 | struct pci_dynid *dynid; | ||
46 | struct pci_driver *pdrv = to_pci_driver(driver); | 107 | struct pci_driver *pdrv = to_pci_driver(driver); |
47 | const struct pci_device_id *ids = pdrv->id_table; | 108 | const struct pci_device_id *ids = pdrv->id_table; |
48 | __u32 vendor, device, subvendor=PCI_ANY_ID, | 109 | __u32 vendor, device, subvendor=PCI_ANY_ID, |
49 | subdevice=PCI_ANY_ID, class=0, class_mask=0; | 110 | subdevice=PCI_ANY_ID, class=0, class_mask=0; |
50 | unsigned long driver_data=0; | 111 | unsigned long driver_data=0; |
51 | int fields=0; | 112 | int fields=0; |
52 | int retval=0; | 113 | int retval; |
53 | 114 | ||
54 | fields = sscanf(buf, "%x %x %x %x %x %x %lx", | 115 | fields = sscanf(buf, "%x %x %x %x %x %x %lx", |
55 | &vendor, &device, &subvendor, &subdevice, | 116 | &vendor, &device, &subvendor, &subdevice, |
@@ -72,27 +133,8 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||
72 | return retval; | 133 | return retval; |
73 | } | 134 | } |
74 | 135 | ||
75 | dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | 136 | retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice, |
76 | if (!dynid) | 137 | class, class_mask, driver_data); |
77 | return -ENOMEM; | ||
78 | |||
79 | dynid->id.vendor = vendor; | ||
80 | dynid->id.device = device; | ||
81 | dynid->id.subvendor = subvendor; | ||
82 | dynid->id.subdevice = subdevice; | ||
83 | dynid->id.class = class; | ||
84 | dynid->id.class_mask = class_mask; | ||
85 | dynid->id.driver_data = driver_data; | ||
86 | |||
87 | spin_lock(&pdrv->dynids.lock); | ||
88 | list_add_tail(&dynid->node, &pdrv->dynids.list); | ||
89 | spin_unlock(&pdrv->dynids.lock); | ||
90 | |||
91 | if (get_driver(&pdrv->driver)) { | ||
92 | retval = driver_attach(&pdrv->driver); | ||
93 | put_driver(&pdrv->driver); | ||
94 | } | ||
95 | |||
96 | if (retval) | 138 | if (retval) |
97 | return retval; | 139 | return retval; |
98 | return count; | 140 | return count; |
@@ -145,19 +187,6 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) | |||
145 | } | 187 | } |
146 | static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); | 188 | static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); |
147 | 189 | ||
148 | static void | ||
149 | pci_free_dynids(struct pci_driver *drv) | ||
150 | { | ||
151 | struct pci_dynid *dynid, *n; | ||
152 | |||
153 | spin_lock(&drv->dynids.lock); | ||
154 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { | ||
155 | list_del(&dynid->node); | ||
156 | kfree(dynid); | ||
157 | } | ||
158 | spin_unlock(&drv->dynids.lock); | ||
159 | } | ||
160 | |||
161 | static int | 190 | static int |
162 | pci_create_newid_file(struct pci_driver *drv) | 191 | pci_create_newid_file(struct pci_driver *drv) |
163 | { | 192 | { |
@@ -186,7 +215,6 @@ static void pci_remove_removeid_file(struct pci_driver *drv) | |||
186 | driver_remove_file(&drv->driver, &driver_attr_remove_id); | 215 | driver_remove_file(&drv->driver, &driver_attr_remove_id); |
187 | } | 216 | } |
188 | #else /* !CONFIG_HOTPLUG */ | 217 | #else /* !CONFIG_HOTPLUG */ |
189 | static inline void pci_free_dynids(struct pci_driver *drv) {} | ||
190 | static inline int pci_create_newid_file(struct pci_driver *drv) | 218 | static inline int pci_create_newid_file(struct pci_driver *drv) |
191 | { | 219 | { |
192 | return 0; | 220 | return 0; |
@@ -417,8 +445,6 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) | |||
417 | struct pci_dev * pci_dev = to_pci_dev(dev); | 445 | struct pci_dev * pci_dev = to_pci_dev(dev); |
418 | struct pci_driver * drv = pci_dev->driver; | 446 | struct pci_driver * drv = pci_dev->driver; |
419 | 447 | ||
420 | pci_dev->state_saved = false; | ||
421 | |||
422 | if (drv && drv->suspend) { | 448 | if (drv && drv->suspend) { |
423 | pci_power_t prev = pci_dev->current_state; | 449 | pci_power_t prev = pci_dev->current_state; |
424 | int error; | 450 | int error; |
@@ -514,7 +540,6 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev) | |||
514 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | 540 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) |
515 | { | 541 | { |
516 | pci_restore_standard_config(pci_dev); | 542 | pci_restore_standard_config(pci_dev); |
517 | pci_dev->state_saved = false; | ||
518 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 543 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
519 | } | 544 | } |
520 | 545 | ||
@@ -580,8 +605,6 @@ static int pci_pm_suspend(struct device *dev) | |||
580 | if (pci_has_legacy_pm_support(pci_dev)) | 605 | if (pci_has_legacy_pm_support(pci_dev)) |
581 | return pci_legacy_suspend(dev, PMSG_SUSPEND); | 606 | return pci_legacy_suspend(dev, PMSG_SUSPEND); |
582 | 607 | ||
583 | pci_dev->state_saved = false; | ||
584 | |||
585 | if (!pm) { | 608 | if (!pm) { |
586 | pci_pm_default_suspend(pci_dev); | 609 | pci_pm_default_suspend(pci_dev); |
587 | goto Fixup; | 610 | goto Fixup; |
@@ -694,7 +717,7 @@ static int pci_pm_resume(struct device *dev) | |||
694 | pci_pm_reenable_device(pci_dev); | 717 | pci_pm_reenable_device(pci_dev); |
695 | } | 718 | } |
696 | 719 | ||
697 | return 0; | 720 | return error; |
698 | } | 721 | } |
699 | 722 | ||
700 | #else /* !CONFIG_SUSPEND */ | 723 | #else /* !CONFIG_SUSPEND */ |
@@ -716,8 +739,6 @@ static int pci_pm_freeze(struct device *dev) | |||
716 | if (pci_has_legacy_pm_support(pci_dev)) | 739 | if (pci_has_legacy_pm_support(pci_dev)) |
717 | return pci_legacy_suspend(dev, PMSG_FREEZE); | 740 | return pci_legacy_suspend(dev, PMSG_FREEZE); |
718 | 741 | ||
719 | pci_dev->state_saved = false; | ||
720 | |||
721 | if (!pm) { | 742 | if (!pm) { |
722 | pci_pm_default_suspend(pci_dev); | 743 | pci_pm_default_suspend(pci_dev); |
723 | return 0; | 744 | return 0; |
@@ -793,6 +814,8 @@ static int pci_pm_thaw(struct device *dev) | |||
793 | pci_pm_reenable_device(pci_dev); | 814 | pci_pm_reenable_device(pci_dev); |
794 | } | 815 | } |
795 | 816 | ||
817 | pci_dev->state_saved = false; | ||
818 | |||
796 | return error; | 819 | return error; |
797 | } | 820 | } |
798 | 821 | ||
@@ -804,8 +827,6 @@ static int pci_pm_poweroff(struct device *dev) | |||
804 | if (pci_has_legacy_pm_support(pci_dev)) | 827 | if (pci_has_legacy_pm_support(pci_dev)) |
805 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); | 828 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
806 | 829 | ||
807 | pci_dev->state_saved = false; | ||
808 | |||
809 | if (!pm) { | 830 | if (!pm) { |
810 | pci_pm_default_suspend(pci_dev); | 831 | pci_pm_default_suspend(pci_dev); |
811 | goto Fixup; | 832 | goto Fixup; |
@@ -1106,6 +1127,7 @@ static int __init pci_driver_init(void) | |||
1106 | 1127 | ||
1107 | postcore_initcall(pci_driver_init); | 1128 | postcore_initcall(pci_driver_init); |
1108 | 1129 | ||
1130 | EXPORT_SYMBOL_GPL(pci_add_dynid); | ||
1109 | EXPORT_SYMBOL(pci_match_id); | 1131 | EXPORT_SYMBOL(pci_match_id); |
1110 | EXPORT_SYMBOL(__pci_register_driver); | 1132 | EXPORT_SYMBOL(__pci_register_driver); |
1111 | EXPORT_SYMBOL(pci_unregister_driver); | 1133 | EXPORT_SYMBOL(pci_unregister_driver); |