aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJiaxun Yang <jiaxun.yang@flygoat.com>2025-05-28 12:02:49 +0100
committerGerd Hoffmann <kraxel@redhat.com>2025-06-02 11:20:05 +0200
commita6c8e8bbdf24ece39e4f55c8ab464d28e5e44745 (patch)
tree2af63ab3f0564407f768de701f95ead6241dafa7 /src
parent9029a010ec413e6c3c0eb52c29c252a5b9a9f774 (diff)
downloadseabios-a6c8e8bbdf24ece39e4f55c8ab464d28e5e44745.zip
seabios-a6c8e8bbdf24ece39e4f55c8ab464d28e5e44745.tar.gz
seabios-a6c8e8bbdf24ece39e4f55c8ab464d28e5e44745.tar.bz2
ahci: Fix hangs due to controller reset
After adding AHCI controller reset functionality there are multiple reports on AHCI booting regression. As per my experiments on various machines, to reset controller properly it is necessary to poll HOST_CTL_RESET bit until it's clear. It is also required to read back HOST_CTL after changing HOST_CTL_AHCI_EN bits to ensure the controller has accepted write. Tested on ASMedia ASM1061, Intel H61 native SATA and AMD Phoenix native SATA. Link: https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/RDNRKWBN4N5XQX2TQMM5P4WZ2OOPPNAM/ Link: https://github.com/FlyGoat/csmwrap/issues/14 Fixes: 8863cbbd15a7 ("ahci: add controller reset") Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Acked-by: Paul Menzel <pmenzel@molgen.mpg.de> Message-ID: <20250528-ahci-v2-1-9d7310217ca2@flygoat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/hw/ahci.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/hw/ahci.c b/src/hw/ahci.c
index 2285d33..7e7a03d 100644
--- a/src/hw/ahci.c
+++ b/src/hw/ahci.c
@@ -660,8 +660,23 @@ ahci_controller_setup(struct pci_device *pci)
pci_enable_busmaster(pci);
- ahci_ctrl_writel(ctrl, HOST_CTL, HOST_CTL_RESET);
- ahci_ctrl_writel(ctrl, HOST_CTL, HOST_CTL_AHCI_EN);
+ u32 val = ahci_ctrl_readl(ctrl, HOST_CTL);
+ ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_RESET);
+ u32 end = timer_calc(AHCI_RESET_TIMEOUT);
+ for (;;) {
+ val = ahci_ctrl_readl(ctrl, HOST_CTL);
+ if (!(val & HOST_CTL_RESET))
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ dprintf(1, "AHCI: controller reset failed\n");
+ free(ctrl);
+ return;
+ }
+ yield();
+ }
+ ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
+ (void)ahci_ctrl_readl(ctrl, HOST_CTL); /* Flush */
ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP);
ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL);