summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-01-08 22:00:42 -0500
committerIan Moffett <ian@osmora.org>2025-01-08 22:01:34 -0500
commitb5c65e3022f285d389759bb699a9cefee79c5fd0 (patch)
treebe502cdeae88c38fd270bfb2e447295f0ba78517 /sys
parenta5da98ef1f85a78d935a8ba048487eb650b7eb07 (diff)
kernel: xhci: Add xHC interrupt management
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/xhci.c44
-rw-r--r--sys/include/dev/usb/xhciregs.h5
-rw-r--r--sys/include/dev/usb/xhcivar.h1
3 files changed, 50 insertions, 0 deletions
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index ad99f72..d2c671f 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -55,6 +55,12 @@
static struct pci_device *hci_dev;
static struct timer tmr;
+__attribute__((__interrupt__)) static void
+xhci_common_isr(void *sf)
+{
+ pr_trace("Received xHCI interrupt (via PCI MSI-X)\n");
+}
+
/*
* Get port status and control register for a specific
* port.
@@ -215,6 +221,19 @@ xhci_alloc_dcbaa(struct xhci_hc *hc)
}
/*
+ * Initialize MSI-X interrupts.
+ */
+static int
+xhci_init_msix(struct xhci_hc *hc)
+{
+ struct msi_intr intr;
+
+ intr.name = "xHCI MSI-X";
+ intr.handler = xhci_common_isr;
+ return pci_enable_msix(hci_dev, &intr);
+}
+
+/*
* Sets up the event ring.
*/
static void
@@ -313,6 +332,27 @@ xhci_reset(struct xhci_hc *hc)
}
/*
+ * Enable or disable xHC interrupts.
+ */
+static void
+xhci_set_intr(struct xhci_hc *hc, int enable)
+{
+ struct xhci_opregs *opregs = hc->opregs;
+ uint32_t usbcmd;
+
+ enable &= 1;
+ usbcmd = mmio_read32(&opregs->usbcmd);
+
+ if (enable == 1) {
+ usbcmd |= USBCMD_INTE;
+ } else {
+ usbcmd &= ~USBCMD_INTE;
+ }
+
+ mmio_write32(&opregs->usbcmd, usbcmd);
+}
+
+/*
* Start up the host controller and put it into
* a running state. Returns 0 on success.
*/
@@ -419,9 +459,13 @@ xhci_init_hc(struct xhci_hc *hc)
mmio_write64(&opregs->cmd_ring, cmdring);
hc->cr_cycle = 1;
+ xhci_init_msix(hc);
xhci_init_evring(hc);
xhci_parse_ecp(hc);
xhci_start_hc(hc);
+
+ /* Allow the xHC to generate interrupts */
+ xhci_set_intr(hc, 1);
xhci_init_ports(hc);
return 0;
}
diff --git a/sys/include/dev/usb/xhciregs.h b/sys/include/dev/usb/xhciregs.h
index 8c47739..0416601 100644
--- a/sys/include/dev/usb/xhciregs.h
+++ b/sys/include/dev/usb/xhciregs.h
@@ -73,6 +73,7 @@ struct xhci_opregs {
/* USBCMD bits */
#define USBCMD_RUN BIT(0) /* Run/stop */
#define USBCMD_HCRST BIT(1) /* xHC reset */
+#define USBCMD_INTE BIT(2) /* Interrupt Enable */
/* USBSTS bits */
#define USBSTS_HCH BIT(0) /* HC halted */
@@ -113,4 +114,8 @@ struct xhci_opregs {
#define XHCI_BIOS_SEM BIT(16)
#define XHCI_OS_SEM BIT(24)
+/* IMAN bits */
+#define XHCI_IMAN_IP BIT(0)
+#define XHCI_IMAN_IE BIT(1)
+
#endif /* !_USB_XHCIREGS_H_ */
diff --git a/sys/include/dev/usb/xhcivar.h b/sys/include/dev/usb/xhcivar.h
index cd445c8..4b0f1bf 100644
--- a/sys/include/dev/usb/xhcivar.h
+++ b/sys/include/dev/usb/xhcivar.h
@@ -39,6 +39,7 @@
#define XHCI_EVRING_LEN 16
#define XHCI_TRB_SIZE 16 /* In bytes */
#define XHCI_MAX_PROTOS 4
+#define XHCI_IMOD_DEFAULT 0
/*
* USB proto (USB 2.0 or 3.0)