Skip to content

ASRock TURIND8UD-2T/X550: POST codes never reach the BMC, port 0x80 is decoded on one eSPI controller only #1930

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

No POST code ever reaches the BMC. The onboard two digit code display works,
so the codes are being written, but the BMC's POST code log stays empty for
every boot.

The FCH has two eSPI controllers, each with its own pins and its own decode
register. A device is wired to one of them. On this board the code display is
on eSPI 0 and the BMC is on eSPI 1, and firmware opens the port 0x80 window on
eSPI 0 only, so the cycles never reach the bus the BMC is on.

Setting the same bit on eSPI 1 at runtime is enough to make POST codes appear
in the BMC, with the code display still working, so the two windows are
independent and both can be open at once.

How reproducible

100%

How to reproduce

  1. Boot the host and open the POST code page in the BMC web interface. It is
    empty for the current boot, while the onboard code display shows codes
    during boot as normal.

  2. From the host, read the port 0x80 decode bit of both eSPI controllers.
    Bit 2 is the port 0x80 window:

    sudo busybox devmem 0xfec20040 32
    sudo busybox devmem 0xfec30040 32
    

    eSPI 0 reads 0x707, so bit 2 is set. eSPI 1 reads 0x30F00, so bit 2 is
    clear.

  3. Write a byte to port 0x80 from the host and reload the BMC's POST code
    page. Nothing new appears:

    printf "\347" | sudo dd of=/dev/port bs=1 seek=$((0x80)) count=1
    
  4. Open the same window on eSPI 1. With both windows open the FCH alternates
    between the two buses, so take port 0x80 off eSPI 0 for the moment to make
    a single write deterministic, then repeat the write:

    sudo busybox devmem 0xfec30040 32 0x30F04
    sudo busybox devmem 0xfec20040 32 0x703
    printf "\347" | sudo dd of=/dev/port bs=1 seek=$((0x80)) count=1
    

    e7 now shows up in the BMC's POST code log. The code display is unchanged
    while eSPI 0 has no window.

  5. Put eSPI 0 back and write the same byte twice, one dd per write so both
    land on port 0x80. A doubled write always survives the alternation, so it
    arrives with both windows open and the code display working:

    sudo busybox devmem 0xfec20040 32 0x707
    printf "\347" | sudo dd of=/dev/port bs=1 seek=$((0x80)) count=1
    printf "\347" | sudo dd of=/dev/port bs=1 seek=$((0x80)) count=1
    

The BMC web interface fetches the POST code log when the page is created and
does not poll, so the page has to be reloaded to see anything new.

Expected behavior

The BMC receives the POST codes that firmware writes to port 0x80, so its
POST code log is populated for every boot.

Actual behavior

The BMC's POST code log is empty for every boot. Nothing reaches it until bit
2 of the eSPI 1 decode register is set by hand from the host, which is lost on
the next power cycle.

Additional context

  • Measured on Dasharo (coreboot+LinuxBoot). The window is opened in coreboot
    before the payload runs, so UEFI is affected the same way.
  • With both windows open the FCH does not put the cycle on both buses, it
    alternates strictly, one cycle to each. Writing port 0x80 a hundred times
    from the host delivered fifty to the BMC, twice in a row, and a sequence of
    the values 1 to 100 came back as its odd half with no even value anywhere.
  • Writing each of thirty two values twice delivered all thirty two, so a
    value written twice always survives the split, while a value written once
    goes to one consumer or the other.
  • arch_post_code() writes each code once, a single outb to
    CONFIG_POST_IO_PORT, and this board defines no mainboard_post. So with
    both windows open a boot log is halved, and the alternation is visible in
    firmware codes too. The early order is 40 in romstage, 13 and 6e from
    c_start.S, 39 and 6f from hardwaremain.c, then 70 as the first
    boot state, each with one call site. One boot logged 40 6e 6f, positions
    one, three and five of those six, and another logged 13 39 70, positions
    two, four and six. One of them ends 9c 43 7b, BS_PAYLOAD_BOOT, and the
    other ends 76 79 7a fe f8, so which of the closing codes the BMC keeps
    varies by boot.
  • same issue on vendor firmware

Solutions you've tried

  • espi_open_io_window() programs the first controller and stops, which is
    why espi_open_io_window(0x80, 1) reaches only the code display on this
    board. Writing bit 2 of 0xfec30040 from the mainboard code as well is
    enough, and it does not disturb the eSPI 0 window.
  • Programming the BMC's side as a generic IO window instead of the standard
    port 0x80 decode bit, base 0x0080 in 0xfec30080 with size 0 in
    0xfec30088, changes nothing. The alternation is about two controllers
    claiming one address rather than about which decode matched it.
  • Taking port 0x80 off eSPI 0 instead, 0xfec20040 to 0x703, gives the BMC
    every write, a hundred out of a hundred, and leaves the code display unchanged.
    That is a trade between the two consumers rather than a fix, so opening the
    window on both controllers is the better default.

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