aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpiphp_glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c111
1 files changed, 84 insertions, 27 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index d370f999782e..faf7eed5d963 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -116,6 +116,59 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
116 } 116 }
117} 117}
118 118
119/* callback routine to check for the existance of a pci dock device */
120static acpi_status
121is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
122{
123 int *count = (int *)context;
124
125 if (is_dock_device(handle)) {
126 (*count)++;
127 return AE_CTRL_TERMINATE;
128 } else {
129 return AE_OK;
130 }
131}
132
133
134
135
136/*
137 * the _DCK method can do funny things... and sometimes not
138 * hah-hah funny.
139 *
140 * TBD - figure out a way to only call fixups for
141 * systems that require them.
142 */
143static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
144 void *v)
145{
146 struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
147 struct pci_bus *bus = func->slot->bridge->pci_bus;
148 u32 buses;
149
150 if (!bus->self)
151 return NOTIFY_OK;
152
153 /* fixup bad _DCK function that rewrites
154 * secondary bridge on slot
155 */
156 pci_read_config_dword(bus->self,
157 PCI_PRIMARY_BUS,
158 &buses);
159
160 if (((buses >> 8) & 0xff) != bus->secondary) {
161 buses = (buses & 0xff000000)
162 | ((unsigned int)(bus->primary) << 0)
163 | ((unsigned int)(bus->secondary) << 8)
164 | ((unsigned int)(bus->subordinate) << 16);
165 pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
166 }
167 return NOTIFY_OK;
168}
169
170
171
119 172
120/* callback routine to register each ACPI PCI slot object */ 173/* callback routine to register each ACPI PCI slot object */
121static acpi_status 174static acpi_status
@@ -124,7 +177,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
124 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 177 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
125 struct acpiphp_slot *slot; 178 struct acpiphp_slot *slot;
126 struct acpiphp_func *newfunc; 179 struct acpiphp_func *newfunc;
127 struct dependent_device *dd;
128 acpi_handle tmp; 180 acpi_handle tmp;
129 acpi_status status = AE_OK; 181 acpi_status status = AE_OK;
130 unsigned long adr, sun; 182 unsigned long adr, sun;
@@ -137,7 +189,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
137 189
138 status = acpi_get_handle(handle, "_EJ0", &tmp); 190 status = acpi_get_handle(handle, "_EJ0", &tmp);
139 191
140 if (ACPI_FAILURE(status) && !(is_dependent_device(handle))) 192 if (ACPI_FAILURE(status) && !(is_dock_device(handle)))
141 return AE_OK; 193 return AE_OK;
142 194
143 device = (adr >> 16) & 0xffff; 195 device = (adr >> 16) & 0xffff;
@@ -162,18 +214,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
162 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 214 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
163 newfunc->flags |= FUNC_HAS_PS3; 215 newfunc->flags |= FUNC_HAS_PS3;
164 216
165 if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { 217 if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
166 newfunc->flags |= FUNC_HAS_DCK; 218 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 219
178 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 220 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
179 if (ACPI_FAILURE(status)) 221 if (ACPI_FAILURE(status))
@@ -225,20 +267,23 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
225 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 267 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
226 } 268 }
227 269
228 /* if this is a device dependent on a dock station, 270 if (is_dock_device(handle)) {
229 * associate the acpiphp_func to the dependent_device 271 /* we don't want to call this device's _EJ0
230 * struct. 272 * because we want the dock notify handler
231 */ 273 * 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 */ 274 */
239 newfunc->flags &= ~FUNC_HAS_EJ0; 275 newfunc->flags &= ~FUNC_HAS_EJ0;
240 dd->func = newfunc; 276 if (register_hotplug_dock_device(handle,
241 add_pci_dependent_device(dd); 277 handle_hotplug_event_func, newfunc))
278 dbg("failed to register dock device\n");
279
280 /* we need to be notified when dock events happen
281 * outside of the hotplug operation, since we may
282 * need to do fixups before we can hotplug.
283 */
284 newfunc->nb.notifier_call = post_dock_fixups;
285 if (register_dock_notifier(&newfunc->nb))
286 dbg("failed to register a dock notifier");
242 } 287 }
243 288
244 /* install notify handler */ 289 /* install notify handler */
@@ -277,6 +322,15 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle)
277 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 322 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
278 is_ejectable_slot, (void *)&count, NULL); 323 is_ejectable_slot, (void *)&count, NULL);
279 324
325 /*
326 * we also need to add this bridge if there is a dock bridge or
327 * other pci device on a dock station (removable)
328 */
329 if (!count)
330 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
331 (u32)1, is_pci_dock_device, (void *)&count,
332 NULL);
333
280 return count; 334 return count;
281} 335}
282 336
@@ -487,8 +541,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
487 goto out; 541 goto out;
488 542
489 /* check if this bridge has ejectable slots */ 543 /* check if this bridge has ejectable slots */
490 if ((detect_ejectable_slots(handle) > 0) || 544 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)); 545 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
493 add_p2p_bridge(handle, dev); 546 add_p2p_bridge(handle, dev);
494 } 547 }
@@ -605,6 +658,10 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
605 list_for_each_safe (list, tmp, &slot->funcs) { 658 list_for_each_safe (list, tmp, &slot->funcs) {
606 struct acpiphp_func *func; 659 struct acpiphp_func *func;
607 func = list_entry(list, struct acpiphp_func, sibling); 660 func = list_entry(list, struct acpiphp_func, sibling);
661 if (is_dock_device(func->handle)) {
662 unregister_hotplug_dock_device(func->handle);
663 unregister_dock_notifier(&func->nb);
664 }
608 if (!(func->flags & FUNC_HAS_DCK)) { 665 if (!(func->flags & FUNC_HAS_DCK)) {
609 status = acpi_remove_notify_handler(func->handle, 666 status = acpi_remove_notify_handler(func->handle,
610 ACPI_SYSTEM_NOTIFY, 667 ACPI_SYSTEM_NOTIFY,