diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 123 |
1 files changed, 93 insertions, 30 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d370f999782e..ef95d12fb32c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -59,6 +59,7 @@ static LIST_HEAD(bridge_list); | |||
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 acpiphp_sanitize_bus(struct pci_bus *bus); | 60 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
61 | 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); |
62 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); | ||
62 | 63 | ||
63 | 64 | ||
64 | /* | 65 | /* |
@@ -116,6 +117,59 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
116 | } | 117 | } |
117 | } | 118 | } |
118 | 119 | ||
120 | /* callback routine to check for the existance of a pci dock device */ | ||
121 | static acpi_status | ||
122 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
123 | { | ||
124 | int *count = (int *)context; | ||
125 | |||
126 | if (is_dock_device(handle)) { | ||
127 | (*count)++; | ||
128 | return AE_CTRL_TERMINATE; | ||
129 | } else { | ||
130 | return AE_OK; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | |||
137 | /* | ||
138 | * the _DCK method can do funny things... and sometimes not | ||
139 | * hah-hah funny. | ||
140 | * | ||
141 | * TBD - figure out a way to only call fixups for | ||
142 | * systems that require them. | ||
143 | */ | ||
144 | static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | ||
145 | void *v) | ||
146 | { | ||
147 | struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); | ||
148 | struct pci_bus *bus = func->slot->bridge->pci_bus; | ||
149 | u32 buses; | ||
150 | |||
151 | if (!bus->self) | ||
152 | return NOTIFY_OK; | ||
153 | |||
154 | /* fixup bad _DCK function that rewrites | ||
155 | * secondary bridge on slot | ||
156 | */ | ||
157 | pci_read_config_dword(bus->self, | ||
158 | PCI_PRIMARY_BUS, | ||
159 | &buses); | ||
160 | |||
161 | if (((buses >> 8) & 0xff) != bus->secondary) { | ||
162 | buses = (buses & 0xff000000) | ||
163 | | ((unsigned int)(bus->primary) << 0) | ||
164 | | ((unsigned int)(bus->secondary) << 8) | ||
165 | | ((unsigned int)(bus->subordinate) << 16); | ||
166 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); | ||
167 | } | ||
168 | return NOTIFY_OK; | ||
169 | } | ||
170 | |||
171 | |||
172 | |||
119 | 173 | ||
120 | /* callback routine to register each ACPI PCI slot object */ | 174 | /* callback routine to register each ACPI PCI slot object */ |
121 | static acpi_status | 175 | static acpi_status |
@@ -124,7 +178,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
124 | struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; | 178 | struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; |
125 | struct acpiphp_slot *slot; | 179 | struct acpiphp_slot *slot; |
126 | struct acpiphp_func *newfunc; | 180 | struct acpiphp_func *newfunc; |
127 | struct dependent_device *dd; | ||
128 | acpi_handle tmp; | 181 | acpi_handle tmp; |
129 | acpi_status status = AE_OK; | 182 | acpi_status status = AE_OK; |
130 | unsigned long adr, sun; | 183 | unsigned long adr, sun; |
@@ -137,7 +190,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
137 | 190 | ||
138 | status = acpi_get_handle(handle, "_EJ0", &tmp); | 191 | status = acpi_get_handle(handle, "_EJ0", &tmp); |
139 | 192 | ||
140 | if (ACPI_FAILURE(status) && !(is_dependent_device(handle))) | 193 | if (ACPI_FAILURE(status) && !(is_dock_device(handle))) |
141 | return AE_OK; | 194 | return AE_OK; |
142 | 195 | ||
143 | device = (adr >> 16) & 0xffff; | 196 | device = (adr >> 16) & 0xffff; |
@@ -162,22 +215,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
162 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) | 215 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) |
163 | newfunc->flags |= FUNC_HAS_PS3; | 216 | newfunc->flags |= FUNC_HAS_PS3; |
164 | 217 | ||
165 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { | 218 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) |
166 | newfunc->flags |= FUNC_HAS_DCK; | 219 | newfunc->flags |= FUNC_HAS_DCK; |
167 | /* add to devices dependent on dock station, | ||
168 | * because this may actually be the dock bridge | ||
169 | */ | ||
170 | dd = alloc_dependent_device(handle); | ||
171 | if (!dd) | ||
172 | err("Can't allocate memory for " | ||
173 | "new dependent device!\n"); | ||
174 | else | ||
175 | add_dependent_device(dd); | ||
176 | } | ||
177 | 220 | ||
178 | status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); | 221 | status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); |
179 | if (ACPI_FAILURE(status)) | 222 | if (ACPI_FAILURE(status)) { |
180 | sun = -1; | 223 | /* |
224 | * use the count of the number of slots we've found | ||
225 | * for the number of the slot | ||
226 | */ | ||
227 | sun = bridge->nr_slots+1; | ||
228 | } | ||
181 | 229 | ||
182 | /* search for objects that share the same slot */ | 230 | /* search for objects that share the same slot */ |
183 | for (slot = bridge->slots; slot; slot = slot->next) | 231 | for (slot = bridge->slots; slot; slot = slot->next) |
@@ -225,20 +273,23 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
225 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 273 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
226 | } | 274 | } |
227 | 275 | ||
228 | /* if this is a device dependent on a dock station, | 276 | if (is_dock_device(handle)) { |
229 | * associate the acpiphp_func to the dependent_device | 277 | /* we don't want to call this device's _EJ0 |
230 | * struct. | 278 | * because we want the dock notify handler |
231 | */ | 279 | * to call it after it calls _DCK |
232 | if ((dd = get_dependent_device(handle))) { | ||
233 | newfunc->flags |= FUNC_IS_DD; | ||
234 | /* | ||
235 | * we don't want any devices which is dependent | ||
236 | * on the dock to have it's _EJ0 method executed. | ||
237 | * because we need to run _DCK first. | ||
238 | */ | 280 | */ |
239 | newfunc->flags &= ~FUNC_HAS_EJ0; | 281 | newfunc->flags &= ~FUNC_HAS_EJ0; |
240 | dd->func = newfunc; | 282 | if (register_hotplug_dock_device(handle, |
241 | add_pci_dependent_device(dd); | 283 | handle_hotplug_event_func, newfunc)) |
284 | dbg("failed to register dock device\n"); | ||
285 | |||
286 | /* we need to be notified when dock events happen | ||
287 | * outside of the hotplug operation, since we may | ||
288 | * need to do fixups before we can hotplug. | ||
289 | */ | ||
290 | newfunc->nb.notifier_call = post_dock_fixups; | ||
291 | if (register_dock_notifier(&newfunc->nb)) | ||
292 | dbg("failed to register a dock notifier"); | ||
242 | } | 293 | } |
243 | 294 | ||
244 | /* install notify handler */ | 295 | /* install notify handler */ |
@@ -277,6 +328,15 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle) | |||
277 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, | 328 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, |
278 | is_ejectable_slot, (void *)&count, NULL); | 329 | is_ejectable_slot, (void *)&count, NULL); |
279 | 330 | ||
331 | /* | ||
332 | * we also need to add this bridge if there is a dock bridge or | ||
333 | * other pci device on a dock station (removable) | ||
334 | */ | ||
335 | if (!count) | ||
336 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, | ||
337 | (u32)1, is_pci_dock_device, (void *)&count, | ||
338 | NULL); | ||
339 | |||
280 | return count; | 340 | return count; |
281 | } | 341 | } |
282 | 342 | ||
@@ -487,8 +547,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
487 | goto out; | 547 | goto out; |
488 | 548 | ||
489 | /* check if this bridge has ejectable slots */ | 549 | /* check if this bridge has ejectable slots */ |
490 | if ((detect_ejectable_slots(handle) > 0) || | 550 | if ((detect_ejectable_slots(handle) > 0)) { |
491 | (detect_dependent_devices(handle) > 0)) { | ||
492 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | 551 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |
493 | add_p2p_bridge(handle, dev); | 552 | add_p2p_bridge(handle, dev); |
494 | } | 553 | } |
@@ -605,6 +664,10 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
605 | list_for_each_safe (list, tmp, &slot->funcs) { | 664 | list_for_each_safe (list, tmp, &slot->funcs) { |
606 | struct acpiphp_func *func; | 665 | struct acpiphp_func *func; |
607 | func = list_entry(list, struct acpiphp_func, sibling); | 666 | func = list_entry(list, struct acpiphp_func, sibling); |
667 | if (is_dock_device(func->handle)) { | ||
668 | unregister_hotplug_dock_device(func->handle); | ||
669 | unregister_dock_notifier(&func->nb); | ||
670 | } | ||
608 | if (!(func->flags & FUNC_HAS_DCK)) { | 671 | if (!(func->flags & FUNC_HAS_DCK)) { |
609 | status = acpi_remove_notify_handler(func->handle, | 672 | status = acpi_remove_notify_handler(func->handle, |
610 | ACPI_SYSTEM_NOTIFY, | 673 | ACPI_SYSTEM_NOTIFY, |
@@ -1440,7 +1503,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1440 | * handles ACPI event notification on slots | 1503 | * handles ACPI event notification on slots |
1441 | * | 1504 | * |
1442 | */ | 1505 | */ |
1443 | void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) | 1506 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) |
1444 | { | 1507 | { |
1445 | struct acpiphp_func *func; | 1508 | struct acpiphp_func *func; |
1446 | char objname[64]; | 1509 | char objname[64]; |