Merge branches 'acpi-x86', 'acpi-video', 'acpi-apei' and 'acpi-misc'

Merge x86-specific ACPI changes, an ACPI backlight driver change, ACPI
APEI change and miscellaneous ACPI-related changes for 6.9-rc1:

 - Add DELL0501 handling to acpi_quirk_skip_serdev_enumeration() and
   make that function generic (Hans de Goede).

 - Make the ACPI backlight code handle fetching EDID that is longer than
   256 bytes (Mario Limonciello).

 - Skip initialization of GHES_ASSIST structures for Machine Check
   Architecture in APEI (Avadhut Naik).

 - Convert several plaform drivers in the ACPI subsystem to using a
   remove callback that returns void (Uwe Kleine-König).

 - Drop the long-deprecated custom_method debugfs interface that is
   problematic from the security standpoint (Rafael Wysocki).

 - Use %pe in a couple of places in the ACPI code for easier error
   decoding (Onkarnath).

* acpi-x86:
  ACPI: x86: Add DELL0501 handling to acpi_quirk_skip_serdev_enumeration()
  ACPI: x86: Move acpi_quirk_skip_serdev_enumeration() out of CONFIG_X86_ANDROID_TABLETS

* acpi-video:
  ACPI: video: Handle fetching EDID that is longer than 256 bytes

* acpi-apei:
  ACPI: APEI: Skip initialization of GHES_ASSIST structures for Machine Check Architecture
  ACPI: APEI: GHES: Convert to platform remove callback returning void

* acpi-misc:
  ACPI: pfr_update: Convert to platform remove callback returning void
  ACPI: pfr_telemetry: Convert to platform remove callback returning void
  ACPI: fan: Convert to platform remove callback returning void
  ACPI: GED: Convert to platform remove callback returning void
  ACPI: DPTF: Convert to platform remove callback returning void
  ACPI: AGDI: Convert to platform remove callback returning void
  ACPI: TAD: Convert to platform remove callback returning void
  ACPI: Drop the custom_method debugfs interface
  ACPI: use %pe for better readability of errors while printing
This commit is contained in:
Rafael J. Wysocki 2024-03-11 14:42:30 +01:00
21 changed files with 138 additions and 280 deletions

View file

@ -14,7 +14,6 @@ ACPI Support
dsd/phy
enumeration
osi
method-customizing
method-tracing
DSD-properties-rules
debug

View file

@ -1,89 +0,0 @@
.. SPDX-License-Identifier: GPL-2.0
=======================================
Linux ACPI Custom Control Method How To
=======================================
:Author: Zhang Rui <rui.zhang@intel.com>
Linux supports customizing ACPI control methods at runtime.
Users can use this to:
1. override an existing method which may not work correctly,
or just for debugging purposes.
2. insert a completely new method in order to create a missing
method such as _OFF, _ON, _STA, _INI, etc.
For these cases, it is far simpler to dynamically install a single
control method rather than override the entire DSDT, because kernel
rebuild/reboot is not needed and test result can be got in minutes.
.. note::
- Only ACPI METHOD can be overridden, any other object types like
"Device", "OperationRegion", are not recognized. Methods
declared inside scope operators are also not supported.
- The same ACPI control method can be overridden for many times,
and it's always the latest one that used by Linux/kernel.
- To get the ACPI debug object output (Store (AAAA, Debug)),
please run::
echo 1 > /sys/module/acpi/parameters/aml_debug_output
1. override an existing method
==============================
a) get the ACPI table via ACPI sysfs I/F. e.g. to get the DSDT,
just run "cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat"
b) disassemble the table by running "iasl -d dsdt.dat".
c) rewrite the ASL code of the method and save it in a new file,
d) package the new file (psr.asl) to an ACPI table format.
Here is an example of a customized \_SB._AC._PSR method::
DefinitionBlock ("", "SSDT", 1, "", "", 0x20080715)
{
Method (\_SB_.AC._PSR, 0, NotSerialized)
{
Store ("In AC _PSR", Debug)
Return (ACON)
}
}
Note that the full pathname of the method in ACPI namespace
should be used.
e) assemble the file to generate the AML code of the method.
e.g. "iasl -vw 6084 psr.asl" (psr.aml is generated as a result)
If parameter "-vw 6084" is not supported by your iASL compiler,
please try a newer version.
f) mount debugfs by "mount -t debugfs none /sys/kernel/debug"
g) override the old method via the debugfs by running
"cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method"
2. insert a new method
======================
This is easier than overriding an existing method.
We just need to create the ASL code of the method we want to
insert and then follow the step c) ~ g) in section 1.
3. undo your changes
====================
The "undo" operation is not supported for a new inserted method
right now, i.e. we can not remove a method currently.
For an overridden method, in order to undo your changes, please
save a copy of the method original ASL code in step c) section 1,
and redo step c) ~ g) to override the method with the original one.
.. note:: We can use a kernel with multiple custom ACPI method running,
But each individual write to debugfs can implement a SINGLE
method override. i.e. if we want to insert/override multiple
ACPI methods, we need to redo step c) ~ g) for multiple times.
.. note:: Be aware that root can mis-use this driver to modify arbitrary
memory and gain additional rights, if root's privileges got
restricted (for example if root is not allowed to load additional
modules after boot).

