summarylogtreecommitdiffstats
path: root/0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch
diff options
context:
space:
mode:
Diffstat (limited to '0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch')
-rw-r--r--0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch154
1 files changed, 154 insertions, 0 deletions
diff --git a/0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch b/0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch
new file mode 100644
index 000000000000..605f782def8f
--- /dev/null
+++ b/0002-ACPI-EC-fix-ECDT-probe-ordering-issues.patch
@@ -0,0 +1,154 @@
+From 986c9179841b0607302fd5cbf83d5b745cf2a7e6 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 4 Jul 2022 11:38:10 +0200
+Subject: [PATCH 2/9] ACPI: EC: fix ECDT probe ordering issues
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ACPI-2.0 says that the EC OpRegion handler must be available immediately
+(like the standard default OpRegion handlers):
+
+Quoting from the ACPI spec version 6.3: "6.5.4 _REG (Region) ...
+2. OSPM must make Embedded Controller operation regions, accessed via
+the Embedded Controllers described in ECDT, available before executing
+any control method. These operation regions may become inaccessible
+after OSPM runs _REG(EmbeddedControl, 0)."
+
+So acpi_bus_init() calls acpi_ec_ecdt_probe(), which calls
+acpi_install_address_space_handler() to install the EC's OpRegion
+handler, early on.
+
+This not only installs the OpRegion handler, but also calls the EC's
+_REG method. The _REG method call is a problem because it may rely on
+initialization done by the _INI methods of one of the PCI / _SB root devs,
+see for example: https://bugzilla.kernel.org/show_bug.cgi?id=214899 .
+
+Generally speaking _REG methods are executed when the ACPI-device they
+are part of has a driver bound to it. Where as _INI methods must be
+executed at table load time (according to the spec). The problem here
+is that the early acpi_install_address_space_handler() call causes
+the _REG handler to run too early.
+
+To allow fixing this the ACPICA code now allows to split the OpRegion
+handler installation and the executing of _REG into 2 separate steps.
+
+This commit uses this ACPICA functionality to fix the EC probe ordering
+by delaying the executing of _REG for ECDT described ECs till the matching
+EC device in the DSDT gets parsed and acpi_ec_add() for it gets called.
+This moves the calling of _REG for the EC on devices with an ECDT to
+the same point in time where it is called on devices without an ECDT table.
+
+BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214899
+Reported-and-tested-by: Johannes Penßel <johannespenssel@posteo.net>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/acpi/ec.c | 33 +++++++++++++++++++++++----------
+ 1 file changed, 23 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index a1b871a418f8..d2ebe14135bd 100644
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -94,6 +94,7 @@ enum {
+ EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
+ EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
+ EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
++ EC_FLAGS_EC_REG_CALLED, /* OpReg ACPI _REG method called */
+ EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
+ EC_FLAGS_STARTED, /* Driver is started */
+ EC_FLAGS_STOPPED, /* Driver is stopped */
+@@ -1459,6 +1460,7 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
+ * ec_install_handlers - Install service callbacks and register query methods.
+ * @ec: Target EC.
+ * @device: ACPI device object corresponding to @ec.
++ * @call_reg: If _REG should be called to notify OpRegion availability
+ *
+ * Install a handler for the EC address space type unless it has been installed
+ * already. If @device is not NULL, also look for EC query methods in the
+@@ -1471,7 +1473,8 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
+ * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
+ * or 0 (success) otherwise.
+ */
+-static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
++static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
++ bool call_reg)
+ {
+ acpi_status status;
+
+@@ -1479,10 +1482,11 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
+
+ if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
+ acpi_ec_enter_noirq(ec);
+- status = acpi_install_address_space_handler(ec->handle,
+- ACPI_ADR_SPACE_EC,
+- &acpi_ec_space_handler,
+- NULL, ec);
++ status = acpi_install_address_space_handler_flags(ec->handle,
++ ACPI_ADR_SPACE_EC,
++ &acpi_ec_space_handler,
++ NULL, ec,
++ ACPI_NO_EXEC__REG);
+ if (ACPI_FAILURE(status)) {
+ acpi_ec_stop(ec, false);
+ return -ENODEV;
+@@ -1490,6 +1494,15 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
+ set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
+ }
+
++ if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) {
++ acpi_install_address_space_handler_flags(ec->handle,
++ ACPI_ADR_SPACE_EC,
++ &acpi_ec_space_handler,
++ NULL, ec,
++ ACPI_NO_INSTALL_SPACE_HANDLER);
++ set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags);
++ }
++
+ if (!device)
+ return 0;
+
+@@ -1575,11 +1588,11 @@ static void ec_remove_handlers(struct acpi_ec *ec)
+ }
+ }
+
+-static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device)
++static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool call_reg)
+ {
+ int ret;
+
+- ret = ec_install_handlers(ec, device);
++ ret = ec_install_handlers(ec, device, call_reg);
+ if (ret)
+ return ret;
+
+@@ -1641,7 +1654,7 @@ static int acpi_ec_add(struct acpi_device *device)
+ }
+ }
+
+- ret = acpi_ec_setup(ec, device);
++ ret = acpi_ec_setup(ec, device, true);
+ if (ret)
+ goto err;
+
+@@ -1761,7 +1774,7 @@ void __init acpi_ec_dsdt_probe(void)
+ * At this point, the GPE is not fully initialized, so do not to
+ * handle the events.
+ */
+- ret = acpi_ec_setup(ec, NULL);
++ ret = acpi_ec_setup(ec, NULL, true);
+ if (ret) {
+ acpi_ec_free(ec);
+ return;
+@@ -1973,7 +1986,7 @@ void __init acpi_ec_ecdt_probe(void)
+ * At this point, the namespace is not initialized, so do not find
+ * the namespace objects, or handle the events.
+ */
+- ret = acpi_ec_setup(ec, NULL);
++ ret = acpi_ec_setup(ec, NULL, false);
+ if (ret) {
+ acpi_ec_free(ec);
+ goto out;
+--
+2.37.1
+