git: 17c6c686eda8 - stable/13 - acpi: Narrow workaround for broken interrupt settings on x86

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 23 Jul 2024 13:55:11 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=17c6c686eda814c52218ea6b393c8388bc6bc1b4

commit 17c6c686eda814c52218ea6b393c8388bc6bc1b4
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-07-15 19:13:08 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-07-23 13:29:17 +0000

    acpi: Narrow workaround for broken interrupt settings on x86
    
    Commit 9a7bf07ccdc1 from 2016 introduced a workaround for some broken
    BIOSes that specified active-lo instead of active-hi polarity for ISA
    IRQs for UARTs.  The workaround assumed that edge-sensitive ISA IRQs
    on x86 should always be active-hi.  However, some recent AMD systems
    actually use active-lo edge-sensitive ISA IRQs (and not just for
    UARTs, but also for the keyboard and PS/2 mouse devices) and the
    override causes interrupts to be dropped resulting in boot time hangs,
    non-working keyboards, etc.
    
    Add a hw.acpi.override_isa_irq_polarity tunable (readable as a sysctl
    post-boot) to control this quirk.  It can be set to 1 to force enable
    the override and 0 to disable it.  The log of original message
    mentions an Intel motherboard as the sample case, so default the
    tunable to 1 on systems with an Intel CPU and 0 otherwise.
    
    Special thanks to Matthias Lanter <freebsd@lanter-it.ch> for tracking
    down boot time issues on recent AMD systems to mismatched interrupt
    polarity.
    
    PR:             270707
    Reported by:    aixdroix_OSS@protonmail.com, Michael Dexter
    Reported by:    mfw_burn@pm.me, Hannes Hfauswedell <h2+fbsdports@fsfe.org>
    Reported by:    Matthias Lanter <freebsd@lanter-it.ch>
    Reported by:    William Bulley <web@umich.edu>
    Reviewed by:    imp, emaste
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D45554
    
    (cherry picked from commit 0a34d050ae8ea14feddd3d2a62fd2f612613b2c5)
---
 share/man/man4/acpi.4          |  8 +++++++-
 sys/dev/acpica/acpi.c          | 19 +++++++++++++++++++
 sys/dev/acpica/acpi_resource.c | 11 ++++-------
 sys/dev/acpica/acpivar.h       | 12 ++++++++++++
 4 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4
index 53ed47fdfaee..cdad3ceeedfc 100644
--- a/share/man/man4/acpi.4
+++ b/share/man/man4/acpi.4
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 24, 2021
+.Dd July 15, 2024
 .Dt ACPI 4
 .Os
 .Sh NAME
@@ -256,6 +256,12 @@ is a valid list of two interfaces
 .Qq Li FreeBSD
 and
 .Qq Li Linux .
+.It Va hw.acpi.hw.acpi.override_isa_irq_polarity (x86)
+Forces active-lo polarity for edge-triggered ISA interrupts.
+Some older systems incorrectly specify active-lo polarity for ISA
+interrupts and this override fixes those systems.
+This override is enabled by default on systems with Intel CPUs,
+but can be enabled or disabled by setting the tunable explicitly.
 .It Va hw.acpi.reset_video
 Enables calling the VESA reset BIOS vector on the resume path.
 This can fix some graphics cards that have problems such as LCD white-out
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 1706938e49a3..0dd75166c5d2 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -55,6 +55,8 @@
 #if defined(__i386__) || defined(__amd64__)
 #include <machine/clock.h>
 #include <machine/pci_cfgreg.h>
+#include <x86/cputypes.h>
+#include <x86/x86_var.h>
 #endif
 #include <machine/resource.h>
 #include <machine/bus.h>
@@ -301,6 +303,10 @@ int acpi_susp_bounce;
 SYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW,
     &acpi_susp_bounce, 0, "Don't actually suspend, just test devices.");
 
+#if defined(__amd64__) || defined(__i386__)
+int acpi_override_isa_irq_polarity;
+#endif
+
 /*
  * ACPI standard UUID for Device Specific Data Package
  * "Device Properties UUID for _DSD" Rev. 2.0
@@ -613,6 +619,19 @@ acpi_attach(device_t dev)
 	OID_AUTO, "handle_reboot", CTLFLAG_RW,
 	&sc->acpi_handle_reboot, 0, "Use ACPI Reset Register to reboot");
 
+#if defined(__amd64__) || defined(__i386__)
+    /*
+     * Enable workaround for incorrect ISA IRQ polarity by default on
+     * systems with Intel CPUs.
+     */
+    if (cpu_vendor_id == CPU_VENDOR_INTEL)
+	acpi_override_isa_irq_polarity = 1;
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+	OID_AUTO, "override_isa_irq_polarity", CTLFLAG_RDTUN,
+	&acpi_override_isa_irq_polarity, 0,
+	"Force active-hi polarity for edge-triggered ISA IRQs");
+#endif
+
     /*
      * Default to 1 second before sleeping to give some machines time to
      * stabilize.
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index e81b5ec53f2d..ebfcc7447677 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -159,14 +159,11 @@ acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
     }
 
 #if defined(__amd64__) || defined(__i386__)
-    /*
-     * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
-     * edge-sensitive and active-lo.  However, edge-sensitive IRQs
-     * should be active-hi.  Force IRQs with an ISA IRQ value to be
-     * active-hi instead.
-     */
-    if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
+    if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW &&
+	acpi_override_isa_irq_polarity) {
+	device_printf(dev, "forcing active-hi polarity for IRQ %u\n", irq);
 	pol = ACPI_ACTIVE_HIGH;
+    }
 #endif
     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
 	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 362538e47bfc..2410dcb14993 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -231,6 +231,18 @@ extern int	acpi_quirks;
 #define ACPI_Q_TIMER		(1 << 1)
 #define ACPI_Q_MADT_IRQ0	(1 << 2)
 
+#if defined(__amd64__) || defined(__i386__)
+/*
+ * Certain Intel BIOSes have buggy AML that specify an IRQ that is
+ * edge-sensitive and active-lo.  Normally, edge-sensitive IRQs should
+ * be active-hi.  If this value is non-zero, edge-sensitive ISA IRQs
+ * are forced to be active-hi instead.  At least some AMD systems use
+ * active-lo edge-sensitive ISA IRQs, so this setting is only enabled
+ * by default on systems with Intel CPUs.
+ */
+extern int	acpi_override_isa_irq_polarity;
+#endif
+
 /*
  * Plug and play information for device matching.  Matching table format
  * is compatible with ids parameter of ACPI_ID_PROBE bus method.