]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'device-properties'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 12 Dec 2016 19:48:18 +0000 (20:48 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 12 Dec 2016 19:48:18 +0000 (20:48 +0100)
* device-properties:
  ACPI / property: Document usage rules for _DSD properties
  ACPI / property: Hierarchical properties support update

Documentation/acpi/DSD-properties-rules.txt [new file with mode: 0644]
Documentation/acpi/enumeration.txt
drivers/acpi/device_sysfs.c
drivers/acpi/property.c

diff --git a/Documentation/acpi/DSD-properties-rules.txt b/Documentation/acpi/DSD-properties-rules.txt
new file mode 100644 (file)
index 0000000..3e4862b
--- /dev/null
@@ -0,0 +1,97 @@
+_DSD Device Properties Usage Rules
+----------------------------------
+
+Properties, Property Sets and Property Subsets
+----------------------------------------------
+
+The _DSD (Device Specific Data) configuration object, introduced in ACPI 5.1,
+allows any type of device configuration data to be provided via the ACPI
+namespace.  In principle, the format of the data may be arbitrary, but it has to
+be identified by a UUID which must be recognized by the driver processing the
+_DSD output.  However, there are generic UUIDs defined for _DSD recognized by
+the ACPI subsystem in the Linux kernel which automatically processes the data
+packages associated with them and makes those data available to device drivers
+as "device properties".
+
+A device property is a data item consisting of a string key and a value (of a
+specific type) associated with it.
+
+In the ACPI _DSD context it is an element of the sub-package following the
+generic Device Properties UUID in the _DSD return package as specified in the
+Device Properties UUID definition document [1].
+
+It also may be regarded as the definition of a key and the associated data type
+that can be returned by _DSD in the Device Properties UUID sub-package for a
+given device.
+
+A property set is a collection of properties applicable to a hardware entity
+like a device.  In the ACPI _DSD context it is the set of all properties that
+can be returned in the Device Properties UUID sub-package for the device in
+question.
+
+Property subsets are nested collections of properties.  Each of them is
+associated with an additional key (name) allowing the subset to be referred
+to as a whole (and to be treated as a separate entity).  The canonical
+representation of property subsets is via the mechanism specified in the
+Hierarchical Properties Extension UUID definition document [2].
+
+Property sets may be hierarchical.  That is, a property set may contain
+multiple property subsets that each may contain property subsets of its
+own and so on.
+
+General Validity Rule for Property Sets
+---------------------------------------
+
+Valid property sets must follow the guidance given by the Device Properties UUID
+definition document [1].
+
+_DSD properties are intended to be used in addition to, and not instead of, the
+existing mechanisms defined by the ACPI specification.  Therefore, as a rule,
+they should only be used if the ACPI specification does not make direct
+provisions for handling the underlying use case.  It generally is invalid to
+return property sets which do not follow that rule from _DSD in data packages
+associated with the Device Properties UUID.
+
+Additional Considerations
+-------------------------
+
+There are cases in which, even if the general rule given above is followed in
+principle, the property set may still not be regarded as a valid one.
+
+For example, that applies to device properties which may cause kernel code
+(either a device driver or a library/subsystem) to access hardware in a way
+possibly leading to a conflict with AML methods in the ACPI namespace.  In
+particular, that may happen if the kernel code uses device properties to
+manipulate hardware normally controlled by ACPI methods related to power
+management, like _PSx and _DSW (for device objects) or _ON and _OFF (for power
+resource objects), or by ACPI device disabling/enabling methods, like _DIS and
+_SRS.
+
+In all cases in which kernel code may do something that will confuse AML as a
+result of using device properties, the device properties in question are not
+suitable for the ACPI environment and consequently they cannot belong to a valid
+property set.
+
+Property Sets and Device Tree Bindings
+--------------------------------------
+
+It often is useful to make _DSD return property sets that follow Device Tree
+bindings.
+
+In those cases, however, the above validity considerations must be taken into
+account in the first place and returning invalid property sets from _DSD must be
+avoided.  For this reason, it may not be possible to make _DSD return a property
+set following the given DT binding literally and completely.  Still, for the
+sake of code re-use, it may make sense to provide as much of the configuration
+data as possible in the form of device properties and complement that with an
+ACPI-specific mechanism suitable for the use case at hand.
+
+In any case, property sets following DT bindings literally should not be
+expected to automatically work in the ACPI environment regardless of their
+contents.
+
+References
+----------
+
+[1] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+[2] http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
index a91ec5af52df28cf3ff3c2ae03b163272caae0e6..209a5eba6b8711e34000b102f68814e76bfcded8 100644 (file)
@@ -415,3 +415,12 @@ the "compatible" property in the _DSD or a _CID as long as one of their
 ancestors provides a _DSD with a valid "compatible" property.  Such device
 objects are then simply regarded as additional "blocks" providing hierarchical
 configuration information to the driver of the composite ancestor device.
+
+However, PRP0001 can only be returned from either _HID or _CID of a device
+object if all of the properties returned by the _DSD associated with it (either
+the _DSD of the device object itself or the _DSD of its ancestor in the
+"composite device" case described above) can be used in the ACPI environment.
+Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible"
+property returned by it is meaningless.
+
+Refer to DSD-properties-rules.txt for more information.
index 7b2c48fde4e2b19f7134c1900931ff0695469ad9..24418932612eeabc62d72185df50980ed55ee5bd 100644 (file)
@@ -52,7 +52,7 @@ struct acpi_data_node_attr {
 
 static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
 {
-       return acpi_object_path(dn->handle, buf);
+       return dn->handle ? acpi_object_path(dn->handle, buf) : 0;
 }
 
 DATA_NODE_ATTR(path);
@@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
                init_completion(&dn->kobj_done);
                ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
                                           kobj, "%s", dn->name);
-               if (ret)
-                       acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
-               else
+               if (!ret)
                        acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
+               else if (dn->handle)
+                       acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
        }
 }
 
