Merge branches 'acpi-init', 'acpi-pnp', 'acpi-scan', 'acpi-proc' and 'acpi-doc'
* acpi-init: ACPI / init: Switch over platform to the ACPI mode later * acpi-pnp: ACPI / PNP: Avoid conflicting resource reservations * acpi-scan: ACPI / scan: constify ACPI device ids ACPI / property: Define a symbol for PRP0001 ACPI / property: Refine consistency check for PRP0001 * acpi-proc: ACPI / proc: make ACPI_PROCFS_POWER X86 only * acpi-doc: ACPI: Constify ACPI device IDs in documentation ACPI / enumeration: Document the rules regarding the PRP0001 device ID ACPI: fix kernel-parameters ordering in Documentation
This commit is contained in:
commit
3a5cf05adf
|
@ -42,7 +42,7 @@ Adding ACPI support for an existing driver should be pretty
|
||||||
straightforward. Here is the simplest example:
|
straightforward. Here is the simplest example:
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static struct acpi_device_id mydrv_acpi_match[] = {
|
static const struct acpi_device_id mydrv_acpi_match[] = {
|
||||||
/* ACPI IDs here */
|
/* ACPI IDs here */
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -166,7 +166,7 @@ the platform device drivers. Below is an example where we add ACPI support
|
||||||
to at25 SPI eeprom driver (this is meant for the above ACPI snippet):
|
to at25 SPI eeprom driver (this is meant for the above ACPI snippet):
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static struct acpi_device_id at25_acpi_match[] = {
|
static const struct acpi_device_id at25_acpi_match[] = {
|
||||||
{ "AT25", 0 },
|
{ "AT25", 0 },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
@ -230,7 +230,7 @@ Below is an example of how to add ACPI support to the existing mpu3050
|
||||||
input driver:
|
input driver:
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static struct acpi_device_id mpu3050_acpi_match[] = {
|
static const struct acpi_device_id mpu3050_acpi_match[] = {
|
||||||
{ "MPU3050", 0 },
|
{ "MPU3050", 0 },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
@ -359,3 +359,54 @@ the id should be set like:
|
||||||
The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
|
The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
|
||||||
the MFD device and if found, that ACPI companion device is bound to the
|
the MFD device and if found, that ACPI companion device is bound to the
|
||||||
resulting child platform device.
|
resulting child platform device.
|
||||||
|
|
||||||
|
Device Tree namespace link device ID
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
The Device Tree protocol uses device indentification based on the "compatible"
|
||||||
|
property whose value is a string or an array of strings recognized as device
|
||||||
|
identifiers by drivers and the driver core. The set of all those strings may be
|
||||||
|
regarded as a device indentification namespace analogous to the ACPI/PNP device
|
||||||
|
ID namespace. Consequently, in principle it should not be necessary to allocate
|
||||||
|
a new (and arguably redundant) ACPI/PNP device ID for a devices with an existing
|
||||||
|
identification string in the Device Tree (DT) namespace, especially if that ID
|
||||||
|
is only needed to indicate that a given device is compatible with another one,
|
||||||
|
presumably having a matching driver in the kernel already.
|
||||||
|
|
||||||
|
In ACPI, the device identification object called _CID (Compatible ID) is used to
|
||||||
|
list the IDs of devices the given one is compatible with, but those IDs must
|
||||||
|
belong to one of the namespaces prescribed by the ACPI specification (see
|
||||||
|
Section 6.1.2 of ACPI 6.0 for details) and the DT namespace is not one of them.
|
||||||
|
Moreover, the specification mandates that either a _HID or an _ADR identificaion
|
||||||
|
object be present for all ACPI objects representing devices (Section 6.1 of ACPI
|
||||||
|
6.0). For non-enumerable bus types that object must be _HID and its value must
|
||||||
|
be a device ID from one of the namespaces prescribed by the specification too.
|
||||||
|
|
||||||
|
The special DT namespace link device ID, PRP0001, provides a means to use the
|
||||||
|
existing DT-compatible device identification in ACPI and to satisfy the above
|
||||||
|
requirements following from the ACPI specification at the same time. Namely,
|
||||||
|
if PRP0001 is returned by _HID, the ACPI subsystem will look for the
|
||||||
|
"compatible" property in the device object's _DSD and will use the value of that
|
||||||
|
property to identify the corresponding device in analogy with the original DT
|
||||||
|
device identification algorithm. If the "compatible" property is not present
|
||||||
|
or its value is not valid, the device will not be enumerated by the ACPI
|
||||||
|
subsystem. Otherwise, it will be enumerated automatically as a platform device
|
||||||
|
(except when an I2C or SPI link from the device to its parent is present, in
|
||||||
|
which case the ACPI core will leave the device enumeration to the parent's
|
||||||
|
driver) and the identification strings from the "compatible" property value will
|
||||||
|
be used to find a driver for the device along with the device IDs listed by _CID
|
||||||
|
(if present).
|
||||||
|
|
||||||
|
Analogously, if PRP0001 is present in the list of device IDs returned by _CID,
|
||||||
|
the identification strings listed by the "compatible" property value (if present
|
||||||
|
and valid) will be used to look for a driver matching the device, but in that
|
||||||
|
case their relative priority with respect to the other device IDs listed by
|
||||||
|
_HID and _CID depends on the position of PRP0001 in the _CID return package.
|
||||||
|
Specifically, the device IDs returned by _HID and preceding PRP0001 in the _CID
|
||||||
|
return package will be checked first. Also in that case the bus type the device
|
||||||
|
will be enumerated to depends on the device ID returned by _HID.
|
||||||
|
|
||||||
|
It is valid to define device objects with a _HID returning PRP0001 and without
|
||||||
|
the "compatible" property in the _DSD or a _CID as long as one of their
|
||||||
|
ancestors provides a _DSD with a valid "compatible" property. Such device
|
||||||
|
objects are then simply regarded as additional "blocks" providing hierarchical
|
||||||
|
configuration information to the driver of the composite ancestor device.
|
||||||
|
|
|
@ -179,11 +179,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
|
|
||||||
See also Documentation/power/runtime_pm.txt, pci=noacpi
|
See also Documentation/power/runtime_pm.txt, pci=noacpi
|
||||||
|
|
||||||
acpi_rsdp= [ACPI,EFI,KEXEC]
|
|
||||||
Pass the RSDP address to the kernel, mostly used
|
|
||||||
on machines running EFI runtime service to boot the
|
|
||||||
second kernel for kdump.
|
|
||||||
|
|
||||||
acpi_apic_instance= [ACPI, IOAPIC]
|
acpi_apic_instance= [ACPI, IOAPIC]
|
||||||
Format: <int>
|
Format: <int>
|
||||||
2: use 2nd APIC table, if available
|
2: use 2nd APIC table, if available
|
||||||
|
@ -197,6 +192,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
(e.g. thinkpad_acpi, sony_acpi, etc.) instead
|
(e.g. thinkpad_acpi, sony_acpi, etc.) instead
|
||||||
of the ACPI video.ko driver.
|
of the ACPI video.ko driver.
|
||||||
|
|
||||||
|
acpica_no_return_repair [HW, ACPI]
|
||||||
|
Disable AML predefined validation mechanism
|
||||||
|
This mechanism can repair the evaluation result to make
|
||||||
|
the return objects more ACPI specification compliant.
|
||||||
|
This option is useful for developers to identify the
|
||||||
|
root cause of an AML interpreter issue when the issue
|
||||||
|
has something to do with the repair mechanism.
|
||||||
|
|
||||||
acpi.debug_layer= [HW,ACPI,ACPI_DEBUG]
|
acpi.debug_layer= [HW,ACPI,ACPI_DEBUG]
|
||||||
acpi.debug_level= [HW,ACPI,ACPI_DEBUG]
|
acpi.debug_level= [HW,ACPI,ACPI_DEBUG]
|
||||||
Format: <int>
|
Format: <int>
|
||||||
|
@ -225,6 +228,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
unusable. The "log_buf_len" parameter may be useful
|
unusable. The "log_buf_len" parameter may be useful
|
||||||
if you need to capture more output.
|
if you need to capture more output.
|
||||||
|
|
||||||
|
acpi_enforce_resources= [ACPI]
|
||||||
|
{ strict | lax | no }
|
||||||
|
Check for resource conflicts between native drivers
|
||||||
|
and ACPI OperationRegions (SystemIO and SystemMemory
|
||||||
|
only). IO ports and memory declared in ACPI might be
|
||||||
|
used by the ACPI subsystem in arbitrary AML code and
|
||||||
|
can interfere with legacy drivers.
|
||||||
|
strict (default): access to resources claimed by ACPI
|
||||||
|
is denied; legacy drivers trying to access reserved
|
||||||
|
resources will fail to bind to device using them.
|
||||||
|
lax: access to resources claimed by ACPI is allowed;
|
||||||
|
legacy drivers trying to access reserved resources
|
||||||
|
will bind successfully but a warning message is logged.
|
||||||
|
no: ACPI OperationRegions are not marked as reserved,
|
||||||
|
no further checks are performed.
|
||||||
|
|
||||||
acpi_force_table_verification [HW,ACPI]
|
acpi_force_table_verification [HW,ACPI]
|
||||||
Enable table checksum verification during early stage.
|
Enable table checksum verification during early stage.
|
||||||
By default, this is disabled due to x86 early mapping
|
By default, this is disabled due to x86 early mapping
|
||||||
|
@ -253,6 +272,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
This feature is enabled by default.
|
This feature is enabled by default.
|
||||||
This option allows to turn off the feature.
|
This option allows to turn off the feature.
|
||||||
|
|
||||||
|
acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump
|
||||||
|
kernels.
|
||||||
|
|
||||||
acpi_no_static_ssdt [HW,ACPI]
|
acpi_no_static_ssdt [HW,ACPI]
|
||||||
Disable installation of static SSDTs at early boot time
|
Disable installation of static SSDTs at early boot time
|
||||||
By default, SSDTs contained in the RSDT/XSDT will be
|
By default, SSDTs contained in the RSDT/XSDT will be
|
||||||
|
@ -263,13 +285,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
dynamic table installation which will install SSDT
|
dynamic table installation which will install SSDT
|
||||||
tables to /sys/firmware/acpi/tables/dynamic.
|
tables to /sys/firmware/acpi/tables/dynamic.
|
||||||
|
|
||||||
acpica_no_return_repair [HW, ACPI]
|
acpi_rsdp= [ACPI,EFI,KEXEC]
|
||||||
Disable AML predefined validation mechanism
|
Pass the RSDP address to the kernel, mostly used
|
||||||
This mechanism can repair the evaluation result to make
|
on machines running EFI runtime service to boot the
|
||||||
the return objects more ACPI specification compliant.
|
second kernel for kdump.
|
||||||
This option is useful for developers to identify the
|
|
||||||
root cause of an AML interpreter issue when the issue
|
|
||||||
has something to do with the repair mechanism.
|
|
||||||
|
|
||||||
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
|
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
|
||||||
Format: To spoof as Windows 98: ="Microsoft Windows"
|
Format: To spoof as Windows 98: ="Microsoft Windows"
|
||||||
|
@ -365,25 +384,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
Use timer override. For some broken Nvidia NF5 boards
|
Use timer override. For some broken Nvidia NF5 boards
|
||||||
that require a timer override, but don't have HPET
|
that require a timer override, but don't have HPET
|
||||||
|
|
||||||
acpi_enforce_resources= [ACPI]
|
|
||||||
{ strict | lax | no }
|
|
||||||
Check for resource conflicts between native drivers
|
|
||||||
and ACPI OperationRegions (SystemIO and SystemMemory
|
|
||||||
only). IO ports and memory declared in ACPI might be
|
|
||||||
used by the ACPI subsystem in arbitrary AML code and
|
|
||||||
can interfere with legacy drivers.
|
|
||||||
strict (default): access to resources claimed by ACPI
|
|
||||||
is denied; legacy drivers trying to access reserved
|
|
||||||
resources will fail to bind to device using them.
|
|
||||||
lax: access to resources claimed by ACPI is allowed;
|
|
||||||
legacy drivers trying to access reserved resources
|
|
||||||
will bind successfully but a warning message is logged.
|
|
||||||
no: ACPI OperationRegions are not marked as reserved,
|
|
||||||
no further checks are performed.
|
|
||||||
|
|
||||||
acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump
|
|
||||||
kernels.
|
|
||||||
|
|
||||||
add_efi_memmap [EFI; X86] Include EFI memory map in
|
add_efi_memmap [EFI; X86] Include EFI memory map in
|
||||||
kernel's map of available physical RAM.
|
kernel's map of available physical RAM.
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ config ACPI_SLEEP
|
||||||
|
|
||||||
config ACPI_PROCFS_POWER
|
config ACPI_PROCFS_POWER
|
||||||
bool "Deprecated power /proc/acpi directories"
|
bool "Deprecated power /proc/acpi directories"
|
||||||
depends on PROC_FS
|
depends on X86 && PROC_FS
|
||||||
help
|
help
|
||||||
For backwards compatibility, this option allows
|
For backwards compatibility, this option allows
|
||||||
deprecated power /proc/acpi/ directories to exist, even when
|
deprecated power /proc/acpi/ directories to exist, even when
|
||||||
|
|
|
@ -470,6 +470,16 @@ static int __init acpi_bus_init_irq(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
|
||||||
|
*
|
||||||
|
* The ACPI tables are accessible after this, but the handling of events has not
|
||||||
|
* been initialized and the global lock is not available yet, so AML should not
|
||||||
|
* be executed at this point.
|
||||||
|
*
|
||||||
|
* Doing this before switching the EFI runtime services to virtual mode allows
|
||||||
|
* the EfiBootServices memory to be freed slightly earlier on boot.
|
||||||
|
*/
|
||||||
void __init acpi_early_init(void)
|
void __init acpi_early_init(void)
|
||||||
{
|
{
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
@ -533,26 +543,42 @@ void __init acpi_early_init(void)
|
||||||
acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
|
acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return;
|
||||||
|
|
||||||
|
error0:
|
||||||
|
disable_acpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_subsystem_init - Finalize the early initialization of ACPI.
|
||||||
|
*
|
||||||
|
* Switch over the platform to the ACPI mode (if possible), initialize the
|
||||||
|
* handling of ACPI events, install the interrupt and global lock handlers.
|
||||||
|
*
|
||||||
|
* Doing this too early is generally unsafe, but at the same time it needs to be
|
||||||
|
* done before all things that really depend on ACPI. The right spot appears to
|
||||||
|
* be before finalizing the EFI initialization.
|
||||||
|
*/
|
||||||
|
void __init acpi_subsystem_init(void)
|
||||||
|
{
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
if (acpi_disabled)
|
||||||
|
return;
|
||||||
|
|
||||||
status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
|
status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
|
printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
|
||||||
goto error0;
|
disable_acpi();
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If the system is using ACPI then we can be reasonably
|
||||||
|
* confident that any regulators are managed by the firmware
|
||||||
|
* so tell the regulator core it has everything it needs to
|
||||||
|
* know.
|
||||||
|
*/
|
||||||
|
regulator_has_full_constraints();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If the system is using ACPI then we can be reasonably
|
|
||||||
* confident that any regulators are managed by the firmware
|
|
||||||
* so tell the regulator core it has everything it needs to
|
|
||||||
* know.
|
|
||||||
*/
|
|
||||||
regulator_has_full_constraints();
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
error0:
|
|
||||||
disable_acpi();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init acpi_bus_init(void)
|
static int __init acpi_bus_init(void)
|
||||||
|
|
|
@ -191,6 +191,8 @@ bool acpi_osi_is_win8(void);
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
Device properties
|
Device properties
|
||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
#define ACPI_DT_NAMESPACE_HID "PRP0001"
|
||||||
|
|
||||||
void acpi_init_properties(struct acpi_device *adev);
|
void acpi_init_properties(struct acpi_device *adev);
|
||||||
void acpi_free_properties(struct acpi_device *adev);
|
void acpi_free_properties(struct acpi_device *adev);
|
||||||
|
|
||||||
|
|
|
@ -175,11 +175,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
|
||||||
if (!addr || !length)
|
if (!addr || !length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Resources are never freed */
|
acpi_reserve_region(addr, length, gas->space_id, 0, desc);
|
||||||
if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
|
||||||
request_region(addr, length, desc);
|
|
||||||
else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
|
||||||
request_mem_region(addr, length, desc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init acpi_reserve_resources(void)
|
static void __init acpi_reserve_resources(void)
|
||||||
|
|
|
@ -79,50 +79,51 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
|
||||||
static void acpi_init_of_compatible(struct acpi_device *adev)
|
static void acpi_init_of_compatible(struct acpi_device *adev)
|
||||||
{
|
{
|
||||||
const union acpi_object *of_compatible;
|
const union acpi_object *of_compatible;
|
||||||
struct acpi_hardware_id *hwid;
|
|
||||||
bool acpi_of = false;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the special PRP0001 ACPI ID is present and in that
|
|
||||||
* case we fill in Device Tree compatible properties for this
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
list_for_each_entry(hwid, &adev->pnp.ids, list) {
|
|
||||||
if (!strcmp(hwid->id, "PRP0001")) {
|
|
||||||
acpi_of = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!acpi_of)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
|
ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
|
||||||
&of_compatible);
|
&of_compatible);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = acpi_dev_get_property(adev, "compatible",
|
ret = acpi_dev_get_property(adev, "compatible",
|
||||||
ACPI_TYPE_STRING, &of_compatible);
|
ACPI_TYPE_STRING, &of_compatible);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
acpi_handle_warn(adev->handle,
|
if (adev->parent
|
||||||
"PRP0001 requires compatible property\n");
|
&& adev->parent->flags.of_compatible_ok)
|
||||||
|
goto out;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
adev->data.of_compatible = of_compatible;
|
adev->data.of_compatible = of_compatible;
|
||||||
|
|
||||||
|
out:
|
||||||
|
adev->flags.of_compatible_ok = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_init_properties(struct acpi_device *adev)
|
void acpi_init_properties(struct acpi_device *adev)
|
||||||
{
|
{
|
||||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||||
|
bool acpi_of = false;
|
||||||
|
struct acpi_hardware_id *hwid;
|
||||||
const union acpi_object *desc;
|
const union acpi_object *desc;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
|
||||||
|
* Device Tree compatible properties for this device.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(hwid, &adev->pnp.ids, list) {
|
||||||
|
if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
|
||||||
|
acpi_of = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
|
status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
|
||||||
ACPI_TYPE_PACKAGE);
|
ACPI_TYPE_PACKAGE);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
desc = buf.pointer;
|
desc = buf.pointer;
|
||||||
if (desc->package.count % 2)
|
if (desc->package.count % 2)
|
||||||
|
@ -156,13 +157,20 @@ void acpi_init_properties(struct acpi_device *adev)
|
||||||
adev->data.pointer = buf.pointer;
|
adev->data.pointer = buf.pointer;
|
||||||
adev->data.properties = properties;
|
adev->data.properties = properties;
|
||||||
|
|
||||||
acpi_init_of_compatible(adev);
|
if (acpi_of)
|
||||||
return;
|
acpi_init_of_compatible(adev);
|
||||||
|
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
|
dev_dbg(&adev->dev, "Returned _DSD data is not valid, skipping\n");
|
||||||
ACPI_FREE(buf.pointer);
|
ACPI_FREE(buf.pointer);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (acpi_of && !adev->flags.of_compatible_ok)
|
||||||
|
acpi_handle_info(adev->handle,
|
||||||
|
ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_free_properties(struct acpi_device *adev)
|
void acpi_free_properties(struct acpi_device *adev)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
|
@ -621,3 +622,162 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
|
||||||
return (type & types) ? 0 : 1;
|
return (type & types) ? 0 : 1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
|
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
|
||||||
|
|
||||||
|
struct reserved_region {
|
||||||
|
struct list_head node;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(reserved_io_regions);
|
||||||
|
static LIST_HEAD(reserved_mem_regions);
|
||||||
|
|
||||||
|
static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
|
||||||
|
char *desc)
|
||||||
|
{
|
||||||
|
unsigned int length = end - start + 1;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
|
||||||
|
request_region(start, length, desc) :
|
||||||
|
request_mem_region(start, length, desc);
|
||||||
|
if (!res)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
res->flags &= ~flags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_region_before(u64 start, u64 end, u8 space_id,
|
||||||
|
unsigned long flags, char *desc,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
struct reserved_region *reg;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
reg = kmalloc(sizeof(*reg), GFP_KERNEL);
|
||||||
|
if (!reg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
error = request_range(start, end, space_id, flags, desc);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
reg->start = start;
|
||||||
|
reg->end = end;
|
||||||
|
list_add_tail(®->node, head);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_reserve_region - Reserve an I/O or memory region as a system resource.
|
||||||
|
* @start: Starting address of the region.
|
||||||
|
* @length: Length of the region.
|
||||||
|
* @space_id: Identifier of address space to reserve the region from.
|
||||||
|
* @flags: Resource flags to clear for the region after requesting it.
|
||||||
|
* @desc: Region description (for messages).
|
||||||
|
*
|
||||||
|
* Reserve an I/O or memory region as a system resource to prevent others from
|
||||||
|
* using it. If the new region overlaps with one of the regions (in the given
|
||||||
|
* address space) already reserved by this routine, only the non-overlapping
|
||||||
|
* parts of it will be reserved.
|
||||||
|
*
|
||||||
|
* Returned is either 0 (success) or a negative error code indicating a resource
|
||||||
|
* reservation problem. It is the code of the first encountered error, but the
|
||||||
|
* routine doesn't abort until it has attempted to request all of the parts of
|
||||||
|
* the new region that don't overlap with other regions reserved previously.
|
||||||
|
*
|
||||||
|
* The resources requested by this routine are never released.
|
||||||
|
*/
|
||||||
|
int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
|
||||||
|
unsigned long flags, char *desc)
|
||||||
|
{
|
||||||
|
struct list_head *regions;
|
||||||
|
struct reserved_region *reg;
|
||||||
|
u64 end = start + length - 1;
|
||||||
|
int ret = 0, error = 0;
|
||||||
|
|
||||||
|
if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
||||||
|
regions = &reserved_io_regions;
|
||||||
|
else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
||||||
|
regions = &reserved_mem_regions;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (list_empty(regions))
|
||||||
|
return add_region_before(start, end, space_id, flags, desc, regions);
|
||||||
|
|
||||||
|
list_for_each_entry(reg, regions, node)
|
||||||
|
if (reg->start == end + 1) {
|
||||||
|
/* The new region can be prepended to this one. */
|
||||||
|
ret = request_range(start, end, space_id, flags, desc);
|
||||||
|
if (!ret)
|
||||||
|
reg->start = start;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else if (reg->start > end) {
|
||||||
|
/* No overlap. Add the new region here and get out. */
|
||||||
|
return add_region_before(start, end, space_id, flags,
|
||||||
|
desc, ®->node);
|
||||||
|
} else if (reg->end == start - 1) {
|
||||||
|
goto combine;
|
||||||
|
} else if (reg->end >= start) {
|
||||||
|
goto overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The new region goes after the last existing one. */
|
||||||
|
return add_region_before(start, end, space_id, flags, desc, regions);
|
||||||
|
|
||||||
|
overlap:
|
||||||
|
/*
|
||||||
|
* The new region overlaps an existing one.
|
||||||
|
*
|
||||||
|
* The head part of the new region immediately preceding the existing
|
||||||
|
* overlapping one can be combined with it right away.
|
||||||
|
*/
|
||||||
|
if (reg->start > start) {
|
||||||
|
error = request_range(start, reg->start - 1, space_id, flags, desc);
|
||||||
|
if (error)
|
||||||
|
ret = error;
|
||||||
|
else
|
||||||
|
reg->start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
combine:
|
||||||
|
/*
|
||||||
|
* The new region is adjacent to an existing one. If it extends beyond
|
||||||
|
* that region all the way to the next one, it is possible to combine
|
||||||
|
* all three of them.
|
||||||
|
*/
|
||||||
|
while (reg->end < end) {
|
||||||
|
struct reserved_region *next = NULL;
|
||||||
|
u64 a = reg->end + 1, b = end;
|
||||||
|
|
||||||
|
if (!list_is_last(®->node, regions)) {
|
||||||
|
next = list_next_entry(reg, node);
|
||||||
|
if (next->start <= end)
|
||||||
|
b = next->start - 1;
|
||||||
|
}
|
||||||
|
error = request_range(a, b, space_id, flags, desc);
|
||||||
|
if (!error) {
|
||||||
|
if (next && next->start == b + 1) {
|
||||||
|
reg->end = next->end;
|
||||||
|
list_del(&next->node);
|
||||||
|
kfree(next);
|
||||||
|
} else {
|
||||||
|
reg->end = end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (next) {
|
||||||
|
if (!ret)
|
||||||
|
ret = error;
|
||||||
|
|
||||||
|
reg = next;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret ? ret : error;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(acpi_reserve_region);
|
||||||
|
|
|
@ -135,12 +135,13 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
|
||||||
struct acpi_hardware_id *id;
|
struct acpi_hardware_id *id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we skip PRP0001 from the modalias below, 0 should be returned
|
* Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
|
||||||
* if PRP0001 is the only ACPI/PNP ID in the device's list.
|
* be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
|
||||||
|
* device's list.
|
||||||
*/
|
*/
|
||||||
count = 0;
|
count = 0;
|
||||||
list_for_each_entry(id, &acpi_dev->pnp.ids, list)
|
list_for_each_entry(id, &acpi_dev->pnp.ids, list)
|
||||||
if (strcmp(id->id, "PRP0001"))
|
if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
|
@ -153,7 +154,7 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
|
||||||
size -= len;
|
size -= len;
|
||||||
|
|
||||||
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
|
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
|
||||||
if (!strcmp(id->id, "PRP0001"))
|
if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
count = snprintf(&modalias[len], size, "%s:", id->id);
|
count = snprintf(&modalias[len], size, "%s:", id->id);
|
||||||
|
@ -177,7 +178,8 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
|
||||||
* @size: Size of the buffer.
|
* @size: Size of the buffer.
|
||||||
*
|
*
|
||||||
* Expose DT compatible modalias as of:NnameTCcompatible. This function should
|
* Expose DT compatible modalias as of:NnameTCcompatible. This function should
|
||||||
* only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
|
* only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
|
||||||
|
* ACPI/PNP IDs.
|
||||||
*/
|
*/
|
||||||
static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
|
static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
|
||||||
int size)
|
int size)
|
||||||
|
@ -980,9 +982,9 @@ static void acpi_device_remove_files(struct acpi_device *dev)
|
||||||
* @adev: ACPI device object to match.
|
* @adev: ACPI device object to match.
|
||||||
* @of_match_table: List of device IDs to match against.
|
* @of_match_table: List of device IDs to match against.
|
||||||
*
|
*
|
||||||
* If @dev has an ACPI companion which has the special PRP0001 device ID in its
|
* If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of
|
||||||
* list of identifiers and a _DSD object with the "compatible" property, use
|
* identifiers and a _DSD object with the "compatible" property, use that
|
||||||
* that property to match against the given list of identifiers.
|
* property to match against the given list of identifiers.
|
||||||
*/
|
*/
|
||||||
static bool acpi_of_match_device(struct acpi_device *adev,
|
static bool acpi_of_match_device(struct acpi_device *adev,
|
||||||
const struct of_device_id *of_match_table)
|
const struct of_device_id *of_match_table)
|
||||||
|
@ -1038,14 +1040,14 @@ static const struct acpi_device_id *__acpi_match_device(
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next, check the special "PRP0001" ID and try to match the
|
* Next, check ACPI_DT_NAMESPACE_HID and try to match the
|
||||||
* "compatible" property if found.
|
* "compatible" property if found.
|
||||||
*
|
*
|
||||||
* The id returned by the below is not valid, but the only
|
* The id returned by the below is not valid, but the only
|
||||||
* caller passing non-NULL of_ids here is only interested in
|
* caller passing non-NULL of_ids here is only interested in
|
||||||
* whether or not the return value is NULL.
|
* whether or not the return value is NULL.
|
||||||
*/
|
*/
|
||||||
if (!strcmp("PRP0001", hwid->id)
|
if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)
|
||||||
&& acpi_of_match_device(device, of_ids))
|
&& acpi_of_match_device(device, of_ids))
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -1671,7 +1673,7 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
|
||||||
|
|
||||||
static void acpi_wakeup_gpe_init(struct acpi_device *device)
|
static void acpi_wakeup_gpe_init(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
struct acpi_device_id button_device_ids[] = {
|
static const struct acpi_device_id button_device_ids[] = {
|
||||||
{"PNP0C0C", 0},
|
{"PNP0C0C", 0},
|
||||||
{"PNP0C0D", 0},
|
{"PNP0C0D", 0},
|
||||||
{"PNP0C0E", 0},
|
{"PNP0C0E", 0},
|
||||||
|
@ -2405,7 +2407,7 @@ static void acpi_default_enumeration(struct acpi_device *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct acpi_device_id generic_device_ids[] = {
|
static const struct acpi_device_id generic_device_ids[] = {
|
||||||
{"PRP0001", },
|
{ACPI_DT_NAMESPACE_HID, },
|
||||||
{"", },
|
{"", },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2413,8 +2415,8 @@ static int acpi_generic_device_attach(struct acpi_device *adev,
|
||||||
const struct acpi_device_id *not_used)
|
const struct acpi_device_id *not_used)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Since PRP0001 is the only ID handled here, the test below can be
|
* Since ACPI_DT_NAMESPACE_HID is the only ID handled here, the test
|
||||||
* unconditional.
|
* below can be unconditional.
|
||||||
*/
|
*/
|
||||||
if (adev->data.of_compatible)
|
if (adev->data.of_compatible)
|
||||||
acpi_default_enumeration(adev);
|
acpi_default_enumeration(adev);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/pnp.h>
|
#include <linux/pnp.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -22,25 +23,41 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
||||||
{"", 0}
|
{"", 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
|
||||||
|
{
|
||||||
|
u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY;
|
||||||
|
return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
res = io ? request_region(start, length, desc) :
|
||||||
|
request_mem_region(start, length, desc);
|
||||||
|
if (res) {
|
||||||
|
res->flags &= ~IORESOURCE_BUSY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
||||||
{
|
{
|
||||||
char *regionid;
|
char *regionid;
|
||||||
const char *pnpid = dev_name(&dev->dev);
|
const char *pnpid = dev_name(&dev->dev);
|
||||||
resource_size_t start = r->start, end = r->end;
|
resource_size_t start = r->start, end = r->end;
|
||||||
struct resource *res;
|
bool reserved;
|
||||||
|
|
||||||
regionid = kmalloc(16, GFP_KERNEL);
|
regionid = kmalloc(16, GFP_KERNEL);
|
||||||
if (!regionid)
|
if (!regionid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(regionid, 16, "pnp %s", pnpid);
|
snprintf(regionid, 16, "pnp %s", pnpid);
|
||||||
if (port)
|
reserved = __reserve_range(start, end - start + 1, !!port, regionid);
|
||||||
res = request_region(start, end - start + 1, regionid);
|
if (!reserved)
|
||||||
else
|
|
||||||
res = request_mem_region(start, end - start + 1, regionid);
|
|
||||||
if (res)
|
|
||||||
res->flags &= ~IORESOURCE_BUSY;
|
|
||||||
else
|
|
||||||
kfree(regionid);
|
kfree(regionid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -49,7 +66,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
||||||
* have double reservations.
|
* have double reservations.
|
||||||
*/
|
*/
|
||||||
dev_info(&dev->dev, "%pR %s reserved\n", r,
|
dev_info(&dev->dev, "%pR %s reserved\n", r,
|
||||||
res ? "has been" : "could not be");
|
reserved ? "has been" : "could not be");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reserve_resources_of_dev(struct pnp_dev *dev)
|
static void reserve_resources_of_dev(struct pnp_dev *dev)
|
||||||
|
|
|
@ -208,7 +208,8 @@ struct acpi_device_flags {
|
||||||
u32 visited:1;
|
u32 visited:1;
|
||||||
u32 hotplug_notify:1;
|
u32 hotplug_notify:1;
|
||||||
u32 is_dock_station:1;
|
u32 is_dock_station:1;
|
||||||
u32 reserved:23;
|
u32 of_compatible_ok:1;
|
||||||
|
u32 reserved:22;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* File System */
|
/* File System */
|
||||||
|
|
|
@ -332,6 +332,9 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||||
|
|
||||||
int acpi_resources_are_enforced(void);
|
int acpi_resources_are_enforced(void);
|
||||||
|
|
||||||
|
int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
|
||||||
|
unsigned long flags, char *desc);
|
||||||
|
|
||||||
#ifdef CONFIG_HIBERNATION
|
#ifdef CONFIG_HIBERNATION
|
||||||
void __init acpi_no_s4_hw_signature(void);
|
void __init acpi_no_s4_hw_signature(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -440,6 +443,7 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
|
||||||
#define ACPI_OST_SC_INSERT_NOT_SUPPORTED 0x82
|
#define ACPI_OST_SC_INSERT_NOT_SUPPORTED 0x82
|
||||||
|
|
||||||
extern void acpi_early_init(void);
|
extern void acpi_early_init(void);
|
||||||
|
extern void acpi_subsystem_init(void);
|
||||||
|
|
||||||
extern int acpi_nvs_register(__u64 start, __u64 size);
|
extern int acpi_nvs_register(__u64 start, __u64 size);
|
||||||
|
|
||||||
|
@ -494,6 +498,7 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void acpi_early_init(void) { }
|
static inline void acpi_early_init(void) { }
|
||||||
|
static inline void acpi_subsystem_init(void) { }
|
||||||
|
|
||||||
static inline int early_acpi_boot_init(void)
|
static inline int early_acpi_boot_init(void)
|
||||||
{
|
{
|
||||||
|
@ -525,6 +530,13 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int acpi_reserve_region(u64 start, unsigned int length,
|
||||||
|
u8 space_id, unsigned long flags,
|
||||||
|
char *desc)
|
||||||
|
{
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
struct acpi_table_header;
|
struct acpi_table_header;
|
||||||
static inline int acpi_table_parse(char *id,
|
static inline int acpi_table_parse(char *id,
|
||||||
int (*handler)(struct acpi_table_header *))
|
int (*handler)(struct acpi_table_header *))
|
||||||
|
|
|
@ -664,6 +664,7 @@ asmlinkage __visible void __init start_kernel(void)
|
||||||
|
|
||||||
check_bugs();
|
check_bugs();
|
||||||
|
|
||||||
|
acpi_subsystem_init();
|
||||||
sfi_init_late();
|
sfi_init_late();
|
||||||
|
|
||||||
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
||||||
|
|
Loading…
Reference in a new issue