[PATCH] acpi hotplug: decouple slot power state changes from physical hotplug

Current acpiphp code does not distinguish between the physical presence and
power state of a device/slot. That is, if a device has to be disabled, it
also tries to physically ejects the device. This patch decouples power state
from physical presence. You can now echo to the corresponding sysfs power
control file to repeatedly enable and disable a device without having to
physically re-insert it.

Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by Rajesh Shah and committed by Greg Kroah-Hartman 8d50e332 8e7561cf

+38 -31
+38 -31
drivers/pci/hotplug/acpiphp_glue.c
··· 592 592 acpi_status status; 593 593 struct acpiphp_func *func; 594 594 struct list_head *l; 595 - struct acpi_object_list arg_list; 596 - union acpi_object arg; 597 595 598 596 int retval = 0; 599 597 ··· 606 608 status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 607 609 if (ACPI_FAILURE(status)) { 608 610 warn("%s: _PS3 failed\n", __FUNCTION__); 609 - retval = -1; 610 - goto err_exit; 611 - } else 612 - break; 613 - } 614 - } 615 - 616 - list_for_each (l, &slot->funcs) { 617 - func = list_entry(l, struct acpiphp_func, sibling); 618 - 619 - /* We don't want to call _EJ0 on non-existing functions. */ 620 - if (func->flags & FUNC_HAS_EJ0) { 621 - /* _EJ0 method take one argument */ 622 - arg_list.count = 1; 623 - arg_list.pointer = &arg; 624 - arg.type = ACPI_TYPE_INTEGER; 625 - arg.integer.value = 1; 626 - 627 - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); 628 - if (ACPI_FAILURE(status)) { 629 - warn("%s: _EJ0 failed\n", __FUNCTION__); 630 611 retval = -1; 631 612 goto err_exit; 632 613 } else ··· 759 782 } 760 783 761 784 /** 785 + * acpiphp_eject_slot - physically eject the slot 786 + */ 787 + static int acpiphp_eject_slot(struct acpiphp_slot *slot) 788 + { 789 + acpi_status status; 790 + struct acpiphp_func *func; 791 + struct list_head *l; 792 + struct acpi_object_list arg_list; 793 + union acpi_object arg; 794 + 795 + list_for_each (l, &slot->funcs) { 796 + func = list_entry(l, struct acpiphp_func, sibling); 797 + 798 + /* We don't want to call _EJ0 on non-existing functions. */ 799 + if ((func->flags & FUNC_HAS_EJ0)) { 800 + /* _EJ0 method take one argument */ 801 + arg_list.count = 1; 802 + arg_list.pointer = &arg; 803 + arg.type = ACPI_TYPE_INTEGER; 804 + arg.integer.value = 1; 805 + 806 + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); 807 + if (ACPI_FAILURE(status)) { 808 + warn("%s: _EJ0 failed\n", __FUNCTION__); 809 + return -1; 810 + } else 811 + break; 812 + } 813 + } 814 + return 0; 815 + } 816 + 817 + /** 762 818 * acpiphp_check_bridge - re-enumerate devices 763 819 * 764 820 * Iterate over all slots under this bridge and make sure that if a ··· 814 804 if (retval) { 815 805 err("Error occurred in disabling\n"); 816 806 goto err_exit; 807 + } else { 808 + acpiphp_eject_slot(slot); 817 809 } 818 810 disabled++; 819 811 } else { ··· 1053 1041 } 1054 1042 } 1055 1043 1056 - 1057 1044 /** 1058 1045 * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 1059 1046 * ··· 1095 1084 case ACPI_NOTIFY_EJECT_REQUEST: 1096 1085 /* request device eject */ 1097 1086 dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 1098 - acpiphp_disable_slot(func->slot); 1087 + if (!(acpiphp_disable_slot(func->slot))) 1088 + acpiphp_eject_slot(func->slot); 1099 1089 break; 1100 1090 1101 1091 default: ··· 1280 1268 return retval; 1281 1269 } 1282 1270 1283 - 1284 1271 /** 1285 1272 * acpiphp_disable_slot - power off slot 1286 1273 */ ··· 1311 1300 */ 1312 1301 u8 acpiphp_get_power_status(struct acpiphp_slot *slot) 1313 1302 { 1314 - unsigned int sta; 1315 - 1316 - sta = get_slot_status(slot); 1317 - 1318 - return (sta & ACPI_STA_ENABLED) ? 1 : 0; 1303 + return (slot->flags & SLOT_POWEREDON); 1319 1304 } 1320 1305 1321 1306