Commit 8c34f112 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'acpi-scan', 'acpi-bus', 'acpi-pm' and 'acpi-resource'

Merge ACPI device enumeration and bus type changes, ACPI power
management changes and ACPI IRQ override handling quirks for 6.9-rc1:

 - Rearrange Device Check and Bus Check notification handling in the
   ACPI device hotplug code to make it get the "enabled" _STA bit into
   account (Rafael Wysocki).

 - Modify acpi_processor_add() to skip processors with the "enabled"
   _STA bit clear, as per the specification (Rafael Wysocki).

 - Stop failing Device Check notification handling without a valid
   reason (Rafael Wysocki).

 - Defer enumeration of devices that depend on a device with an ACPI
   device ID equalt to INTC10CF to address probe ordering issues on
   some platforms (Wentong Wu).

 - Constify acpi_bus_type (Ricardo Marliere).

 - Make the ACPI-specific suspend-to-idle code take the Low-Power S0
   Idle MSFT UUID into account on non-AMD systems (Rafael Wysocki).

 - Add ACPI IRQ override quirks for some new platforms (Sergey
   Kalinichev, Maxim Kudinov, Alexey Froloff, Sviatoslav Harasymchuk,
   Nicolas Haye).

* acpi-scan:
  ACPI: scan: Consolidate Device Check and Bus Check notification handling
  ACPI: scan: Rework Device Check and Bus Check notification handling
  ACPI: scan: Make acpi_processor_add() check the device enabled bit
  ACPI: scan: Relocate acpi_bus_trim_one()
  ACPI: scan: Fix device check notification handling
  ACPI: scan: Defer enumeration of devices with a _DEP pointing to IVSC device

* acpi-bus:
  ACPI: bus: make acpi_bus_type const

* acpi-pm:
  ACPI: PM: s2idle: Enable Low-Power S0 Idle MSFT UUID for non-AMD systems

* acpi-resource:
  ACPI: resource: Use IRQ override on Maibenben X565
  ACPI: resource: Add MAIBENBEN X577 to irq1_edge_low_force_override
  ACPI: resource: Do IRQ override on Lunnen Ground laptops
  ACPI: resource: Add IRQ override quirk for ASUS ExpertBook B2502FBA
  ACPI: resource: Skip IRQ override on ASUS ExpertBook B1502CVA
