summaryrefslogtreecommitdiff
path: root/src/sys/io
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-09-21 14:54:26 -0400
committerIan Moffett <ian@osmora.org>2025-09-21 15:11:17 -0400
commitd88c40fc062f28c63ae7bc3836407df3470287a3 (patch)
tree5dcb8faf7177793565f05409435fd85e51c4e117 /src/sys/io
parent561ad1494cad32243fa256af8acb755466ef12a7 (diff)
kern: ahci: Add initial port startup logic
Here we ensure that the port is in a stopped state, we have also added port descriptor lists to keep track of each port. Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'src/sys/io')
-rw-r--r--src/sys/io/ic/ahci.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/sys/io/ic/ahci.c b/src/sys/io/ic/ahci.c
index 9f96a00..3a6f0c3 100644
--- a/src/sys/io/ic/ahci.c
+++ b/src/sys/io/ic/ahci.c
@@ -36,10 +36,12 @@
#include <sys/syslog.h>
#include <sys/cdefs.h>
#include <sys/errno.h>
+#include <sys/queue.h>
#include <io/pci/pci.h>
#include <io/pci/bar.h>
#include <io/ic/ahciregs.h>
#include <io/ic/ahcivar.h>
+#include <os/kalloc.h>
#include <os/module.h>
#include <os/clkdev.h>
#include <os/mmio.h>
@@ -61,6 +63,7 @@ static struct pci_adv driver;
static struct pci_device dev;
static struct clkdev *clkdev;
static struct ahci_hba root_hba;
+static TAILQ_HEAD(, ahci_port) portlist;
/*
* Poll register to have 'bits' set/unset.
@@ -103,6 +106,48 @@ ahci_poll32(volatile uint32_t *reg, uint32_t bits, bool pollset)
}
/*
+ * Stop a running port, turn off the command list engine,
+ * as well as its FIS receive engine
+ *
+ * @port: Port to stop
+ *
+ * Returns zero if the port has been stopped successfully,
+ * otherwise a less than zero value
+ */
+static int
+ahci_port_stop(struct ahci_port *port)
+{
+ volatile struct hba_port *io = port->io;
+ uint32_t cmd, mask;
+ int error;
+
+ /*
+ * If the port is already stopped, then don't try to do
+ * it again.
+ */
+ mask = AHCI_PXCMD_FR | AHCI_PXCMD_CR;
+ cmd = mmio_read32(&io->cmd);
+ if (!ISSET(cmd, mask)) {
+ dtrace("port %d already stopped\n", port->portno);
+ return 0;
+ }
+
+ /* Stop everything */
+ dtrace("stopping port %d...\n", port->portno);
+ cmd &= ~(AHCI_PXCMD_FRE | AHCI_PXCMD_ST);
+ mmio_write32(&io->cmd, cmd);
+
+ /* Wait until everything has truly stopped */
+ error = ahci_poll32(&io->cmd, mask, false);
+ if (error < 0) {
+ pr_trace("timed out stopping port %d\n", port->portno);
+ return error;
+ }
+
+ return 0;
+}
+
+/*
* Perform a full HBA reset by using the HR bit
* within the GHC register.
*
@@ -144,13 +189,56 @@ ahci_hba_reset(struct ahci_hba *hba)
}
/*
+ * Logically detaches our link with the port, cleans up
+ * resources, etc.
+ *
+ * @port: Port to "detach"
+ */
+static void
+ahci_port_detach(struct ahci_port *port)
+{
+ if (port == NULL) {
+ return;
+ }
+
+ kfree(port);
+}
+
+/*
+ * Initialize a specific port on the HBA as per section
+ * 10.1.2 of the AHCI specification
+ *
+ * @hba: HBA port belongs to
+ * @port: Port to initialize
+ *
+ * XXX: Upon failure, the caller is to clean up resources relating
+ * to 'port'
+ */
+static int
+ahci_init_port(struct ahci_hba *hba, struct ahci_port *port)
+{
+ volatile struct hba_port *regs;
+ uint32_t cmd;
+
+ if (hba == NULL || port == NULL) {
+ return -EINVAL;
+ }
+
+ ahci_port_stop(port);
+ TAILQ_INSERT_TAIL(&portlist, port, link);
+ return 0;
+}
+
+/*
* Initialize the ports of an HBA
*/
static int
ahci_init_ports(struct ahci_hba *hba)
{
volatile struct hba_memspace *io = hba->io;
+ struct ahci_port *port;
uint32_t pi, nbits;
+ int error;
pi = hba->pi;
for (int i = 0; i < hba->nport; ++i) {
@@ -158,7 +246,25 @@ ahci_init_ports(struct ahci_hba *hba)
continue;
}
+ /* Allocate a new port descriptor */
dtrace("port %d implemented\n", i);
+ port = kalloc(sizeof(*port));
+ if (port == NULL) {
+ printf("failed to allocate port\n");
+ continue;
+ }
+
+ port->io = &io->ports[i];
+ port->portno = i;
+ port->parent = hba;
+
+ /* Initialize the port */
+ error = ahci_init_port(hba, port);
+ if (error < 0) {
+ ahci_port_detach(port);
+ printf("port init failed (error=%d)\n", error);
+ continue;
+ }
}
return 0;
@@ -226,6 +332,7 @@ ahci_init(struct module *modp)
}
root_hba.io = NULL;
+ TAILQ_INIT(&portlist);
return 0;
}