Skip to content

Commit

Permalink
Merge branches 'acpi-pm', 'acpi-pci', 'acpi-sysfs' and 'acpi-tables'
Browse files Browse the repository at this point in the history
Merge power management, PCI and sysfs-related material and changes
related to handling ACPI tables for 5.19-rc1:

 - Improve debug messages in the ACPI device PM code (Rafael Wysocki).

 - Block ASUS B1400CEAE from suspend to idle by default (Mario
   Limonciello).

 - Improve handling of PCI devices that are in D3cold during system
   initialization (Rafael Wysocki).

 - Fix BERT error region memory mapping (Lorenzo Pieralisi).

 - Add support for NVIDIA 16550-compatible port subtype to the SPCR
   parsing code (Jeff Brasen).

 - Use static for BGRT_SHOW kobj_attribute defines (Tom Rix).

 - Fix missing prototype warning for acpi_agdi_init() (Ilkka Koskinen).

* acpi-pm:
  ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default
  ACPI: PM: Always print final debug message in acpi_device_set_power()
  ACPI: PM: Unify debug messages in acpi_device_set_power()
  ACPI: PM: Change pr_fmt() in device_pm.c
  ACPI: PM: Convert debug message in acpi_device_get_power()

* acpi-pci:
  ACPI: bus: Avoid non-ACPI device objects in walks over children
  PCI: ACPI: PM: Power up devices in D3cold before scanning them
  ACPI: PM: Introduce acpi_dev_power_up_children_with_adr()
  ACPI: bus: Introduce acpi_dev_for_each_child()

* acpi-sysfs:
  ACPI: sysfs: Fix BERT error region memory mapping

* acpi-tables:
  ACPI: AGDI: Fix missing prototype warning for acpi_agdi_init()
  ACPI: BGRT: use static for BGRT_SHOW kobj_attribute defines
  ACPI: SPCR: Add support for NVIDIA 16550-compatible port subtype
  • Loading branch information
Rafael J. Wysocki committed May 23, 2022
5 parents ec1ff61 + d528486 + 10fa1b2 + 1bbc217 + 988d7a1 commit 4aa8c70
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 34 deletions.
1 change: 1 addition & 0 deletions drivers/acpi/arm64/agdi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/bgrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 26 additions & 0 deletions drivers/acpi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------------------------------------------------------------------- */
Expand Down
83 changes: 57 additions & 26 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
/*
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions drivers/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
},
},
{},
};

Expand Down
1 change: 1 addition & 0 deletions drivers/acpi/spcr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
25 changes: 18 additions & 7 deletions drivers/acpi/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions drivers/pci/pci-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions include/acpi/acpi_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,8 @@ void acpi_initialize_hp_context(struct acpi_device *adev,
extern struct bus_type acpi_bus_type;

int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
int acpi_dev_for_each_child(struct acpi_device *adev,
int (*fn)(struct acpi_device *, void *), void *data);

/*
* Events
Expand Down Expand Up @@ -522,6 +524,7 @@ int acpi_device_fix_up_power(struct acpi_device *device);
int acpi_bus_update_power(acpi_handle handle, int *state_p);
int acpi_device_update_power(struct acpi_device *device, int *state_p);
bool acpi_bus_power_manageable(acpi_handle handle);
void acpi_dev_power_up_children_with_adr(struct acpi_device *adev);
int acpi_device_power_add_dependent(struct acpi_device *adev,
struct device *dev);
void acpi_device_power_remove_dependent(struct acpi_device *adev,
Expand Down

0 comments on commit 4aa8c70

Please sign in to comment.