...@@ -381,6 +381,9 @@ static int acpi_processor_add(struct acpi_device *device, ...@@ -381,6 +381,9 @@ static int acpi_processor_add(struct acpi_device *device,
struct device *dev; struct device *dev;
int result = 0; int result = 0;
if (!acpi_device_is_enabled(device))
return -ENODEV;
pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr) if (!pr)
return -ENOMEM; return -ENOMEM;
......
...@@ -1097,7 +1097,7 @@ static void acpi_device_remove(struct device *dev) ...@@ -1097,7 +1097,7 @@ static void acpi_device_remove(struct device *dev)
put_device(dev); put_device(dev);
} }
struct bus_type acpi_bus_type = { const struct bus_type acpi_bus_type = {
.name = "acpi", .name = "acpi",
.match = acpi_bus_match, .match = acpi_bus_match,
.probe = acpi_device_probe, .probe = acpi_device_probe,
......
...@@ -121,6 +121,7 @@ int acpi_device_setup_files(struct acpi_device *dev); ...@@ -121,6 +121,7 @@ int acpi_device_setup_files(struct acpi_device *dev);
void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev);
void acpi_device_add_finalize(struct acpi_device *device); void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
bool acpi_device_is_enabled(const struct acpi_device *adev);
bool acpi_device_is_present(const struct acpi_device *adev); 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,
......
...@@ -468,6 +468,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { ...@@ -468,6 +468,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "B1502CGA"), DMI_MATCH(DMI_BOARD_NAME, "B1502CGA"),
}, },
}, },
{
/* Asus ExpertBook B1502CVA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BOARD_NAME, "B1502CVA"),
},
},
{ {
/* Asus ExpertBook B2402CBA */ /* Asus ExpertBook B2402CBA */
.matches = { .matches = {
...@@ -489,6 +496,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { ...@@ -489,6 +496,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"),
}, },
}, },
{
/* Asus ExpertBook B2502FBA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BOARD_NAME, "B2502FBA"),
},
},
{ {
/* Asus Vivobook E1504GA */ /* Asus Vivobook E1504GA */
.matches = { .matches = {
...@@ -588,6 +602,34 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = { ...@@ -588,6 +602,34 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"), DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"),
}, },
}, },
{
/* Lunnen Ground 15 / AMD Ryzen 5 5500U */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"),
DMI_MATCH(DMI_BOARD_NAME, "LLL5DAW"),
},
},
{
/* Lunnen Ground 16 / AMD Ryzen 7 5800U */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"),
DMI_MATCH(DMI_BOARD_NAME, "LL6FA"),
},
},
{
/* MAIBENBEN X577 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MAIBENBEN"),
DMI_MATCH(DMI_BOARD_NAME, "X577"),
},
},
{
/* Maibenben X565 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MAIBENBEN"),
DMI_MATCH(DMI_BOARD_NAME, "X565"),
},
},
{ } { }
}; };
......
...@@ -244,6 +244,53 @@ static int acpi_scan_try_to_offline(struct acpi_device *device) ...@@ -244,6 +244,53 @@ static int acpi_scan_try_to_offline(struct acpi_device *device)
return 0; return 0;
} }
static int acpi_scan_check_and_detach(struct acpi_device *adev, void *check)
{
struct acpi_scan_handler *handler = adev->handler;
acpi_dev_for_each_child_reverse(adev, acpi_scan_check_and_detach, check);
if (check) {
acpi_bus_get_status(adev);
/*
* Skip devices that are still there and take the enabled
* flag into account.
*/
if (acpi_device_is_enabled(adev))
return 0;
/* Skip device that have not been enumerated. */
if (!acpi_device_enumerated(adev)) {
dev_dbg(&adev->dev, "Still not enumerated\n");
return 0;
}
}
adev->flags.match_driver = false;
if (handler) {
if (handler->detach)
handler->detach(adev);
adev->handler = NULL;
} else {
device_release_driver(&adev->dev);
}
/*
* Most likely, the device is going away, so put it into D3cold before
* that.
*/
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
adev->flags.initialized = false;
acpi_device_clear_enumerated(adev);
return 0;
}
static void acpi_scan_check_subtree(struct acpi_device *adev)
{
acpi_scan_check_and_detach(adev, (void *)true);
}
static int acpi_scan_hot_remove(struct acpi_device *device) static int acpi_scan_hot_remove(struct acpi_device *device)
{ {
acpi_handle handle = device->handle; acpi_handle handle = device->handle;
...@@ -289,75 +336,62 @@ static int acpi_scan_hot_remove(struct acpi_device *device) ...@@ -289,75 +336,62 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
return 0; return 0;
} }
static int acpi_scan_device_not_enumerated(struct acpi_device *adev) static int acpi_scan_rescan_bus(struct acpi_device *adev)
{ {
if (!acpi_device_enumerated(adev)) { struct acpi_scan_handler *handler = adev->handler;
dev_warn(&adev->dev, "Still not enumerated\n"); int ret;
return -EALREADY;
} if (handler && handler->hotplug.scan_dependent)
acpi_bus_trim(adev); ret = handler->hotplug.scan_dependent(adev);
return 0; else
ret = acpi_bus_scan(adev->handle);
if (ret)
dev_info(&adev->dev, "Namespace scan failure\n");
return ret;
} }
static int acpi_scan_device_check(struct acpi_device *adev) static int acpi_scan_device_check(struct acpi_device *adev)
{ {
int error; struct acpi_device *parent;
acpi_scan_check_subtree(adev);
if (!acpi_device_is_present(adev))
return 0;
acpi_bus_get_status(adev);
if (acpi_device_is_present(adev)) {
/* /*
* This function is only called for device objects for which * This function is only called for device objects for which matching
* matching scan handlers exist. The only situation in which * scan handlers exist. The only situation in which the scan handler
* the scan handler is not attached to this device object yet * is not attached to this device object yet is when the device has
* is when the device has just appeared (either it wasn't * just appeared (either it wasn't present at all before or it was
* present at all before or it was removed and then added * removed and then added again).
* again).
*/ */
if (adev->handler) { if (adev->handler) {
dev_warn(&adev->dev, "Already enumerated\n"); dev_dbg(&adev->dev, "Already enumerated\n");
return -EALREADY; return 0;
}
error = acpi_bus_scan(adev->handle);
if (error) {
dev_warn(&adev->dev, "Namespace scan failure\n");
return error;
}
if (!adev->handler) {
dev_warn(&adev->dev, "Enumeration failure\n");
error = -ENODEV;
}
} else {
error = acpi_scan_device_not_enumerated(adev);
} }
return error;
parent = acpi_dev_parent(adev);
if (!parent)
parent = adev;
return acpi_scan_rescan_bus(parent);
} }
static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) static int acpi_scan_bus_check(struct acpi_device *adev)
{ {
struct acpi_scan_handler *handler = adev->handler; acpi_scan_check_subtree(adev);
int error;
acpi_bus_get_status(adev);
if (!acpi_device_is_present(adev)) {
acpi_scan_device_not_enumerated(adev);
return 0;
}
if (handler && handler->hotplug.scan_dependent)
return handler->hotplug.scan_dependent(adev);
error = acpi_bus_scan(adev->handle); return acpi_scan_rescan_bus(adev);
if (error) {
dev_warn(&adev->dev, "Namespace scan failure\n");
return error;
}
return acpi_dev_for_each_child(adev, acpi_scan_bus_check, NULL);
} }
static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
{ {
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
return acpi_scan_bus_check(adev, NULL); return acpi_scan_bus_check(adev);
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
return acpi_scan_device_check(adev); return acpi_scan_device_check(adev);
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
...@@ -798,6 +832,7 @@ static const char * const acpi_honor_dep_ids[] = { ...@@ -798,6 +832,7 @@ static const char * const acpi_honor_dep_ids[] = {
"INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */ "INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */ "INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
"INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */ "INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */
"INTC10CF", /* IVSC (MTL) driver must be loaded to allow i2c access to camera sensors */
NULL NULL
}; };
...@@ -1922,6 +1957,11 @@ bool acpi_device_is_present(const struct acpi_device *adev) ...@@ -1922,6 +1957,11 @@ bool acpi_device_is_present(const struct acpi_device *adev)
return adev->status.present || adev->status.functional; return adev->status.present || adev->status.functional;
} }
bool acpi_device_is_enabled(const struct acpi_device *adev)
{
return adev->status.present && adev->status.enabled;
}
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
const char *idstr, const char *idstr,
const struct acpi_device_id **matchid) const struct acpi_device_id **matchid)
...@@ -2550,32 +2590,6 @@ int acpi_bus_scan(acpi_handle handle) ...@@ -2550,32 +2590,6 @@ int acpi_bus_scan(acpi_handle handle)
} }
EXPORT_SYMBOL(acpi_bus_scan); EXPORT_SYMBOL(acpi_bus_scan);
static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used)
{
struct acpi_scan_handler *handler = adev->handler;
acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL);
adev->flags.match_driver = false;
if (handler) {
if (handler->detach)
handler->detach(adev);
adev->handler = NULL;
} else {
device_release_driver(&adev->dev);
}
/*
* Most likely, the device is going away, so put it into D3cold before
* that.
*/
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
adev->flags.initialized = false;
acpi_device_clear_enumerated(adev);
return 0;
}
/** /**
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
* @adev: Root of the ACPI namespace scope to walk. * @adev: Root of the ACPI namespace scope to walk.
...@@ -2584,7 +2598,7 @@ static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) ...@@ -2584,7 +2598,7 @@ static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used)
*/ */
void acpi_bus_trim(struct acpi_device *adev) void acpi_bus_trim(struct acpi_device *adev)
{ {
acpi_bus_trim_one(adev, NULL); acpi_scan_check_and_detach(adev, NULL);
} }
EXPORT_SYMBOL_GPL(acpi_bus_trim); EXPORT_SYMBOL_GPL(acpi_bus_trim);
......
...@@ -488,7 +488,21 @@ static int lps0_device_attach(struct acpi_device *adev, ...@@ -488,7 +488,21 @@ static int lps0_device_attach(struct acpi_device *adev,
rev_id = 1; rev_id = 1;
lps0_dsm_func_mask = validate_dsm(adev->handle, lps0_dsm_func_mask = validate_dsm(adev->handle,
ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid); ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid);
lps0_dsm_func_mask_microsoft = -EINVAL; if (lps0_dsm_func_mask > 0 && lps0_dsm_func_mask_microsoft > 0) {
unsigned int func_mask;
/*
* Avoid evaluating the same _DSM function for two
* different UUIDs and prioritize the MSFT one.
*/
func_mask = lps0_dsm_func_mask & lps0_dsm_func_mask_microsoft;
if (func_mask) {
acpi_handle_info(adev->handle,
"Duplicate LPS0 _DSM functions (mask: 0x%x)\n",
func_mask);
lps0_dsm_func_mask &= ~func_mask;
}
}
} }
if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0) if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0)
...@@ -549,19 +563,22 @@ int acpi_s2idle_prepare_late(void) ...@@ -549,19 +563,22 @@ int acpi_s2idle_prepare_late(void)
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* LPS0 entry */ /* LPS0 entry */
if (lps0_dsm_func_mask > 0) if (lps0_dsm_func_mask > 0 && acpi_s2idle_vendor_amd())
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ? acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
ACPI_LPS0_ENTRY_AMD :
ACPI_LPS0_ENTRY,
lps0_dsm_func_mask, lps0_dsm_guid); lps0_dsm_func_mask, lps0_dsm_guid);
if (lps0_dsm_func_mask_microsoft > 0) { if (lps0_dsm_func_mask_microsoft > 0) {
/* modern standby entry */ /* Modern Standby entry */
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY, acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY, acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
} }
if (lps0_dsm_func_mask > 0 && !acpi_s2idle_vendor_amd())
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
lps0_dsm_func_mask, lps0_dsm_guid);
list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) { list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
if (handler->prepare) if (handler->prepare)
handler->prepare(); handler->prepare();
...@@ -600,14 +617,14 @@ void acpi_s2idle_restore_early(void) ...@@ -600,14 +617,14 @@ void acpi_s2idle_restore_early(void)
ACPI_LPS0_EXIT_AMD : ACPI_LPS0_EXIT_AMD :
ACPI_LPS0_EXIT, ACPI_LPS0_EXIT,
lps0_dsm_func_mask, lps0_dsm_guid); lps0_dsm_func_mask, lps0_dsm_guid);
if (lps0_dsm_func_mask_microsoft > 0)
if (lps0_dsm_func_mask_microsoft > 0) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT, acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* Modern Standby exit */
/* Modern standby exit */
if (lps0_dsm_func_mask_microsoft > 0)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT, acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
}
/* Screen on */ /* Screen on */
if (lps0_dsm_func_mask_microsoft > 0) if (lps0_dsm_func_mask_microsoft > 0)
......
...@@ -582,7 +582,7 @@ void acpi_initialize_hp_context(struct acpi_device *adev, ...@@ -582,7 +582,7 @@ void acpi_initialize_hp_context(struct acpi_device *adev,
void (*uevent)(struct acpi_device *, u32)); void (*uevent)(struct acpi_device *, u32));
/* acpi_device.dev.bus == &acpi_bus_type */ /* acpi_device.dev.bus == &acpi_bus_type */
extern struct bus_type acpi_bus_type; extern const struct bus_type acpi_bus_type;
int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data); int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
int acpi_dev_for_each_child(struct acpi_device *adev, int acpi_dev_for_each_child(struct acpi_device *adev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment