Skip to content

ASRock TURIND8UD-2T/X550: ttyS2 at 0x3e8 is assigned IRQ 4 but no interrupt arrives #1929

Description

@m-iwanicki

Component

Dasharo firmware

Device

ASRock Rack TURIND8UD-2T/X550

Dasharo version

v0.9.0 (UEFI & LinuxBoot)

Dasharo Tools Suite version

No response

Test case ID

No response

Brief summary

The UART A of the Nuvoton NCT6796D behind eSPI 0, which the operating system
enumerates as /dev/ttyS2 at I/O 0x3e8, is assigned IRQ 4 and that interrupt
never arrives. Kernel printk reaches the header, because it polls the line
status register, but any userspace read or write stalls after the first FIFO
burst. console=ttyS2,115200 in the LinuxBoot command line stops the boot
before the distribution starts, same when added to Ubuntu

The port itself is fine. Once the interrupt is taken out of the path with
setserial /dev/ttyS2 irq 0, the same port runs at full line rate in both
directions, 11520 bytes in 4.357 s at 115200.

Seen on both Dasharo (coreboot+UEFI) and Dasharo (coreboot+LinuxBoot).

How reproducible

100%

How to reproduce

Attach a terminal to the UART1 header at 115200 8N1.

  1. Check how firmware left the port:

    dmesg | grep ttyS2
    cat /proc/tty/driver/serial

    Expect ttyS2 at I/O 0x3e8 (irq = 4, base_baud = 115200) is a 16550A and
    2: uart:16550A port:000003E8 irq:4.

  2. Exercise the port with the interrupt in play. The cat holds it open so
    the stty settings survive, you can check how many interrupts arrived,
    and the write has to exceed the kernel's one page of transmit buffer to
    mean anything.:

    sudo setserial /dev/ttyS2 irq 4
    sudo sh -c 'cat /dev/ttyS2 > /dev/null &'
    grep -i ttys /proc/interrupts
    sudo stty -F /dev/ttyS2 115200 raw -echo
    time sh -c 'yes uarttest | head -c 11520 | sudo tee /dev/ttyS2 > /dev/null'
    grep -i ttys /proc/interrupts

    Be ready to interrupt the timed write, because it does not return.
    Trying again results in only maybe 4-5 bytes appearing and only after CTRL+C

  3. Repeat the same write with the interrupt out of the path, which shows the
    port itself is healthy:

    # kill cat keeping ttyS2 open
    sudo fuser -k /dev/ttyS2
    sudo setserial /dev/ttyS2 irq 0
    sudo sh -c 'cat /dev/ttyS2 > /dev/null &'
    sudo stty -F /dev/ttyS2 115200 raw -echo
    time sh -c 'yes uarttest | head -c 11520 | sudo tee /dev/ttyS2 > /dev/null'

Expected behavior

The port delivers interrupts on the IRQ that firmware assigned to it, so
userspace transmit and receive work, and console=ttyS2,115200 gives a working
serial console.

Alternatively, if IRQ 4 cannot be delivered on this board, firmware should not
advertise the port as interrupt driven, so the operating system falls back to
polling on its own.

Actual behavior

  • With IRQ 4, about nine uarttest words reach the terminal and then the write
    blocks indefinitely, so the timed write never returns. Interrupting and
    rerunning gets one more burst out, because a fresh open produces a new
    transmit-holding-register-empty transition.
  • /proc/interrupts has no row for ttyS2 at all, even with the cat holding
    the port open.
  • console=ttyS2,115200 on the LinuxBoot command line hangs the boot.
  • console=ttyS2,115200 on Ubuntu command line hangs the boot
  • The same dead interrupt breaks receive, not just transmit. Kernel printk
    gets out because it polls the line status register, but nothing polls for
    incoming bytes, so they sit in the FIFO until it overruns and no read ever
    completes.
  • With irq 0 the same 11520 bytes go out in full, in 4.357 s, and both
    directions work. The extra time over the 1 s of wire time is the polling
    timer, which is what serial8250_timeout predicts.

Screenshots

No response

Additional context

  • Unlike COM1, this port is not shared with the BMC, so nothing on the BMC
    side is involved.
  • It has not been checked against the ASRock vendor host firmware, so whether
    IRQ 4 ever works on this board is still open.
    - vendor firmware doesn't expose
    this uart at all

Solutions you've tried

Four host firmware variants were built and all four fail:

  1. Unmasking the IRQ 4 wire in PM_ESPI_INTR_CTRL at 0xfed80340, which
    reads 0x00ffffff and so masks every eSPI device interrupt. No change on
    its own.
  2. Setting ESPI_RXVW_POLARITY at offset 0xac, which reads 0x0 on both
    eSPI controllers and so inverts every incoming virtual wire, in either
    state on either controller. No difference.
  3. Adding a MADT interrupt source override for IRQ 4 as level triggered
    active low. The MADT today has overrides for source 0 and source 9 only,
    so the operating system uses the ISA default of edge triggered active
    high. With the override the IO-APIC input reads asserted forever, and
    opening the port raises exactly a hundred thousand interrupts that the 8250
    driver does not recognise as its own. The kernel then prints
    irq 4: nobody cared and Disabling IRQ #4, and masks IRQ 4, so the port
    is left with no interrupt at all. Reopening the port re-enables the line
    and the storm repeats.
  4. The same override as level triggered active high. The input reads
    deasserted forever and nothing arrives.

The working configuration today is setserial /dev/ttyS2 irq 0, which puts
the port in polled mode and restores both directions at full rate.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions