Commit d077c9c3 authored by Mika Westerberg's avatar Mika Westerberg Committed by Sasha Levin

ACPI: Add support for device specific properties

[ Upstream commit ffdcd955 ]

Device Tree is used in many embedded systems to describe the system
configuration to the OS. It supports attaching properties or name-value
pairs to the devices it describe. With these properties one can pass
additional information to the drivers that would not be available
otherwise.

ACPI is another configuration mechanism (among other things) typically
seen, but not limited to, x86 machines. ACPI allows passing arbitrary
data from methods but there has not been mechanism equivalent to Device
Tree until the introduction of _DSD in the recent publication of the
ACPI 5.1 specification.

In order to facilitate ACPI usage in systems where Device Tree is
typically used, it would be beneficial to standardize a way to retrieve
Device Tree style properties from ACPI devices, which is what we do in
this patch.

If a given device described in ACPI namespace wants to export properties it
must implement _DSD method (Device Specific Data, introduced with ACPI 5.1)
that returns the properties in a package of packages. For example:

	Name (_DSD, Package () {
		ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
		Package () {
			Package () {"name1", <VALUE1>},
			Package () {"name2", <VALUE2>},
			...
		}
	})

The UUID reserved for properties is daffd814-6eba-4d8c-8a91-bc9bbf4aa301
and is documented in the ACPI 5.1 companion document called "_DSD
Implementation Guide" [1], [2].

We add several helper functions that can be used to extract these
properties and convert them to different Linux data types.

The ultimate goal is that we only have one device property API that
retrieves the requested properties from Device Tree or from ACPI
transparent to the caller.

[1] http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel.htm
[2] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdfReviewed-by: default avatarHanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: default avatarJosh Triplett <josh@joshtriplett.org>
Reviewed-by: default avatarGrant Likely <grant.likely@linaro.org>
Signed-off-by: default avatarDarren Hart <dvhart@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent e7bc7f46
...@@ -47,6 +47,7 @@ acpi-y += int340x_thermal.o ...@@ -47,6 +47,7 @@ acpi-y += int340x_thermal.o
acpi-y += power.o acpi-y += power.o
acpi-y += event.o acpi-y += event.o
acpi-y += sysfs.o acpi-y += sysfs.o
acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_NUMA) += numa.o
......
...@@ -173,4 +173,10 @@ static inline void suspend_nvs_restore(void) {} ...@@ -173,4 +173,10 @@ static inline void suspend_nvs_restore(void) {}
bool acpi_osi_is_win8(void); bool acpi_osi_is_win8(void);
#endif #endif
/*--------------------------------------------------------------------------
Device properties
-------------------------------------------------------------------------- */
void acpi_init_properties(struct acpi_device *adev);
void acpi_free_properties(struct acpi_device *adev);
#endif /* _ACPI_INTERNAL_H_ */ #endif /* _ACPI_INTERNAL_H_ */
This diff is collapsed.
...@@ -926,6 +926,7 @@ static void acpi_device_release(struct device *dev) ...@@ -926,6 +926,7 @@ static void acpi_device_release(struct device *dev)
{ {
struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_device *acpi_dev = to_acpi_device(dev);
acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp); acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev); acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev); kfree(acpi_dev);
...@@ -1928,6 +1929,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, ...@@ -1928,6 +1929,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
acpi_set_device_status(device, sta); acpi_set_device_status(device, sta);
acpi_device_get_busid(device); acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type); acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_init_properties(device);
acpi_bus_get_flags(device); acpi_bus_get_flags(device);
device->flags.match_driver = false; device->flags.match_driver = false;
device->flags.initialized = true; device->flags.initialized = true;
......
...@@ -338,6 +338,12 @@ struct acpi_device_physical_node { ...@@ -338,6 +338,12 @@ struct acpi_device_physical_node {
bool put_online:1; bool put_online:1;
}; };
/* ACPI Device Specific Data (_DSD) */
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
};
/* Device */ /* Device */
struct acpi_device { struct acpi_device {
int device_type; int device_type;
...@@ -354,6 +360,7 @@ struct acpi_device { ...@@ -354,6 +360,7 @@ struct acpi_device {
struct acpi_device_wakeup wakeup; struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance; struct acpi_device_perf performance;
struct acpi_device_dir dir; struct acpi_device_dir dir;
struct acpi_device_data data;
struct acpi_scan_handler *handler; struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp; struct acpi_hotplug_context *hp;
struct acpi_driver *driver; struct acpi_driver *driver;
......
...@@ -659,4 +659,44 @@ do { \ ...@@ -659,4 +659,44 @@ do { \
#endif #endif
#endif #endif
/* Device properties */
#define MAX_ACPI_REFERENCE_ARGS 8
struct acpi_reference_args {
struct acpi_device *adev;
size_t nargs;
u64 args[MAX_ACPI_REFERENCE_ARGS];
};
#ifdef CONFIG_ACPI
int acpi_dev_get_property(struct acpi_device *adev, const char *name,
acpi_object_type type, const union acpi_object **obj);
int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
acpi_object_type type,
const union acpi_object **obj);
int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
const char *cells_name, size_t index,
struct acpi_reference_args *args);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
const union acpi_object **obj)
{
return -ENXIO;
}
static inline int acpi_dev_get_property_array(struct acpi_device *adev,
const char *name,
acpi_object_type type,
const union acpi_object **obj)
{
return -ENXIO;
}
static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
const char *name, const char *cells_name,
size_t index, struct acpi_reference_args *args)
{
return -ENXIO;
}
#endif
#endif /*_LINUX_ACPI_H*/ #endif /*_LINUX_ACPI_H*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment