Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit beb0082e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'acpi-resources', 'acpi-ec' and 'acpi-sleep'

* acpi-resources:
  ACPI / resources: ignore invalid ACPI device resources

* acpi-ec:
  ACPI / EC: Clear stale EC events on Samsung systems

* acpi-sleep:
  ACPI / sleep: pm_power_off needs more sanity checks to be installed
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ enum ec_command {
#define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
#define ACPI_EC_MSI_UDELAY	550	/* Wait 550us for MSI EC */
#define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
					 * when trying to clear the EC */

enum {
	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */

/* --------------------------------------------------------------------------
                             Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)

EXPORT_SYMBOL(ec_get_handle);

static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);

/*
 * Clears stale _Q events that might have accumulated in the EC.
 * Run with locked ec mutex.
 */
static void acpi_ec_clear(struct acpi_ec *ec)
{
	int i, status;
	u8 value = 0;

	for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
		status = acpi_ec_query_unlocked(ec, &value);
		if (status || !value)
			break;
	}

	if (unlikely(i == ACPI_EC_CLEAR_MAX))
		pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
	else
		pr_info("%d stale EC events cleared\n", i);
}

void acpi_ec_block_transactions(void)
{
	struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
	mutex_lock(&ec->mutex);
	/* Allow transactions to be carried out again */
	clear_bit(EC_FLAGS_BLOCKED, &ec->flags);

	if (EC_FLAGS_CLEAR_ON_RESUME)
		acpi_ec_clear(ec);

	mutex_unlock(&ec->mutex);
}

@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)

	/* EC is fully operational, allow queries */
	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);

	/* Clear stale _Q events if hardware might require that */
	if (EC_FLAGS_CLEAR_ON_RESUME) {
		mutex_lock(&ec->mutex);
		acpi_ec_clear(ec);
		mutex_unlock(&ec->mutex);
	}
	return ret;
}

@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
	return 0;
}

/*
 * On some hardware it is necessary to clear events accumulated by the EC during
 * sleep. These ECs stop reporting GPEs until they are manually polled, if too
 * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
 *
 * https://bugzilla.kernel.org/show_bug.cgi?id=44161
 *
 * Ideally, the EC should also be instructed NOT to accumulate events during
 * sleep (which Windows seems to do somehow), but the interface to control this
 * behaviour is not known at this time.
 *
 * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
 * however it is very likely that other Samsung models are affected.
 *
 * On systems which don't accumulate _Q events during sleep, this extra check
 * should be harmless.
 */
static int ec_clear_on_resume(const struct dmi_system_id *id)
{
	pr_debug("Detected system needing EC poll on resume.\n");
	EC_FLAGS_CLEAR_ON_RESUME = 1;
	return 0;
}

static struct dmi_system_id ec_dmi_table[] __initdata = {
	{
	ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
	ec_validate_ecdt, "ASUS hardware", {
	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
	DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
	{
	ec_clear_on_resume, "Samsung hardware", {
	DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
	{},
};

+10 −0
Original line number Diff line number Diff line
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
	switch (ares->type) {
	case ACPI_RESOURCE_TYPE_MEMORY24:
		memory24 = &ares->data.memory24;
		if (!memory24->address_length)
			return false;
		acpi_dev_get_memresource(res, memory24->minimum,
					 memory24->address_length,
					 memory24->write_protect);
		break;
	case ACPI_RESOURCE_TYPE_MEMORY32:
		memory32 = &ares->data.memory32;
		if (!memory32->address_length)
			return false;
		acpi_dev_get_memresource(res, memory32->minimum,
					 memory32->address_length,
					 memory32->write_protect);
		break;
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
		fixed_memory32 = &ares->data.fixed_memory32;
		if (!fixed_memory32->address_length)
			return false;
		acpi_dev_get_memresource(res, fixed_memory32->address,
					 fixed_memory32->address_length,
					 fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
	switch (ares->type) {
	case ACPI_RESOURCE_TYPE_IO:
		io = &ares->data.io;
		if (!io->address_length)
			return false;
		acpi_dev_get_ioresource(res, io->minimum,
					io->address_length,
					io->io_decode);
		break;
	case ACPI_RESOURCE_TYPE_FIXED_IO:
		fixed_io = &ares->data.fixed_io;
		if (!fixed_io->address_length)
			return false;
		acpi_dev_get_ioresource(res, fixed_io->address,
					fixed_io->address_length,
					ACPI_DECODE_10);
+6 −1
Original line number Diff line number Diff line
@@ -807,7 +807,12 @@ int __init acpi_sleep_init(void)
	acpi_sleep_hibernate_setup();

	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
	if (ACPI_SUCCESS(status)) {
	/*
	 * Check both ACPI S5 object and ACPI sleep registers to
	 * install pm_power_off_prepare/pm_power_off hook
	 */
	if (ACPI_SUCCESS(status) && acpi_gbl_FADT.sleep_control.address
	    && acpi_gbl_FADT.sleep_status.address) {
		sleep_states[ACPI_STATE_S5] = 1;
		pm_power_off_prepare = acpi_power_off_prepare;
		pm_power_off = acpi_power_off;