[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 acpi_status status; 593 struct acpiphp_func *func; 594 struct list_head *l; 595 - struct acpi_object_list arg_list; 596 - union acpi_object arg; 597 598 int retval = 0; 599 ··· 606 status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 607 if (ACPI_FAILURE(status)) { 608 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 retval = -1; 631 goto err_exit; 632 } else ··· 759 } 760 761 /** 762 * acpiphp_check_bridge - re-enumerate devices 763 * 764 * Iterate over all slots under this bridge and make sure that if a ··· 814 if (retval) { 815 err("Error occurred in disabling\n"); 816 goto err_exit; 817 } 818 disabled++; 819 } else { ··· 1053 } 1054 } 1055 1056 - 1057 /** 1058 * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 1059 * ··· 1095 case ACPI_NOTIFY_EJECT_REQUEST: 1096 /* request device eject */ 1097 dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 1098 - acpiphp_disable_slot(func->slot); 1099 break; 1100 1101 default: ··· 1280 return retval; 1281 } 1282 1283 - 1284 /** 1285 * acpiphp_disable_slot - power off slot 1286 */ ··· 1311 */ 1312 u8 acpiphp_get_power_status(struct acpiphp_slot *slot) 1313 { 1314 - unsigned int sta; 1315 - 1316 - sta = get_slot_status(slot); 1317 - 1318 - return (sta & ACPI_STA_ENABLED) ? 1 : 0; 1319 } 1320 1321
··· 592 acpi_status status; 593 struct acpiphp_func *func; 594 struct list_head *l; 595 596 int retval = 0; 597 ··· 608 status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 609 if (ACPI_FAILURE(status)) { 610 warn("%s: _PS3 failed\n", __FUNCTION__); 611 retval = -1; 612 goto err_exit; 613 } else ··· 782 } 783 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 + /** 818 * acpiphp_check_bridge - re-enumerate devices 819 * 820 * Iterate over all slots under this bridge and make sure that if a ··· 804 if (retval) { 805 err("Error occurred in disabling\n"); 806 goto err_exit; 807 + } else { 808 + acpiphp_eject_slot(slot); 809 } 810 disabled++; 811 } else { ··· 1041 } 1042 } 1043 1044 /** 1045 * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 1046 * ··· 1084 case ACPI_NOTIFY_EJECT_REQUEST: 1085 /* request device eject */ 1086 dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 1087 + if (!(acpiphp_disable_slot(func->slot))) 1088 + acpiphp_eject_slot(func->slot); 1089 break; 1090 1091 default: ··· 1268 return retval; 1269 } 1270 1271 /** 1272 * acpiphp_disable_slot - power off slot 1273 */ ··· 1300 */ 1301 u8 acpiphp_get_power_status(struct acpiphp_slot *slot) 1302 { 1303 + return (slot->flags & SLOT_POWEREDON); 1304 } 1305 1306