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.c85
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
59static void handle_hotplug_event_bridge (acpi_handle, u32, void *); 59static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
60static void handle_hotplug_event_func (acpi_handle, u32, void *);
61static void acpiphp_sanitize_bus(struct pci_bus *bus); 60static void acpiphp_sanitize_bus(struct pci_bus *bus);
62static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); 61static 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 */
1310static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 1351void 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];