summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-05-09 22:47:13 -0400
committerIan Moffett <ian@osmora.org>2025-05-09 22:47:13 -0400
commit64b2cb973b109d10c2a15edcbf2a102712564271 (patch)
treeea6d122ed447859bbf21bcd758bf64e08cf61a08
parent0973627785f3b2387bb5c4bb13c634b74348e1b1 (diff)
kernel: ahci: Add HBA port reset logic
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--sys/dev/ic/ahci.c67
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