diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 85 |
1 files changed, 63 insertions, 22 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index fe0a6b7662f7..22d0f1cf1362 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -57,7 +57,6 @@ static LIST_HEAD(bridge_list); | |||
57 | #define MY_NAME "acpiphp_glue" | 57 | #define MY_NAME "acpiphp_glue" |
58 | 58 | ||
59 | static void handle_hotplug_event_bridge (acpi_handle, u32, void *); | 59 | static void handle_hotplug_event_bridge (acpi_handle, u32, void *); |
60 | static void handle_hotplug_event_func (acpi_handle, u32, void *); | ||
61 | static void acpiphp_sanitize_bus(struct pci_bus *bus); | 60 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
62 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); | 61 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); |
63 | 62 | ||
@@ -125,6 +124,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
125 | struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; | 124 | struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; |
126 | struct acpiphp_slot *slot; | 125 | struct acpiphp_slot *slot; |
127 | struct acpiphp_func *newfunc; | 126 | struct acpiphp_func *newfunc; |
127 | struct dependent_device *dd; | ||
128 | acpi_handle tmp; | 128 | acpi_handle tmp; |
129 | acpi_status status = AE_OK; | 129 | acpi_status status = AE_OK; |
130 | unsigned long adr, sun; | 130 | unsigned long adr, sun; |
@@ -138,7 +138,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
138 | 138 | ||
139 | status = acpi_get_handle(handle, "_EJ0", &tmp); | 139 | status = acpi_get_handle(handle, "_EJ0", &tmp); |
140 | 140 | ||
141 | if (ACPI_FAILURE(status)) | 141 | if (ACPI_FAILURE(status) && !(is_dependent_device(handle))) |
142 | return AE_OK; | 142 | return AE_OK; |
143 | 143 | ||
144 | device = (adr >> 16) & 0xffff; | 144 | device = (adr >> 16) & 0xffff; |
@@ -152,7 +152,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
152 | INIT_LIST_HEAD(&newfunc->sibling); | 152 | INIT_LIST_HEAD(&newfunc->sibling); |
153 | newfunc->handle = handle; | 153 | newfunc->handle = handle; |
154 | newfunc->function = function; | 154 | newfunc->function = function; |
155 | newfunc->flags = FUNC_HAS_EJ0; | 155 | if (ACPI_SUCCESS(status)) |
156 | newfunc->flags = FUNC_HAS_EJ0; | ||
156 | 157 | ||
157 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) | 158 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) |
158 | newfunc->flags |= FUNC_HAS_STA; | 159 | newfunc->flags |= FUNC_HAS_STA; |
@@ -163,6 +164,19 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
163 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) | 164 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) |
164 | newfunc->flags |= FUNC_HAS_PS3; | 165 | newfunc->flags |= FUNC_HAS_PS3; |
165 | 166 | ||
167 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { | ||
168 | newfunc->flags |= FUNC_HAS_DCK; | ||
169 | /* add to devices dependent on dock station, | ||
170 | * because this may actually be the dock bridge | ||
171 | */ | ||
172 | dd = alloc_dependent_device(handle); | ||
173 | if (!dd) | ||
174 | err("Can't allocate memory for " | ||
175 | "new dependent device!\n"); | ||
176 | else | ||
177 | add_dependent_device(dd); | ||
178 | } | ||
179 | |||
166 | status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); | 180 | status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); |
167 | if (ACPI_FAILURE(status)) | 181 | if (ACPI_FAILURE(status)) |
168 | sun = -1; | 182 | sun = -1; |
@@ -210,18 +224,35 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
210 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 224 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
211 | } | 225 | } |
212 | 226 | ||
227 | /* if this is a device dependent on a dock station, | ||
228 | * associate the acpiphp_func to the dependent_device | ||
229 | * struct. | ||
230 | */ | ||
231 | if ((dd = get_dependent_device(handle))) { | ||
232 | newfunc->flags |= FUNC_IS_DD; | ||
233 | /* | ||
234 | * we don't want any devices which is dependent | ||
235 | * on the dock to have it's _EJ0 method executed. | ||
236 | * because we need to run _DCK first. | ||
237 | */ | ||
238 | newfunc->flags &= ~FUNC_HAS_EJ0; | ||
239 | dd->func = newfunc; | ||
240 | add_pci_dependent_device(dd); | ||
241 | } | ||
242 | |||
213 | /* install notify handler */ | 243 | /* install notify handler */ |
214 | status = acpi_install_notify_handler(handle, | 244 | if (!(newfunc->flags & FUNC_HAS_DCK)) { |
245 | status = acpi_install_notify_handler(handle, | ||
215 | ACPI_SYSTEM_NOTIFY, | 246 | ACPI_SYSTEM_NOTIFY, |
216 | handle_hotplug_event_func, | 247 | handle_hotplug_event_func, |
217 | newfunc); | 248 | newfunc); |
218 | 249 | ||
219 | if (ACPI_FAILURE(status)) { | 250 | if (ACPI_FAILURE(status)) |
220 | err("failed to register interrupt notify handler\n"); | 251 | err("failed to register interrupt notify handler\n"); |
221 | return status; | 252 | } else |
222 | } | 253 | status = AE_OK; |
223 | 254 | ||
224 | return AE_OK; | 255 | return status; |
225 | } | 256 | } |
226 | 257 | ||
227 | 258 | ||
@@ -410,7 +441,8 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
410 | goto out; | 441 | goto out; |
411 | 442 | ||
412 | /* check if this bridge has ejectable slots */ | 443 | /* check if this bridge has ejectable slots */ |
413 | if (detect_ejectable_slots(handle) > 0) { | 444 | if ((detect_ejectable_slots(handle) > 0) || |
445 | (detect_dependent_devices(handle) > 0)) { | ||
414 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | 446 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |
415 | add_p2p_bridge(handle, dev); | 447 | add_p2p_bridge(handle, dev); |
416 | } | 448 | } |
@@ -512,11 +544,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
512 | list_for_each_safe (list, tmp, &slot->funcs) { | 544 | list_for_each_safe (list, tmp, &slot->funcs) { |
513 | struct acpiphp_func *func; | 545 | struct acpiphp_func *func; |
514 | func = list_entry(list, struct acpiphp_func, sibling); | 546 | func = list_entry(list, struct acpiphp_func, sibling); |
515 | status = acpi_remove_notify_handler(func->handle, | 547 | if (!(func->flags & FUNC_HAS_DCK)) { |
548 | status = acpi_remove_notify_handler(func->handle, | ||
516 | ACPI_SYSTEM_NOTIFY, | 549 | ACPI_SYSTEM_NOTIFY, |
517 | handle_hotplug_event_func); | 550 | handle_hotplug_event_func); |
518 | if (ACPI_FAILURE(status)) | 551 | if (ACPI_FAILURE(status)) |
519 | err("failed to remove notify handler\n"); | 552 | err("failed to remove notify handler\n"); |
553 | } | ||
520 | pci_dev_put(func->pci_dev); | 554 | pci_dev_put(func->pci_dev); |
521 | list_del(list); | 555 | list_del(list); |
522 | kfree(func); | 556 | kfree(func); |
@@ -828,14 +862,21 @@ static int acpiphp_bus_add(struct acpiphp_func *func) | |||
828 | dbg("no parent device, assuming NULL\n"); | 862 | dbg("no parent device, assuming NULL\n"); |
829 | pdevice = NULL; | 863 | pdevice = NULL; |
830 | } | 864 | } |
831 | if (acpi_bus_get_device(func->handle, &device)) { | 865 | if (!acpi_bus_get_device(func->handle, &device)) { |
832 | ret_val = acpi_bus_add(&device, pdevice, func->handle, | 866 | dbg("bus exists... trim\n"); |
833 | ACPI_BUS_TYPE_DEVICE); | 867 | /* this shouldn't be in here, so remove |
834 | if (ret_val) { | 868 | * the bus then re-add it... |
835 | dbg("error adding bus, %x\n", | 869 | */ |
836 | -ret_val); | 870 | ret_val = acpi_bus_trim(device, 1); |
837 | goto acpiphp_bus_add_out; | 871 | dbg("acpi_bus_trim return %x\n", ret_val); |
838 | } | 872 | } |
873 | |||
874 | ret_val = acpi_bus_add(&device, pdevice, func->handle, | ||
875 | ACPI_BUS_TYPE_DEVICE); | ||
876 | if (ret_val) { | ||
877 | dbg("error adding bus, %x\n", | ||
878 | -ret_val); | ||
879 | goto acpiphp_bus_add_out; | ||
839 | } | 880 | } |
840 | /* | 881 | /* |
841 | * try to start anyway. We could have failed to add | 882 | * try to start anyway. We could have failed to add |
@@ -1307,7 +1348,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1307 | * handles ACPI event notification on slots | 1348 | * handles ACPI event notification on slots |
1308 | * | 1349 | * |
1309 | */ | 1350 | */ |
1310 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) | 1351 | void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) |
1311 | { | 1352 | { |
1312 | struct acpiphp_func *func; | 1353 | struct acpiphp_func *func; |
1313 | char objname[64]; | 1354 | char objname[64]; |