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

ACPI / property: Hierarchical properties support update

The definition document of the Hierarchical Properties Extension UUID
for _DSD has been changed recently to allow local references to be
used as sub-node link targets (previously, it only allowed strings to
be used for that purpose).

Update the code in drivers/acpi/property.c to reflect that change.

Link: http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+96 -43
+4 -4
drivers/acpi/device_sysfs.c
··· 52 52 53 53 static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf) 54 54 { 55 - return acpi_object_path(dn->handle, buf); 55 + return dn->handle ? acpi_object_path(dn->handle, buf) : 0; 56 56 } 57 57 58 58 DATA_NODE_ATTR(path); ··· 105 105 init_completion(&dn->kobj_done); 106 106 ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype, 107 107 kobj, "%s", dn->name); 108 - if (ret) 109 - acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); 110 - else 108 + if (!ret) 111 109 acpi_expose_nondev_subnodes(&dn->kobj, &dn->data); 110 + else if (dn->handle) 111 + acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); 112 112 } 113 113 } 114 114
+92 -39
drivers/acpi/property.c
··· 41 41 static bool acpi_extract_properties(const union acpi_object *desc, 42 42 struct acpi_device_data *data); 43 43 44 - static bool acpi_nondev_subnode_ok(acpi_handle scope, 45 - const union acpi_object *link, 46 - struct list_head *list) 44 + static bool acpi_nondev_subnode_extract(const union acpi_object *desc, 45 + acpi_handle handle, 46 + const union acpi_object *link, 47 + struct list_head *list) 47 48 { 48 - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 49 49 struct acpi_data_node *dn; 50 - acpi_handle handle; 51 - acpi_status status; 50 + bool result; 52 51 53 52 dn = kzalloc(sizeof(*dn), GFP_KERNEL); 54 53 if (!dn) ··· 57 58 dn->fwnode.type = FWNODE_ACPI_DATA; 58 59 INIT_LIST_HEAD(&dn->data.subnodes); 59 60 60 - status = acpi_get_handle(scope, link->package.elements[1].string.pointer, 61 - &handle); 62 - if (ACPI_FAILURE(status)) 63 - goto fail; 61 + result = acpi_extract_properties(desc, &dn->data); 64 62 65 - status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, 66 - ACPI_TYPE_PACKAGE); 67 - if (ACPI_FAILURE(status)) 68 - goto fail; 63 + if (handle) { 64 + acpi_handle scope; 65 + acpi_status status; 69 66 70 - if (acpi_extract_properties(buf.pointer, &dn->data)) 67 + /* 68 + * The scope for the subnode object lookup is the one of the 69 + * namespace node (device) containing the object that has 70 + * returned the package. That is, it's the scope of that 71 + * object's parent. 72 + */ 73 + status = acpi_get_parent(handle, &scope); 74 + if (ACPI_SUCCESS(status) 75 + && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data)) 76 + result = true; 77 + } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) { 78 + result = true; 79 + } 80 + 81 + if (result) { 71 82 dn->handle = handle; 72 - 73 - /* 74 - * The scope for the subnode object lookup is the one of the namespace 75 - * node (device) containing the object that has returned the package. 76 - * That is, it's the scope of that object's parent. 77 - */ 78 - status = acpi_get_parent(handle, &scope); 79 - if (ACPI_SUCCESS(status) 80 - && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data)) 81 - dn->handle = handle; 82 - 83 - if (dn->handle) { 84 - dn->data.pointer = buf.pointer; 83 + dn->data.pointer = desc; 85 84 list_add_tail(&dn->sibling, list); 86 85 return true; 87 86 } 88 87 89 - acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); 90 - 91 - fail: 92 - ACPI_FREE(buf.pointer); 93 88 kfree(dn); 89 + acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); 94 90 return false; 91 + } 92 + 93 + static bool acpi_nondev_subnode_data_ok(acpi_handle handle, 94 + const union acpi_object *link, 95 + struct list_head *list) 96 + { 97 + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 98 + acpi_status status; 99 + 100 + status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, 101 + ACPI_TYPE_PACKAGE); 102 + if (ACPI_FAILURE(status)) 103 + return false; 104 + 105 + if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list)) 106 + return true; 107 + 108 + ACPI_FREE(buf.pointer); 109 + return false; 110 + } 111 + 112 + static bool acpi_nondev_subnode_ok(acpi_handle scope, 113 + const union acpi_object *link, 114 + struct list_head *list) 115 + { 116 + acpi_handle handle; 117 + acpi_status status; 118 + 119 + if (!scope) 120 + return false; 121 + 122 + status = acpi_get_handle(scope, link->package.elements[1].string.pointer, 123 + &handle); 124 + if (ACPI_FAILURE(status)) 125 + return false; 126 + 127 + return acpi_nondev_subnode_data_ok(handle, link, list); 95 128 } 96 129 97 130 static int acpi_add_nondev_subnodes(acpi_handle scope, ··· 134 103 int i; 135 104 136 105 for (i = 0; i < links->package.count; i++) { 137 - const union acpi_object *link; 106 + const union acpi_object *link, *desc; 107 + acpi_handle handle; 108 + bool result; 138 109 139 110 link = &links->package.elements[i]; 140 - /* Only two elements allowed, both must be strings. */ 141 - if (link->package.count == 2 142 - && link->package.elements[0].type == ACPI_TYPE_STRING 143 - && link->package.elements[1].type == ACPI_TYPE_STRING 144 - && acpi_nondev_subnode_ok(scope, link, list)) 145 - ret = true; 111 + /* Only two elements allowed. */ 112 + if (link->package.count != 2) 113 + continue; 114 + 115 + /* The first one must be a string. */ 116 + if (link->package.elements[0].type != ACPI_TYPE_STRING) 117 + continue; 118 + 119 + /* The second one may be a string, a reference or a package. */ 120 + switch (link->package.elements[1].type) { 121 + case ACPI_TYPE_STRING: 122 + result = acpi_nondev_subnode_ok(scope, link, list); 123 + break; 124 + case ACPI_TYPE_LOCAL_REFERENCE: 125 + handle = link->package.elements[1].reference.handle; 126 + result = acpi_nondev_subnode_data_ok(handle, link, list); 127 + break; 128 + case ACPI_TYPE_PACKAGE: 129 + desc = &link->package.elements[1]; 130 + result = acpi_nondev_subnode_extract(desc, NULL, link, list); 131 + break; 132 + default: 133 + result = false; 134 + break; 135 + } 136 + ret = ret || result; 146 137 } 147 138 148 139 return ret;