View file

@ -449,20 +449,6 @@ config ACPI_HED
which is used to report some hardware errors notified via
SCI, mainly the corrected errors.
config ACPI_CUSTOM_METHOD
tristate "Allow ACPI methods to be inserted/replaced at run time"
depends on DEBUG_FS
help
This debug facility allows ACPI AML methods to be inserted and/or
replaced without rebooting the system. For details refer to:
Documentation/firmware-guide/acpi/method-customizing.rst.
NOTE: This option is security sensitive, because it allows arbitrary
kernel memory to be written to by root (uid=0) users, allowing them
to bypass certain security measures (e.g. if root is not allowed to
load additional kernel modules after boot, this feature may be used
to override that restriction).
config ACPI_BGRT
bool "Boottime Graphics Resource Table support"
depends on EFI && (X86 || ARM64)

View file

@ -101,7 +101,6 @@ obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_HED) += hed.o
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o

View file

@ -161,7 +161,7 @@ static void cpufreq_add_device(const char *name)
pdev = platform_device_register_simple(name, PLATFORM_DEVID_NONE, NULL, 0);
if (IS_ERR(pdev))
pr_info("%s device creation failed: %ld\n", name, PTR_ERR(pdev));
pr_info("%s device creation failed: %pe\n", name, pdev);
}
#ifdef CONFIG_X86

View file

@ -554,7 +554,7 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
}
static int acpi_tad_remove(struct platform_device *pdev)
static void acpi_tad_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
acpi_handle handle = ACPI_HANDLE(dev);
@ -579,7 +579,6 @@ static int acpi_tad_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
acpi_remove_cmos_rtc_space_handler(handle);
return 0;
}
static int acpi_tad_probe(struct platform_device *pdev)
@ -684,7 +683,7 @@ static struct platform_driver acpi_tad_driver = {
.acpi_match_table = acpi_tad_ids,
},
.probe = acpi_tad_probe,
.remove = acpi_tad_remove,
.remove_new = acpi_tad_remove,
};
MODULE_DEVICE_TABLE(acpi, acpi_tad_ids);

View file

