Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPICA: Also handle "orphan" _REG methods for GPIO OpRegions

ACPICA commit b9dc31e2fc67cf196fab5253a9a673bee68b2ef5

Before this commit acpi_ev_execute_reg_methods() had special handling
to handle "orphan" (no matching op_region declared) _REG methods for EC
nodes.

On Intel Cherry Trail devices there are 2 possible ACPI op_regions for
accessing GPIOs. The standard general_purpose_io op_region and the Cherry
Trail specific user_defined 0x9X op_regions.

Having 2 different types of op_regions leads to potential issues with
checks for op_region availability, or in other words checks if _REG has
been called for the op_region which the ACPI code wants to use.

Except for the "orphan" EC handling, ACPICA core does not call _REG on
an ACPI node which does not define an op_region matching the type being
registered; and the reference design DSDT, from which most Cherry Trail
DSDTs are derived, does not define general_purpose_io, nor user_defined(0x93)
op_regions for the GPO2 (UID 3) device, because no pins were assigned ACPI
controlled functions in the reference design.

Together this leads to the perfect storm, at least on the Cherry Trail
based Medion Akayo E1239T. This design does use a GPO2 pin from its ACPI
code and has added the Cherry Trail specific user_defined(0x93) opregion
to its GPO2 ACPI node to access this pin.

But it uses a has _REG been called availability check for the standard
general_purpose_io op_region. This clearly is a bug in the DSDT, but this
does work under Windows. This issue leads to the intel_vbtn driver
reporting the device always being in tablet-mode at boot, even if it
is in laptop mode. Which in turn causes userspace to ignore touchpad
events. So iow this issues causes the touchpad to not work at boot.

This commit fixes this by extending the "orphan" _REG method handling
to also apply to GPIO address-space handlers.

Note it seems that Windows always calls "orphan" _REG methods so me
may want to consider dropping the space-id check and always do
"orphan" _REG method handling.

Link: https://github.com/acpica/acpica/commit/b9dc31e2
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Erik Kaneda <erik.kaneda@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Hans de Goede and committed by
Rafael J. Wysocki
0306f035 f2f51e7a

+27 -27
+27 -27
drivers/acpi/acpica/evregion.c
··· 21 21 /* Local prototypes */ 22 22 23 23 static void 24 - acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node); 24 + acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node, 25 + acpi_adr_space_type space_id); 25 26 26 27 static acpi_status 27 28 acpi_ev_reg_run(acpi_handle obj_handle, ··· 685 684 ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL, 686 685 &info, NULL); 687 686 688 - /* Special case for EC: handle "orphan" _REG methods with no region */ 689 - 690 - if (space_id == ACPI_ADR_SPACE_EC) { 691 - acpi_ev_orphan_ec_reg_method(node); 687 + /* 688 + * Special case for EC and GPIO: handle "orphan" _REG methods with 689 + * no region. 690 + */ 691 + if (space_id == ACPI_ADR_SPACE_EC || space_id == ACPI_ADR_SPACE_GPIO) { 692 + acpi_ev_execute_orphan_reg_method(node, space_id); 692 693 } 693 694 694 695 ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, ··· 763 760 764 761 /******************************************************************************* 765 762 * 766 - * FUNCTION: acpi_ev_orphan_ec_reg_method 763 + * FUNCTION: acpi_ev_execute_orphan_reg_method 767 764 * 768 - * PARAMETERS: ec_device_node - Namespace node for an EC device 765 + * PARAMETERS: device_node - Namespace node for an ACPI device 766 + * space_id - The address space ID 769 767 * 770 768 * RETURN: None 771 769 * 772 - * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC 770 + * DESCRIPTION: Execute an "orphan" _REG method that appears under an ACPI 773 771 * device. This is a _REG method that has no corresponding region 774 - * within the EC device scope. The orphan _REG method appears to 775 - * have been enabled by the description of the ECDT in the ACPI 776 - * specification: "The availability of the region space can be 777 - * detected by providing a _REG method object underneath the 778 - * Embedded Controller device." 779 - * 780 - * To quickly access the EC device, we use the ec_device_node used 781 - * during EC handler installation. Otherwise, we would need to 782 - * perform a time consuming namespace walk, executing _HID 783 - * methods to find the EC device. 772 + * within the device's scope. ACPI tables depending on these 773 + * "orphan" _REG methods have been seen for both EC and GPIO 774 + * Operation Regions. Presumably the Windows ACPI implementation 775 + * always calls the _REG method independent of the presence of 776 + * an actual Operation Region with the correct address space ID. 784 777 * 785 778 * MUTEX: Assumes the namespace is locked 786 779 * 787 780 ******************************************************************************/ 788 781 789 782 static void 790 - acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node) 783 + acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node, 784 + acpi_adr_space_type space_id) 791 785 { 792 786 acpi_handle reg_method; 793 787 struct acpi_namespace_node *next_node; ··· 792 792 struct acpi_object_list args; 793 793 union acpi_object objects[2]; 794 794 795 - ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); 795 + ACPI_FUNCTION_TRACE(ev_execute_orphan_reg_method); 796 796 797 - if (!ec_device_node) { 797 + if (!device_node) { 798 798 return_VOID; 799 799 } 800 800 ··· 804 804 805 805 /* Get a handle to a _REG method immediately under the EC device */ 806 806 807 - status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method); 807 + status = acpi_get_handle(device_node, METHOD_NAME__REG, &reg_method); 808 808 if (ACPI_FAILURE(status)) { 809 809 goto exit; /* There is no _REG method present */ 810 810 } ··· 816 816 * with other space IDs to be present; but the code below will then 817 817 * execute the _REG method with the embedded_control space_ID argument. 818 818 */ 819 - next_node = acpi_ns_get_next_node(ec_device_node, NULL); 819 + next_node = acpi_ns_get_next_node(device_node, NULL); 820 820 while (next_node) { 821 821 if ((next_node->type == ACPI_TYPE_REGION) && 822 822 (next_node->object) && 823 - (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { 823 + (next_node->object->region.space_id == space_id)) { 824 824 goto exit; /* Do not execute the _REG */ 825 825 } 826 826 827 - next_node = acpi_ns_get_next_node(ec_device_node, next_node); 827 + next_node = acpi_ns_get_next_node(device_node, next_node); 828 828 } 829 829 830 - /* Evaluate the _REG(embedded_control,Connect) method */ 830 + /* Evaluate the _REG(space_id,Connect) method */ 831 831 832 832 args.count = 2; 833 833 args.pointer = objects; 834 834 objects[0].type = ACPI_TYPE_INTEGER; 835 - objects[0].integer.value = ACPI_ADR_SPACE_EC; 835 + objects[0].integer.value = space_id; 836 836 objects[1].type = ACPI_TYPE_INTEGER; 837 837 objects[1].integer.value = ACPI_REG_CONNECT; 838 838