diff options
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/Makefile | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/fakephp.c | 39 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_core.c | 11 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 9 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 33 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 27 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 314 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_pci.c | 43 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 14 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_slot.c | 47 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 2 |
16 files changed, 332 insertions, 226 deletions
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index a64449d489d6..2cdd8326f136 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -3,8 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | menuconfig HOTPLUG_PCI | 5 | menuconfig HOTPLUG_PCI |
6 | tristate "Support for PCI Hotplug (EXPERIMENTAL)" | 6 | tristate "Support for PCI Hotplug" |
7 | depends on PCI && EXPERIMENTAL && HOTPLUG | 7 | depends on PCI && HOTPLUG |
8 | ---help--- | 8 | ---help--- |
9 | Say Y here if you have a motherboard with a PCI Hotplug controller. | 9 | Say Y here if you have a motherboard with a PCI Hotplug controller. |
10 | This allows you to add and remove PCI cards while the machine is | 10 | This allows you to add and remove PCI cards while the machine is |
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 34a1891191fd..9bdbe1a6688f 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o | 5 | obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o |
6 | obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o | ||
7 | obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o | 6 | obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o |
8 | obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o | 7 | obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o |
9 | obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o | 8 | obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o |
@@ -16,6 +15,9 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o | |||
16 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o | 15 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o |
17 | obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o | 16 | obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o |
18 | 17 | ||
18 | # Link this last so it doesn't claim devices that have a real hotplug driver | ||
19 | obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o | ||
20 | |||
19 | pci_hotplug-objs := pci_hotplug_core.o | 21 | pci_hotplug-objs := pci_hotplug_core.o |
20 | 22 | ||
21 | ifdef CONFIG_HOTPLUG_PCI_CPCI | 23 | ifdef CONFIG_HOTPLUG_PCI_CPCI |
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 1ef417cca2db..7a29164d4b32 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -113,7 +113,6 @@ struct acpiphp_slot { | |||
113 | u8 device; /* pci device# */ | 113 | u8 device; /* pci device# */ |
114 | 114 | ||
115 | u32 sun; /* ACPI _SUN (slot unique number) */ | 115 | u32 sun; /* ACPI _SUN (slot unique number) */ |
116 | u32 slotno; /* slot number relative to bridge */ | ||
117 | u32 flags; /* see below */ | 116 | u32 flags; /* see below */ |
118 | }; | 117 | }; |
119 | 118 | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ff1b1c71291a..cf22f9e01e00 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -102,7 +102,7 @@ static int is_ejectable(acpi_handle handle) | |||
102 | } | 102 | } |
103 | 103 | ||
104 | 104 | ||
105 | /* callback routine to check the existence of ejectable slots */ | 105 | /* callback routine to check for the existence of ejectable slots */ |
106 | static acpi_status | 106 | static acpi_status |
107 | is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | 107 | is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) |
108 | { | 108 | { |
@@ -117,7 +117,7 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
117 | } | 117 | } |
118 | } | 118 | } |
119 | 119 | ||
120 | /* callback routine to check for the existance of a pci dock device */ | 120 | /* callback routine to check for the existence of a pci dock device */ |
121 | static acpi_status | 121 | static acpi_status |
122 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | 122 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) |
123 | { | 123 | { |
@@ -1528,7 +1528,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
1528 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 1528 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
1529 | dbg("%s: re-enumerating slots under %s\n", | 1529 | dbg("%s: re-enumerating slots under %s\n", |
1530 | __FUNCTION__, objname); | 1530 | __FUNCTION__, objname); |
1531 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
1532 | acpiphp_check_bridge(bridge); | 1531 | acpiphp_check_bridge(bridge); |
1533 | } | 1532 | } |
1534 | return AE_OK ; | 1533 | return AE_OK ; |
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index d7a293e3faf5..94b640146d44 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/string.h> | 40 | #include <linux/string.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <linux/workqueue.h> | ||
42 | #include "../pci.h" | 43 | #include "../pci.h" |
43 | 44 | ||
44 | #if !defined(MODULE) | 45 | #if !defined(MODULE) |
@@ -63,10 +64,16 @@ struct dummy_slot { | |||
63 | struct list_head node; | 64 | struct list_head node; |
64 | struct hotplug_slot *slot; | 65 | struct hotplug_slot *slot; |
65 | struct pci_dev *dev; | 66 | struct pci_dev *dev; |
67 | struct work_struct remove_work; | ||
68 | unsigned long removed; | ||
66 | }; | 69 | }; |
67 | 70 | ||
68 | static int debug; | 71 | static int debug; |
69 | static LIST_HEAD(slot_list); | 72 | static LIST_HEAD(slot_list); |
73 | static struct workqueue_struct *dummyphp_wq; | ||
74 | |||
75 | static void pci_rescan_worker(struct work_struct *work); | ||
76 | static DECLARE_WORK(pci_rescan_work, pci_rescan_worker); | ||
70 | 77 | ||
71 | static int enable_slot (struct hotplug_slot *slot); | 78 | static int enable_slot (struct hotplug_slot *slot); |
72 | static int disable_slot (struct hotplug_slot *slot); | 79 | static int disable_slot (struct hotplug_slot *slot); |
@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev) | |||
109 | slot->name = &dev->dev.bus_id[0]; | 116 | slot->name = &dev->dev.bus_id[0]; |
110 | dbg("slot->name = %s\n", slot->name); | 117 | dbg("slot->name = %s\n", slot->name); |
111 | 118 | ||
112 | dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); | 119 | dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); |
113 | if (!dslot) | 120 | if (!dslot) |
114 | goto error_info; | 121 | goto error_info; |
115 | 122 | ||
@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot) | |||
164 | err("Problem unregistering a slot %s\n", dslot->slot->name); | 171 | err("Problem unregistering a slot %s\n", dslot->slot->name); |
165 | } | 172 | } |
166 | 173 | ||
174 | /* called from the single-threaded workqueue handler to remove a slot */ | ||
175 | static void remove_slot_worker(struct work_struct *work) | ||
176 | { | ||
177 | struct dummy_slot *dslot = | ||
178 | container_of(work, struct dummy_slot, remove_work); | ||
179 | remove_slot(dslot); | ||
180 | } | ||
181 | |||
167 | /** | 182 | /** |
168 | * pci_rescan_slot - Rescan slot | 183 | * pci_rescan_slot - Rescan slot |
169 | * @temp: Device template. Should be set: bus and devfn. | 184 | * @temp: Device template. Should be set: bus and devfn. |
@@ -267,11 +282,17 @@ static inline void pci_rescan(void) { | |||
267 | pci_rescan_buses(&pci_root_buses); | 282 | pci_rescan_buses(&pci_root_buses); |
268 | } | 283 | } |
269 | 284 | ||
285 | /* called from the single-threaded workqueue handler to rescan all pci buses */ | ||
286 | static void pci_rescan_worker(struct work_struct *work) | ||
287 | { | ||
288 | pci_rescan(); | ||
289 | } | ||
270 | 290 | ||
271 | static int enable_slot(struct hotplug_slot *hotplug_slot) | 291 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
272 | { | 292 | { |
273 | /* mis-use enable_slot for rescanning of the pci bus */ | 293 | /* mis-use enable_slot for rescanning of the pci bus */ |
274 | pci_rescan(); | 294 | cancel_work_sync(&pci_rescan_work); |
295 | queue_work(dummyphp_wq, &pci_rescan_work); | ||
275 | return -ENODEV; | 296 | return -ENODEV; |
276 | } | 297 | } |
277 | 298 | ||
@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot) | |||
306 | err("Can't remove PCI devices with other PCI devices behind it yet.\n"); | 327 | err("Can't remove PCI devices with other PCI devices behind it yet.\n"); |
307 | return -ENODEV; | 328 | return -ENODEV; |
308 | } | 329 | } |
330 | if (test_and_set_bit(0, &dslot->removed)) { | ||
331 | dbg("Slot already scheduled for removal\n"); | ||
332 | return -ENODEV; | ||
333 | } | ||
309 | /* search for subfunctions and disable them first */ | 334 | /* search for subfunctions and disable them first */ |
310 | if (!(dslot->dev->devfn & 7)) { | 335 | if (!(dslot->dev->devfn & 7)) { |
311 | for (func = 1; func < 8; func++) { | 336 | for (func = 1; func < 8; func++) { |
@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot) | |||
328 | /* remove the device from the pci core */ | 353 | /* remove the device from the pci core */ |
329 | pci_remove_bus_device(dslot->dev); | 354 | pci_remove_bus_device(dslot->dev); |
330 | 355 | ||
331 | /* blow away this sysfs entry and other parts. */ | 356 | /* queue work item to blow away this sysfs entry and other parts. */ |
332 | remove_slot(dslot); | 357 | INIT_WORK(&dslot->remove_work, remove_slot_worker); |
358 | queue_work(dummyphp_wq, &dslot->remove_work); | ||
333 | 359 | ||
334 | return 0; | 360 | return 0; |
335 | } | 361 | } |
@@ -340,6 +366,7 @@ static void cleanup_slots (void) | |||
340 | struct list_head *next; | 366 | struct list_head *next; |
341 | struct dummy_slot *dslot; | 367 | struct dummy_slot *dslot; |
342 | 368 | ||
369 | destroy_workqueue(dummyphp_wq); | ||
343 | list_for_each_safe (tmp, next, &slot_list) { | 370 | list_for_each_safe (tmp, next, &slot_list) { |
344 | dslot = list_entry (tmp, struct dummy_slot, node); | 371 | dslot = list_entry (tmp, struct dummy_slot, node); |
345 | remove_slot(dslot); | 372 | remove_slot(dslot); |
@@ -351,6 +378,10 @@ static int __init dummyphp_init(void) | |||
351 | { | 378 | { |
352 | info(DRIVER_DESC "\n"); | 379 | info(DRIVER_DESC "\n"); |
353 | 380 | ||
381 | dummyphp_wq = create_singlethread_workqueue(MY_NAME); | ||
382 | if (!dummyphp_wq) | ||
383 | return -ENOMEM; | ||
384 | |||
354 | return pci_scan_buses(); | 385 | return pci_scan_buses(); |
355 | } | 386 | } |
356 | 387 | ||
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index a90c28d0c69d..87b6b8b280e6 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c | |||
@@ -761,10 +761,13 @@ static void ibm_unconfigure_device(struct pci_func *func) | |||
761 | debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); | 761 | debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); |
762 | 762 | ||
763 | for (j = 0; j < 0x08; j++) { | 763 | for (j = 0; j < 0x08; j++) { |
764 | temp = pci_find_slot(func->busno, (func->device << 3) | j); | 764 | temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); |
765 | if (temp) | 765 | if (temp) { |
766 | pci_remove_bus_device(temp); | 766 | pci_remove_bus_device(temp); |
767 | pci_dev_put(temp); | ||
768 | } | ||
767 | } | 769 | } |
770 | pci_dev_put(func->dev); | ||
768 | } | 771 | } |
769 | 772 | ||
770 | /* | 773 | /* |
@@ -823,7 +826,7 @@ static int ibm_configure_device(struct pci_func *func) | |||
823 | if (!(bus_structure_fixup(func->busno))) | 826 | if (!(bus_structure_fixup(func->busno))) |
824 | flag = 1; | 827 | flag = 1; |
825 | if (func->dev == NULL) | 828 | if (func->dev == NULL) |
826 | func->dev = pci_find_slot(func->busno, | 829 | func->dev = pci_get_bus_and_slot(func->busno, |
827 | PCI_DEVFN(func->device, func->function)); | 830 | PCI_DEVFN(func->device, func->function)); |
828 | 831 | ||
829 | if (func->dev == NULL) { | 832 | if (func->dev == NULL) { |
@@ -836,7 +839,7 @@ static int ibm_configure_device(struct pci_func *func) | |||
836 | if (num) | 839 | if (num) |
837 | pci_bus_add_devices(bus); | 840 | pci_bus_add_devices(bus); |
838 | 841 | ||
839 | func->dev = pci_find_slot(func->busno, | 842 | func->dev = pci_get_bus_and_slot(func->busno, |
840 | PCI_DEVFN(func->device, func->function)); | 843 | PCI_DEVFN(func->device, func->function)); |
841 | if (func->dev == NULL) { | 844 | if (func->dev == NULL) { |
842 | err("ERROR... : pci_dev still NULL\n"); | 845 | err("ERROR... : pci_dev still NULL\n"); |
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 47bb0e1ff3fa..dd59a050260f 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
@@ -137,7 +137,7 @@ static int get_##name (struct hotplug_slot *slot, type *value) \ | |||
137 | int retval = 0; \ | 137 | int retval = 0; \ |
138 | if (try_module_get(ops->owner)) { \ | 138 | if (try_module_get(ops->owner)) { \ |
139 | if (ops->get_##name) \ | 139 | if (ops->get_##name) \ |
140 | retval = ops->get_##name (slot, value); \ | 140 | retval = ops->get_##name(slot, value); \ |
141 | else \ | 141 | else \ |
142 | *value = slot->info->name; \ | 142 | *value = slot->info->name; \ |
143 | module_put(ops->owner); \ | 143 | module_put(ops->owner); \ |
@@ -625,7 +625,7 @@ int pci_hp_register (struct hotplug_slot *slot) | |||
625 | if ((slot->info == NULL) || (slot->ops == NULL)) | 625 | if ((slot->info == NULL) || (slot->ops == NULL)) |
626 | return -EINVAL; | 626 | return -EINVAL; |
627 | if (slot->release == NULL) { | 627 | if (slot->release == NULL) { |
628 | dbg("Why are you trying to register a hotplug slot" | 628 | dbg("Why are you trying to register a hotplug slot " |
629 | "without a proper release function?\n"); | 629 | "without a proper release function?\n"); |
630 | return -EINVAL; | 630 | return -EINVAL; |
631 | } | 631 | } |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 7959c222dc24..ca656b27a500 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -82,24 +82,18 @@ struct event_info { | |||
82 | }; | 82 | }; |
83 | 83 | ||
84 | struct controller { | 84 | struct controller { |
85 | struct controller *next; | ||
86 | struct mutex crit_sect; /* critical section mutex */ | 85 | struct mutex crit_sect; /* critical section mutex */ |
87 | struct mutex ctrl_lock; /* controller lock */ | 86 | struct mutex ctrl_lock; /* controller lock */ |
88 | int num_slots; /* Number of slots on ctlr */ | 87 | int num_slots; /* Number of slots on ctlr */ |
89 | int slot_num_inc; /* 1 or -1 */ | 88 | int slot_num_inc; /* 1 or -1 */ |
90 | struct pci_dev *pci_dev; | 89 | struct pci_dev *pci_dev; |
91 | struct list_head slot_list; | 90 | struct list_head slot_list; |
92 | struct slot *slot; | ||
93 | struct hpc_ops *hpc_ops; | 91 | struct hpc_ops *hpc_ops; |
94 | wait_queue_head_t queue; /* sleep & wake process */ | 92 | wait_queue_head_t queue; /* sleep & wake process */ |
95 | u8 bus; | ||
96 | u8 device; | ||
97 | u8 function; | ||
98 | u8 slot_device_offset; | 93 | u8 slot_device_offset; |
99 | u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ | 94 | u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ |
100 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ | 95 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ |
101 | u8 ctrlcap; | 96 | u8 ctrlcap; |
102 | u16 vendor_id; | ||
103 | u8 cap_base; | 97 | u8 cap_base; |
104 | struct timer_list poll_timer; | 98 | struct timer_list poll_timer; |
105 | volatile int cmd_busy; | 99 | volatile int cmd_busy; |
@@ -161,6 +155,9 @@ extern int pciehp_configure_device(struct slot *p_slot); | |||
161 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 155 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
162 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | 156 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); |
163 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); | 157 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); |
158 | int pciehp_enable_slot(struct slot *p_slot); | ||
159 | int pciehp_disable_slot(struct slot *p_slot); | ||
160 | int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev); | ||
164 | 161 | ||
165 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | 162 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) |
166 | { | 163 | { |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 6462ac3b405f..7f4836b8e71e 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -453,13 +453,9 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
453 | 453 | ||
454 | pci_set_drvdata(pdev, ctrl); | 454 | pci_set_drvdata(pdev, ctrl); |
455 | 455 | ||
456 | ctrl->bus = pdev->bus->number; /* ctrl bus */ | 456 | dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", |
457 | ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ | 457 | __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn), |
458 | 458 | PCI_FUNC(pdev->devfn), pdev->irq); | |
459 | ctrl->device = PCI_SLOT(pdev->devfn); | ||
460 | ctrl->function = PCI_FUNC(pdev->devfn); | ||
461 | dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, | ||
462 | ctrl->bus, ctrl->device, ctrl->function, pdev->irq); | ||
463 | 459 | ||
464 | /* Setup the slot information structures */ | 460 | /* Setup the slot information structures */ |
465 | rc = init_slots(ctrl); | 461 | rc = init_slots(ctrl); |
@@ -471,6 +467,11 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
471 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 467 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
472 | 468 | ||
473 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ | 469 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ |
470 | if (value) { | ||
471 | rc = pciehp_enable_slot(t_slot); | ||
472 | if (rc) /* -ENODEV: shouldn't happen, but deal with it */ | ||
473 | value = 0; | ||
474 | } | ||
474 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { | 475 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { |
475 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ | 476 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ |
476 | if (rc) | 477 | if (rc) |
@@ -509,6 +510,24 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) | |||
509 | static int pciehp_resume (struct pcie_device *dev) | 510 | static int pciehp_resume (struct pcie_device *dev) |
510 | { | 511 | { |
511 | printk("%s ENTRY\n", __FUNCTION__); | 512 | printk("%s ENTRY\n", __FUNCTION__); |
513 | if (pciehp_force) { | ||
514 | struct pci_dev *pdev = dev->port; | ||
515 | struct controller *ctrl = pci_get_drvdata(pdev); | ||
516 | struct slot *t_slot; | ||
517 | u8 status; | ||
518 | |||
519 | /* reinitialize the chipset's event detection logic */ | ||
520 | pcie_init_hardware_part2(ctrl, dev); | ||
521 | |||
522 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | ||
523 | |||
524 | /* Check if slot is occupied */ | ||
525 | t_slot->hpc_ops->get_adapter_status(t_slot, &status); | ||
526 | if (status) | ||
527 | pciehp_enable_slot(t_slot); | ||
528 | else | ||
529 | pciehp_disable_slot(t_slot); | ||
530 | } | ||
512 | return 0; | 531 | return 0; |
513 | } | 532 | } |
514 | #endif | 533 | #endif |
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f1e0966cee95..b23061c56115 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -37,8 +37,6 @@ | |||
37 | #include "pciehp.h" | 37 | #include "pciehp.h" |
38 | 38 | ||
39 | static void interrupt_event_handler(struct work_struct *work); | 39 | static void interrupt_event_handler(struct work_struct *work); |
40 | static int pciehp_enable_slot(struct slot *p_slot); | ||
41 | static int pciehp_disable_slot(struct slot *p_slot); | ||
42 | 40 | ||
43 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) | 41 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) |
44 | { | 42 | { |
@@ -197,12 +195,6 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) | |||
197 | __FUNCTION__); | 195 | __FUNCTION__); |
198 | return; | 196 | return; |
199 | } | 197 | } |
200 | /* | ||
201 | * After turning power off, we must wait for at least | ||
202 | * 1 second before taking any action that relies on | ||
203 | * power having been removed from the slot/adapter. | ||
204 | */ | ||
205 | msleep(1000); | ||
206 | } | 198 | } |
207 | } | 199 | } |
208 | 200 | ||
@@ -215,15 +207,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) | |||
215 | */ | 207 | */ |
216 | static int board_added(struct slot *p_slot) | 208 | static int board_added(struct slot *p_slot) |
217 | { | 209 | { |
218 | u8 hp_slot; | ||
219 | int retval = 0; | 210 | int retval = 0; |
220 | struct controller *ctrl = p_slot->ctrl; | 211 | struct controller *ctrl = p_slot->ctrl; |
221 | 212 | ||
222 | hp_slot = p_slot->device - ctrl->slot_device_offset; | ||
223 | |||
224 | dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n", | 213 | dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n", |
225 | __FUNCTION__, p_slot->device, | 214 | __FUNCTION__, p_slot->device, |
226 | ctrl->slot_device_offset, hp_slot); | 215 | ctrl->slot_device_offset, p_slot->hp_slot); |
227 | 216 | ||
228 | if (POWER_CTRL(ctrl->ctrlcap)) { | 217 | if (POWER_CTRL(ctrl->ctrlcap)) { |
229 | /* Power on slot */ | 218 | /* Power on slot */ |
@@ -281,8 +270,6 @@ err_exit: | |||
281 | */ | 270 | */ |
282 | static int remove_board(struct slot *p_slot) | 271 | static int remove_board(struct slot *p_slot) |
283 | { | 272 | { |
284 | u8 device; | ||
285 | u8 hp_slot; | ||
286 | int retval = 0; | 273 | int retval = 0; |
287 | struct controller *ctrl = p_slot->ctrl; | 274 | struct controller *ctrl = p_slot->ctrl; |
288 | 275 | ||
@@ -290,11 +277,7 @@ static int remove_board(struct slot *p_slot) | |||
290 | if (retval) | 277 | if (retval) |
291 | return retval; | 278 | return retval; |
292 | 279 | ||
293 | device = p_slot->device; | 280 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot); |
294 | hp_slot = p_slot->device - ctrl->slot_device_offset; | ||
295 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
296 | |||
297 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); | ||
298 | 281 | ||
299 | if (POWER_CTRL(ctrl->ctrlcap)) { | 282 | if (POWER_CTRL(ctrl->ctrlcap)) { |
300 | /* power off slot */ | 283 | /* power off slot */ |
@@ -621,12 +604,6 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
621 | mutex_unlock(&p_slot->ctrl->crit_sect); | 604 | mutex_unlock(&p_slot->ctrl->crit_sect); |
622 | return -EINVAL; | 605 | return -EINVAL; |
623 | } | 606 | } |
624 | /* | ||
625 | * After turning power off, we must wait for at least | ||
626 | * 1 second before taking any action that relies on | ||
627 | * power having been removed from the slot/adapter. | ||
628 | */ | ||
629 | msleep(1000); | ||
630 | } | 607 | } |
631 | 608 | ||
632 | ret = remove_board(p_slot); | 609 | ret = remove_board(p_slot); |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 06d025b8b13f..6eba9b2cfb90 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot) | |||
636 | return retval; | 636 | return retval; |
637 | } | 637 | } |
638 | 638 | ||
639 | static inline int pcie_mask_bad_dllp(struct controller *ctrl) | ||
640 | { | ||
641 | struct pci_dev *dev = ctrl->pci_dev; | ||
642 | int pos; | ||
643 | u32 reg; | ||
644 | |||
645 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
646 | if (!pos) | ||
647 | return 0; | ||
648 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | ||
649 | if (reg & PCI_ERR_COR_BAD_DLLP) | ||
650 | return 0; | ||
651 | reg |= PCI_ERR_COR_BAD_DLLP; | ||
652 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | ||
653 | return 1; | ||
654 | } | ||
655 | |||
656 | static inline void pcie_unmask_bad_dllp(struct controller *ctrl) | ||
657 | { | ||
658 | struct pci_dev *dev = ctrl->pci_dev; | ||
659 | u32 reg; | ||
660 | int pos; | ||
661 | |||
662 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
663 | if (!pos) | ||
664 | return; | ||
665 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | ||
666 | if (!(reg & PCI_ERR_COR_BAD_DLLP)) | ||
667 | return; | ||
668 | reg &= ~PCI_ERR_COR_BAD_DLLP; | ||
669 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | ||
670 | } | ||
671 | |||
639 | static int hpc_power_off_slot(struct slot * slot) | 672 | static int hpc_power_off_slot(struct slot * slot) |
640 | { | 673 | { |
641 | struct controller *ctrl = slot->ctrl; | 674 | struct controller *ctrl = slot->ctrl; |
642 | u16 slot_cmd; | 675 | u16 slot_cmd; |
643 | u16 cmd_mask; | 676 | u16 cmd_mask; |
644 | int retval = 0; | 677 | int retval = 0; |
678 | int changed; | ||
645 | 679 | ||
646 | dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); | 680 | dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); |
647 | 681 | ||
682 | /* | ||
683 | * Set Bad DLLP Mask bit in Correctable Error Mask | ||
684 | * Register. This is the workaround against Bad DLLP error | ||
685 | * that sometimes happens during turning power off the slot | ||
686 | * which conforms to PCI Express 1.0a spec. | ||
687 | */ | ||
688 | changed = pcie_mask_bad_dllp(ctrl); | ||
689 | |||
648 | slot_cmd = POWER_OFF; | 690 | slot_cmd = POWER_OFF; |
649 | cmd_mask = PWR_CTRL; | 691 | cmd_mask = PWR_CTRL; |
650 | /* | 692 | /* |
@@ -674,6 +716,16 @@ static int hpc_power_off_slot(struct slot * slot) | |||
674 | dbg("%s: SLOTCTRL %x write cmd %x\n", | 716 | dbg("%s: SLOTCTRL %x write cmd %x\n", |
675 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); | 717 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); |
676 | 718 | ||
719 | /* | ||
720 | * After turning power off, we must wait for at least 1 second | ||
721 | * before taking any action that relies on power having been | ||
722 | * removed from the slot/adapter. | ||
723 | */ | ||
724 | msleep(1000); | ||
725 | |||
726 | if (changed) | ||
727 | pcie_unmask_bad_dllp(ctrl); | ||
728 | |||
677 | return retval; | 729 | return retval; |
678 | } | 730 | } |
679 | 731 | ||
@@ -1067,13 +1119,143 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1067 | } | 1119 | } |
1068 | #endif | 1120 | #endif |
1069 | 1121 | ||
1070 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) | 1122 | static int pcie_init_hardware_part1(struct controller *ctrl, |
1123 | struct pcie_device *dev) | ||
1124 | { | ||
1125 | int rc; | ||
1126 | u16 temp_word; | ||
1127 | u32 slot_cap; | ||
1128 | u16 slot_status; | ||
1129 | |||
1130 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); | ||
1131 | if (rc) { | ||
1132 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); | ||
1133 | return -1; | ||
1134 | } | ||
1135 | |||
1136 | /* Mask Hot-plug Interrupt Enable */ | ||
1137 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | ||
1138 | if (rc) { | ||
1139 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | ||
1140 | return -1; | ||
1141 | } | ||
1142 | |||
1143 | dbg("%s: SLOTCTRL %x value read %x\n", | ||
1144 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); | ||
1145 | temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | | ||
1146 | 0x00; | ||
1147 | |||
1148 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1149 | if (rc) { | ||
1150 | err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); | ||
1151 | return -1; | ||
1152 | } | ||
1153 | |||
1154 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1155 | if (rc) { | ||
1156 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1157 | return -1; | ||
1158 | } | ||
1159 | |||
1160 | temp_word = 0x1F; /* Clear all events */ | ||
1161 | rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); | ||
1162 | if (rc) { | ||
1163 | err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); | ||
1164 | return -1; | ||
1165 | } | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) | ||
1071 | { | 1170 | { |
1072 | int rc; | 1171 | int rc; |
1073 | u16 temp_word; | 1172 | u16 temp_word; |
1074 | u16 cap_reg; | ||
1075 | u16 intr_enable = 0; | 1173 | u16 intr_enable = 0; |
1076 | u32 slot_cap; | 1174 | u32 slot_cap; |
1175 | u16 slot_status; | ||
1176 | |||
1177 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | ||
1178 | if (rc) { | ||
1179 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | ||
1180 | goto abort; | ||
1181 | } | ||
1182 | |||
1183 | intr_enable = intr_enable | PRSN_DETECT_ENABLE; | ||
1184 | |||
1185 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); | ||
1186 | if (rc) { | ||
1187 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); | ||
1188 | goto abort; | ||
1189 | } | ||
1190 | |||
1191 | if (ATTN_BUTTN(slot_cap)) | ||
1192 | intr_enable = intr_enable | ATTN_BUTTN_ENABLE; | ||
1193 | |||
1194 | if (POWER_CTRL(slot_cap)) | ||
1195 | intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; | ||
1196 | |||
1197 | if (MRL_SENS(slot_cap)) | ||
1198 | intr_enable = intr_enable | MRL_DETECT_ENABLE; | ||
1199 | |||
1200 | temp_word = (temp_word & ~intr_enable) | intr_enable; | ||
1201 | |||
1202 | if (pciehp_poll_mode) { | ||
1203 | temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; | ||
1204 | } else { | ||
1205 | temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; | ||
1206 | } | ||
1207 | |||
1208 | /* | ||
1209 | * Unmask Hot-plug Interrupt Enable for the interrupt | ||
1210 | * notification mechanism case. | ||
1211 | */ | ||
1212 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1213 | if (rc) { | ||
1214 | err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); | ||
1215 | goto abort; | ||
1216 | } | ||
1217 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1218 | if (rc) { | ||
1219 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1220 | goto abort_disable_intr; | ||
1221 | } | ||
1222 | |||
1223 | temp_word = 0x1F; /* Clear all events */ | ||
1224 | rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); | ||
1225 | if (rc) { | ||
1226 | err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); | ||
1227 | goto abort_disable_intr; | ||
1228 | } | ||
1229 | |||
1230 | if (pciehp_force) { | ||
1231 | dbg("Bypassing BIOS check for pciehp use on %s\n", | ||
1232 | pci_name(ctrl->pci_dev)); | ||
1233 | } else { | ||
1234 | rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); | ||
1235 | if (rc) | ||
1236 | goto abort_disable_intr; | ||
1237 | } | ||
1238 | |||
1239 | return 0; | ||
1240 | |||
1241 | /* We end up here for the many possible ways to fail this API. */ | ||
1242 | abort_disable_intr: | ||
1243 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | ||
1244 | if (!rc) { | ||
1245 | temp_word &= ~(intr_enable | HP_INTR_ENABLE); | ||
1246 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1247 | } | ||
1248 | if (rc) | ||
1249 | err("%s : disabling interrupts failed\n", __FUNCTION__); | ||
1250 | abort: | ||
1251 | return -1; | ||
1252 | } | ||
1253 | |||
1254 | int pcie_init(struct controller *ctrl, struct pcie_device *dev) | ||
1255 | { | ||
1256 | int rc; | ||
1257 | u16 cap_reg; | ||
1258 | u32 slot_cap; | ||
1077 | int cap_base; | 1259 | int cap_base; |
1078 | u16 slot_status, slot_ctrl; | 1260 | u16 slot_status, slot_ctrl; |
1079 | struct pci_dev *pdev; | 1261 | struct pci_dev *pdev; |
@@ -1084,9 +1266,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1084 | dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", | 1266 | dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", |
1085 | __FUNCTION__, pdev->vendor, pdev->device); | 1267 | __FUNCTION__, pdev->vendor, pdev->device); |
1086 | 1268 | ||
1087 | if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { | 1269 | cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); |
1270 | if (cap_base == 0) { | ||
1088 | dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); | 1271 | dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); |
1089 | goto abort_free_ctlr; | 1272 | goto abort; |
1090 | } | 1273 | } |
1091 | 1274 | ||
1092 | ctrl->cap_base = cap_base; | 1275 | ctrl->cap_base = cap_base; |
@@ -1096,7 +1279,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1096 | rc = pciehp_readw(ctrl, CAPREG, &cap_reg); | 1279 | rc = pciehp_readw(ctrl, CAPREG, &cap_reg); |
1097 | if (rc) { | 1280 | if (rc) { |
1098 | err("%s: Cannot read CAPREG register\n", __FUNCTION__); | 1281 | err("%s: Cannot read CAPREG register\n", __FUNCTION__); |
1099 | goto abort_free_ctlr; | 1282 | goto abort; |
1100 | } | 1283 | } |
1101 | dbg("%s: CAPREG offset %x cap_reg %x\n", | 1284 | dbg("%s: CAPREG offset %x cap_reg %x\n", |
1102 | __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); | 1285 | __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); |
@@ -1106,26 +1289,26 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1106 | && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { | 1289 | && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { |
1107 | dbg("%s : This is not a root port or the port is not " | 1290 | dbg("%s : This is not a root port or the port is not " |
1108 | "connected to a slot\n", __FUNCTION__); | 1291 | "connected to a slot\n", __FUNCTION__); |
1109 | goto abort_free_ctlr; | 1292 | goto abort; |
1110 | } | 1293 | } |
1111 | 1294 | ||
1112 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); | 1295 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); |
1113 | if (rc) { | 1296 | if (rc) { |
1114 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); | 1297 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); |
1115 | goto abort_free_ctlr; | 1298 | goto abort; |
1116 | } | 1299 | } |
1117 | dbg("%s: SLOTCAP offset %x slot_cap %x\n", | 1300 | dbg("%s: SLOTCAP offset %x slot_cap %x\n", |
1118 | __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); | 1301 | __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); |
1119 | 1302 | ||
1120 | if (!(slot_cap & HP_CAP)) { | 1303 | if (!(slot_cap & HP_CAP)) { |
1121 | dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); | 1304 | dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); |
1122 | goto abort_free_ctlr; | 1305 | goto abort; |
1123 | } | 1306 | } |
1124 | /* For debugging purpose */ | 1307 | /* For debugging purpose */ |
1125 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | 1308 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); |
1126 | if (rc) { | 1309 | if (rc) { |
1127 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | 1310 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); |
1128 | goto abort_free_ctlr; | 1311 | goto abort; |
1129 | } | 1312 | } |
1130 | dbg("%s: SLOTSTATUS offset %x slot_status %x\n", | 1313 | dbg("%s: SLOTSTATUS offset %x slot_status %x\n", |
1131 | __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); | 1314 | __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); |
@@ -1133,7 +1316,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1133 | rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); | 1316 | rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); |
1134 | if (rc) { | 1317 | if (rc) { |
1135 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | 1318 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); |
1136 | goto abort_free_ctlr; | 1319 | goto abort; |
1137 | } | 1320 | } |
1138 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", | 1321 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", |
1139 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); | 1322 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); |
@@ -1161,36 +1344,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1161 | ctrl->first_slot = slot_cap >> 19; | 1344 | ctrl->first_slot = slot_cap >> 19; |
1162 | ctrl->ctrlcap = slot_cap & 0x0000007f; | 1345 | ctrl->ctrlcap = slot_cap & 0x0000007f; |
1163 | 1346 | ||
1164 | /* Mask Hot-plug Interrupt Enable */ | 1347 | rc = pcie_init_hardware_part1(ctrl, dev); |
1165 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | 1348 | if (rc) |
1166 | if (rc) { | 1349 | goto abort; |
1167 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | ||
1168 | goto abort_free_ctlr; | ||
1169 | } | ||
1170 | |||
1171 | dbg("%s: SLOTCTRL %x value read %x\n", | ||
1172 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); | ||
1173 | temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | | ||
1174 | 0x00; | ||
1175 | |||
1176 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1177 | if (rc) { | ||
1178 | err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); | ||
1179 | goto abort_free_ctlr; | ||
1180 | } | ||
1181 | |||
1182 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1183 | if (rc) { | ||
1184 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1185 | goto abort_free_ctlr; | ||
1186 | } | ||
1187 | |||
1188 | temp_word = 0x1F; /* Clear all events */ | ||
1189 | rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); | ||
1190 | if (rc) { | ||
1191 | err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); | ||
1192 | goto abort_free_ctlr; | ||
1193 | } | ||
1194 | 1350 | ||
1195 | if (pciehp_poll_mode) { | 1351 | if (pciehp_poll_mode) { |
1196 | /* Install interrupt polling timer. Start with 10 sec delay */ | 1352 | /* Install interrupt polling timer. Start with 10 sec delay */ |
@@ -1206,7 +1362,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1206 | if (rc) { | 1362 | if (rc) { |
1207 | err("Can't get irq %d for the hotplug controller\n", | 1363 | err("Can't get irq %d for the hotplug controller\n", |
1208 | ctrl->pci_dev->irq); | 1364 | ctrl->pci_dev->irq); |
1209 | goto abort_free_ctlr; | 1365 | goto abort; |
1210 | } | 1366 | } |
1211 | } | 1367 | } |
1212 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, | 1368 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, |
@@ -1224,82 +1380,16 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1224 | } | 1380 | } |
1225 | } | 1381 | } |
1226 | 1382 | ||
1227 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | 1383 | rc = pcie_init_hardware_part2(ctrl, dev); |
1228 | if (rc) { | 1384 | if (rc == 0) { |
1229 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | 1385 | ctrl->hpc_ops = &pciehp_hpc_ops; |
1230 | goto abort_free_irq; | 1386 | return 0; |
1231 | } | 1387 | } |
1232 | |||
1233 | intr_enable = intr_enable | PRSN_DETECT_ENABLE; | ||
1234 | |||
1235 | if (ATTN_BUTTN(slot_cap)) | ||
1236 | intr_enable = intr_enable | ATTN_BUTTN_ENABLE; | ||
1237 | |||
1238 | if (POWER_CTRL(slot_cap)) | ||
1239 | intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; | ||
1240 | |||
1241 | if (MRL_SENS(slot_cap)) | ||
1242 | intr_enable = intr_enable | MRL_DETECT_ENABLE; | ||
1243 | |||
1244 | temp_word = (temp_word & ~intr_enable) | intr_enable; | ||
1245 | |||
1246 | if (pciehp_poll_mode) { | ||
1247 | temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; | ||
1248 | } else { | ||
1249 | temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; | ||
1250 | } | ||
1251 | |||
1252 | /* | ||
1253 | * Unmask Hot-plug Interrupt Enable for the interrupt | ||
1254 | * notification mechanism case. | ||
1255 | */ | ||
1256 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1257 | if (rc) { | ||
1258 | err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); | ||
1259 | goto abort_free_irq; | ||
1260 | } | ||
1261 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1262 | if (rc) { | ||
1263 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1264 | goto abort_disable_intr; | ||
1265 | } | ||
1266 | |||
1267 | temp_word = 0x1F; /* Clear all events */ | ||
1268 | rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); | ||
1269 | if (rc) { | ||
1270 | err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); | ||
1271 | goto abort_disable_intr; | ||
1272 | } | ||
1273 | |||
1274 | if (pciehp_force) { | ||
1275 | dbg("Bypassing BIOS check for pciehp use on %s\n", | ||
1276 | pci_name(ctrl->pci_dev)); | ||
1277 | } else { | ||
1278 | rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); | ||
1279 | if (rc) | ||
1280 | goto abort_disable_intr; | ||
1281 | } | ||
1282 | |||
1283 | ctrl->hpc_ops = &pciehp_hpc_ops; | ||
1284 | |||
1285 | return 0; | ||
1286 | |||
1287 | /* We end up here for the many possible ways to fail this API. */ | ||
1288 | abort_disable_intr: | ||
1289 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | ||
1290 | if (!rc) { | ||
1291 | temp_word &= ~(intr_enable | HP_INTR_ENABLE); | ||
1292 | rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); | ||
1293 | } | ||
1294 | if (rc) | ||
1295 | err("%s : disabling interrupts failed\n", __FUNCTION__); | ||
1296 | |||
1297 | abort_free_irq: | 1388 | abort_free_irq: |
1298 | if (pciehp_poll_mode) | 1389 | if (pciehp_poll_mode) |
1299 | del_timer_sync(&ctrl->poll_timer); | 1390 | del_timer_sync(&ctrl->poll_timer); |
1300 | else | 1391 | else |
1301 | free_irq(ctrl->pci_dev->irq, ctrl); | 1392 | free_irq(ctrl->pci_dev->irq, ctrl); |
1302 | 1393 | abort: | |
1303 | abort_free_ctlr: | ||
1304 | return -1; | 1394 | return -1; |
1305 | } | 1395 | } |
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index c424aded13fb..dd50713966d1 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c | |||
@@ -105,12 +105,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) | |||
105 | } | 105 | } |
106 | 106 | ||
107 | /* Find Advanced Error Reporting Enhanced Capability */ | 107 | /* Find Advanced Error Reporting Enhanced Capability */ |
108 | pos = 256; | 108 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
109 | do { | ||
110 | pci_read_config_dword(dev, pos, ®32); | ||
111 | if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) | ||
112 | break; | ||
113 | } while ((pos = PCI_EXT_CAP_NEXT(reg32))); | ||
114 | if (!pos) | 109 | if (!pos) |
115 | return; | 110 | return; |
116 | 111 | ||
@@ -248,11 +243,15 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
248 | u8 bctl = 0; | 243 | u8 bctl = 0; |
249 | u8 presence = 0; | 244 | u8 presence = 0; |
250 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; | 245 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; |
246 | u16 command; | ||
251 | 247 | ||
252 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, | 248 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, |
253 | p_slot->device); | 249 | p_slot->device); |
250 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); | ||
251 | if (ret) | ||
252 | presence = 0; | ||
254 | 253 | ||
255 | for (j=0; j<8 ; j++) { | 254 | for (j = 0; j < 8; j++) { |
256 | struct pci_dev* temp = pci_get_slot(parent, | 255 | struct pci_dev* temp = pci_get_slot(parent, |
257 | (p_slot->device << 3) | j); | 256 | (p_slot->device << 3) | j); |
258 | if (!temp) | 257 | if (!temp) |
@@ -263,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
263 | pci_dev_put(temp); | 262 | pci_dev_put(temp); |
264 | continue; | 263 | continue; |
265 | } | 264 | } |
266 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 265 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { |
267 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, | 266 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); |
268 | &presence); | 267 | if (bctl & PCI_BRIDGE_CTL_VGA) { |
269 | if (!ret && presence) { | 268 | err("Cannot remove display device %s\n", |
270 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, | 269 | pci_name(temp)); |
271 | &bctl); | 270 | pci_dev_put(temp); |
272 | if (bctl & PCI_BRIDGE_CTL_VGA) { | 271 | continue; |
273 | err("Cannot remove display device %s\n", | ||
274 | pci_name(temp)); | ||
275 | pci_dev_put(temp); | ||
276 | continue; | ||
277 | } | ||
278 | } | 272 | } |
279 | } | 273 | } |
280 | pci_remove_bus_device(temp); | 274 | pci_remove_bus_device(temp); |
275 | /* | ||
276 | * Ensure that no new Requests will be generated from | ||
277 | * the device. | ||
278 | */ | ||
279 | if (presence) { | ||
280 | pci_read_config_word(temp, PCI_COMMAND, &command); | ||
281 | command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); | ||
282 | command |= PCI_COMMAND_INTX_DISABLE; | ||
283 | pci_write_config_word(temp, PCI_COMMAND, command); | ||
284 | } | ||
281 | pci_dev_put(temp); | 285 | pci_dev_put(temp); |
282 | } | 286 | } |
283 | /* | 287 | /* |
@@ -288,4 +292,3 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
288 | 292 | ||
289 | return rc; | 293 | return rc; |
290 | } | 294 | } |
291 | |||
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index c822a779653f..7d5921b1ee78 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h | |||
@@ -74,7 +74,6 @@ struct slot { | |||
74 | u32 type; | 74 | u32 type; |
75 | u32 power_domain; | 75 | u32 power_domain; |
76 | char *name; | 76 | char *name; |
77 | char *location; | ||
78 | struct device_node *dn; | 77 | struct device_node *dn; |
79 | struct pci_bus *bus; | 78 | struct pci_bus *bus; |
80 | struct list_head *pci_devs; | 79 | struct list_head *pci_devs; |
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0de84533cd80..6571e9b4c2ec 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
@@ -64,19 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) | |||
64 | return rc; | 64 | return rc; |
65 | } | 65 | } |
66 | 66 | ||
67 | static void set_slot_name(struct slot *slot) | ||
68 | { | ||
69 | struct pci_bus *bus = slot->bus; | ||
70 | struct pci_dev *bridge; | ||
71 | |||
72 | bridge = bus->self; | ||
73 | if (bridge) | ||
74 | strcpy(slot->name, pci_name(bridge)); | ||
75 | else | ||
76 | sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), | ||
77 | bus->number); | ||
78 | } | ||
79 | |||
80 | /** | 67 | /** |
81 | * rpaphp_enable_slot - record slot state, config pci device | 68 | * rpaphp_enable_slot - record slot state, config pci device |
82 | * @slot: target &slot | 69 | * @slot: target &slot |
@@ -115,7 +102,6 @@ int rpaphp_enable_slot(struct slot *slot) | |||
115 | info->adapter_status = EMPTY; | 102 | info->adapter_status = EMPTY; |
116 | slot->bus = bus; | 103 | slot->bus = bus; |
117 | slot->pci_devs = &bus->devices; | 104 | slot->pci_devs = &bus->devices; |
118 | set_slot_name(slot); | ||
119 | 105 | ||
120 | /* if there's an adapter in the slot, go add the pci devices */ | 106 | /* if there's an adapter in the slot, go add the pci devices */ |
121 | if (state == PRESENT) { | 107 | if (state == PRESENT) { |
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index d4ee8723fcb3..8ad3debb3794 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c | |||
@@ -33,23 +33,31 @@ | |||
33 | #include <asm/rtas.h> | 33 | #include <asm/rtas.h> |
34 | #include "rpaphp.h" | 34 | #include "rpaphp.h" |
35 | 35 | ||
36 | static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) | 36 | static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf) |
37 | { | 37 | { |
38 | char *value; | 38 | int retval; |
39 | int retval = -ENOENT; | ||
40 | struct slot *slot = (struct slot *)php_slot->private; | 39 | struct slot *slot = (struct slot *)php_slot->private; |
40 | struct pci_bus *bus; | ||
41 | 41 | ||
42 | if (!slot) | 42 | if (!slot) |
43 | return retval; | 43 | return -ENOENT; |
44 | |||
45 | bus = slot->bus; | ||
46 | if (!bus) | ||
47 | return -ENOENT; | ||
48 | |||
49 | if (bus->self) | ||
50 | retval = sprintf(buf, pci_name(bus->self)); | ||
51 | else | ||
52 | retval = sprintf(buf, "%04x:%02x:00.0", | ||
53 | pci_domain_nr(bus), bus->number); | ||
44 | 54 | ||
45 | value = slot->location; | ||
46 | retval = sprintf (buf, "%s\n", value); | ||
47 | return retval; | 55 | return retval; |
48 | } | 56 | } |
49 | 57 | ||
50 | static struct hotplug_slot_attribute php_attr_location = { | 58 | static struct hotplug_slot_attribute php_attr_address = { |
51 | .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, | 59 | .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, |
52 | .show = location_read_file, | 60 | .show = address_read_file, |
53 | }; | 61 | }; |
54 | 62 | ||
55 | /* free up the memory used by a slot */ | 63 | /* free up the memory used by a slot */ |
@@ -64,7 +72,6 @@ void dealloc_slot_struct(struct slot *slot) | |||
64 | kfree(slot->hotplug_slot->info); | 72 | kfree(slot->hotplug_slot->info); |
65 | kfree(slot->hotplug_slot->name); | 73 | kfree(slot->hotplug_slot->name); |
66 | kfree(slot->hotplug_slot); | 74 | kfree(slot->hotplug_slot); |
67 | kfree(slot->location); | ||
68 | kfree(slot); | 75 | kfree(slot); |
69 | } | 76 | } |
70 | 77 | ||
@@ -83,16 +90,13 @@ struct slot *alloc_slot_struct(struct device_node *dn, | |||
83 | GFP_KERNEL); | 90 | GFP_KERNEL); |
84 | if (!slot->hotplug_slot->info) | 91 | if (!slot->hotplug_slot->info) |
85 | goto error_hpslot; | 92 | goto error_hpslot; |
86 | slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL); | 93 | slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); |
87 | if (!slot->hotplug_slot->name) | 94 | if (!slot->hotplug_slot->name) |
88 | goto error_info; | 95 | goto error_info; |
89 | slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); | ||
90 | if (!slot->location) | ||
91 | goto error_name; | ||
92 | slot->name = slot->hotplug_slot->name; | 96 | slot->name = slot->hotplug_slot->name; |
97 | strcpy(slot->name, drc_name); | ||
93 | slot->dn = dn; | 98 | slot->dn = dn; |
94 | slot->index = drc_index; | 99 | slot->index = drc_index; |
95 | strcpy(slot->location, drc_name); | ||
96 | slot->power_domain = power_domain; | 100 | slot->power_domain = power_domain; |
97 | slot->hotplug_slot->private = slot; | 101 | slot->hotplug_slot->private = slot; |
98 | slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; | 102 | slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; |
@@ -100,8 +104,6 @@ struct slot *alloc_slot_struct(struct device_node *dn, | |||
100 | 104 | ||
101 | return (slot); | 105 | return (slot); |
102 | 106 | ||
103 | error_name: | ||
104 | kfree(slot->hotplug_slot->name); | ||
105 | error_info: | 107 | error_info: |
106 | kfree(slot->hotplug_slot->info); | 108 | kfree(slot->hotplug_slot->info); |
107 | error_hpslot: | 109 | error_hpslot: |
@@ -133,8 +135,8 @@ int rpaphp_deregister_slot(struct slot *slot) | |||
133 | 135 | ||
134 | list_del(&slot->rpaphp_slot_list); | 136 | list_del(&slot->rpaphp_slot_list); |
135 | 137 | ||
136 | /* remove "phy_location" file */ | 138 | /* remove "address" file */ |
137 | sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr); | 139 | sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr); |
138 | 140 | ||
139 | retval = pci_hp_deregister(php_slot); | 141 | retval = pci_hp_deregister(php_slot); |
140 | if (retval) | 142 | if (retval) |
@@ -166,8 +168,8 @@ int rpaphp_register_slot(struct slot *slot) | |||
166 | return retval; | 168 | return retval; |
167 | } | 169 | } |
168 | 170 | ||
169 | /* create "phy_location" file */ | 171 | /* create "address" file */ |
170 | retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr); | 172 | retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr); |
171 | if (retval) { | 173 | if (retval) { |
172 | err("sysfs_create_file failed with error %d\n", retval); | 174 | err("sysfs_create_file failed with error %d\n", retval); |
173 | goto sysfs_fail; | 175 | goto sysfs_fail; |
@@ -175,8 +177,7 @@ int rpaphp_register_slot(struct slot *slot) | |||
175 | 177 | ||
176 | /* add slot to our internal list */ | 178 | /* add slot to our internal list */ |
177 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | 179 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); |
178 | info("Slot [%s](PCI location=%s) registered\n", slot->name, | 180 | info("Slot [%s] registered\n", slot->name); |
179 | slot->location); | ||
180 | return 0; | 181 | return 0; |
181 | 182 | ||
182 | sysfs_fail: | 183 | sysfs_fail: |
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 5183a45d45b5..e8aa138128ce 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -597,7 +597,7 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
597 | cleanup_slots(ctrl); | 597 | cleanup_slots(ctrl); |
598 | 598 | ||
599 | /* | 599 | /* |
600 | * Mask SERR and System Interrut generation | 600 | * Mask SERR and System Interrupt generation |
601 | */ | 601 | */ |
602 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); | 602 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
603 | serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | | 603 | serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | |