Commit aab7ce2b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull ACPI updates from Rafael Wysocki:
 "These update the ACPICA code in the kernel to upstream revision
  20201113, fix and clean up some resources manipulation code, extend
  the enumeration and gpio-line-names property documentation, clean up
  the handling of _DEP during device enumeration, add a new backlight
  DMI quirk, clean up transaction handling in the EC driver and make
  some assorted janitorial changes.

  Specifics:

   - Update ACPICA code in the kernel to upstream revision 20201113 with
     changes as follows:
       * Add 5 new UUIDs to the known UUID table (Bob Moore)
       * Remove extreaneous "the" in comments (Colin Ian King)
       * Add function trace macros to improve debugging (Erik Kaneda)
       * Fix interpreter memory leak (Erik Kaneda)
       * Handle "orphan" _REG for GPIO OpRegions (Hans de Goede)

   - Introduce resource_union() and resource_intersection() helpers and
     clean up some resource-manipulation code with the help of them
     (Andy Shevchenko)

   - Revert problematic commit related to the handling of resources in
     the ACPI core (Daniel Scally)

   - Extend the ACPI device enumeration documentation and the
     gpio-line-names _DSD property documentation, clean up the latter
     (Flavio Suligoi)

   - Clean up _DEP handling during device enumeration, modify the list
     of _DEP exceptions and the handling of it and fix up terminology
     related to _DEP (Hans de Goede, Rafael Wysocki)

   - Eliminate in_interrupt() usage from the ACPI EC driver (Sebastian
     Andrzej Siewior)

   - Clean up the advance_transaction() routine and related code in the
     ACPI EC driver (Rafael Wysocki)

   - Add new backlight quirk for GIGABYTE GB-BXBT-2807 (Jasper St
     Pierre)

   - Make assorted janitorial changes in several ACPI-related pieces of
     code (Hanjun Guo, Jason Yan, Punit Agrawal)"

* tag 'acpi-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (40 commits)
  ACPI: scan: Fix up _DEP-related terminology with supplier/consumer
  ACPI: scan: Drop INT3396 from acpi_ignore_dep_ids[]
  ACPI: video: Add DMI quirk for GIGABYTE GB-BXBT-2807
  Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources walks"
  ACPI: scan: Add PNP0D80 to the _DEP exceptions list
  ACPI: scan: Call acpi_get_object_info() from acpi_add_single_object()
  ACPI: scan: Add acpi_info_matches_hids() helper
  ACPICA: Update version to 20201113
  ACPICA: Interpreter: fix memory leak by using existing buffer
  ACPICA: Add function trace macros to improve debugging
  ACPICA: Also handle "orphan" _REG methods for GPIO OpRegions
  ACPICA: Remove extreaneous "the" in comments
  ACPICA: Add 5 new UUIDs to the known UUID table
  resource: provide meaningful MODULE_LICENSE() in test suite
  ASoC: Intel: catpt: Replace open coded variant of resource_intersection()
  ACPI: processor: Drop duplicate setting of shared_cpu_map
  ACPI: EC: Clean up status flags checks in advance_transaction()
  ACPI: EC: Untangle error handling in advance_transaction()
  ACPI: EC: Simplify error handling in advance_transaction()
  ACPI: EC: Rename acpi_ec_is_gpe_raised()
  ...
parents b4ec8054 38a0925c
......@@ -90,10 +90,10 @@ where
References
==========
[1] Device tree. <URL:https://www.devicetree.org>, referenced 2019-02-21.
[1] Device tree. https://www.devicetree.org, referenced 2019-02-21.
[2] Advanced Configuration and Power Interface Specification.
<URL:https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf>,
https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf,
referenced 2019-02-21.
[3] Documentation/devicetree/bindings/leds/common.txt
......@@ -101,11 +101,11 @@ References
[4] Documentation/devicetree/bindings/media/video-interfaces.txt
[5] Device Properties UUID For _DSD.
<URL:https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>,
https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf,
referenced 2019-02-21.
[6] Hierarchical Data Extension UUID For _DSD.
<URL:https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf>,
https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf,
referenced 2019-02-21.
[7] Documentation/firmware-guide/acpi/dsd/data-node-references.rst
......@@ -461,3 +461,157 @@ Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible"
property returned by it is meaningless.
Refer to :doc:`DSD-properties-rules` for more information.
PCI hierarchy representation
============================
Sometimes could be useful to enumerate a PCI device, knowing its position on the
PCI bus.
For example, some systems use PCI devices soldered directly on the mother board,
in a fixed position (ethernet, Wi-Fi, serial ports, etc.). In this conditions it
is possible to refer to these PCI devices knowing their position on the PCI bus
topology.
To identify a PCI device, a complete hierarchical description is required, from
the chipset root port to the final device, through all the intermediate
bridges/switches of the board.
For example, let us assume to have a system with a PCIe serial port, an
Exar XR17V3521, soldered on the main board. This UART chip also includes
16 GPIOs and we want to add the property ``gpio-line-names`` [1] to these pins.
In this case, the ``lspci`` output for this component is::
07:00.0 Serial controller: Exar Corp. XR17V3521 Dual PCIe UART (rev 03)
The complete ``lspci`` output (manually reduced in length) is::
00:00.0 Host bridge: Intel Corp... Host Bridge (rev 0d)
...
00:13.0 PCI bridge: Intel Corp... PCI Express Port A #1 (rev fd)
00:13.1 PCI bridge: Intel Corp... PCI Express Port A #2 (rev fd)
00:13.2 PCI bridge: Intel Corp... PCI Express Port A #3 (rev fd)
00:14.0 PCI bridge: Intel Corp... PCI Express Port B #1 (rev fd)
00:14.1 PCI bridge: Intel Corp... PCI Express Port B #2 (rev fd)
...
05:00.0 PCI bridge: Pericom Semiconductor Device 2404 (rev 05)
06:01.0 PCI bridge: Pericom Semiconductor Device 2404 (rev 05)
06:02.0 PCI bridge: Pericom Semiconductor Device 2404 (rev 05)
06:03.0 PCI bridge: Pericom Semiconductor Device 2404 (rev 05)
07:00.0 Serial controller: Exar Corp. XR17V3521 Dual PCIe UART (rev 03) <-- Exar
...
The bus topology is::
-[0000:00]-+-00.0
...
+-13.0-[01]----00.0
+-13.1-[02]----00.0
+-13.2-[03]--
+-14.0-[04]----00.0
+-14.1-[05-09]----00.0-[06-09]--+-01.0-[07]----00.0 <-- Exar
| +-02.0-[08]----00.0
| \-03.0-[09]--
...
\-1f.1
To describe this Exar device on the PCI bus, we must start from the ACPI name
of the chipset bridge (also called "root port") with address::
Bus: 0 - Device: 14 - Function: 1
To find this information is necessary disassemble the BIOS ACPI tables, in
particular the DSDT (see also [2])::
mkdir ~/tables/
cd ~/tables/
acpidump > acpidump
acpixtract -a acpidump
iasl -e ssdt?.* -d dsdt.dat
Now, in the dsdt.dsl, we have to search the device whose address is related to
0x14 (device) and 0x01 (function). In this case we can find the following
device::
Scope (_SB.PCI0)
{
... other definitions follow ...
Device (RP02)
{
Method (_ADR, 0, NotSerialized) // _ADR: Address
{
If ((RPA2 != Zero))
{
Return (RPA2) /* \RPA2 */
}
Else
{
Return (0x00140001)
}
}
... other definitions follow ...
and the _ADR method [3] returns exactly the device/function couple that
we are looking for. With this information and analyzing the above ``lspci``
output (both the devices list and the devices tree), we can write the following
ACPI description for the Exar PCIe UART, also adding the list of its GPIO line
names::
Scope (_SB.PCI0.RP02)
{
Device (BRG1) //Bridge
{
Name (_ADR, 0x0000)
Device (BRG2) //Bridge
{
Name (_ADR, 0x00010000)
Device (EXAR)
{
Name (_ADR, 0x0000)
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package ()
{
"gpio-line-names",
Package ()
{
"mode_232",
"mode_422",
"mode_485",
"misc_1",
"misc_2",
"misc_3",
"",
"",
"aux_1",
"aux_2",
"aux_3",
}
}
}
})
}
}
}
}
The location "_SB.PCI0.RP02" is obtained by the above investigation in the
dsdt.dsl table, whereas the device names "BRG1", "BRG2" and "EXAR" are
created analyzing the position of the Exar UART in the PCI bus topology.
References
==========
[1] Documentation/firmware-guide/acpi/gpio-properties.rst
[2] Documentation/admin-guide/acpi/initrd_table_override.rst
[3] ACPI Specifications, Version 6.3 - Paragraph 6.1.1 _ADR Address)
https://uefi.org/sites/default/files/resources/ACPI_6_3_May16.pdf,
referenced 2020-11-18
......@@ -133,7 +133,61 @@ Example::
- gpio-line-names
Example::
The ``gpio-line-names`` declaration is a list of strings ("names"), which
describes each line/pin of a GPIO controller/expander. This list, contained in
a package, must be inserted inside the GPIO controller declaration of an ACPI
table (typically inside the DSDT). The ``gpio-line-names`` list must respect the
following rules (see also the examples):
- the first name in the list corresponds with the first line/pin of the GPIO
controller/expander
- the names inside the list must be consecutive (no "holes" are permitted)
- the list can be incomplete and can end before the last GPIO line: in
other words, it is not mandatory to fill all the GPIO lines
- empty names are allowed (two quotation marks ``""`` correspond to an empty
name)
Example of a GPIO controller of 16 lines, with an incomplete list with two
empty names::
Package () {
"gpio-line-names",
Package () {
"pin_0",
"pin_1",
"",
"",
"pin_3",
"pin_4_push_button",
}
}
At runtime, the above declaration produces the following result (using the
"libgpiod" tools)::
root@debian:~# gpioinfo gpiochip4
gpiochip4 - 16 lines:
line 0: "pin_0" unused input active-high
line 1: "pin_1" unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
line 4: "pin_3" unused input active-high
line 5: "pin_4_push_button" unused input active-high
line 6: unnamed unused input active-high
line 7 unnamed unused input active-high
line 8: unnamed unused input active-high
line 9: unnamed unused input active-high
line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: unnamed unused input active-high
line 13: unnamed unused input active-high
line 14: unnamed unused input active-high
line 15: unnamed unused input active-high
root@debian:~# gpiofind pin_4_push_button
gpiochip4 5
root@debian:~#
Another example::
Package () {
"gpio-line-names",
......
......@@ -117,13 +117,6 @@ static inline bool __acpi_aml_busy(void)
return false;
}
static inline bool __acpi_aml_opened(void)
{
if (acpi_aml_io.flags & ACPI_AML_OPEN)
return true;
return false;
}
static inline bool __acpi_aml_used(void)
{
return acpi_aml_io.usages ? true : false;
......
......@@ -151,11 +151,7 @@ void __init acpi_watchdog_init(void)
found = false;
resource_list_for_each_entry(rentry, &resource_list) {
if (rentry->res->flags == res.flags &&
resource_overlaps(rentry->res, &res)) {
if (res.start < rentry->res->start)
rentry->res->start = res.start;
if (res.end > rentry->res->end)
rentry->res->end = res.end;
resource_union(rentry->res, &res, rentry->res)) {
found = true;
break;
}
......
......@@ -13,7 +13,7 @@
/*
* Common set of includes for all ACPICA source files.
* We put them here because we don't want to duplicate them
* in the the source code again and again.
* in the source code again and again.
*
* Note: The order of these include files is important.
*/
......
......@@ -21,7 +21,8 @@ extern u8 acpi_gbl_default_address_spaces[];
/* Local prototypes */
static void
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node,
acpi_adr_space_type space_id);
static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
......@@ -684,10 +685,12 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL,
&info, NULL);
/* Special case for EC: handle "orphan" _REG methods with no region */
if (space_id == ACPI_ADR_SPACE_EC) {
acpi_ev_orphan_ec_reg_method(node);
/*
* Special case for EC and GPIO: handle "orphan" _REG methods with
* no region.
*/
if (space_id == ACPI_ADR_SPACE_EC || space_id == ACPI_ADR_SPACE_GPIO) {
acpi_ev_execute_orphan_reg_method(node, space_id);
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES,
......@@ -760,31 +763,28 @@ acpi_ev_reg_run(acpi_handle obj_handle,
/*******************************************************************************
*
* FUNCTION: acpi_ev_orphan_ec_reg_method
* FUNCTION: acpi_ev_execute_orphan_reg_method
*
* PARAMETERS: ec_device_node - Namespace node for an EC device
* PARAMETERS: device_node - Namespace node for an ACPI device
* space_id - The address space ID
*
* RETURN: None
*
* DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
* DESCRIPTION: Execute an "orphan" _REG method that appears under an ACPI
* device. This is a _REG method that has no corresponding region
* within the EC device scope. The orphan _REG method appears to
* have been enabled by the description of the ECDT in the ACPI
* specification: "The availability of the region space can be
* detected by providing a _REG method object underneath the
* Embedded Controller device."
*
* To quickly access the EC device, we use the ec_device_node used
* during EC handler installation. Otherwise, we would need to
* perform a time consuming namespace walk, executing _HID
* methods to find the EC device.
* within the device's scope. ACPI tables depending on these
* "orphan" _REG methods have been seen for both EC and GPIO
* Operation Regions. Presumably the Windows ACPI implementation
* always calls the _REG method independent of the presence of
* an actual Operation Region with the correct address space ID.
*
* MUTEX: Assumes the namespace is locked
*
******************************************************************************/
static void
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node,
acpi_adr_space_type space_id)
{
acpi_handle reg_method;
struct acpi_namespace_node *next_node;
......@@ -792,9 +792,9 @@ acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
struct acpi_object_list args;
union acpi_object objects[2];
ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
ACPI_FUNCTION_TRACE(ev_execute_orphan_reg_method);
if (!ec_device_node) {
if (!device_node) {
return_VOID;
}
......@@ -804,7 +804,7 @@ acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
/* Get a handle to a _REG method immediately under the EC device */
status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method);
status = acpi_get_handle(device_node, METHOD_NAME__REG, &reg_method);
if (ACPI_FAILURE(status)) {
goto exit; /* There is no _REG method present */
}
......@@ -816,23 +816,23 @@ acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
* with other space IDs to be present; but the code below will then
* execute the _REG method with the embedded_control space_ID argument.
*/
next_node = acpi_ns_get_next_node(ec_device_node, NULL);
next_node = acpi_ns_get_next_node(device_node, NULL);
while (next_node) {
if ((next_node->type == ACPI_TYPE_REGION) &&
(next_node->object) &&
(next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
(next_node->object->region.space_id == space_id)) {
goto exit; /* Do not execute the _REG */
}
next_node = acpi_ns_get_next_node(ec_device_node, next_node);
next_node = acpi_ns_get_next_node(device_node, next_node);
}
/* Evaluate the _REG(embedded_control,Connect) method */
/* Evaluate the _REG(space_id,Connect) method */
args.count = 2;
args.pointer = objects;
objects[0].type = ACPI_TYPE_INTEGER;
objects[0].integer.value = ACPI_ADR_SPACE_EC;
objects[0].integer.value = space_id;
objects[1].type = ACPI_TYPE_INTEGER;
objects[1].integer.value = ACPI_REG_CONNECT;
......
......@@ -71,11 +71,13 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node,
acpi_status status;
const union acpi_predefined_info *predefined;
ACPI_FUNCTION_TRACE(ns_check_return_value);
/* If not a predefined name, we cannot validate the return object */
predefined = info->predefined;
if (!predefined) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/*
......@@ -83,7 +85,7 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node,
* validate the return object
*/
if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/*
......@@ -102,7 +104,7 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node,
if (acpi_gbl_disable_auto_repair ||
(!predefined->info.expected_btypes) ||
(predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/*
......@@ -163,7 +165,7 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node,
node->flags |= ANOBJ_EVALUATED;
}
return (status);
return_ACPI_STATUS(status);
}
/*******************************************************************************
......
......@@ -59,7 +59,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
u32 count;
u32 i;
ACPI_FUNCTION_NAME(ns_check_package);
ACPI_FUNCTION_TRACE(ns_check_package);
/* The package info for this name is in the next table entry */
......@@ -88,14 +88,14 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
*/
if (!count) {
if (package->ret_info.type == ACPI_PTYPE1_VAR) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
info->node_flags,
"Return Package has no elements (empty)"));
return (AE_AML_OPERAND_VALUE);
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
}
/*
......@@ -152,7 +152,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
package->ret_info.
object_type1, i);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
elements++;
......@@ -186,7 +186,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
object_type[i],
i);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
} else {
/* These are the optional package elements */
......@@ -198,7 +198,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
tail_object_type,
i);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
}
......@@ -214,7 +214,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
elements++;
......@@ -234,7 +234,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
/*
......@@ -279,7 +279,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
acpi_ns_wrap_with_package(info, return_object,
return_object_ptr);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
/* Update locals to point to the new package (of 1 element) */
......@@ -316,7 +316,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
package->ret_info.
object_type1, 0);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
/* Validate length of the UUID buffer */
......@@ -326,14 +326,14 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
info->full_pathname,
info->node_flags,
"Invalid length for UUID Buffer"));
return (AE_AML_OPERAND_VALUE);
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
}
status = acpi_ns_check_object_type(info, elements + 1,
package->ret_info.
object_type2, 0);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
elements += 2;
......@@ -350,10 +350,10 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
"Invalid internal return type in table entry: %X",
package->ret_info.type));
return (AE_AML_INTERNAL);
return_ACPI_STATUS(AE_AML_INTERNAL);
}
return (status);
return_ACPI_STATUS(status);
package_too_small:
......@@ -363,7 +363,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
"Return Package is too small - found %u elements, expected %u",
count, expected_count));
return (AE_AML_OPERAND_VALUE);
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
}
/*******************************************************************************
......@@ -708,6 +708,8 @@ acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
acpi_status status;
u32 i;
ACPI_FUNCTION_TRACE(ns_check_package_elements);
/*
* Up to two groups of package elements are supported by the data
* structure. All elements in each group must be of the same type.
......@@ -717,7 +719,7 @@ acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
status = acpi_ns_check_object_type(info, this_element,
type1, i + start_index);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
this_element++;
......@@ -728,11 +730,11 @@ acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
type2,
(i + count1 + start_index));
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
this_element++;
}
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
......@@ -155,15 +155,17 @@ acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
const struct acpi_repair_info *predefined;
acpi_status status;
ACPI_FUNCTION_TRACE(ns_complex_repairs);
/* Check if this name is in the list of repairable names */
predefined = acpi_ns_match_complex_repair(node);
if (!predefined) {
return (validate_status);
return_ACPI_STATUS(validate_status);
}
status = predefined->repair_function(info, return_object_ptr);
return (status);
return_ACPI_STATUS(status);
}
/******************************************************************************
......@@ -344,17 +346,19 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
u16 original_ref_count;
u32 i;
ACPI_FUNCTION_TRACE(ns_repair_CID);
/* Check for _CID as a simple string */
if (return_object->common.type == ACPI_TYPE_STRING) {
status = acpi_ns_repair_HID(info, return_object_ptr);
return (status);
return_ACPI_STATUS(status);
}
/* Exit if not a Package */
if (return_object->common.type != ACPI_TYPE_PACKAGE) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/* Examine each element of the _CID package */
......@@ -366,7 +370,7 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
status = acpi_ns_repair_HID(info, element_ptr);
if (ACPI_FAILURE(status)) {
return (status);
return_ACPI_STATUS(status);
}
if (original_element != *element_ptr) {
......@@ -380,7 +384,7 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
element_ptr++;
}
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/******************************************************************************
......@@ -491,16 +495,15 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
union acpi_operand_object *new_string;
char *source;
char *dest;
char *source;
ACPI_FUNCTION_NAME(ns_repair_HID);
/* We only care about string _HID objects (not integers) */
if (return_object->common.type != ACPI_TYPE_STRING) {
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
if (return_object->string.length == 0) {
......@@ -511,14 +514,7 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info,
/* Return AE_OK anyway, let driver handle it */
info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
/* It is simplest to always create a new string object */
new_string = acpi_ut_create_string_object(return_object->string.length);
if (!new_string) {
return (AE_NO_MEMORY);
return_ACPI_STATUS(AE_OK);
}
/*
......@@ -530,7 +526,7 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info,
source = return_object->string.pointer;
if (*source == '*') {
source++;
new_string->string.length--;
return_object->string.length--;
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Removed invalid leading asterisk\n",
......@@ -545,13 +541,12 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info,
* "NNNN####" where N is an uppercase letter or decimal digit, and
* # is a hex digit.
*/
for (dest = new_string->string.pointer; *source; dest++, source++) {
for (dest = return_object->string.pointer; *source; dest++, source++) {
*dest = (char)toupper((int)*source);
}
return_object->string.pointer[return_object->string.length] = 0;
acpi_ut_remove_reference(return_object);
*return_object_ptr = new_string;
return (AE_OK);
return_ACPI_STATUS(AE_OK);
}
/******************************************************************************
......
......@@ -287,7 +287,7 @@ struct apei_res {
};
/* Collect all resources requested, to avoid conflict */
struct apei_resources apei_resources_all = {
static struct apei_resources apei_resources_all = {
.iomem = LIST_HEAD_INIT(apei_resources_all.iomem),
.ioport = LIST_HEAD_INIT(apei_resources_all.ioport),
};
......
......@@ -169,7 +169,7 @@ struct acpi_ec_query {
};
static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
static void advance_transaction(struct acpi_ec *ec);
static void advance_transaction(struct acpi_ec *ec, bool interrupt);
static void acpi_ec_event_handler(struct work_struct *work);
static void acpi_ec_event_processor(struct work_struct *work);
......@@ -335,12 +335,12 @@ static const char *acpi_ec_cmd_string(u8 cmd)
* GPE Registers
* -------------------------------------------------------------------------- */
static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
static inline bool acpi_ec_gpe_status_set(struct acpi_ec *ec)
{
acpi_event_status gpe_status = 0;
(void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
return (gpe_status & ACPI_EVENT_FLAG_STATUS_SET) ? true : false;
return !!(gpe_status & ACPI_EVENT_FLAG_STATUS_SET);
}
static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
......@@ -351,14 +351,14 @@ static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
BUG_ON(ec->reference_count < 1);
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
}
if (acpi_ec_is_gpe_raised(ec)) {
if (acpi_ec_gpe_status_set(ec)) {
/*
* On some platforms, EN=1 writes cannot trigger GPE. So
* software need to manually trigger a pseudo GPE event on
* EN=1 writes.
*/
ec_dbg_raw("Polling quirk");
advance_transaction(ec);
advance_transaction(ec, false);
}
}
......@@ -372,23 +372,6 @@ static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
}
}
static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
{
/*
* GPE STS is a W1C register, which means:
* 1. Software can clear it without worrying about clearing other
* GPEs' STS bits when the hardware sets them in parallel.
* 2. As long as software can ensure only clearing it when it is
* set, hardware won't set it in parallel.
* So software can clear GPE in any contexts.
* Warning: do not move the check into advance_transaction() as the
* EC commands will be sent without GPE raised.
*/
if (!acpi_ec_is_gpe_raised(ec))
return;
acpi_clear_gpe(NULL, ec->gpe);
}
/* --------------------------------------------------------------------------
* Transaction Management
* -------------------------------------------------------------------------- */
......@@ -488,7 +471,7 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
* Unconditionally invoke this once after enabling the event
* handling mechanism to detect the pending events.
*/
advance_transaction(ec);
advance_transaction(ec, false);
}
static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
......@@ -632,24 +615,41 @@ static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long f
}
}
static void advance_transaction(struct acpi_ec *ec)
static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t)
{
struct transaction *t;
u8 status;
if (t->irq_count < ec_storm_threshold)
++t->irq_count;
/* Trigger if the threshold is 0 too. */
if (t->irq_count == ec_storm_threshold)
acpi_ec_mask_events(ec);
}
static void advance_transaction(struct acpi_ec *ec, bool interrupt)
{
struct transaction *t = ec->curr;
bool wakeup = false;
u8 status;
ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
ec_dbg_stm("%s (%d)", in_interrupt() ? "IRQ" : "TASK",
smp_processor_id());
/*
* By always clearing STS before handling all indications, we can
* ensure a hardware STS 0->1 change after this clearing can always
* trigger a GPE interrupt.
* Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
* changes to always trigger a GPE interrupt.
*
* GPE STS is a W1C register, which means:
*
* 1. Software can clear it without worrying about clearing the other
* GPEs' STS bits when the hardware sets them in parallel.
*
* 2. As long as software can ensure only clearing it when it is set,
* hardware won't set it in parallel.
*/
if (ec->gpe >= 0)
acpi_ec_clear_gpe(ec);
if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
acpi_clear_gpe(NULL, ec->gpe);
status = acpi_ec_read_status(ec);
t = ec->curr;
/*
* Another IRQ or a guarded polling mode advancement is detected,
* the next QR_EC submission is then allowed.
......@@ -661,56 +661,43 @@ static void advance_transaction(struct acpi_ec *ec)
clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
acpi_ec_complete_query(ec);
}
if (!t)
goto out;
}
if (!t)
goto err;
if (t->flags & ACPI_EC_COMMAND_POLL) {
if (t->wlen > t->wi) {
if ((status & ACPI_EC_FLAG_IBF) == 0)
if (!(status & ACPI_EC_FLAG_IBF))
acpi_ec_write_data(ec, t->wdata[t->wi++]);
else
goto err;
else if (interrupt && !(status & ACPI_EC_FLAG_SCI))
acpi_ec_spurious_interrupt(ec, t);
} else if (t->rlen > t->ri) {
if ((status & ACPI_EC_FLAG_OBF) == 1) {
if (status & ACPI_EC_FLAG_OBF) {
t->rdata[t->ri++] = acpi_ec_read_data(ec);
if (t->rlen == t->ri) {
ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
wakeup = true;
if (t->command == ACPI_EC_COMMAND_QUERY)
ec_dbg_evt("Command(%s) completed by hardware",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
wakeup = true;
}
} else
goto err;
} else if (t->wlen == t->wi &&
(status & ACPI_EC_FLAG_IBF) == 0) {
} else if (interrupt && !(status & ACPI_EC_FLAG_SCI)) {
acpi_ec_spurious_interrupt(ec, t);
}
} else if (t->wlen == t->wi && !(status & ACPI_EC_FLAG_IBF)) {
ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
wakeup = true;
}
goto out;
} else if (!(status & ACPI_EC_FLAG_IBF)) {
acpi_ec_write_cmd(ec, t->command);
ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
goto out;
}
err:
/*
* If SCI bit is set, then don't think it's a false IRQ
* otherwise will take a not handled IRQ as a false one.
*/
if (!(status & ACPI_EC_FLAG_SCI)) {
if (in_interrupt() && t) {
if (t->irq_count < ec_storm_threshold)
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
acpi_ec_mask_events(ec);
}
}
out:
if (status & ACPI_EC_FLAG_SCI)
acpi_ec_submit_query(ec);
if (wakeup && in_interrupt())
if (wakeup && interrupt)
wake_up(&ec->wait);
}
......@@ -767,7 +754,7 @@ static int ec_poll(struct acpi_ec *ec)
if (!ec_guard(ec))
return 0;
spin_lock_irqsave(&ec->lock, flags);
advance_transaction(ec);
advance_transaction(ec, false);
spin_unlock_irqrestore(&ec->lock, flags);
} while (time_before(jiffies, delay));
pr_debug("controller reset, restart transaction\n");
......@@ -1216,7 +1203,7 @@ static void acpi_ec_check_event(struct acpi_ec *ec)
* taking care of it.
*/
if (!ec->curr)
advance_transaction(ec);
advance_transaction(ec, false);
spin_unlock_irqrestore(&ec->lock, flags);
}
}
......@@ -1259,7 +1246,7 @@ static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
unsigned long flags;
spin_lock_irqsave(&ec->lock, flags);
advance_transaction(ec);
advance_transaction(ec, true);
spin_unlock_irqrestore(&ec->lock, flags);
}
......
......@@ -105,7 +105,8 @@ struct acpi_device_bus_id {
int acpi_device_add(struct acpi_device *device,
void (*release)(struct device *));
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta);
int type, unsigned long long sta,
struct acpi_device_info *info);
int acpi_device_setup_files(struct acpi_device *dev);
void acpi_device_remove_files(struct acpi_device *dev);
void acpi_device_add_finalize(struct acpi_device *device);
......
......@@ -722,9 +722,7 @@ static void acpi_pci_root_validate_resources(struct device *dev,
* our resources no longer match the ACPI _CRS, but
* the kernel resource tree doesn't allow overlaps.
*/
if (resource_overlaps(res1, res2)) {
res2->start = min(res1->start, res2->start);
res2->end = max(res1->end, res2->end);
if (resource_union(res1, res2, res2)) {
dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
res2, res1);
free = true;
......
......@@ -939,7 +939,7 @@ int acpi_add_power_resource(acpi_handle handle)
device = &resource->device;
acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
ACPI_STA_DEFAULT);
ACPI_STA_DEFAULT, NULL);
mutex_init(&resource->resource_lock);
INIT_LIST_HEAD(&resource->list_node);
INIT_LIST_HEAD(&resource->dependents);
......
......@@ -31,7 +31,6 @@
#include <asm/apic.h>
#endif
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
......
......@@ -22,7 +22,6 @@
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_perflib");
......@@ -616,7 +615,6 @@ int acpi_processor_preregister_performance(
continue;
pr->performance = per_cpu_ptr(performance, i);
cpumask_set_cpu(i, pr->performance->shared_cpu_map);
pdomain = &(pr->performance->domain_info);
if (acpi_processor_get_psd(pr->handle, pdomain)) {
retval = -EINVAL;
......
......@@ -19,8 +19,6 @@
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
#ifdef CONFIG_CPU_FREQ
/* If a passive cooling situation is detected, primarily CPUfreq is used, as it
......
......@@ -22,7 +22,6 @@
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling");
......
......@@ -534,7 +534,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
ret = c->preproc(ares, c->preproc_data);
if (ret < 0) {
c->error = ret;
return AE_CTRL_TERMINATE;
return AE_ABORT_METHOD;
} else if (ret > 0) {
return AE_OK;
}
......
......@@ -711,26 +711,4 @@ static struct acpi_driver acpi_sbs_driver = {
},
.drv.pm = &acpi_sbs_pm,
};
static int __init acpi_sbs_init(void)
{
int result = 0;
if (acpi_disabled)
return -ENODEV;
result = acpi_bus_register_driver(&acpi_sbs_driver);
if (result < 0)
return -ENODEV;
return 0;
}
static void __exit acpi_sbs_exit(void)
{
acpi_bus_unregister_driver(&acpi_sbs_driver);
return;
}
module_init(acpi_sbs_init);
module_exit(acpi_sbs_exit);
module_acpi_driver(acpi_sbs_driver);
......@@ -51,8 +51,8 @@ static u64 spcr_uart_addr;
struct acpi_dep_data {
struct list_head node;
acpi_handle master;
acpi_handle slave;
acpi_handle supplier;
acpi_handle consumer;
};
void acpi_scan_lock_acquire(void)
......@@ -719,6 +719,42 @@ int acpi_device_add(struct acpi_device *device,
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
static bool acpi_info_matches_ids(struct acpi_device_info *info,
const char * const ids[])
{
struct acpi_pnp_device_id_list *cid_list = NULL;
int i;
if (!(info->valid & ACPI_VALID_HID))
return false;
if (info->valid & ACPI_VALID_CID)
cid_list = &info->compatible_id_list;
for (i = 0; ids[i]; i++) {
int j;
if (!strcmp(info->hardware_id.string, ids[i]))
return true;
if (!cid_list)
continue;
for (j = 0; j < cid_list->count; j++) {
if (!strcmp(cid_list->ids[j].string, ids[i]))
return true;
}
}
return false;
}
/* List of HIDs for which we ignore matching ACPI devices, when checking _DEP lists. */
static const char * const acpi_ignore_dep_ids[] = {
"PNP0D80", /* Windows-compatible System Power Management Controller */
NULL
};
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
struct acpi_device *device = NULL;
......@@ -1236,10 +1272,8 @@ static bool acpi_object_is_system_bus(acpi_handle handle)
}
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
int device_type)
int device_type, struct acpi_device_info *info)
{
acpi_status status;
struct acpi_device_info *info;
struct acpi_pnp_device_id_list *cid_list;
int i;
......@@ -1250,8 +1284,7 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
break;
}
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
if (!info) {
pr_err(PREFIX "%s: Error reading device info\n",
__func__);
return;
......@@ -1276,8 +1309,6 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
if (info->valid & ACPI_VALID_CLS)
acpi_add_id(pnp, info->class_code.string);
kfree(info);
/*
* Some devices don't reliably have _HIDs & _CIDs, so add
* synthetic HIDs to make sure drivers can find them.
......@@ -1583,7 +1614,8 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
}
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta)
int type, unsigned long long sta,
struct acpi_device_info *info)
{
INIT_LIST_HEAD(&device->pnp.ids);
device->device_type = type;
......@@ -1592,7 +1624,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_set_pnp_ids(handle, &device->pnp, type, info);
acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
......@@ -1620,14 +1652,20 @@ static int acpi_add_single_object(struct acpi_device **child,
int result;
struct acpi_device *device;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info = NULL;
if (handle != ACPI_ROOT_OBJECT && type == ACPI_BUS_TYPE_DEVICE)
acpi_get_object_info(handle, &info);
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
printk(KERN_ERR PREFIX "Memory allocation error\n");
kfree(info);
return -ENOMEM;
}
acpi_init_device_object(device, handle, type, sta);
acpi_init_device_object(device, handle, type, sta, info);
kfree(info);
/*
* For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so
* that we can call acpi_bus_get_status() and use its quirk handling.
......@@ -1833,13 +1871,7 @@ static void acpi_device_dep_initialize(struct acpi_device *adev)
continue;
}
/*
* Skip the dependency of Windows System Power
* Management Controller
*/
skip = info->valid & ACPI_VALID_HID &&
!strcmp(info->hardware_id.string, "INT3396");
skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
kfree(info);
if (skip)
......@@ -1849,8 +1881,8 @@ static void acpi_device_dep_initialize(struct acpi_device *adev)
if (!dep)
return;
dep->master = dep_devices.handles[i];
dep->slave = adev->handle;
dep->supplier = dep_devices.handles[i];
dep->consumer = adev->handle;
adev->dep_unmet++;
mutex_lock(&acpi_dep_list_lock);
......@@ -2026,8 +2058,8 @@ void acpi_walk_dep_device_list(acpi_handle handle)
mutex_lock(&acpi_dep_list_lock);
list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
if (dep->master == handle) {
acpi_bus_get_device(dep->slave, &adev);
if (dep->supplier == handle) {
acpi_bus_get_device(dep->consumer, &adev);
if (!adev)
continue;
......
......@@ -40,6 +40,4 @@ static struct acpi_driver acpi_tiny_power_button_driver = {
},
};
module_driver(acpi_tiny_power_button_driver,
acpi_bus_register_driver,
acpi_bus_unregister_driver);
module_acpi_driver(acpi_tiny_power_button_driver);
......@@ -140,6 +140,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
{
.callback = video_detect_force_vendor,
.ident = "GIGABYTE GB-BXBT-2807",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
},
},
{
.ident = "Sony VPCEH3U1E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
......
......@@ -64,14 +64,14 @@
-------------------------------------------------------------------------- */
/* ACPI PCI Interrupt Link (pci_link.c) */
/* ACPI PCI Interrupt Link */
int acpi_irq_penalty_init(void);
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
int *polarity, char **name);
int acpi_pci_link_free_irq(acpi_handle handle);
/* ACPI PCI Device Binding (pci_bind.c) */
/* ACPI PCI Device Binding */
struct pci_bus;
......@@ -94,14 +94,6 @@ void pci_acpi_crs_quirks(void);
static inline void pci_acpi_crs_quirks(void) { }
#endif
/* --------------------------------------------------------------------------
Processor
-------------------------------------------------------------------------- */
#define ACPI_PROCESSOR_LIMIT_NONE 0x00
#define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01
#define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02
/*--------------------------------------------------------------------------
Dock Station
-------------------------------------------------------------------------- */
......
......@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
#define ACPI_CA_VERSION 0x20200925
#define ACPI_CA_VERSION 0x20201113
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
......
......@@ -39,6 +39,7 @@
/* NVDIMM - NFIT table */
#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
#define UUID_VOLATILE_MEMORY "7305944f-fdda-44e3-b16c-3f22d252e5d0"
#define UUID_PERSISTENT_MEMORY "66f0d379-b4f3-4074-ac43-0d3318b78cdb"
#define UUID_CONTROL_REGION "92f701f6-13b4-405d-910b-299367e8234c"
......@@ -47,6 +48,10 @@
#define UUID_VOLATILE_VIRTUAL_CD "3d5abd30-4175-87ce-6d64-d2ade523c4bb"
#define UUID_PERSISTENT_VIRTUAL_DISK "5cea02c9-4d07-69d3-269f-4496fbe096f9"
#define UUID_PERSISTENT_VIRTUAL_CD "08018188-42cd-bb48-100f-5387d53ded3d"
#define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05"
#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
#define UUID_NFIT_DIMM_N_HYPERV "5746c5f2-a9a2-4264-ad0e-e4ddc9e09e80"
/* Processor Properties (ACPI 6.2) */
......
......@@ -10,9 +10,10 @@
#define _LINUX_IOPORT_H
#ifndef __ASSEMBLY__
#include <linux/bits.h>
#include <linux/compiler.h>
#include <linux/minmax.h>
#include <linux/types.h>
#include <linux/bits.h>
/*
* Resources are tree-like, allowing
* nesting etc..
......@@ -229,6 +230,31 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2)
return r1->start <= r2->start && r1->end >= r2->end;
}
/* True if any part of r1 overlaps r2 */
static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
{
return r1->start <= r2->end && r1->end >= r2->start;
}
static inline bool
resource_intersection(struct resource *r1, struct resource *r2, struct resource *r)
{
if (!resource_overlaps(r1, r2))
return false;
r->start = max(r1->start, r2->start);
r->end = min(r1->end, r2->end);
return true;
}
static inline bool
resource_union(struct resource *r1, struct resource *r2, struct resource *r)
{
if (!resource_overlaps(r1, r2))
return false;
r->start = min(r1->start, r2->start);
r->end = max(r1->end, r2->end);
return true;
}
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
......@@ -296,12 +322,6 @@ extern int
walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end,
void *arg, int (*func)(struct resource *, void *));
/* True if any part of r1 overlaps r2 */
static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
{
return (r1->start <= r2->end && r1->end >= r2->start);
}
struct resource *devm_request_free_mem_region(struct device *dev,
struct resource *base, unsigned long size);
struct resource *request_free_mem_region(struct resource *base,
......
......@@ -122,6 +122,7 @@ obj-$(CONFIG_HAS_IOMEM) += iomem.o
obj-$(CONFIG_RSEQ) += rseq.o
obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o
obj-$(CONFIG_RESOURCE_KUNIT_TEST) += resource_kunit.o
obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
CFLAGS_stackleak.o += $(DISABLE_STACKLEAK_PLUGIN)
......
......@@ -557,13 +557,13 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags,
}
read_unlock(&resource_lock);
if (other == 0)
return type ? REGION_INTERSECTS : REGION_DISJOINT;
if (type == 0)
return REGION_DISJOINT;
if (type)
return REGION_MIXED;
if (other == 0)
return REGION_INTERSECTS;
return REGION_DISJOINT;
return REGION_MIXED;
}
EXPORT_SYMBOL_GPL(region_intersects);
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Test cases for API provided by resource.c and ioport.h
*/
#include <kunit/test.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/string.h>
#define R0_START 0x0000
#define R0_END 0xffff
#define R1_START 0x1234
#define R1_END 0x2345
#define R2_START 0x4567
#define R2_END 0x5678
#define R3_START 0x6789
#define R3_END 0x789a
#define R4_START 0x2000
#define R4_END 0x7000
static struct resource r0 = { .start = R0_START, .end = R0_END };
static struct resource r1 = { .start = R1_START, .end = R1_END };
static struct resource r2 = { .start = R2_START, .end = R2_END };
static struct resource r3 = { .start = R3_START, .end = R3_END };
static struct resource r4 = { .start = R4_START, .end = R4_END };
struct result {
struct resource *r1;
struct resource *r2;
struct resource r;
bool ret;
};
static struct result results_for_union[] = {
{
.r1 = &r1, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true,
}, {
.r1 = &r3, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true,
}, {
.r1 = &r4, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r1, .ret = false,
}, {
.r1 = &r3, .r2 = &r1, .ret = false,
}, {
.r1 = &r4, .r2 = &r1, .r.start = R1_START, .r.end = R4_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r3, .ret = false,
}, {
.r1 = &r2, .r2 = &r4, .r.start = R4_START, .r.end = R4_END, .ret = true,
}, {
.r1 = &r3, .r2 = &r4, .r.start = R4_START, .r.end = R3_END, .ret = true,
},
};
static struct result results_for_intersection[] = {
{
.r1 = &r1, .r2 = &r0, .r.start = R1_START, .r.end = R1_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r0, .r.start = R2_START, .r.end = R2_END, .ret = true,
}, {
.r1 = &r3, .r2 = &r0, .r.start = R3_START, .r.end = R3_END, .ret = true,
}, {
.r1 = &r4, .r2 = &r0, .r.start = R4_START, .r.end = R4_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r1, .ret = false,
}, {
.r1 = &r3, .r2 = &r1, .ret = false,
}, {
.r1 = &r4, .r2 = &r1, .r.start = R4_START, .r.end = R1_END, .ret = true,
}, {
.r1 = &r2, .r2 = &r3, .ret = false,
}, {
.r1 = &r2, .r2 = &r4, .r.start = R2_START, .r.end = R2_END, .ret = true,
}, {
.r1 = &r3, .r2 = &r4, .r.start = R3_START, .r.end = R4_END, .ret = true,
},
};
static void resource_do_test(struct kunit *test, bool ret, struct resource *r,
bool exp_ret, struct resource *exp_r,
struct resource *r1, struct resource *r2)
{
KUNIT_EXPECT_EQ_MSG(test, ret, exp_ret, "Resources %pR %pR", r1, r2);
KUNIT_EXPECT_EQ_MSG(test, r->start, exp_r->start, "Start elements are not equal");
KUNIT_EXPECT_EQ_MSG(test, r->end, exp_r->end, "End elements are not equal");
}
static void resource_do_union_test(struct kunit *test, struct result *r)
{
struct resource result;
bool ret;
memset(&result, 0, sizeof(result));
ret = resource_union(r->r1, r->r2, &result);
resource_do_test(test, ret, &result, r->ret, &r->r, r->r1, r->r2);
memset(&result, 0, sizeof(result));
ret = resource_union(r->r2, r->r1, &result);
resource_do_test(test, ret, &result, r->ret, &r->r, r->r2, r->r1);
}
static void resource_test_union(struct kunit *test)
{
struct result *r = results_for_union;
unsigned int i = 0;
do {
resource_do_union_test(test, &r[i]);
} while (++i < ARRAY_SIZE(results_for_union));
}
static void resource_do_intersection_test(struct kunit *test, struct result *r)
{
struct resource result;
bool ret;
memset(&result, 0, sizeof(result));
ret = resource_intersection(r->r1, r->r2, &result);
resource_do_test(test, ret, &result, r->ret, &r->r, r->r1, r->r2);
memset(&result, 0, sizeof(result));
ret = resource_intersection(r->r2, r->r1, &result);
resource_do_test(test, ret, &result, r->ret, &r->r, r->r2, r->r1);
}
static void resource_test_intersection(struct kunit *test)
{
struct result *r = results_for_intersection;
unsigned int i = 0;
do {
resource_do_intersection_test(test, &r[i]);
} while (++i < ARRAY_SIZE(results_for_intersection));
}
static struct kunit_case resource_test_cases[] = {
KUNIT_CASE(resource_test_union),
KUNIT_CASE(resource_test_intersection),
{}
};
static struct kunit_suite resource_test_suite = {
.name = "resource",
.test_cases = resource_test_cases,
};
kunit_test_suite(resource_test_suite);
MODULE_LICENSE("GPL");
......@@ -2257,6 +2257,17 @@ config BITFIELD_KUNIT
If unsure, say N.
config RESOURCE_KUNIT_TEST
tristate "KUnit test for resource API"
depends on KUNIT
help
This builds the resource API unit test.
Tests the logic of API provided by resource.c and ioport.h.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
config SYSCTL_KUNIT_TEST
tristate "KUnit test for sysctl" if !KUNIT_ALL_TESTS
depends on KUNIT
......
......@@ -22,17 +22,6 @@ void catpt_sram_free(struct resource *sram);
struct resource *
catpt_request_region(struct resource *root, resource_size_t size);
static inline bool catpt_resource_overlapping(struct resource *r1,
struct resource *r2,
struct resource *ret)
{
if (!resource_overlaps(r1, r2))
return false;
ret->start = max(r1->start, r2->start);
ret->end = min(r1->end, r2->end);
return true;
}
struct catpt_ipc_msg {
union {
u32 header;
......
......@@ -267,7 +267,7 @@ static int catpt_restore_fwimage(struct catpt_dev *cdev,
r2.start = off;
r2.end = r2.start + info->size - 1;
if (!catpt_resource_overlapping(&r2, &r1, &common))
if (!resource_intersection(&r2, &r1, &common))
continue;
/* calculate start offset of common data area */
off = common.start - r1.start;
......
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