diff mbox series

[09/10] ACPI / property: Allow multiple property compatible _DSD entries

Message ID 20180906155020.51700-10-mika.westerberg@linux.intel.com (mailing list archive)
State Not Applicable
Headers show
Series PCI: Allow D3cold for PCIe hierarchies | expand

Commit Message

Mika Westerberg Sept. 6, 2018, 3:50 p.m. UTC
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 }
            }
        })
    }

For 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

In order 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 differerentiate
between entries. The supported GUIDs are then listed in prp_guids array.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/acpi/property.c     | 94 +++++++++++++++++++++++++++----------
 drivers/acpi/x86/apple.c    |  2 +-
 drivers/gpio/gpiolib-acpi.c |  2 +-
 include/acpi/acpi_bus.h     |  8 +++-
 include/linux/acpi.h        |  9 ++++
 5 files changed, 86 insertions(+), 29 deletions(-)

Comments

Rafael J. Wysocki Sept. 11, 2018, 9 a.m. UTC | #1
On Thursday, September 6, 2018 5:50:19 PM CEST Mika Westerberg wrote:
> 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 }
>             }
>         })
>     }
> 
> For 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
> 
> In order 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 differerentiate
> between entries. The supported GUIDs are then listed in prp_guids array.
> 
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> ---
>  drivers/acpi/property.c     | 94 +++++++++++++++++++++++++++----------
>  drivers/acpi/x86/apple.c    |  2 +-
>  drivers/gpio/gpiolib-acpi.c |  2 +-
>  include/acpi/acpi_bus.h     |  8 +++-
>  include/linux/acpi.h        |  9 ++++
>  5 files changed, 86 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
> index 693cf05b0cc4..f3ddb279d2de 100644
> --- a/drivers/acpi/property.c
> +++ b/drivers/acpi/property.c
> @@ -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;
> +	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;
> +		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;
> diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c
> index 51b4cf9f25da..130df1c8ed7d 100644
> --- a/drivers/acpi/x86/apple.c
> +++ b/drivers/acpi/x86/apple.c
> @@ -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);
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> index c48ed9d89ff5..7be705fae4b8 100644
> --- a/drivers/gpio/gpiolib-acpi.c
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -1192,7 +1192,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;
> diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> index ba4dd54f2c82..cd35e3ce9a8b 100644
> --- a/include/acpi/acpi_bus.h
> +++ b/include/acpi/acpi_bus.h
> @@ -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;
>  };
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index de8d3d3fa651..51e3c29663fe 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -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,
> 

Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Sakari Ailus Sept. 13, 2018, 8 a.m. UTC | #2
Moi Mika,

On Thu, Sep 06, 2018 at 06:50:19PM +0300, Mika Westerberg wrote:
> @@ -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;
> +	struct acpi_device_properties *props;

props could be const.

>  
>  	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;
> +		int i;

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];
>  

With the above considered,

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
diff mbox series

Patch

diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 693cf05b0cc4..f3ddb279d2de 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -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;
+	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;
+		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;
diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c
index 51b4cf9f25da..130df1c8ed7d 100644
--- a/drivers/acpi/x86/apple.c
+++ b/drivers/acpi/x86/apple.c
@@ -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);
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index c48ed9d89ff5..7be705fae4b8 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -1192,7 +1192,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;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index ba4dd54f2c82..cd35e3ce9a8b 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -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;
 };
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index de8d3d3fa651..51e3c29663fe 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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,