@ -612,7 +612,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
static int
acpi_video_device_EDID(struct acpi_video_device *device,
union acpi_object **edid, ssize_t length)
union acpi_object **edid, int length)
{
int status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@ -625,13 +625,11 @@ acpi_video_device_EDID(struct acpi_video_device *device,
if (!device)
return -ENODEV;
if (length == 128)
arg0.integer.value = 1;
else if (length == 256)
arg0.integer.value = 2;
else
if (!length || (length % 128))
return -EINVAL;
arg0.integer.value = length / 128;
status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
if (ACPI_FAILURE(status))
return -ENODEV;
@ -641,7 +639,8 @@ acpi_video_device_EDID(struct acpi_video_device *device,
if (obj && obj->type == ACPI_TYPE_BUFFER)
*edid = obj;
else {
acpi_handle_info(device->dev->handle, "Invalid _DDC data\n");
acpi_handle_debug(device->dev->handle,
"Invalid _DDC data for length %d\n", length);
status = -EFAULT;
kfree(obj);
}
@ -1447,7 +1446,6 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info;
length = 256;
if (!video_device)
continue;
@ -1478,18 +1476,14 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
continue;
}
status = acpi_video_device_EDID(video_device, &buffer, length);
if (ACPI_FAILURE(status) || !buffer ||
buffer->type != ACPI_TYPE_BUFFER) {
length = 128;
for (length = 512; length > 0; length -= 128) {
status = acpi_video_device_EDID(video_device, &buffer,
length);
if (ACPI_FAILURE(status) || !buffer ||
buffer->type != ACPI_TYPE_BUFFER) {
continue;
}
if (ACPI_SUCCESS(status))
break;
}
if (!length)
continue;
*edid = buffer->buffer.pointer;
return length;

View file

@ -179,7 +179,7 @@ void __init acpi_watchdog_init(void)
pdev = platform_device_register_simple("wdat_wdt", PLATFORM_DEVID_NONE,
resources, nresources);
if (IS_ERR(pdev))
pr_err("Device creation failed: %ld\n", PTR_ERR(pdev));
pr_err("Device creation failed: %pe\n", pdev);
kfree(resources);

View file

@ -1455,7 +1455,7 @@ static int ghes_probe(struct platform_device *ghes_dev)
return rc;
}
static int ghes_remove(struct platform_device *ghes_dev)
static void ghes_remove(struct platform_device *ghes_dev)
{
int rc;
struct ghes *ghes;
@ -1492,8 +1492,15 @@ static int ghes_remove(struct platform_device *ghes_dev)
break;
case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED:
rc = apei_sdei_unregister_ghes(ghes);
if (rc)
return rc;
if (rc) {
/*
* Returning early results in a resource leak, but we're
* only here if stopping the hardware failed.
*/
dev_err(&ghes_dev->dev, "Failed to unregister ghes (%pe)\n",
ERR_PTR(rc));
return;
}
break;
default:
BUG();
@ -1507,8 +1514,6 @@ static int ghes_remove(struct platform_device *ghes_dev)
mutex_unlock(&ghes_devs_mutex);
kfree(ghes);
return 0;
}
static struct platform_driver ghes_platform_driver = {
@ -1516,7 +1521,7 @@ static struct platform_driver ghes_platform_driver = {
.name = "GHES",
},
.probe = ghes_probe,
.remove = ghes_remove,
.remove_new = ghes_remove,
};
void __init acpi_ghes_init(void)

View file

@ -37,6 +37,20 @@ EXPORT_SYMBOL_GPL(hest_disable);
static struct acpi_table_hest *__read_mostly hest_tab;
/*
* Since GHES_ASSIST is not supported, skip initialization of GHES_ASSIST
* structures for MCA.
* During HEST parsing, detected MCA error sources are cached from early
* table entries so that the Flags and Source Id fields from these cached
* values are then referred to in later table entries to determine if the
* encountered GHES_ASSIST structure should be initialized.
*/
static struct {
struct acpi_hest_ia_corrected *cmc;
struct acpi_hest_ia_machine_check *mc;
struct acpi_hest_ia_deferred_check *dmc;
} mces;
static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
[ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
[ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
@ -70,22 +84,54 @@ static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
len = sizeof(*cmc) + cmc->num_hardware_banks *
sizeof(struct acpi_hest_ia_error_bank);
mces.cmc = cmc;
} else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) {
struct acpi_hest_ia_machine_check *mc;
mc = (struct acpi_hest_ia_machine_check *)hest_hdr;
len = sizeof(*mc) + mc->num_hardware_banks *
sizeof(struct acpi_hest_ia_error_bank);
mces.mc = mc;
} else if (hest_type == ACPI_HEST_TYPE_IA32_DEFERRED_CHECK) {
struct acpi_hest_ia_deferred_check *mc;
mc = (struct acpi_hest_ia_deferred_check *)hest_hdr;
len = sizeof(*mc) + mc->num_hardware_banks *
sizeof(struct acpi_hest_ia_error_bank);
mces.dmc = mc;
}
BUG_ON(len == -1);
return len;
};
/*
* GHES and GHESv2 structures share the same format, starting from
* Source Id and ending in Error Status Block Length (inclusive).
*/
static bool is_ghes_assist_struct(struct acpi_hest_header *hest_hdr)
{
struct acpi_hest_generic *ghes;
u16 related_source_id;
if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR &&
hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR_V2)
return false;
ghes = (struct acpi_hest_generic *)hest_hdr;
related_source_id = ghes->related_source_id;
if (mces.cmc && mces.cmc->flags & ACPI_HEST_GHES_ASSIST &&
related_source_id == mces.cmc->header.source_id)
return true;
if (mces.mc && mces.mc->flags & ACPI_HEST_GHES_ASSIST &&
related_source_id == mces.mc->header.source_id)
return true;
if (mces.dmc && mces.dmc->flags & ACPI_HEST_GHES_ASSIST &&
related_source_id == mces.dmc->header.source_id)
return true;
return false;
}
typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
static int apei_hest_parse(apei_hest_func_t func, void *data)
@ -114,6 +160,11 @@ static int apei_hest_parse(apei_hest_func_t func, void *data)
return -EINVAL;
}
if (is_ghes_assist_struct(hest_hdr)) {
hest_hdr = (void *)hest_hdr + len;
continue;
}
rc = func(hest_hdr, data);
if (rc)
return rc;

