ACPI fixes for v4.15-rc2

- 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).
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJaIAgnAAoJEILEb/54YlRxiiMP/1rhzfSIAsOZUJktp3fr/fc6
 kBoAKw8sqaTLntWmZMfqMvBtJcaq1x7d+mCqMO2uArp9mppMEz8sCdSxcv2YpRuN
 TPq/Yl78NjUIGxltxPmx6mQRYHwjxLpTzgFqDGL1LwT66+zhA/o3U+gNK0CRywAF
 C36AMtY9EWkKT8hymDv0BeI1VnBLKg7bluIWJ26Ay1BglUPvplTUcCPzX89qwHqF
 061p3/9+DnMPoB6WCFiXPFuSLFQdAd/wgNn1E6EDUFfjOpBB/VHl8Cd469tJT5Np
 0DBQuRIj90Itw4ewVX78z110+LI2fqw7scer5u3mOFHYpYYUohQcGK9NJFKGK+Tb
 6HGaEm0IV4Rp6/23aRva0e8wTCZYvyBuxfrKhvAgUGuXTzehQmN+k+fQdPD688wY
 1oHYE4RoMc3mQWBxcK9Bc+bjN47H4sVVbNkP2/IcHYtAIVA2wUc35PnonmWMX/Hi
 FAKArWxV0KaP0Y6UMpvISq4FnAd6Gbzyw5MoIaANAxVFnVasgpCptOKdmxKbSIcl
 F6LVucLj60S6tNU3nbleNu7eGGBn5z3t/nXMwioR/XoSfVC6duSeCdqdxjwWRYcg
 bbTOg4Zm8S9zYOI7sFId25hR1nwoYLFqSTwzgJNq/Ln01csXh+jRixDnehsmlwWr
 Ca4oJcMImZXGbktyhcOZ
 =dmeF
 -----END PGP SIGNATURE-----

Merge tag 'acpi-4.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

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
This commit is contained in:
Linus Torvalds 2017-11-30 18:49:50 -05:00
commit 42062b9882
6 changed files with 73 additions and 24 deletions

View File

@ -146,6 +146,10 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
int count; int count;
struct acpi_hardware_id *id; 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 * 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 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the

View File

@ -1597,32 +1597,41 @@ static int acpi_ec_add(struct acpi_device *device)
{ {
struct acpi_ec *ec = NULL; struct acpi_ec *ec = NULL;
int ret; int ret;
bool is_ecdt = false;
acpi_status status;
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS); strcpy(acpi_device_class(device), ACPI_EC_CLASS);
ec = acpi_ec_alloc(); if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
if (!ec) is_ecdt = true;
return -ENOMEM; ec = boot_ec;
if (ec_parse_device(device->handle, 0, ec, NULL) != } else {
AE_CTRL_TERMINATE) { ec = acpi_ec_alloc();
if (!ec)
return -ENOMEM;
status = ec_parse_device(device->handle, 0, ec, NULL);
if (status != AE_CTRL_TERMINATE) {
ret = -EINVAL; ret = -EINVAL;
goto err_alloc; goto err_alloc;
}
} }
if (acpi_is_boot_ec(ec)) { 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. /*
* * Trust PNP0C09 namespace location rather than
* But trust ECDT GPE rather than _GPE because of ASUS quirks, * ECDT ID. But trust ECDT GPE rather than _GPE
* so do not change boot_ec->gpe to ec->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"); boot_ec->handle = ec->handle;
acpi_ec_free(ec); acpi_handle_debug(ec->handle, "duplicated.\n");
ec = boot_ec; acpi_ec_free(ec);
ret = acpi_config_boot_ec(ec, ec->handle, true, false); ec = boot_ec;
}
ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt);
} else } else
ret = acpi_ec_setup(ec, true); ret = acpi_ec_setup(ec, true);
if (ret) if (ret)
@ -1635,8 +1644,10 @@ static int acpi_ec_add(struct acpi_device *device)
ret = !!request_region(ec->command_addr, 1, "EC cmd"); ret = !!request_region(ec->command_addr, 1, "EC cmd");
WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
/* Reprobe devices depending on the EC */ if (!is_ecdt) {
acpi_walk_dep_device_list(ec->handle); /* Reprobe devices depending on the EC */
acpi_walk_dep_device_list(ec->handle);
}
acpi_handle_debug(ec->handle, "enumerated.\n"); acpi_handle_debug(ec->handle, "enumerated.\n");
return 0; 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[] = { static const struct acpi_device_id ec_device_ids[] = {
{"PNP0C09", 0}, {"PNP0C09", 0},
{ACPI_ECDT_HID, 0},
{"", 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 * Note: ec->handle can be valid if this function is called after
* acpi_ec_add(), hence the fast path. * acpi_ec_add(), hence the fast path.
*/ */
if (boot_ec->handle != ACPI_ROOT_OBJECT) if (boot_ec->handle == ACPI_ROOT_OBJECT) {
handle = boot_ec->handle; if (!acpi_ec_ecdt_get_handle(&handle))
else if (!acpi_ec_ecdt_get_handle(&handle)) return -ENODEV;
return -ENODEV; boot_ec->handle = handle;
return acpi_config_boot_ec(boot_ec, handle, true, true); }
/* Register to ACPI bus with PM ops attached */
return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
} }
#if 0 #if 0
@ -2022,6 +2037,12 @@ int __init acpi_ec_init(void)
/* Drivers must be started after acpi_ec_query_init() */ /* Drivers must be started after acpi_ec_query_init() */
dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); 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(); ecdt_fail = acpi_ec_ecdt_start();
return ecdt_fail && dsdt_fail ? -ENODEV : 0; return ecdt_fail && dsdt_fail ? -ENODEV : 0;
} }

