diff options
author | Ian Moffett <ian@osmora.org> | 2025-06-10 23:29:17 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-06-10 23:35:14 -0400 |
commit | c3fe4c4c4dfb662e65299669147a904585eb5aca (patch) | |
tree | 9d3c49747877ab9795d54bdc19270db4a21ae398 /sys/dev | |
parent | 031dc9ef078da2fcf6e804447f5782f12f70725e (diff) |
kernel: ahci: Improve port reset logic
- Set PxCMD.SUD if the HBA supports staggered spin-up to ensure the
device will be detectable.
- Wait for the device link to be established
- Detect and log SATA link speed
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/ahci.c | 73 |
1 files changed, 46 insertions, 27 deletions
diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c index 905149e..b713711 100644 --- a/sys/dev/ic/ahci.c +++ b/sys/dev/ic/ahci.c @@ -328,22 +328,24 @@ hba_port_chkerr(struct hba_port *port) static int hba_port_reset(struct ahci_hba *hba, struct hba_port *port) { - uint32_t sctl, ssts; - uint8_t det, ipm; - int error; + uint32_t sctl, ssts, cmd; + uint8_t det, ipm, spd; + uint32_t elapsed = 0; + + sctl = mmio_read32(&port->sctl); /* - * The port must not be in an idle state when a - * COMRESET is sent over the interface as some - * chipsets do not know how to handle this... - * - * After bringing up the port, send a COMRESET - * over the interface for roughly ~2ms. + * Transmit a COMRESET to the device. If the HBA + * supports staggered spin-up, we'll need to set + * the PxCMD.SUD bit as well. */ - hba_port_start(port); - sctl = mmio_read32(&port->sctl); sctl = (sctl & ~0x0F) | AHCI_DET_COMRESET; mmio_write32(&port->sctl, sctl); + if (hba->sss) { + cmd = mmio_read32(&port->cmd); + cmd |= AHCI_PXCMD_SUD; + mmio_write32(&port->cmd, cmd); + } /* * Wait for the link to become reestablished @@ -353,33 +355,50 @@ hba_port_reset(struct ahci_hba *hba, struct hba_port *port) sctl &= ~AHCI_DET_COMRESET; mmio_write32(&port->sctl, sctl); - /* - * Now we'll need to grab some power management - * and detection flags as the port must have - * a device present along with an active - * interface. - */ - ssts = mmio_read32(&port->ssts); - det = AHCI_PXSCTL_DET(ssts); - ipm = AHCI_PXSSTS_IPM(ssts); + for (;;) { + if (elapsed >= AHCI_TIMEOUT) { + break; + } + ssts = mmio_read32(&port->ssts); + det = AHCI_PXSSTS_DET(ssts); + if (det == AHCI_DET_COMM) { + break; + } - if (det == AHCI_DET_NULL) { - return -ENODEV; + tmr.msleep(10); + elapsed += 10; } + ipm = AHCI_PXSSTS_IPM(ssts); + spd = AHCI_PXSSTS_SPD(ssts); + + if (det == AHCI_DET_PRESENT) { + pr_error("SATA link timeout\n"); + return -EAGAIN; + } if (det != AHCI_DET_COMM) { - pr_trace("failed to establish link\n"); return -EAGAIN; } + /* + * Ensure the interface is in an active + * state. + */ if (ipm != AHCI_IPM_ACTIVE) { - pr_trace("device interface not active\n"); + pr_error("device interface not active\n"); return -EAGAIN; } - if ((error = hba_port_stop(port)) < 0) { - pr_trace("failed to stop port\n"); - return error; + switch (spd) { + case AHCI_SPD_GEN1: + pr_trace("SATA link rate @ ~1.5 Gb/s\n"); + break; + case AHCI_SPD_GEN2: + pr_trace("SATA link rate @ ~3 Gb/s\n"); + break; + case AHCI_SPD_GEN3: + pr_trace("SATA link rate @ ~6 Gb/s\n"); + break; } return 0; |