summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/arm64/agdi.c1
-rw-r--r--drivers/acpi/bgrt.c2
-rw-r--r--drivers/acpi/bus.c26
-rw-r--r--drivers/acpi/device_pm.c83
-rw-r--r--drivers/acpi/pci_root.c2
-rw-r--r--drivers/acpi/sleep.c12
-rw-r--r--drivers/acpi/spcr.c1
-rw-r--r--drivers/acpi/sysfs.c25
-rw-r--r--drivers/pci/pci-acpi.c3
9 files changed, 121 insertions, 34 deletions
diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c
index 4df337d545b7..cf31abd0ed1b 100644
--- a/drivers/acpi/arm64/agdi.c
+++ b/drivers/acpi/arm64/agdi.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) "ACPI: AGDI: " fmt
#include <linux/acpi.h>
+#include <linux/acpi_agdi.h>
#include <linux/arm_sdei.h>
#include <linux/io.h>
#include <linux/kernel.h>
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index 02d208732f9a..e4fb9e225ddf 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -21,7 +21,7 @@ static struct kobject *bgrt_kobj;
{ \
return sysfs_emit(buf, "%d\n", bgrt_tab._member); \
} \
- struct kobj_attribute bgrt_attr_##_name = __ATTR_RO(_name)
+ static struct kobj_attribute bgrt_attr_##_name = __ATTR_RO(_name)
BGRT_SHOW(version, version);
BGRT_SHOW(status, status);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 3e58b613a2c4..fe0000eb7cae 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1070,6 +1070,32 @@ int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data)
}
EXPORT_SYMBOL_GPL(acpi_bus_for_each_dev);
+struct acpi_dev_walk_context {
+ int (*fn)(struct acpi_device *, void *);
+ void *data;
+};
+
+static int acpi_dev_for_one_check(struct device *dev, void *context)
+{
+ struct acpi_dev_walk_context *adwc = context;
+
+ if (dev->bus != &acpi_bus_type)
+ return 0;
+
+ return adwc->fn(to_acpi_device(dev), adwc->data);
+}
+
+int acpi_dev_for_each_child(struct acpi_device *adev,
+ int (*fn)(struct acpi_device *, void *), void *data)
+{
+ struct acpi_dev_walk_context adwc = {
+ .fn = fn,
+ .data = data,
+ };
+
+ return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check);
+}
+
/* --------------------------------------------------------------------------
Initialization/Cleanup
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index cc6c97e7dcae..130b5f4a50a3 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -10,7 +10,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-#define pr_fmt(fmt) "ACPI: PM: " fmt
+#define pr_fmt(fmt) "PM: " fmt
#include <linux/acpi.h>
#include <linux/export.h>
@@ -130,8 +130,8 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
*state = result;
out:
- dev_dbg(&device->dev, "Device power state is %s\n",
- acpi_power_state_string(*state));
+ acpi_handle_debug(device->handle, "Power state: %s\n",
+ acpi_power_state_string(*state));
return 0;
}
@@ -173,11 +173,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
/* Make sure this is a valid target state */
/* There is a special case for D0 addressed below. */
- if (state > ACPI_STATE_D0 && state == device->power.state) {
- dev_dbg(&device->dev, "Device already in %s\n",
- acpi_power_state_string(state));
- return 0;
- }
+ if (state > ACPI_STATE_D0 && state == device->power.state)
+ goto no_change;
if (state == ACPI_STATE_D3_COLD) {
/*
@@ -189,17 +186,17 @@ int acpi_device_set_power(struct acpi_device *device, int state)
if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid)
target_state = state;
} else if (!device->power.states[state].flags.valid) {
- dev_warn(&device->dev, "Power state %s not supported\n",
- acpi_power_state_string(state));
+ acpi_handle_debug(device->handle, "Power state %s not supported\n",
+ acpi_power_state_string(state));
return -ENODEV;
}
- if (!device->power.flags.ignore_parent &&
- device->parent && (state < device->parent->power.state)) {
- dev_warn(&device->dev,
- "Cannot transition to power state %s for parent in %s\n",
- acpi_power_state_string(state),
- acpi_power_state_string(device->parent->power.state));
+ if (!device->power.flags.ignore_parent && device->parent &&
+ state < device->parent->power.state) {
+ acpi_handle_debug(device->handle,
+ "Cannot transition to %s for parent in %s\n",
+ acpi_power_state_string(state),
+ acpi_power_state_string(device->parent->power.state));
return -ENODEV;
}
@@ -216,9 +213,10 @@ int acpi_device_set_power(struct acpi_device *device, int state)
* (deeper) states to higher-power (shallower) states.
*/
if (state < device->power.state) {
- dev_warn(&device->dev, "Cannot transition from %s to %s\n",
- acpi_power_state_string(device->power.state),
- acpi_power_state_string(state));
+ acpi_handle_debug(device->handle,
+ "Cannot transition from %s to %s\n",
+ acpi_power_state_string(device->power.state),
+ acpi_power_state_string(state));
return -ENODEV;
}
@@ -248,7 +246,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
/* Nothing to do here if _PSC is not present. */
if (!device->power.flags.explicit_get)
- return 0;
+ goto no_change;
/*
* The power state of the device was set to D0 last
@@ -263,23 +261,29 @@ int acpi_device_set_power(struct acpi_device *device, int state)
*/
result = acpi_dev_pm_explicit_get(device, &psc);
if (result || psc == ACPI_STATE_D0)
- return 0;
+ goto no_change;
}
result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);
}
- end:
+end:
if (result) {
- dev_warn(&device->dev, "Failed to change power state to %s\n",
- acpi_power_state_string(target_state));
+ acpi_handle_debug(device->handle,
+ "Failed to change power state to %s\n",
+ acpi_power_state_string(target_state));
} else {
device->power.state = target_state;
- dev_dbg(&device->dev, "Power state changed to %s\n",
- acpi_power_state_string(target_state));
+ acpi_handle_debug(device->handle, "Power state changed to %s\n",
+ acpi_power_state_string(target_state));
}
return result;
+
+no_change:
+ acpi_handle_debug(device->handle, "Already in %s\n",
+ acpi_power_state_string(state));
+ return 0;
}
EXPORT_SYMBOL(acpi_device_set_power);
@@ -425,6 +429,33 @@ bool acpi_bus_power_manageable(acpi_handle handle)
}
EXPORT_SYMBOL(acpi_bus_power_manageable);
+static int acpi_power_up_if_adr_present(struct acpi_device *adev, void *not_used)
+{
+ if (!(adev->flags.power_manageable && adev->pnp.type.bus_address))
+ return 0;
+
+ acpi_handle_debug(adev->handle, "Power state: %s\n",
+ acpi_power_state_string(adev->power.state));
+
+ if (adev->power.state == ACPI_STATE_D3_COLD)
+ return acpi_device_set_power(adev, ACPI_STATE_D0);
+
+ return 0;
+}
+
+/**
+ * acpi_dev_power_up_children_with_adr - Power up childres with valid _ADR
+ * @adev: Parent ACPI device object.
+ *
+ * Change the power states of the direct children of @adev that are in D3cold
+ * and hold valid _ADR objects to D0 in order to allow bus (e.g. PCI)
+ * enumeration code to access them.
+ */
+void acpi_dev_power_up_children_with_adr(struct acpi_device *adev)
+{
+ acpi_dev_for_each_child(adev, acpi_power_up_if_adr_present, NULL);
+}
+
#ifdef CONFIG_PM
static DEFINE_MUTEX(acpi_pm_notifier_lock);
static DEFINE_MUTEX(acpi_pm_notifier_install_lock);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 6f9e75d14808..b3b507f20e87 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -927,6 +927,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
host_bridge->preserve_config = 1;
ACPI_FREE(obj);
+ acpi_dev_power_up_children_with_adr(device);
+
pci_scan_child_bus(bus);
pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info,
info);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index c992e57b2c79..3147702710af 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -373,6 +373,18 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
},
},
+ /*
+ * ASUS B1400CEAE hangs on resume from suspend (see
+ * https://bugzilla.kernel.org/show_bug.cgi?id=215742).
+ */
+ {
+ .callback = init_default_s3,
+ .ident = "ASUS B1400CEAE",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
+ },
+ },
{},
};
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index d589543875b8..1eabfcd122ee 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -142,6 +142,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
case ACPI_DBG2_16550_COMPATIBLE:
case ACPI_DBG2_16550_SUBSET:
case ACPI_DBG2_16550_WITH_GAS:
+ case ACPI_DBG2_16550_NVIDIA:
uart = "uart";
break;
default:
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index a4b638bea6f1..cc2fe0618178 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -415,19 +415,30 @@ static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
loff_t offset, size_t count)
{
struct acpi_data_attr *data_attr;
- void *base;
- ssize_t rc;
+ void __iomem *base;
+ ssize_t size;
data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
+ size = data_attr->attr.size;
+
+ if (offset < 0)
+ return -EINVAL;
+
+ if (offset >= size)
+ return 0;
- base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size);
+ if (count > size - offset)
+ count = size - offset;
+
+ base = acpi_os_map_iomem(data_attr->addr, size);
if (!base)
return -ENOMEM;
- rc = memory_read_from_buffer(buf, count, &offset, base,
- data_attr->attr.size);
- acpi_os_unmap_memory(base, data_attr->attr.size);
- return rc;
+ memcpy_fromio(buf, base + offset, count);
+
+ acpi_os_unmap_iomem(base, size);
+
+ return count;
}
static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 1f15ab7eabf8..3787876ecb24 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1374,6 +1374,9 @@ void pci_acpi_setup(struct device *dev, struct acpi_device *adev)
acpi_pci_wakeup(pci_dev, false);
acpi_device_power_add_dependent(adev, dev);
+
+ if (pci_is_bridge(pci_dev))
+ acpi_dev_power_up_children_with_adr(adev);
}
void pci_acpi_cleanup(struct device *dev, struct acpi_device *adev)