View file

@ -58,7 +58,7 @@ static int agdi_probe(struct platform_device *pdev)
return agdi_sdei_probe(pdev, adata);
}
static int agdi_remove(struct platform_device *pdev)
static void agdi_remove(struct platform_device *pdev)
{
struct agdi_data *adata = dev_get_platdata(&pdev->dev);
int err, i;
@ -67,7 +67,7 @@ static int agdi_remove(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev, "Failed to disable sdei-event #%d (%pe)\n",
adata->sdei_event, ERR_PTR(err));
return 0;
return;
}
for (i = 0; i < 3; i++) {
@ -81,8 +81,6 @@ static int agdi_remove(struct platform_device *pdev)
if (err)
dev_err(&pdev->dev, "Failed to unregister sdei-event #%d (%pe)\n",
adata->sdei_event, ERR_PTR(err));
return 0;
}
static struct platform_driver agdi_driver = {
@ -90,7 +88,7 @@ static struct platform_driver agdi_driver = {
.name = "agdi",
},
.probe = agdi_probe,
.remove = agdi_remove,
.remove_new = agdi_remove,
};
void __init acpi_agdi_init(void)

View file

@ -1,103 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* custom_method.c - debugfs interface for customizing ACPI control method
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/acpi.h>
#include <linux/security.h>
#include "internal.h"
MODULE_LICENSE("GPL");
static struct dentry *cm_dentry;
/* /sys/kernel/debug/acpi/custom_method */
static ssize_t cm_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
static char *buf;
static u32 max_size;
static u32 uncopied_bytes;
struct acpi_table_header table;
acpi_status status;
int ret;
ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
if (ret)
return ret;
if (!(*ppos)) {
/* parse the table header to get the table length */
if (count <= sizeof(struct acpi_table_header))
return -EINVAL;
if (copy_from_user(&table, user_buf,
sizeof(struct acpi_table_header)))
return -EFAULT;
uncopied_bytes = max_size = table.length;
/* make sure the buf is not allocated */
kfree(buf);
buf = kzalloc(max_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
}
if (buf == NULL)
return -EINVAL;
if ((*ppos > max_size) ||
(*ppos + count > max_size) ||
(*ppos + count < count) ||
(count > uncopied_bytes)) {
kfree(buf);
buf = NULL;
return -EINVAL;
}
if (copy_from_user(buf + (*ppos), user_buf, count)) {
kfree(buf);
buf = NULL;
return -EFAULT;
}
uncopied_bytes -= count;
*ppos += count;
if (!uncopied_bytes) {
status = acpi_install_method(buf);
kfree(buf);
buf = NULL;
if (ACPI_FAILURE(status))
return -EINVAL;
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
return count;
}
static const struct file_operations cm_fops = {
.write = cm_write,
.llseek = default_llseek,
};
static int __init acpi_custom_method_init(void)
{
cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
acpi_debugfs_dir, NULL, &cm_fops);
return 0;
}
static void __exit acpi_custom_method_exit(void)
{
debugfs_remove(cm_dentry);
}
module_init(acpi_custom_method_init);
module_exit(acpi_custom_method_exit);

