diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4 --- 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 @@ .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 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -55,6 +55,8 @@ #if defined(__i386__) || defined(__amd64__) #include #include +#include +#include #endif #include #include @@ -297,6 +299,10 @@ 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 @@ 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 --- a/sys/dev/acpica/acpi_resource.c +++ b/sys/dev/acpica/acpi_resource.c @@ -159,14 +159,11 @@ } #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 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -234,6 +234,18 @@ #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.