diff options
author | Ian Moffett <ian@osmora.org> | 2025-05-09 22:47:13 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-05-09 22:47:13 -0400 |
commit | 64b2cb973b109d10c2a15edcbf2a102712564271 (patch) | |
tree | ea6d122ed447859bbf21bcd758bf64e08cf61a08 | |
parent | 0973627785f3b2387bb5c4bb13c634b74348e1b1 (diff) |
kernel: ahci: Add HBA port reset logic
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r-- | sys/dev/ic/ahci.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c index 3078ec3..60ad759 100644 --- a/sys/dev/ic/ahci.c +++ b/sys/dev/ic/ahci.c @@ -216,6 +216,73 @@ hba_port_start(struct hba_port *port) } /* + * Reset a port on the HBA + * + * XXX: This function stops the port once the + * COMRESET is complete. + */ +static int +hba_port_reset(struct hba_port *port) +{ + uint32_t sctl, ssts; + uint8_t det, ipm; + int error; + + /* + * 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. + */ + hba_port_start(port); + sctl = mmio_read32(&port->sctl); + sctl = (sctl & ~0x0F) | AHCI_DET_COMRESET; + mmio_write32(&port->sctl, sctl); + + /* + * Wait for the link to become reestablished + * between the port and the HBA. + */ + tmr.msleep(150); + 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); + + /* If there is no device, fake success */ + if (det == AHCI_DET_NULL) { + return 0; + } + + if (det != AHCI_DET_COMM) { + pr_trace("failed to establish link\n"); + return -EAGAIN; + } + + if (ipm != AHCI_IPM_ACTIVE) { + pr_trace("device interface not active\n"); + return -EAGAIN; + } + + if ((error = hba_port_stop(port)) < 0) { + pr_trace("failed to stop port\n"); + return error; + } + + return 0; +} + +/* * Initialize a drive on an HBA port * * @hba: HBA descriptor |