aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2024-07-15 19:13:08 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2024-07-15 19:13:51 +0000
commit0a34d050ae8ea14feddd3d2a62fd2f612613b2c5 (patch)
tree43268604868ba77f741f026807615b4b625c69f4
parent3ab5e29778835065d80cbb6610ece981ac65c4c7 (diff)
downloadsrc-0a34d050ae8ea14feddd3d2a62fd2f612613b2c5.tar.gz
src-0a34d050ae8ea14feddd3d2a62fd2f612613b2c5.zip
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
-rw-r--r--share/man/man4/acpi.48
-rw-r--r--sys/dev/acpica/acpi.c19
-rw-r--r--sys/dev/acpica/acpi_resource.c11
-rw-r--r--sys/dev/acpica/acpivar.h12
4 files changed, 42 insertions, 8 deletions
diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4
index 434e97d529f5..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 October 12, 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 24d7027f165d..91a1636f2808 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>
@@ -297,6 +299,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
@@ -611,6 +617,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 87b82a574beb..1257ed30cc65 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 2322ab96014b..a71eb9b47eb7 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -234,6 +234,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.