Commit 42062b98 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ACPI fixes from Rafael Wysocki:
 "These fix a regression related to the ACPI EC handling during system
  suspend/resume on some platforms and prevent modalias from being
  exposed to user space for ACPI device object with "not functional and
  not present" status.

  Specifics:

   - Fix an ACPI EC driver regression (from the 4.9 cycle) causing the
     driver's power management operations to be omitted during system
     suspend/resume on platforms where the EC instance from the ECDT
     table is used instead of the one from the DSDT (Lv Zheng).

   - Prevent modalias from being exposed to user space for ACPI device
     objects with _STA returning 0 (not present and not functional) to
     prevent driver modules from being loaded automatically for hardware
     that is not actually present on some platforms (Hans de Goede)"

* tag 'acpi-4.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / EC: Fix regression related to PM ops support in ECDT device
  ACPI / bus: Leave modalias empty for devices which are not present
parents 0cf710f8 b6c70268
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -146,6 +146,10 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
	int count;
	struct acpi_hardware_id *id;

	/* Avoid unnecessarily loading modules for non present devices. */
	if (!acpi_device_is_present(acpi_dev))
		return 0;

	/*
	 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
	 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
+45 −24
Original line number Diff line number Diff line
@@ -1597,32 +1597,41 @@ static int acpi_ec_add(struct acpi_device *device)
{
	struct acpi_ec *ec = NULL;
	int ret;
	bool is_ecdt = false;
	acpi_status status;

	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_EC_CLASS);

	if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
		is_ecdt = true;
		ec = boot_ec;
	} else {
		ec = acpi_ec_alloc();
		if (!ec)
			return -ENOMEM;
	if (ec_parse_device(device->handle, 0, ec, NULL) !=
		AE_CTRL_TERMINATE) {
		status = ec_parse_device(device->handle, 0, ec, NULL);
		if (status != AE_CTRL_TERMINATE) {
			ret = -EINVAL;
			goto err_alloc;
		}
	}

	if (acpi_is_boot_ec(ec)) {
		boot_ec_is_ecdt = false;
		boot_ec_is_ecdt = is_ecdt;
		if (!is_ecdt) {
			/*
		 * Trust PNP0C09 namespace location rather than ECDT ID.
		 *
		 * But trust ECDT GPE rather than _GPE because of ASUS quirks,
		 * so do not change boot_ec->gpe to ec->gpe.
			 * Trust PNP0C09 namespace location rather than
			 * ECDT ID. But trust ECDT GPE rather than _GPE
			 * because of ASUS quirks, so do not change
			 * boot_ec->gpe to ec->gpe.
			 */
			boot_ec->handle = ec->handle;
			acpi_handle_debug(ec->handle, "duplicated.\n");
			acpi_ec_free(ec);
			ec = boot_ec;
		ret = acpi_config_boot_ec(ec, ec->handle, true, false);
		}
		ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt);
	} else
		ret = acpi_ec_setup(ec, true);
	if (ret)
@@ -1635,8 +1644,10 @@ static int acpi_ec_add(struct acpi_device *device)
	ret = !!request_region(ec->command_addr, 1, "EC cmd");
	WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);

	if (!is_ecdt) {
		/* Reprobe devices depending on the EC */
		acpi_walk_dep_device_list(ec->handle);
	}
	acpi_handle_debug(ec->handle, "enumerated.\n");
	return 0;

@@ -1692,6 +1703,7 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)

static const struct acpi_device_id ec_device_ids[] = {
	{"PNP0C09", 0},
	{ACPI_ECDT_HID, 0},
	{"", 0},
};

@@ -1764,11 +1776,14 @@ static int __init acpi_ec_ecdt_start(void)
	 * Note: ec->handle can be valid if this function is called after
	 * acpi_ec_add(), hence the fast path.
	 */
	if (boot_ec->handle != ACPI_ROOT_OBJECT)
		handle = boot_ec->handle;
	else if (!acpi_ec_ecdt_get_handle(&handle))
	if (boot_ec->handle == ACPI_ROOT_OBJECT) {
		if (!acpi_ec_ecdt_get_handle(&handle))
			return -ENODEV;
	return acpi_config_boot_ec(boot_ec, handle, true, true);
		boot_ec->handle = handle;
	}

	/* Register to ACPI bus with PM ops attached */
	return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
}

#if 0
@@ -2022,6 +2037,12 @@ int __init acpi_ec_init(void)

	/* Drivers must be started after acpi_ec_query_init() */
	dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver);
	/*
	 * Register ECDT to ACPI bus only when PNP0C09 probe fails. This is
	 * useful for platforms (confirmed on ASUS X550ZE) with valid ECDT
	 * settings but invalid DSDT settings.
	 * https://bugzilla.kernel.org/show_bug.cgi?id=196847
	 */
	ecdt_fail = acpi_ec_ecdt_start();
	return ecdt_fail && dsdt_fail ? -ENODEV : 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ bool acpi_device_is_present(const struct acpi_device *adev);
bool acpi_device_is_battery(struct acpi_device *adev);
bool acpi_device_is_first_physical_node(struct acpi_device *adev,
					const struct device *dev);
int acpi_bus_register_early_device(int type);

/* --------------------------------------------------------------------------
                     Device Matching and Notification
+21 −0
Original line number Diff line number Diff line
@@ -1024,6 +1024,9 @@ static void acpi_device_get_busid(struct acpi_device *device)
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
		strcpy(device->pnp.bus_id, "SLPF");
		break;
	case ACPI_BUS_TYPE_ECDT_EC:
		strcpy(device->pnp.bus_id, "ECDT");
		break;
	default:
		acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
		/* Clean up trailing underscores (if any) */
@@ -1304,6 +1307,9 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
		acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
		break;
	case ACPI_BUS_TYPE_ECDT_EC:
		acpi_add_id(pnp, ACPI_ECDT_HID);
		break;
	}
}

@@ -2046,6 +2052,21 @@ void acpi_bus_trim(struct acpi_device *adev)
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);

int acpi_bus_register_early_device(int type)
{
	struct acpi_device *device = NULL;
	int result;

	result = acpi_add_single_object(&device, NULL,
					type, ACPI_STA_DEFAULT);
	if (result)
		return result;

	device->flags.match_driver = true;
	return device_attach(&device->dev);
}
EXPORT_SYMBOL_GPL(acpi_bus_register_early_device);

static int acpi_bus_scan_fixed(void)
{
	int result = 0;
+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ enum acpi_bus_device_type {
	ACPI_BUS_TYPE_THERMAL,
	ACPI_BUS_TYPE_POWER_BUTTON,
	ACPI_BUS_TYPE_SLEEP_BUTTON,
	ACPI_BUS_TYPE_ECDT_EC,
	ACPI_BUS_DEVICE_TYPE_COUNT
};

Loading