@@ -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 = {
@@ -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]"
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é <philmd@linaro.org> --- hw/ide/ahci.c | 31 ++++++++++++++++++++++++++++--- hw/ide/trace-events | 1 + 2 files changed, 29 insertions(+), 3 deletions(-)