index 03f5ec11ab3197de66ced4e7f09d39dbab6b8232..3afddcd834efdb407f8b5dec1bebf42ce704c0c5 100644 (file)
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
 static bool acpi_extract_properties(const union acpi_object *desc,
                                    struct acpi_device_data *data);
 
-static bool acpi_nondev_subnode_ok(acpi_handle scope,
-                                  const union acpi_object *link,
-                                  struct list_head *list)
+static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
+                                       acpi_handle handle,
+                                       const union acpi_object *link,
+                                       struct list_head *list)
 {
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
        struct acpi_data_node *dn;
-       acpi_handle handle;
-       acpi_status status;
+       bool result;
 
        dn = kzalloc(sizeof(*dn), GFP_KERNEL);
        if (!dn)
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
        dn->fwnode.type = FWNODE_ACPI_DATA;
        INIT_LIST_HEAD(&dn->data.subnodes);
 
-       status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
-                                &handle);
-       if (ACPI_FAILURE(status))
-               goto fail;
+       result = acpi_extract_properties(desc, &dn->data);
 
-       status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
-                                           ACPI_TYPE_PACKAGE);
-       if (ACPI_FAILURE(status))
-               goto fail;
+       if (handle) {
+               acpi_handle scope;
+               acpi_status status;
 
-       if (acpi_extract_properties(buf.pointer, &dn->data))
-               dn->handle = handle;
+               /*
+                * The scope for the subnode object lookup is the one of the
+                * namespace node (device) containing the object that has
+                * returned the package.  That is, it's the scope of that
+                * object's parent.
+                */
+               status = acpi_get_parent(handle, &scope);
+               if (ACPI_SUCCESS(status)
+                   && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
+                       result = true;
+       } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
+               result = true;
+       }
 
-       /*
-        * The scope for the subnode object lookup is the one of the namespace
-        * node (device) containing the object that has returned the package.
-        * That is, it's the scope of that object's parent.
-        */
-       status = acpi_get_parent(handle, &scope);
-       if (ACPI_SUCCESS(status)
-           && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
+       if (result) {
                dn->handle = handle;
-
-       if (dn->handle) {
-               dn->data.pointer = buf.pointer;
+               dn->data.pointer = desc;
                list_add_tail(&dn->sibling, list);
                return true;
        }
 
+       kfree(dn);
        acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
+       return false;
+}
+
+static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
+                                       const union acpi_object *link,
+                                       struct list_head *list)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       acpi_status status;
+
+       status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
+                                           ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
+               return false;
+
+       if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
+               return true;
 
- fail:
        ACPI_FREE(buf.pointer);
-       kfree(dn);
        return false;
 }
 
+static bool acpi_nondev_subnode_ok(acpi_handle scope,
+                                  const union acpi_object *link,
+                                  struct list_head *list)
+{
+       acpi_handle handle;
+       acpi_status status;
+
+       if (!scope)
+               return false;
+
+       status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
+                                &handle);
+       if (ACPI_FAILURE(status))
+               return false;
+
+       return acpi_nondev_subnode_data_ok(handle, link, list);
+}
+
 static int acpi_add_nondev_subnodes(acpi_handle scope,
                                    const union acpi_object *links,
                                    struct list_head *list)
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
        int i;
 
        for (i = 0; i < links->package.count; i++) {
-               const union acpi_object *link;
+               const union acpi_object *link, *desc;
+               acpi_handle handle;
+               bool result;
 
                link = &links->package.elements[i];
-               /* Only two elements allowed, both must be strings. */
-               if (link->package.count == 2
-                   && link->package.elements[0].type == ACPI_TYPE_STRING
-                   && link->package.elements[1].type == ACPI_TYPE_STRING
-                   && acpi_nondev_subnode_ok(scope, link, list))
-                       ret = true;
+               /* Only two elements allowed. */
+               if (link->package.count != 2)
+                       continue;
+
+               /* The first one must be a string. */
+               if (link->package.elements[0].type != ACPI_TYPE_STRING)
+                       continue;
+
+               /* The second one may be a string, a reference or a package. */
+               switch (link->package.elements[1].type) {
+               case ACPI_TYPE_STRING:
+                       result = acpi_nondev_subnode_ok(scope, link, list);
+                       break;
+               case ACPI_TYPE_LOCAL_REFERENCE:
+                       handle = link->package.elements[1].reference.handle;
+                       result = acpi_nondev_subnode_data_ok(handle, link, list);
+                       break;
+               case ACPI_TYPE_PACKAGE:
+                       desc = &link->package.elements[1];
+                       result = acpi_nondev_subnode_extract(desc, NULL, link, list);
+                       break;
+               default:
+                       result = false;
+                       break;
+               }
+               ret = ret || result;
        }
 
        return ret;