diff options
28 files changed, 528 insertions, 277 deletions
diff --git a/Documentation/acpi/dsd/data-node-references.txt b/Documentation/acpi/dsd/data-node-references.txt new file mode 100644 index 000000000000..c3871565c8cf --- /dev/null +++ b/Documentation/acpi/dsd/data-node-references.txt @@ -0,0 +1,89 @@ +Copyright (C) 2018 Intel Corporation +Author: Sakari Ailus <sakari.ailus@linux.intel.com> + + +Referencing hierarchical data nodes +----------------------------------- + +ACPI in general allows referring to device objects in the tree only. +Hierarchical data extension nodes may not be referred to directly, hence this +document defines a scheme to implement such references. + +A reference consist of the device object name followed by one or more +hierarchical data extension [1] keys. Specifically, the hierarchical data +extension node which is referred to by the key shall lie directly under the +parent object i.e. either the device object or another hierarchical data +extension node. + +The keys in the hierarchical data nodes shall consist of the name of the node, +"@" character and the number of the node in hexadecimal notation (without pre- +or postfixes). The same ACPI object shall include the _DSD property extension +with a property "reg" that shall have the same numerical value as the number of +the node. + +In case a hierarchical data extensions node has no numerical value, then the +"reg" property shall be omitted from the ACPI object's _DSD properties and the +"@" character and the number shall be omitted from the hierarchical data +extension key. + + +Example +------- + + In the ASL snippet below, the "reference" _DSD property [2] contains a + device object reference to DEV0 and under that device object, a + hierarchical data extension key "node@1" referring to the NOD1 object + and lastly, a hierarchical data extension key "anothernode" referring to + the ANOD object which is also the final target node of the reference. + + Device (DEV0) + { + Name (_DSD, Package () { + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + Package () { + Package () { "node@0", NOD0 }, + Package () { "node@1", NOD1 }, + } + }) + Name (NOD0, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "random-property", 3 }, + } + }) + Name (NOD1, Package() { + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + Package () { + Package () { "anothernode", ANOD }, + } + }) + Name (ANOD, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "random-property", 0 }, + } + }) + } + + Device (DEV1) + { + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "reference", ^DEV0, "node@1", "anothernode" }, + } + }) + } + +Please also see a graph example in graph.txt . + +References +---------- + +[1] Hierarchical Data Extension UUID For _DSD. + <URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf>, + referenced 2018-07-17. + +[2] Device Properties UUID For _DSD. + <URL:http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>, + referenced 2016-10-04. diff --git a/Documentation/acpi/dsd/graph.txt b/Documentation/acpi/dsd/graph.txt index ac09e3138b79..b9ce910781dc 100644 --- a/Documentation/acpi/dsd/graph.txt +++ b/Documentation/acpi/dsd/graph.txt @@ -36,29 +36,41 @@ The port and endpoint concepts are very similar to those in Devicetree [3]. A port represents an interface in a device, and an endpoint represents a connection to that interface. -All port nodes are located under the device's "_DSD" node in the -hierarchical data extension tree. The property extension related to -each port node must contain the key "port" and an integer value which -is the number of the port. The object it refers to should be called "PRTX", -where "X" is the number of the port. - -Further on, endpoints are located under the individual port nodes. The -first hierarchical data extension package list entry of the endpoint -nodes must begin with "endpoint" and must be followed by the number -of the endpoint. The object it refers to should be called "EPXY", where -"X" is the number of the port and "Y" is the number of the endpoint. - -Each port node contains a property extension key "port", the value of -which is the number of the port node. The each endpoint is similarly numbered -with a property extension key "endpoint". Port numbers must be unique within a -device and endpoint numbers must be unique within a port. +All port nodes are located under the device's "_DSD" node in the hierarchical +data extension tree. The data extension related to each port node must begin +with "port" and must be followed by the "@" character and the number of the port +as its key. The target object it refers to should be called "PRTX", where "X" is +the number of the port. An example of such a package would be: + + Package() { "port@4", PRT4 } + +Further on, endpoints are located under the port nodes. The hierarchical +data extension key of the endpoint nodes must begin with +"endpoint" and must be followed by the "@" character and the number of the +endpoint. The object it refers to should be called "EPXY", where "X" is the +number of the port and "Y" is the number of the endpoint. An example of such a +package would be: + + Package() { "endpoint@0", EP40 } + +Each port node contains a property extension key "port", the value of which is +the number of the port. Each endpoint is similarly numbered with a property +extension key "reg", the value of which is the number of the endpoint. Port +numbers must be unique within a device and endpoint numbers must be unique +within a port. If a device object may only has a single port, then the number +of that port shall be zero. Similarly, if a port may only have a single +endpoint, the number of that endpoint shall be zero. The endpoint reference uses property extension with "remote-endpoint" property name followed by a reference in the same package. Such references consist of the -the remote device reference, number of the port in the device and finally the -number of the endpoint in that port. Individual references thus appear as: +the remote device reference, the first package entry of the port data extension +reference under the device and finally the first package entry of the endpoint +data extension reference under the port. Individual references thus appear as: - Package() { device, port_number, endpoint_number } + Package() { device, "port@X", "endpoint@Y" } + +In the above example, "X" is the number of the port and "Y" is the number of the +endpoint. The references to endpoints must be always done both ways, to the remote endpoint and back from the referred remote endpoint node. @@ -76,24 +88,24 @@ A simple example of this is show below: }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port0", "PRT0" }, + Package () { "port@0", PRT0 }, } }) Name (PRT0, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "port", 0 }, + Package () { "reg", 0 }, }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", "EP00" }, + Package () { "endpoint@0", EP00 }, } }) Name (EP00, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "endpoint", 0 }, - Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } }, + Package () { "reg", 0 }, + Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, "port@4", "endpoint@0" } }, } }) } @@ -106,26 +118,26 @@ A simple example of this is show below: Name (_DSD, Package () { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port4", "PRT4" }, + Package () { "port@4", PRT4 }, } }) Name (PRT4, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "port", 4 }, /* CSI-2 port number */ + Package () { "reg", 4 }, /* CSI-2 port number */ }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", "EP40" }, + Package () { "endpoint@0", EP40 }, } }) Name (EP40, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "endpoint", 0 }, - Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } }, + Package () { "reg", 0 }, + Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, "port@0", "endpoint@0" } }, } }) } @@ -151,7 +163,7 @@ References referenced 2016-10-04. [5] Hierarchical Data Extension UUID For _DSD. - <URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf>, + <URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf>, referenced 2016-10-04. [6] Advanced Configuration and Power Interface Specification. diff --git a/MAINTAINERS b/MAINTAINERS index fefe315dc6b4..3d6e7e7b30d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -367,6 +367,12 @@ L: linux-acpi@vger.kernel.org S: Maintained F: drivers/acpi/arm64 +ACPI I2C MULTI INSTANTIATE DRIVER +M: Hans de Goede <hdegoede@redhat.com> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/i2c-multi-instantiate.c + ACPI PMIC DRIVERS M: "Rafael J. Wysocki" <rjw@rjwysocki.net> M: Len Brown <lenb@kernel.org> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index b8eecc7b9531..9ffe01d7042a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -727,12 +727,7 @@ static const struct fault_info fault_info[] = { int handle_guest_sea(phys_addr_t addr, unsigned int esr) { - int ret = -ENOENT; - - if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) - ret = ghes_notify_sea(); - - return ret; + return ghes_notify_sea(); } asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 51c386bf230d..c5367bf5487f 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -165,7 +165,6 @@ struct acpi_namespace_node { #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ -#define IMPLICIT_EXTERNAL 0x02 /* iASL only: This object created implicitly via External */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ #define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 220a718fbce9..83a593e2155d 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -613,13 +613,6 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, /* Special handling for the last segment (num_segments == 0) */ else { -#ifdef ACPI_ASL_COMPILER - if (!acpi_gbl_disasm_flag - && (this_node->flags & ANOBJ_IS_EXTERNAL)) { - this_node->flags &= ~IMPLICIT_EXTERNAL; - } -#endif - /* * Sanity typecheck of the target object: * diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index e9c9a63bb6a4..f594ab75a5fe 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -381,7 +381,6 @@ acpi_ns_search_and_enter(u32 target_name, if (flags & ACPI_NS_EXTERNAL || (walk_state && walk_state->opcode == AML_SCOPE_OP)) { new_node->flags |= ANOBJ_IS_EXTERNAL; - new_node->flags |= IMPLICIT_EXTERNAL; } #endif diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d79ad844c78f..cb97b6105f52 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -23,18 +23,18 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/async.h> +#include <linux/delay.h> +#include <linux/dmi.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/jiffies.h> -#include <linux/async.h> -#include <linux/dmi.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/suspend.h> +#include <linux/types.h> + #include <asm/unaligned.h> #ifdef CONFIG_ACPI_PROCFS_POWER @@ -364,6 +364,20 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; +static enum power_supply_property energy_battery_full_cap_broken_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_POWER_NOW, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_SERIAL_NUMBER, +}; + /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ @@ -577,8 +591,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && (s16)(battery->rate_now) < 0) { battery->rate_now = abs((s16)battery->rate_now); - printk_once(KERN_WARNING FW_BUG - "battery: (dis)charge rate invalid.\n"); + pr_warn_once(FW_BUG "battery: (dis)charge rate invalid.\n"); } if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) @@ -799,6 +812,11 @@ static int sysfs_add_battery(struct acpi_battery *battery) battery->bat_desc.properties = charge_battery_props; battery->bat_desc.num_properties = ARRAY_SIZE(charge_battery_props); + } else if (battery->full_charge_capacity == 0) { + battery->bat_desc.properties = + energy_battery_full_cap_broken_props; + battery->bat_desc.num_properties = + ARRAY_SIZE(energy_battery_full_cap_broken_props); } else { battery->bat_desc.properties = energy_battery_props; battery->bat_desc.num_properties = @@ -918,10 +936,11 @@ static void acpi_battery_quirks(struct acpi_battery *battery) static int acpi_battery_update(struct acpi_battery *battery, bool resume) { - int result, old_present = acpi_battery_present(battery); - result = acpi_battery_get_status(battery); + int result = acpi_battery_get_status(battery); + if (result) return result; + if (!acpi_battery_present(battery)) { sysfs_remove_battery(battery); battery->update_time = 0; @@ -931,8 +950,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) if (resume) return 0; - if (!battery->update_time || - old_present != acpi_battery_present(battery)) { + if (!battery->update_time) { result = acpi_battery_get_info(battery); if (result) return result; @@ -1021,7 +1039,7 @@ static int acpi_battery_info_proc_show(struct seq_file *seq, void *offset) acpi_battery_units(battery)); seq_printf(seq, "battery technology: %srechargeable\n", - (!battery->technology)?"non-":""); + battery->technology ? "" : "non-"); if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); @@ -1112,11 +1130,12 @@ static int acpi_battery_alarm_proc_show(struct seq_file *seq, void *offset) goto end; } seq_printf(seq, "alarm: "); - if (!battery->alarm) - seq_printf(seq, "unsupported\n"); - else + if (battery->alarm) { seq_printf(seq, "%u %sh\n", battery->alarm, acpi_battery_units(battery)); + } else { + seq_printf(seq, "unsupported\n"); + } end: if (result) seq_printf(seq, "ERROR: Unable to read battery alarm\n"); @@ -1149,9 +1168,9 @@ static ssize_t acpi_battery_write_alarm(struct file *file, } result = acpi_battery_set_alarm(battery); end: - if (!result) - return count; - return result; + if (result) + return result; + return count; } static int acpi_battery_alarm_proc_open(struct inode *inode, struct file *file) @@ -1170,8 +1189,7 @@ static const struct file_operations acpi_battery_alarm_fops = { static int acpi_battery_add_fs(struct acpi_device *device) { - printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," - " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); + pr_warning(PREFIX "Deprecated procfs I/F for battery is loaded, please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_battery_dir); @@ -1247,7 +1265,9 @@ static int battery_notify(struct notifier_block *nb, if (!acpi_battery_present(battery)) return 0; - if (!battery->bat) { + if (battery->bat) { + acpi_battery_refresh(battery); + } else { result = acpi_battery_get_info(battery); if (result) return result; @@ -1255,8 +1275,7 @@ static int battery_notify(struct notifier_block *nb, result = sysfs_add_battery(battery); if (result) return result; - } else - acpi_battery_refresh(battery); + } acpi_battery_init_alarm(battery); acpi_battery_get_state(battery); @@ -1398,7 +1417,7 @@ static int acpi_battery_add(struct acpi_device *device) } #endif - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + pr_info(PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 84b4a62018eb..292088fcc624 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -66,37 +66,10 @@ static int set_copy_dsdt(const struct dmi_system_id *id) return 0; } #endif -static int set_gbl_term_list(const struct dmi_system_id *id) -{ - acpi_gbl_execute_tables_as_methods = 1; - return 0; -} -static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { - /* - * Touchpad on Dell XPS 9570/Precision M5530 doesn't work under I2C - * mode. - * https://bugzilla.kernel.org/show_bug.cgi?id=198515 - */ - { - .callback = set_gbl_term_list, - .ident = "Dell Precision M5530", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Precision M5530"), - }, - }, - { - .callback = set_gbl_term_list, - .ident = "Dell XPS 15 9570", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9570"), - }, - }, +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { /* * Invoke DSDT corruption work-around on all Toshiba Satellite. - * DSDT will be copied to memory. * https://bugzilla.kernel.org/show_bug.cgi?id=14679 */ { @@ -110,7 +83,7 @@ static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { {} }; #else -static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { {} }; #endif @@ -962,7 +935,7 @@ static int acpi_device_probe(struct device *dev) return 0; } -static int acpi_device_remove(struct device * dev) +static int acpi_device_remove(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; @@ -1060,8 +1033,11 @@ void __init acpi_early_init(void) acpi_permanent_mmap = true; - /* Check machine-specific quirks */ - dmi_check_system(acpi_quirks_dmi_table); + /* + * If the machine falls into the DMI check table, + * DSDT will be copied to memory + */ + dmi_check_system(dsdt_dmi_table); status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 2345a5ee2dbb..a19ff3977ac4 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -21,6 +21,7 @@ #define pr_fmt(fmt) "ACPI: button: " fmt +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -235,9 +236,6 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) button->last_time = ktime_get(); } - if (state) - acpi_pm_wakeup_event(&device->dev); - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); if (ret == NOTIFY_DONE) ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, @@ -252,7 +250,8 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) return ret; } -static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) +static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, + void *offset) { struct acpi_device *device = seq->private; int state; @@ -366,7 +365,8 @@ int acpi_lid_open(void) } EXPORT_SYMBOL(acpi_lid_open); -static int acpi_lid_update_state(struct acpi_device *device) +static int acpi_lid_update_state(struct acpi_device *device, + bool signal_wakeup) { int state; @@ -374,6 +374,9 @@ static int acpi_lid_update_state(struct acpi_device *device) if (state < 0) return state; + if (state && signal_wakeup) + acpi_pm_wakeup_event(&device->dev); + return acpi_lid_notify_state(device, state); } @@ -384,7 +387,7 @@ static void acpi_lid_initialize_state(struct acpi_device *device) (void)acpi_lid_notify_state(device, 1); break; case ACPI_BUTTON_LID_INIT_METHOD: - (void)acpi_lid_update_state(device); + (void)acpi_lid_update_state(device, false); break; case ACPI_BUTTON_LID_INIT_IGNORE: default: @@ -409,7 +412,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) users = button->input->users; mutex_unlock(&button->input->mutex); if (users) - acpi_lid_update_state(device); + acpi_lid_update_state(device, true); } else { int keycode; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 917f77f4cb55..d4e5610e09c5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -2045,6 +2045,20 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"), }, }, + { + .ident = "ThinkPad X1 Carbon 6th", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"), + }, + }, + { + .ident = "ThinkPad X1 Yoga 3rd", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"), + }, + }, { }, }; diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index 8a8f43568510..b2a16ed7e81a 100644 --- a/drivers/acpi/osi.c +++ b/drivers/acpi/osi.c @@ -66,6 +66,14 @@ osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { * be removed if both new and old graphics cards are supported. */ {"Linux-Dell-Video", true}, + /* + * Linux-Lenovo-NV-HDMI-Audio is used by BIOS to power on NVidia's HDMI + * audio device which is turned off for power-saving in Windows OS. + * This power management feature observed on some Lenovo Thinkpad + * systems which will not be able to output audio via HDMI without + * a BIOS workaround. + */ + {"Linux-Lenovo-NV-HDMI-Audio", true}, }; static u32 acpi_osi_handler(acpi_string interface, u32 supported) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 5815356ea6ad..693cf05b0cc4 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -542,6 +542,23 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data, return 0; } +static struct fwnode_handle * +acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, + const char *childname) +{ + struct fwnode_handle *child; + + /* + * Find first matching named child node of this fwnode. + * For ACPI this will be a data only sub-node. + */ + fwnode_for_each_child_node(fwnode, child) + if (acpi_data_node_match(child, childname)) + return child; + + return NULL; +} + /** * __acpi_node_get_property_reference - returns handle to the referenced object * @fwnode: Firmware node to get the property from @@ -579,7 +596,7 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data, */ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const char *propname, size_t index, size_t num_args, - struct acpi_reference_args *args) + struct fwnode_reference_args *args) { const union acpi_object *element, *end; const union acpi_object *obj; @@ -607,7 +624,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (ret) return ret == -ENODEV ? -EINVAL : ret; - args->adev = device; + args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; return 0; } @@ -633,6 +650,8 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, u32 nargs, i; if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { + struct fwnode_handle *ref_fwnode; + ret = acpi_bus_get_device(element->reference.handle, &device); if (ret) @@ -641,6 +660,19 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, nargs = 0; element++; + /* + * Find the referred data extension node under the + * referred device node. + */ + for (ref_fwnode = acpi_fwnode_handle(device); + element < end && element->type == ACPI_TYPE_STRING; + element++) { + ref_fwnode = acpi_fwnode_get_named_child_node( + ref_fwnode, element->string.pointer); + if (!ref_fwnode) + return -EINVAL; + } + /* assume following integer elements are all args */ for (i = 0; element + i < end && i < num_args; i++) { int type = element[i].type; @@ -653,11 +685,11 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, return -EINVAL; } - if (nargs > MAX_ACPI_REFERENCE_ARGS) + if (nargs > NR_FWNODE_REFERENCE_ARGS) return -EINVAL; if (idx == index) { - args->adev = device; + args->fwnode = ref_fwnode; args->nargs = nargs; for (i = 0; i < nargs; i++) args->args[i] = element[i].integer.value; @@ -995,16 +1027,36 @@ struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode) return NULL; } +/* + * Return true if the node is an ACPI graph node. Called on either ports + * or endpoints. + */ +static bool is_acpi_graph_node(struct fwnode_handle *fwnode, + const char *str) +{ + unsigned int len = strlen(str); + const char *name; + + if (!len || !is_acpi_data_node(fwnode)) + return false; + + name = to_acpi_data_node(fwnode)->name; + + return (fwnode_property_present(fwnode, "reg") && + !strncmp(name, str, len) && name[len] == '@') || + fwnode_property_present(fwnode, str); +} + /** * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node * @fwnode: Pointer to the parent firmware node * @prev: Previous endpoint node or %NULL to get the first * * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns - * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case - * of success the next endpoint is returned. + * %NULL if there is no next endpoint or in case of error. In case of success + * the next endpoint is returned. */ -struct fwnode_handle *acpi_graph_get_next_endpoint( +static struct fwnode_handle *acpi_graph_get_next_endpoint( const struct fwnode_handle *fwnode, struct fwnode_handle *prev) { struct fwnode_handle *port = NULL; @@ -1013,8 +1065,14 @@ struct fwnode_handle *acpi_graph_get_next_endpoint( if (!prev) { do { port = fwnode_get_next_child_node(fwnode, port); - /* Ports must have port property */ - if (fwnode_property_present(port, "port")) + /* + * The names of the port nodes begin with "port@" + * followed by the number of the port node and they also + * have a "reg" property that also has the number of the + * port node. For compatibility reasons a node is also |
