]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
ACPI / property: Allow multiple property compatible _DSD entries
authorMika Westerberg <mika.westerberg@linux.intel.com>
Thu, 27 Sep 2018 21:57:05 +0000 (16:57 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 2 Oct 2018 21:04:40 +0000 (16:04 -0500)
It is possible to have _DSD entries where the data is compatible with
device properties format but are using different GUID for various reasons.
In addition to that there can be many such _DSD entries for a single device
such as for PCIe root port used to host a Thunderbolt hierarchy:

    Scope (\_SB.PCI0.RP21)
    {
        Name (_DSD, Package () {
            ToUUID ("6211e2c0-58a3-4af3-90e1-927a4e0c55a4"),
            Package () {
                Package () {"HotPlugSupportInD3", 1}
            },

            ToUUID ("efcc06cc-73ac-4bc3-bff0-76143807c389"),
            Package () {
                Package () {"ExternalFacingPort", 1},
                Package () {"UID", 0 }
            }
        })
    }

More information about these new _DSD entries can be found in:

  https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/dsd-for-pcie-root-ports

To make these available for drivers via unified device property APIs,
modify ACPI property core so that it supports multiple _DSD entries
organized in a linked list. We also store GUID of each _DSD entry in struct
acpi_device_properties in case there is need to differentiate between
entries. The supported GUIDs are then listed in prp_guids array.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
drivers/acpi/property.c
drivers/acpi/x86/apple.c
drivers/gpio/gpiolib-acpi.c
include/acpi/acpi_bus.h
include/linux/acpi.h

index 693cf05b0cc44ffba54427fa12abf3017830e0e1..90ba9371bae65d018664a105c767c7a2a40341ea 100644 (file)
@@ -24,11 +24,12 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data,
                                        acpi_object_type type,
                                        const union acpi_object **obj);
 
-/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
-static const guid_t prp_guid =
+static const guid_t prp_guids[] = {
+       /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
        GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
-                 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01);
-/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
+                 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01),
+};
+
 static const guid_t ads_guid =
        GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
                  0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
@@ -56,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
        dn->name = link->package.elements[0].string.pointer;
        dn->fwnode.ops = &acpi_data_fwnode_ops;
        dn->parent = parent;
+       INIT_LIST_HEAD(&dn->data.properties);
        INIT_LIST_HEAD(&dn->data.subnodes);
 
        result = acpi_extract_properties(desc, &dn->data);
@@ -288,6 +290,35 @@ static void acpi_init_of_compatible(struct acpi_device *adev)
        adev->flags.of_compatible_ok = 1;
 }
 
+static bool acpi_is_property_guid(const guid_t *guid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
+               if (guid_equal(guid, &prp_guids[i]))
+                       return true;
+       }
+
+       return false;
+}
+
+struct acpi_device_properties *
+acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
+                   const union acpi_object *properties)
+{
+       struct acpi_device_properties *props;
+
+       props = kzalloc(sizeof(*props), GFP_KERNEL);
+       if (props) {
+               INIT_LIST_HEAD(&props->list);
+               props->guid = guid;
+               props->properties = properties;
+               list_add_tail(&props->list, &data->properties);
+       }
+
+       return props;
+}
+
 static bool acpi_extract_properties(const union acpi_object *desc,
                                    struct acpi_device_data *data)
 {
@@ -312,7 +343,7 @@ static bool acpi_extract_properties(const union acpi_object *desc,
                    properties->type != ACPI_TYPE_PACKAGE)
                        break;
 
-               if (!guid_equal((guid_t *)guid->buffer.pointer, &prp_guid))
+               if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
                        continue;
 
                /*
@@ -320,13 +351,13 @@ static bool acpi_extract_properties(const union acpi_object *desc,
                 * package immediately following it.
                 */
                if (!acpi_properties_format_valid(properties))
-                       break;
+                       continue;
 
-               data->properties = properties;
-               return true;
+               acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
+                                   properties);
        }
 
-       return false;
+       return !list_empty(&data->properties);
 }
 
 void acpi_init_properties(struct acpi_device *adev)
@@ -336,6 +367,7 @@ void acpi_init_properties(struct acpi_device *adev)
        acpi_status status;
        bool acpi_of = false;
 
+       INIT_LIST_HEAD(&adev->data.properties);
        INIT_LIST_HEAD(&adev->data.subnodes);
 
        if (!adev->handle)
@@ -398,11 +430,16 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list)
 
 void acpi_free_properties(struct acpi_device *adev)
 {
+       struct acpi_device_properties *props, *tmp;
+
        acpi_destroy_nondev_subnodes(&adev->data.subnodes);
        ACPI_FREE((void *)adev->data.pointer);
        adev->data.of_compatible = NULL;
        adev->data.pointer = NULL;
-       adev->data.properties = NULL;
+       list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
+               list_del(&props->list);
+               kfree(props);
+       }
 }
 
 /**
@@ -427,32 +464,37 @@ static int acpi_data_get_property(const struct acpi_device_data *data,
                                  const char *name, acpi_object_type type,
                                  const union acpi_object **obj)
 {
-       const union acpi_object *properties;
-       int i;
+       const struct acpi_device_properties *props;
 
        if (!data || !name)
                return -EINVAL;
 
-       if (!data->pointer || !data->properties)
+       if (!data->pointer || list_empty(&data->properties))
                return -EINVAL;
 
-       properties = data->properties;
-       for (i = 0; i < properties->package.count; i++) {
-               const union acpi_object *propname, *propvalue;
-               const union acpi_object *property;
+       list_for_each_entry(props, &data->properties, list) {
+               const union acpi_object *properties;
+               unsigned int i;
 
-               property = &properties->package.elements[i];
+               properties = props->properties;
+               for (i = 0; i < properties->package.count; i++) {
+                       const union acpi_object *propname, *propvalue;
+                       const union acpi_object *property;
 
-               propname = &property->package.elements[0];
-               propvalue = &property->package.elements[1];
+                       property = &properties->package.elements[i];
 
-               if (!strcmp(name, propname->string.pointer)) {
-                       if (type != ACPI_TYPE_ANY && propvalue->type != type)
-                               return -EPROTO;
-                       if (obj)
-                               *obj = propvalue;
+                       propname = &property->package.elements[0];
+                       propvalue = &property->package.elements[1];
 
-                       return 0;
+                       if (!strcmp(name, propname->string.pointer)) {
+                               if (type != ACPI_TYPE_ANY &&
+                                   propvalue->type != type)
+                                       return -EPROTO;
+                               if (obj)
+                                       *obj = propvalue;
+
+                               return 0;
+                       }
                }
        }
        return -EINVAL;
index 51b4cf9f25da9686d4014e743ef387df0829f93c..130df1c8ed7d80a809e56759c78f056367a4cf15 100644 (file)
@@ -132,8 +132,8 @@ void acpi_extract_apple_properties(struct acpi_device *adev)
        }
        WARN_ON(free_space != (void *)newprops + newsize);
 
-       adev->data.properties = newprops;
        adev->data.pointer = newprops;
+       acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
 
 out_free:
        ACPI_FREE(props);
index 8b9d7e42c600b60d26bad7f26c32ed938be6e7a2..f74aa0e60300b01115db8f79967d757b53cb0d2c 100644 (file)
@@ -1198,7 +1198,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
 bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
 {
        /* Never allow fallback if the device has properties */
-       if (adev->data.properties || adev->driver_gpios)
+       if (acpi_dev_has_props(adev) || adev->driver_gpios)
                return false;
 
        return con_id == NULL;
index ba4dd54f2c8214c81af5449088982e604cb8d3aa..cd35e3ce9a8b91ea32fef39de19a9ee7d9a2cc8b 100644 (file)
@@ -346,10 +346,16 @@ struct acpi_device_physical_node {
        bool put_online:1;
 };
 
+struct acpi_device_properties {
+       const guid_t *guid;
+       const union acpi_object *properties;
+       struct list_head list;
+};
+
 /* ACPI Device Specific Data (_DSD) */
 struct acpi_device_data {
        const union acpi_object *pointer;
-       const union acpi_object *properties;
+       struct list_head properties;
        const union acpi_object *of_compatible;
        struct list_head subnodes;
 };
index de8d3d3fa6512e3e9382e23cf4fcd03c36b77097..51e3c29663fed52ca11a1a1f6130f0cff4647650 100644 (file)
@@ -1074,6 +1074,15 @@ static inline int acpi_node_get_property_reference(
                NR_FWNODE_REFERENCE_ARGS, args);
 }
 
+static inline bool acpi_dev_has_props(const struct acpi_device *adev)
+{
+       return !list_empty(&adev->data.properties);
+}
+
+struct acpi_device_properties *
+acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
+                   const union acpi_object *properties);
+
 int acpi_node_prop_get(const struct fwnode_handle *fwnode, const char *propname,
                       void **valptr);
 int acpi_dev_prop_read_single(struct acpi_device *adev,