acpi: Narrow workaround for broken interrupt settings on x86

Commit 9a7bf07ccd 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)
This commit is contained in:
John Baldwin 2024-07-15 12:13:08 -07:00
parent 12f2e9525b
commit 4ba4cfaf9f
4 changed files with 42 additions and 8 deletions

View file

@ -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

View file

@ -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>
@ -289,6 +291,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
@ -601,6 +607,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.

View file

@ -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) ?

View file

@ -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.