View file

@ -141,11 +141,9 @@ static int pch_fivr_add(struct platform_device *pdev)
return 0;
}
static int pch_fivr_remove(struct platform_device *pdev)
static void pch_fivr_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &pch_fivr_attribute_group);
return 0;
}
static const struct acpi_device_id pch_fivr_device_ids[] = {
@ -159,7 +157,7 @@ MODULE_DEVICE_TABLE(acpi, pch_fivr_device_ids);
static struct platform_driver pch_fivr_driver = {
.probe = pch_fivr_add,
.remove = pch_fivr_remove,
.remove_new = pch_fivr_remove,
.driver = {
.name = "dptf_pch_fivr",
.acpi_match_table = pch_fivr_device_ids,

View file

@ -209,7 +209,7 @@ static int dptf_power_add(struct platform_device *pdev)
return 0;
}
static int dptf_power_remove(struct platform_device *pdev)
static void dptf_power_remove(struct platform_device *pdev)
{
struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
@ -221,8 +221,6 @@ static int dptf_power_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
else
sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
return 0;
}
static const struct acpi_device_id int3407_device_ids[] = {
@ -242,7 +240,7 @@ MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
static struct platform_driver dptf_power_driver = {
.probe = dptf_power_add,
.remove = dptf_power_remove,
.remove_new = dptf_power_remove,
.driver = {
.name = "dptf_power",
.acpi_match_table = int3407_device_ids,

View file

@ -173,10 +173,9 @@ static void ged_shutdown(struct platform_device *pdev)
}
}
static int ged_remove(struct platform_device *pdev)
static void ged_remove(struct platform_device *pdev)
{
ged_shutdown(pdev);
return 0;
}
static const struct acpi_device_id ged_acpi_ids[] = {
@ -186,7 +185,7 @@ static const struct acpi_device_id ged_acpi_ids[] = {
static struct platform_driver ged_driver = {
.probe = ged_probe,
.remove = ged_remove,
.remove_new = ged_remove,
.shutdown = ged_shutdown,
.driver = {
.name = MODULE_NAME,

View file

@ -387,7 +387,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
return result;
}
static int acpi_fan_remove(struct platform_device *pdev)
static void acpi_fan_remove(struct platform_device *pdev)
{
struct acpi_fan *fan = platform_get_drvdata(pdev);
@ -399,8 +399,6 @@ static int acpi_fan_remove(struct platform_device *pdev)
sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
sysfs_remove_link(&fan->cdev->device.kobj, "device");
thermal_cooling_device_unregister(fan->cdev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@ -446,7 +444,7 @@ static const struct dev_pm_ops acpi_fan_pm = {
static struct platform_driver acpi_fan_driver = {
.probe = acpi_fan_probe,
.remove = acpi_fan_remove,
.remove_new = acpi_fan_remove,
.driver = {
.name = "acpi-fan",
.acpi_match_table = fan_device_ids,

View file

@ -111,7 +111,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
snprintf(name, sizeof(name), "%llu", sun);
pci_slot = pci_create_slot(pci_bus, device, name, NULL);
if (IS_ERR(pci_slot)) {
pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
pr_err("pci_create_slot returned %pe\n", pci_slot);
kfree(slot);
return AE_OK;
}

View file

@ -347,13 +347,11 @@ static const struct file_operations acpi_pfrt_log_fops = {
.llseek = noop_llseek,
};
static int acpi_pfrt_log_remove(struct platform_device *pdev)
static void acpi_pfrt_log_remove(struct platform_device *pdev)
{
struct pfrt_log_device *pfrt_log_dev = platform_get_drvdata(pdev);
misc_deregister(&pfrt_log_dev->miscdev);
return 0;
}
static void pfrt_log_put_idx(void *data)
@ -427,7 +425,7 @@ static struct platform_driver acpi_pfrt_log_driver = {
.acpi_match_table = acpi_pfrt_log_ids,
},
.probe = acpi_pfrt_log_probe,
.remove = acpi_pfrt_log_remove,
.remove_new = acpi_pfrt_log_remove,
};
module_platform_driver(acpi_pfrt_log_driver);

View file

@ -489,13 +489,11 @@ static const struct file_operations acpi_pfru_fops = {
.llseek = noop_llseek,
};
static int acpi_pfru_remove(struct platform_device *pdev)
static void acpi_pfru_remove(struct platform_device *pdev)
{
struct pfru_device *pfru_dev = platform_get_drvdata(pdev);
misc_deregister(&pfru_dev->miscdev);
return 0;
}
static void pfru_put_idx(void *data)
@ -567,7 +565,7 @@ static struct platform_driver acpi_pfru_driver = {
.acpi_match_table = acpi_pfru_ids,
},
.probe = acpi_pfru_probe,
.remove = acpi_pfru_remove,
.remove_new = acpi_pfru_remove,
};
module_platform_driver(acpi_pfru_driver);

View file

@ -428,7 +428,7 @@ bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev)
}
EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration);
int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
{
struct acpi_device *adev = ACPI_COMPANION(controller_parent);
const struct dmi_system_id *dmi_id;
@ -436,8 +436,6 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s
u64 uid;
int ret;
*skip = false;
ret = acpi_dev_uid_to_integer(adev, &uid);
if (ret)
return 0;
@ -463,7 +461,6 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s
return 0;
}
EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration);
bool acpi_quirk_skip_gpio_event_handlers(void)
{
@ -478,8 +475,41 @@ bool acpi_quirk_skip_gpio_event_handlers(void)
return (quirks & ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS);
}
EXPORT_SYMBOL_GPL(acpi_quirk_skip_gpio_event_handlers);
#else
static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
{
return 0;
}
#endif
int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
{
struct acpi_device *adev = ACPI_COMPANION(controller_parent);
*skip = false;
/*
* The DELL0501 ACPI HID represents an UART (CID is set to PNP0501) with
* a backlight-controller attached. There is no separate ACPI device with
* an UartSerialBusV2() resource to model the backlight-controller.
* Set skip to true so that the tty core creates a serdev ctrl device.
* The backlight driver will manually create the serdev client device.
*/
if (acpi_dev_hid_match(adev, "DELL0501")) {
*skip = true;
/*
* Create a platform dev for dell-uart-backlight to bind to.
* This is a static device, so no need to store the result.
*/
platform_device_register_simple("dell-uart-backlight", PLATFORM_DEVID_NONE,
NULL, 0);
return 0;
}
return acpi_dmi_skip_serdev_enumeration(controller_parent, skip);
}
EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration);
/* Lists of PMIC ACPI HIDs with an (often better) native charger driver */
static const struct {
const char *hid;

View file

@ -749,6 +749,7 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s
bool acpi_quirk_skip_acpi_ac_and_battery(void);
int acpi_install_cmos_rtc_space_handler(acpi_handle handle);
void acpi_remove_cmos_rtc_space_handler(acpi_handle handle);
int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip);
#else
static inline bool acpi_device_override_status(struct acpi_device *adev,
unsigned long long *status)
@ -766,23 +767,22 @@ static inline int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
static inline void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
{
}
#endif
#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS)
bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev);
int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip);
bool acpi_quirk_skip_gpio_event_handlers(void);
#else
static inline bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev)
{
return false;
}
static inline int
acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
{
*skip = false;
return 0;
}
#endif
#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS)
bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev);
bool acpi_quirk_skip_gpio_event_handlers(void);
#else
static inline bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev)
{
return false;
}
static inline bool acpi_quirk_skip_gpio_event_handlers(void)
{
return false;