diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/uacpi.c | 122 | ||||
-rw-r--r-- | sys/dev/usb/xhci.c | 56 |
2 files changed, 159 insertions, 19 deletions
diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c index b133288..6c2bf50 100644 --- a/sys/dev/acpi/uacpi.c +++ b/sys/dev/acpi/uacpi.c @@ -32,6 +32,8 @@ #include <sys/param.h> #include <sys/syslog.h> #include <sys/panic.h> +#include <sys/proc.h> +#include <sys/queue.h> #include <dev/timer.h> #include <uacpi/kernel_api.h> #include <uacpi/platform/arch_helpers.h> @@ -53,22 +55,96 @@ #include <vm/vm.h> #include <string.h> +#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + typedef struct { uacpi_io_addr base; uacpi_size length; } io_range_t; +struct uacpi_work { + uacpi_work_handler hand; + uacpi_handle ctx; + TAILQ_ENTRY(uacpi_work) link; +}; + +uacpi_status +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx); + +extern struct proc g_proc0; + +static struct proc *event_td; +static TAILQ_HEAD(, uacpi_work) acpi_gpe_eventq; +static TAILQ_HEAD(, uacpi_work) acpi_notify_eventq; + /* - * TODO: Schedule a system shutdown + * Dispatch ACPI general purpose events from + * hardware. */ -static uacpi_interrupt_ret -power_button_handler(uacpi_handle ctx) +static void +uacpi_gpe_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_gpe_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +/* + * Dispatch ACPI general notify events. + */ +static void +uacpi_notify_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_notify_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +static void +uacpi_event_td(void) +{ + for (;;) { + uacpi_gpe_dispatch(); + uacpi_notify_dispatch(); + sched_yield(); + } +} + +static void +shutdown(uacpi_handle ctx) { - md_intoff(); kprintf("power button pressed\n"); kprintf("halting machine...\n"); cpu_halt_all(); - return UACPI_INTERRUPT_HANDLED; +} + +static uacpi_interrupt_ret +power_button_handler(uacpi_handle ctx) +{ + md_intoff(); + uacpi_kernel_schedule_work(UACPI_WORK_GPE_EXECUTION, shutdown, NULL); + md_inton(); + + for (;;) { + md_hlt(); + } + + __builtin_unreachable(); } void * @@ -278,9 +354,28 @@ uacpi_kernel_uninstall_interrupt_handler([[maybe_unused]] uacpi_interrupt_handle } uacpi_status -uacpi_kernel_schedule_work(uacpi_work_type, uacpi_work_handler, uacpi_handle ctx) +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx) { - return UACPI_STATUS_UNIMPLEMENTED; + struct uacpi_work *work; + + work = dynalloc(sizeof(*work)); + if (work == NULL) { + return UACPI_STATUS_OUT_OF_MEMORY; + } + + work->hand = h; + work->ctx = ctx; + + switch (type) { + case UACPI_WORK_GPE_EXECUTION: + TAILQ_INSERT_TAIL(&acpi_gpe_eventq, work, link); + break; + case UACPI_WORK_NOTIFICATION: + TAILQ_INSERT_TAIL(&acpi_notify_eventq, work, link); + break; + } + + return 0; } uacpi_status @@ -541,25 +636,25 @@ uacpi_init(void) ret = uacpi_initialize(0); if (uacpi_unlikely_error(ret)) { - kprintf("uacpi init error: %s\n", uacpi_status_to_string(ret)); + pr_error("uacpi init error: %s\n", uacpi_status_to_string(ret)); return -1; } ret = uacpi_namespace_load(); if (uacpi_unlikely_error(ret)) { - kprintf("uacpi namespace load error: %s\n", uacpi_status_to_string(ret)); + pr_error("uacpi namespace load error: %s\n", uacpi_status_to_string(ret)); return -1; } ret = uacpi_namespace_initialize(); if (uacpi_unlikely_error(ret)) { - kprintf("uacpi namespace init error: %s\n", uacpi_status_to_string(ret)); + pr_error("uacpi namespace init error: %s\n", uacpi_status_to_string(ret)); return -1; } ret = uacpi_finalize_gpe_initialization(); if (uacpi_unlikely_error(ret)) { - kprintf("uacpi GPE init error: %s\n", uacpi_status_to_string(ret)); + pr_error("uacpi GPE init error: %s\n", uacpi_status_to_string(ret)); return -1; } @@ -569,11 +664,14 @@ uacpi_init(void) ); if (uacpi_unlikely_error(ret)) { - kprintf("failed to install power button event: %s\n", + pr_error("failed to install power button event: %s\n", uacpi_status_to_string(ret) ); return -1; } + TAILQ_INIT(&acpi_gpe_eventq); + TAILQ_INIT(&acpi_notify_eventq); + spawn(&g_proc0, uacpi_event_td, NULL, 0, &event_td); return 0; } diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 0ccb7a0..e14cb44 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -71,11 +71,16 @@ xhci_intr(void *sf) static inline uint32_t * xhci_get_portsc(struct xhci_hc *hc, uint8_t portno) { - if (portno > hc->maxports) { - portno = hc->maxports; + if (portno >= hc->maxports) { + return NULL; } - return PTR_OFFSET(hc->opregs, 0x400 + (0x10 * (portno - 1))); + /* Zero based */ + if (portno > 0) { + --portno; + } + + return PTR_OFFSET(hc->opregs, 0x400 + (0x10 * portno)); } static int @@ -200,12 +205,12 @@ xhci_init_scratchpads(struct xhci_hc *hc) for (size_t i = 0; i < max_bufs; ++i) { tmp = vm_alloc_frame(1); - memset(PHYS_TO_VIRT(tmp), 0, 0x1000); if (tmp == 0) { /* TODO: Shutdown, free memory */ pr_error("failed to fill scratchpad buffer array\n"); return -1; } + memset(PHYS_TO_VIRT(tmp), 0, 0x1000); bufarr[i] = tmp; } @@ -221,7 +226,7 @@ xhci_alloc_dcbaa(struct xhci_hc *hc) { size_t size; - size = sizeof(uintptr_t) * hc->maxslots; + size = sizeof(uintptr_t) * (hc->maxslots + 1); hc->dcbaap = dynalloc_memalign(size, 0x1000); __assert(hc->dcbaap != NULL); return VIRT_TO_PHYS(hc->dcbaap); @@ -268,7 +273,7 @@ xhci_init_evring(struct xhci_hc *hc) /* setup the event ring segment */ segtab->base = VIRT_TO_PHYS(tmp_p); - segtab->base = ((uintptr_t)segtab->base) + (2 * 4096) & ~0xF; + segtab->base = ((uintptr_t)segtab->base); segtab->size = XHCI_EVRING_LEN; /* Setup the event ring dequeue pointer */ @@ -335,6 +340,13 @@ xhci_reset(struct xhci_hc *hc) return error; } + /* Wait longer if the xHC is not ready */ + error = xhci_poll32(&opregs->usbsts, USBSTS_CNR, false); + if (error < 0) { + pr_error("xhci_reset: xHC ready wait timeout\n"); + return error; + } + return 0; } @@ -372,13 +384,33 @@ xhci_start_hc(struct xhci_hc *hc) /* Don't start up if we are already running */ usbcmd = mmio_read32(&opregs->usbcmd); if (ISSET(usbcmd, USBCMD_RUN)) - return -EBUSY; + return 0; usbcmd |= USBCMD_RUN; mmio_write32(&opregs->usbcmd, usbcmd); return 0; } +/* + * Stop and bring down the host controller. + * Returns 0 on success. + */ +static int +xhci_stop_hc(struct xhci_hc *hc) +{ + struct xhci_opregs *opregs = hc->opregs; + uint32_t usbcmd; + + /* Don't continue if we aren't running */ + usbcmd = mmio_read32(&opregs->usbcmd); + if (!ISSET(usbcmd, USBCMD_RUN)) + return 0; + + usbcmd &= ~USBCMD_RUN; + mmio_write32(&opregs->usbcmd, usbcmd); + return 0; +} + static int xhci_init_ports(struct xhci_hc *hc) { @@ -388,6 +420,9 @@ xhci_init_ports(struct xhci_hc *hc) for (size_t i = 1; i < hc->maxports; ++i) { portsc_p = xhci_get_portsc(hc, i); + if (portsc_p == NULL) { + continue; + } portsc = mmio_read32(portsc_p); /* @@ -461,8 +496,15 @@ xhci_init_hc(struct xhci_hc *hc) return -1; } + pr_trace("stopping xHC chip...\n"); + if ((error = xhci_stop_hc(hc)) != 0) { + pr_error("run/stop timeout\n"); + return error; + } + pr_trace("resetting xHC chip...\n"); if ((error = xhci_reset(hc)) != 0) { + pr_error("reset timeout\n"); return error; } |