View File

@ -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_battery(struct acpi_device *adev);
bool acpi_device_is_first_physical_node(struct acpi_device *adev, bool acpi_device_is_first_physical_node(struct acpi_device *adev,
const struct device *dev); const struct device *dev);
int acpi_bus_register_early_device(int type);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Device Matching and Notification Device Matching and Notification

View File

@ -1024,6 +1024,9 @@ static void acpi_device_get_busid(struct acpi_device *device)
case ACPI_BUS_TYPE_SLEEP_BUTTON: case ACPI_BUS_TYPE_SLEEP_BUTTON:
strcpy(device->pnp.bus_id, "SLPF"); strcpy(device->pnp.bus_id, "SLPF");
break; break;
case ACPI_BUS_TYPE_ECDT_EC:
strcpy(device->pnp.bus_id, "ECDT");
break;
default: default:
acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */ /* 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: case ACPI_BUS_TYPE_SLEEP_BUTTON:
acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF); acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
break; 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); 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) static int acpi_bus_scan_fixed(void)
{ {
int result = 0; int result = 0;

View File

@ -105,6 +105,7 @@ enum acpi_bus_device_type {
ACPI_BUS_TYPE_THERMAL, ACPI_BUS_TYPE_THERMAL,
ACPI_BUS_TYPE_POWER_BUTTON, ACPI_BUS_TYPE_POWER_BUTTON,
ACPI_BUS_TYPE_SLEEP_BUTTON, ACPI_BUS_TYPE_SLEEP_BUTTON,
ACPI_BUS_TYPE_ECDT_EC,
ACPI_BUS_DEVICE_TYPE_COUNT ACPI_BUS_DEVICE_TYPE_COUNT
}; };

View File

@ -58,6 +58,7 @@
#define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_VIDEO_HID "LNXVIDEO"
#define ACPI_BAY_HID "LNXIOBAY" #define ACPI_BAY_HID "LNXIOBAY"
#define ACPI_DOCK_HID "LNXDOCK" #define ACPI_DOCK_HID "LNXDOCK"
#define ACPI_ECDT_HID "LNXEC"
/* Quirk for broken IBM BIOSes */ /* Quirk for broken IBM BIOSes */
#define ACPI_SMBUS_IBM_HID "SMBUSIBM" #define ACPI_SMBUS_IBM_HID "SMBUSIBM"