AHCI reset is not instantaneous in physical world, and software
might poll the reset bits of port and host control registers to
detect completion (see chapter 14 of AHCI spec).

In preparation of adding a timed reset, split ahci_reset()
as ahci_reset_delayed() which keeps the reset bits and
ahci_reset_complete() which resets them.

No logical changes so far.

Signed-off-by: Philippe Mathieu-Daudé <phi...@linaro.org>
---
 hw/ide/ahci.c       | 31 ++++++++++++++++++++++++++++---
 hw/ide/trace-events |  1 +
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 1303c21cb70..7e586c7a0a4 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -46,6 +46,7 @@ static bool ahci_map_clb_address(AHCIDevice *ad);
 static bool ahci_map_fis_address(AHCIDevice *ad);
 static void ahci_unmap_clb_address(AHCIDevice *ad);
 static void ahci_unmap_fis_address(AHCIDevice *ad);
+static void ahci_reset_delayed(AHCIState *s, bool immediate);
 
 static const char *AHCIHostReg_lookup[AHCI_HOST_REG__COUNT] = {
     [AHCI_HOST_REG_CAP]        = "CAP",
@@ -1623,7 +1624,22 @@ void ahci_uninit(AHCIState *s)
     g_free(s->dev);
 }
 
-void ahci_reset(AHCIState *s)
+static void ahci_reset_complete(void *opaque)
+{
+    AHCIState *s = opaque;
+
+    trace_ahci_reset_done(s);
+
+    for (unsigned i = 0; i < s->ports; i++) {
+        AHCIPortRegs *pr;
+
+        pr = &s->dev[i].port_regs;
+        pr->cmd &= ~PORT_CMD_LIST_ON;
+    }
+    s->control_regs.ghc &= ~HOST_CTL_RESET;
+}
+
+static void ahci_reset_delayed(AHCIState *s, bool immediate)
 {
     AHCIPortRegs *pr;
     int i;
@@ -1639,16 +1655,25 @@ void ahci_reset(AHCIState *s)
      *
      * We set HOST_CAP_AHCI so we must enable AHCI at reset.
      */
-    s->control_regs.ghc = HOST_CTL_AHCI_EN;
+    s->control_regs.ghc = HOST_CTL_RESET | HOST_CTL_AHCI_EN;
 
     for (i = 0; i < s->ports; i++) {
         pr = &s->dev[i].port_regs;
         pr->irq_stat = 0;
         pr->irq_mask = 0;
         pr->scr_ctl = 0;
-        pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
+        pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON | PORT_CMD_LIST_ON;
         ahci_reset_port(s, i);
     }
+
+    if (immediate) {
+        ahci_reset_complete(s);
+    }
+}
+
+void ahci_reset(AHCIState *s)
+{
+    ahci_reset_delayed(s, false);
 }
 
 static const VMStateDescription vmstate_ncq_tfs = {
diff --git a/hw/ide/trace-events b/hw/ide/trace-events
index 57042cafddc..979145c58b8 100644
--- a/hw/ide/trace-events
+++ b/hw/ide/trace-events
@@ -82,6 +82,7 @@ ahci_mem_write_host(void *s, unsigned size, const char *reg, 
uint64_t addr, uint
 ahci_mem_write_unimpl(void *s, unsigned size, uint64_t addr, uint64_t val) 
"ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
 ahci_set_signature(void *s, int port, uint8_t nsector, uint8_t sector, uint8_t 
lcyl, uint8_t hcyl, uint32_t sig) "ahci(%p)[%d]: set signature sector:0x%02x 
nsector:0x%02x lcyl:0x%02x hcyl:0x%02x (cumulatively: 0x%08x)"
 ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port"
+ahci_reset_done(void *s) "ahci(%p): reset done"
 ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap 
NULL FIS address"
 ahci_unmap_clb_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap 
NULL CLB address"
 ahci_populate_sglist(void *s, int port) "ahci(%p)[%d]"
-- 
2.47.1


Reply via email to