diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 242 |
1 files changed, 179 insertions, 63 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 053ee843863c..d370f999782e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -286,13 +286,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge) | |||
286 | { | 286 | { |
287 | acpi_status status; | 287 | acpi_status status; |
288 | 288 | ||
289 | status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp); | 289 | status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp); |
290 | if (ACPI_FAILURE(status)) { | 290 | if (ACPI_FAILURE(status) || |
291 | !bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) { | ||
291 | /* use default numbers */ | 292 | /* use default numbers */ |
292 | bridge->hpp.cache_line_size = 0x10; | 293 | printk(KERN_WARNING |
293 | bridge->hpp.latency_timer = 0x40; | 294 | "%s: Could not get hotplug parameters. Use defaults\n", |
294 | bridge->hpp.enable_serr = 0; | 295 | __FUNCTION__); |
295 | bridge->hpp.enable_perr = 0; | 296 | bridge->hpp.t0 = &bridge->hpp.type0_data; |
297 | bridge->hpp.t0->revision = 0; | ||
298 | bridge->hpp.t0->cache_line_size = 0x10; | ||
299 | bridge->hpp.t0->latency_timer = 0x40; | ||
300 | bridge->hpp.t0->enable_serr = 0; | ||
301 | bridge->hpp.t0->enable_perr = 0; | ||
296 | } | 302 | } |
297 | } | 303 | } |
298 | 304 | ||
@@ -319,6 +325,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
319 | 325 | ||
320 | /* install notify handler */ | 326 | /* install notify handler */ |
321 | if (bridge->type != BRIDGE_TYPE_HOST) { | 327 | if (bridge->type != BRIDGE_TYPE_HOST) { |
328 | if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { | ||
329 | status = acpi_remove_notify_handler(bridge->func->handle, | ||
330 | ACPI_SYSTEM_NOTIFY, | ||
331 | handle_hotplug_event_func); | ||
332 | if (ACPI_FAILURE(status)) | ||
333 | err("failed to remove notify handler\n"); | ||
334 | } | ||
322 | status = acpi_install_notify_handler(bridge->handle, | 335 | status = acpi_install_notify_handler(bridge->handle, |
323 | ACPI_SYSTEM_NOTIFY, | 336 | ACPI_SYSTEM_NOTIFY, |
324 | handle_hotplug_event_bridge, | 337 | handle_hotplug_event_bridge, |
@@ -331,6 +344,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
331 | } | 344 | } |
332 | 345 | ||
333 | 346 | ||
347 | /* find acpiphp_func from acpiphp_bridge */ | ||
348 | static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) | ||
349 | { | ||
350 | struct list_head *node, *l; | ||
351 | struct acpiphp_bridge *bridge; | ||
352 | struct acpiphp_slot *slot; | ||
353 | struct acpiphp_func *func; | ||
354 | |||
355 | list_for_each(node, &bridge_list) { | ||
356 | bridge = list_entry(node, struct acpiphp_bridge, list); | ||
357 | for (slot = bridge->slots; slot; slot = slot->next) { | ||
358 | list_for_each(l, &slot->funcs) { | ||
359 | func = list_entry(l, struct acpiphp_func, | ||
360 | sibling); | ||
361 | if (func->handle == handle) | ||
362 | return func; | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | return NULL; | ||
368 | } | ||
369 | |||
370 | |||
371 | static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) | ||
372 | { | ||
373 | acpi_handle dummy_handle; | ||
374 | |||
375 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
376 | "_STA", &dummy_handle))) | ||
377 | bridge->flags |= BRIDGE_HAS_STA; | ||
378 | |||
379 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
380 | "_EJ0", &dummy_handle))) | ||
381 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
382 | |||
383 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
384 | "_PS0", &dummy_handle))) | ||
385 | bridge->flags |= BRIDGE_HAS_PS0; | ||
386 | |||
387 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
388 | "_PS3", &dummy_handle))) | ||
389 | bridge->flags |= BRIDGE_HAS_PS3; | ||
390 | |||
391 | /* is this ejectable p2p bridge? */ | ||
392 | if (bridge->flags & BRIDGE_HAS_EJ0) { | ||
393 | struct acpiphp_func *func; | ||
394 | |||
395 | dbg("found ejectable p2p bridge\n"); | ||
396 | |||
397 | /* make link between PCI bridge and PCI function */ | ||
398 | func = acpiphp_bridge_handle_to_function(bridge->handle); | ||
399 | if (!func) | ||
400 | return; | ||
401 | bridge->func = func; | ||
402 | func->bridge = bridge; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | |||
334 | /* allocate and initialize host bridge data structure */ | 407 | /* allocate and initialize host bridge data structure */ |
335 | static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) | 408 | static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) |
336 | { | 409 | { |
@@ -364,6 +437,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) | |||
364 | 437 | ||
365 | bridge->type = BRIDGE_TYPE_P2P; | 438 | bridge->type = BRIDGE_TYPE_P2P; |
366 | bridge->handle = handle; | 439 | bridge->handle = handle; |
440 | config_p2p_bridge_flags(bridge); | ||
367 | 441 | ||
368 | bridge->pci_dev = pci_dev_get(pci_dev); | 442 | bridge->pci_dev = pci_dev_get(pci_dev); |
369 | bridge->pci_bus = pci_dev->subordinate; | 443 | bridge->pci_bus = pci_dev->subordinate; |
@@ -423,7 +497,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
423 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 497 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
424 | find_p2p_bridge, dev->subordinate, NULL); | 498 | find_p2p_bridge, dev->subordinate, NULL); |
425 | if (ACPI_FAILURE(status)) | 499 | if (ACPI_FAILURE(status)) |
426 | warn("find_p2p_bridge faied (error code = 0x%x)\n", status); | 500 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
427 | 501 | ||
428 | out: | 502 | out: |
429 | pci_dev_put(dev); | 503 | pci_dev_put(dev); |
@@ -478,7 +552,6 @@ static int add_bridge(acpi_handle handle) | |||
478 | if (detect_ejectable_slots(handle) > 0) { | 552 | if (detect_ejectable_slots(handle) > 0) { |
479 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 553 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
480 | add_host_bridge(handle, pci_bus); | 554 | add_host_bridge(handle, pci_bus); |
481 | return 0; | ||
482 | } | 555 | } |
483 | 556 | ||
484 | /* search P2P bridges under this host bridge */ | 557 | /* search P2P bridges under this host bridge */ |
@@ -486,7 +559,7 @@ static int add_bridge(acpi_handle handle) | |||
486 | find_p2p_bridge, pci_bus, NULL); | 559 | find_p2p_bridge, pci_bus, NULL); |
487 | 560 | ||
488 | if (ACPI_FAILURE(status)) | 561 | if (ACPI_FAILURE(status)) |
489 | warn("find_p2p_bridge faied (error code = 0x%x)\n",status); | 562 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
490 | 563 | ||
491 | return 0; | 564 | return 0; |
492 | } | 565 | } |
@@ -516,6 +589,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
516 | if (ACPI_FAILURE(status)) | 589 | if (ACPI_FAILURE(status)) |
517 | err("failed to remove notify handler\n"); | 590 | err("failed to remove notify handler\n"); |
518 | 591 | ||
592 | if ((bridge->type != BRIDGE_TYPE_HOST) && | ||
593 | ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { | ||
594 | status = acpi_install_notify_handler(bridge->func->handle, | ||
595 | ACPI_SYSTEM_NOTIFY, | ||
596 | handle_hotplug_event_func, | ||
597 | bridge->func); | ||
598 | if (ACPI_FAILURE(status)) | ||
599 | err("failed to install interrupt notify handler\n"); | ||
600 | } | ||
601 | |||
519 | slot = bridge->slots; | 602 | slot = bridge->slots; |
520 | while (slot) { | 603 | while (slot) { |
521 | struct acpiphp_slot *next = slot->next; | 604 | struct acpiphp_slot *next = slot->next; |
@@ -549,6 +632,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
549 | { | 632 | { |
550 | struct acpiphp_bridge *bridge; | 633 | struct acpiphp_bridge *bridge; |
551 | 634 | ||
635 | /* cleanup p2p bridges under this P2P bridge | ||
636 | in a depth-first manner */ | ||
637 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
638 | cleanup_p2p_bridge, NULL, NULL); | ||
639 | |||
552 | if (!(bridge = acpiphp_handle_to_bridge(handle))) | 640 | if (!(bridge = acpiphp_handle_to_bridge(handle))) |
553 | return AE_OK; | 641 | return AE_OK; |
554 | cleanup_bridge(bridge); | 642 | cleanup_bridge(bridge); |
@@ -559,15 +647,14 @@ static void remove_bridge(acpi_handle handle) | |||
559 | { | 647 | { |
560 | struct acpiphp_bridge *bridge; | 648 | struct acpiphp_bridge *bridge; |
561 | 649 | ||
650 | /* cleanup p2p bridges under this host bridge | ||
651 | in a depth-first manner */ | ||
652 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
653 | (u32)1, cleanup_p2p_bridge, NULL, NULL); | ||
654 | |||
562 | bridge = acpiphp_handle_to_bridge(handle); | 655 | bridge = acpiphp_handle_to_bridge(handle); |
563 | if (bridge) { | 656 | if (bridge) |
564 | cleanup_bridge(bridge); | 657 | cleanup_bridge(bridge); |
565 | } else { | ||
566 | /* clean-up p2p bridges under this host bridge */ | ||
567 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
568 | ACPI_UINT32_MAX, cleanup_p2p_bridge, | ||
569 | NULL, NULL); | ||
570 | } | ||
571 | } | 658 | } |
572 | 659 | ||
573 | static struct pci_dev * get_apic_pci_info(acpi_handle handle) | 660 | static struct pci_dev * get_apic_pci_info(acpi_handle handle) |
@@ -634,7 +721,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base) | |||
634 | break; | 721 | break; |
635 | } | 722 | } |
636 | out: | 723 | out: |
637 | acpi_os_free(buffer.pointer); | 724 | kfree(buffer.pointer); |
638 | return result; | 725 | return result; |
639 | } | 726 | } |
640 | 727 | ||
@@ -797,36 +884,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) | |||
797 | } | 884 | } |
798 | 885 | ||
799 | 886 | ||
800 | |||
801 | /** | ||
802 | * get_func - get a pointer to acpiphp_func given a slot, device | ||
803 | * @slot: slot to search | ||
804 | * @dev: pci_dev struct to match. | ||
805 | * | ||
806 | * This function will increase the reference count of pci_dev, | ||
807 | * so callers should call pci_dev_put when complete. | ||
808 | * | ||
809 | */ | ||
810 | static struct acpiphp_func * | ||
811 | get_func(struct acpiphp_slot *slot, struct pci_dev *dev) | ||
812 | { | ||
813 | struct acpiphp_func *func = NULL; | ||
814 | struct pci_bus *bus = slot->bridge->pci_bus; | ||
815 | struct pci_dev *pdev; | ||
816 | |||
817 | list_for_each_entry(func, &slot->funcs, sibling) { | ||
818 | pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, | ||
819 | func->function)); | ||
820 | if (pdev) { | ||
821 | if (pdev == dev) | ||
822 | break; | ||
823 | pci_dev_put(pdev); | ||
824 | } | ||
825 | } | ||
826 | return func; | ||
827 | } | ||
828 | |||
829 | |||
830 | /** | 887 | /** |
831 | * acpiphp_bus_add - add a new bus to acpi subsystem | 888 | * acpiphp_bus_add - add a new bus to acpi subsystem |
832 | * @func: acpiphp_func of the bridge | 889 | * @func: acpiphp_func of the bridge |
@@ -872,6 +929,28 @@ acpiphp_bus_add_out: | |||
872 | } | 929 | } |
873 | 930 | ||
874 | 931 | ||
932 | /** | ||
933 | * acpiphp_bus_trim - trim a bus from acpi subsystem | ||
934 | * @handle: handle to acpi namespace | ||
935 | * | ||
936 | */ | ||
937 | int acpiphp_bus_trim(acpi_handle handle) | ||
938 | { | ||
939 | struct acpi_device *device; | ||
940 | int retval; | ||
941 | |||
942 | retval = acpi_bus_get_device(handle, &device); | ||
943 | if (retval) { | ||
944 | dbg("acpi_device not found\n"); | ||
945 | return retval; | ||
946 | } | ||
947 | |||
948 | retval = acpi_bus_trim(device, 1); | ||
949 | if (retval) | ||
950 | err("cannot remove from acpi list\n"); | ||
951 | |||
952 | return retval; | ||
953 | } | ||
875 | 954 | ||
876 | /** | 955 | /** |
877 | * enable_device - enable, configure a slot | 956 | * enable_device - enable, configure a slot |
@@ -889,6 +968,7 @@ static int enable_device(struct acpiphp_slot *slot) | |||
889 | struct acpiphp_func *func; | 968 | struct acpiphp_func *func; |
890 | int retval = 0; | 969 | int retval = 0; |
891 | int num, max, pass; | 970 | int num, max, pass; |
971 | acpi_status status; | ||
892 | 972 | ||
893 | if (slot->flags & SLOT_ENABLED) | 973 | if (slot->flags & SLOT_ENABLED) |
894 | goto err_exit; | 974 | goto err_exit; |
@@ -918,19 +998,17 @@ static int enable_device(struct acpiphp_slot *slot) | |||
918 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 998 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
919 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { | 999 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
920 | max = pci_scan_bridge(bus, dev, max, pass); | 1000 | max = pci_scan_bridge(bus, dev, max, pass); |
921 | if (pass && dev->subordinate) { | 1001 | if (pass && dev->subordinate) |
922 | pci_bus_size_bridges(dev->subordinate); | 1002 | pci_bus_size_bridges(dev->subordinate); |
923 | func = get_func(slot, dev); | ||
924 | if (func) { | ||
925 | acpiphp_bus_add(func); | ||
926 | /* side effect of get_func */ | ||
927 | pci_dev_put(dev); | ||
928 | } | ||
929 | } | ||
930 | } | 1003 | } |
931 | } | 1004 | } |
932 | } | 1005 | } |
933 | 1006 | ||
1007 | list_for_each (l, &slot->funcs) { | ||
1008 | func = list_entry(l, struct acpiphp_func, sibling); | ||
1009 | acpiphp_bus_add(func); | ||
1010 | } | ||
1011 | |||
934 | pci_bus_assign_resources(bus); | 1012 | pci_bus_assign_resources(bus); |
935 | acpiphp_sanitize_bus(bus); | 1013 | acpiphp_sanitize_bus(bus); |
936 | pci_enable_bridges(bus); | 1014 | pci_enable_bridges(bus); |
@@ -943,6 +1021,17 @@ static int enable_device(struct acpiphp_slot *slot) | |||
943 | func = list_entry(l, struct acpiphp_func, sibling); | 1021 | func = list_entry(l, struct acpiphp_func, sibling); |
944 | func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, | 1022 | func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, |
945 | func->function)); | 1023 | func->function)); |
1024 | if (!func->pci_dev) | ||
1025 | continue; | ||
1026 | |||
1027 | if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && | ||
1028 | func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) | ||
1029 | continue; | ||
1030 | |||
1031 | status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); | ||
1032 | if (ACPI_FAILURE(status)) | ||
1033 | warn("find_p2p_bridge failed (error code = 0x%x)\n", | ||
1034 | status); | ||
946 | } | 1035 | } |
947 | 1036 | ||
948 | slot->flags |= SLOT_ENABLED; | 1037 | slot->flags |= SLOT_ENABLED; |
@@ -967,6 +1056,18 @@ static int disable_device(struct acpiphp_slot *slot) | |||
967 | 1056 | ||
968 | list_for_each (l, &slot->funcs) { | 1057 | list_for_each (l, &slot->funcs) { |
969 | func = list_entry(l, struct acpiphp_func, sibling); | 1058 | func = list_entry(l, struct acpiphp_func, sibling); |
1059 | |||
1060 | if (func->bridge) { | ||
1061 | /* cleanup p2p bridges under this P2P bridge */ | ||
1062 | cleanup_p2p_bridge(func->bridge->handle, | ||
1063 | (u32)1, NULL, NULL); | ||
1064 | func->bridge = NULL; | ||
1065 | } | ||
1066 | |||
1067 | acpiphp_bus_trim(func->handle); | ||
1068 | /* try to remove anyway. | ||
1069 | * acpiphp_bus_add might have been failed */ | ||
1070 | |||
970 | if (!func->pci_dev) | 1071 | if (!func->pci_dev) |
971 | continue; | 1072 | continue; |
972 | 1073 | ||
@@ -1111,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) | |||
1111 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | 1212 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && |
1112 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) | 1213 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) |
1113 | return; | 1214 | return; |
1215 | |||
1114 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, | 1216 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, |
1115 | bridge->hpp.cache_line_size); | 1217 | bridge->hpp.t0->cache_line_size); |
1116 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, | 1218 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, |
1117 | bridge->hpp.latency_timer); | 1219 | bridge->hpp.t0->latency_timer); |
1118 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | 1220 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); |
1119 | if (bridge->hpp.enable_serr) | 1221 | if (bridge->hpp.t0->enable_serr) |
1120 | pci_cmd |= PCI_COMMAND_SERR; | 1222 | pci_cmd |= PCI_COMMAND_SERR; |
1121 | else | 1223 | else |
1122 | pci_cmd &= ~PCI_COMMAND_SERR; | 1224 | pci_cmd &= ~PCI_COMMAND_SERR; |
1123 | if (bridge->hpp.enable_perr) | 1225 | if (bridge->hpp.t0->enable_perr) |
1124 | pci_cmd |= PCI_COMMAND_PARITY; | 1226 | pci_cmd |= PCI_COMMAND_PARITY; |
1125 | else | 1227 | else |
1126 | pci_cmd &= ~PCI_COMMAND_PARITY; | 1228 | pci_cmd &= ~PCI_COMMAND_PARITY; |
@@ -1129,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) | |||
1129 | /* Program bridge control value and child devices */ | 1231 | /* Program bridge control value and child devices */ |
1130 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | 1232 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
1131 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, | 1233 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, |
1132 | bridge->hpp.latency_timer); | 1234 | bridge->hpp.t0->latency_timer); |
1133 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); | 1235 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); |
1134 | if (bridge->hpp.enable_serr) | 1236 | if (bridge->hpp.t0->enable_serr) |
1135 | pci_bctl |= PCI_BRIDGE_CTL_SERR; | 1237 | pci_bctl |= PCI_BRIDGE_CTL_SERR; |
1136 | else | 1238 | else |
1137 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; | 1239 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; |
1138 | if (bridge->hpp.enable_perr) | 1240 | if (bridge->hpp.t0->enable_perr) |
1139 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; | 1241 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; |
1140 | else | 1242 | else |
1141 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; | 1243 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; |
@@ -1155,6 +1257,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) | |||
1155 | 1257 | ||
1156 | memset(&bridge, 0, sizeof(bridge)); | 1258 | memset(&bridge, 0, sizeof(bridge)); |
1157 | bridge.handle = handle; | 1259 | bridge.handle = handle; |
1260 | bridge.pci_bus = bus; | ||
1158 | bridge.pci_dev = bus->self; | 1261 | bridge.pci_dev = bus->self; |
1159 | decode_hpp(&bridge); | 1262 | decode_hpp(&bridge); |
1160 | list_for_each_entry(dev, &bus->devices, bus_list) | 1263 | list_for_each_entry(dev, &bus->devices, bus_list) |
@@ -1297,6 +1400,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1297 | case ACPI_NOTIFY_EJECT_REQUEST: | 1400 | case ACPI_NOTIFY_EJECT_REQUEST: |
1298 | /* request device eject */ | 1401 | /* request device eject */ |
1299 | dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); | 1402 | dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); |
1403 | if ((bridge->type != BRIDGE_TYPE_HOST) && | ||
1404 | (bridge->flags & BRIDGE_HAS_EJ0)) { | ||
1405 | struct acpiphp_slot *slot; | ||
1406 | slot = bridge->func->slot; | ||
1407 | if (!acpiphp_disable_slot(slot)) | ||
1408 | acpiphp_eject_slot(slot); | ||
1409 | } | ||
1300 | break; | 1410 | break; |
1301 | 1411 | ||
1302 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | 1412 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: |
@@ -1490,9 +1600,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) | |||
1490 | if (retval) | 1600 | if (retval) |
1491 | goto err_exit; | 1601 | goto err_exit; |
1492 | 1602 | ||
1493 | if (get_slot_status(slot) == ACPI_STA_ALL) | 1603 | if (get_slot_status(slot) == ACPI_STA_ALL) { |
1494 | /* configure all functions */ | 1604 | /* configure all functions */ |
1495 | retval = enable_device(slot); | 1605 | retval = enable_device(slot); |
1606 | if (retval) | ||
1607 | power_off_slot(slot); | ||
1608 | } else { | ||
1609 | dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__); | ||
1610 | power_off_slot(slot); | ||
1611 | } | ||
1496 | 1612 | ||
1497 | err_exit: | 1613 | err_exit: |
1498 | mutex_unlock(&slot->crit_sect); | 1614 | mutex_unlock(&slot->crit_sect); |