Use a big-lock for kernel sychronization instead of fine-grained locking
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 2m21s
Build documentation / build-and-deploy (push) Successful in 54s

This commit is contained in:
2026-04-27 18:06:02 +02:00
parent 68cdd8d6d2
commit e5ebd7f3ba
56 changed files with 212 additions and 1206 deletions

View File

@@ -15,8 +15,7 @@
static atomic_int usb_ms_counter = 0;
static struct device* usb_ms_init(struct xhci* xhci, struct xhci_usb_device* usb_device,
struct proc* proc, struct reschedule_ctx* rctx,
uint64_t* lockflags) {
struct proc* proc, struct reschedule_ctx* rctx) {
static device_op_func_t ops[] = {
[XDRV_GET_SIZE] = &usbdrv_get_size,
[XDRV_GET_SECTOR_SIZE] = &usbdrv_get_sector_size,
@@ -29,7 +28,6 @@ static struct device* usb_ms_init(struct xhci* xhci, struct xhci_usb_device* usb
struct usbdrv_init init = {
.xhci = xhci,
.usb_device = usb_device,
.lockflags = lockflags,
};
char key[30];

View File

@@ -88,7 +88,7 @@ struct usb_driver_info {
uint8_t if_subclass;
uint8_t if_proto;
struct device* (*init)(struct xhci* xhci, struct xhci_usb_device* usb_device, struct proc* proc,
struct reschedule_ctx* rctx, uint64_t* lockflags);
struct reschedule_ctx* rctx);
};
extern struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES];

View File

@@ -14,6 +14,7 @@
#include <proc/reschedule.h>
#include <proc/suspension_q.h>
#include <status.h>
#include <sync/biglock.h>
#include <sys/debug.h>
#include <sys/memorybarrier.h>
#include <sys/spin_lock.h>
@@ -324,12 +325,8 @@ static void xhci_poll_events(struct xhci* xhci) {
static void xhci_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rctx) {
(void)user, (void)regs, (void)rctx;
uint64_t fd;
struct xhci* xhci = arg;
spin_lock(&xhci->device->lock, &fd);
uintptr_t ir_base = xhci->xhci_runtime_base + 0x20;
/* ack */
@@ -337,8 +334,6 @@ static void xhci_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rc
xhci_write32(xhci->xhci_oper_base, XHCI_USBSTS, (1 << 3));
xhci_poll_events(xhci);
spin_unlock(&xhci->device->lock, fd);
}
static void xhci_ring_put_trb(struct xhci_ring* ring, struct xhci_trb put_trb) {
@@ -369,8 +364,7 @@ static void xhci_ring_put_trb(struct xhci_ring* ring, struct xhci_trb put_trb) {
static bool xhci_endpoint0_ctrl_in(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint8_t request_type, uint8_t request, uint16_t value,
uint16_t index, uintptr_t data_phys, uint16_t length,
uint64_t* lockflags) {
uint16_t index, uintptr_t data_phys, uint16_t length) {
/* clang-format off */
uint64_t setup = ((uint64_t)length << XHCI_SSTRB_PARAM_WLENGTH)
| ((uint64_t)index << XHCI_SSTRB_PARAM_WINDEX)
@@ -417,14 +411,15 @@ static bool xhci_endpoint0_ctrl_in(struct xhci* xhci, struct xhci_usb_device* us
int timeout = 100;
spin_unlock(&xhci->device->lock, *lockflags);
xhci_write32(xhci->xhci_doorbell_base, usb_device->slot_id * 4, 1);
while (atomic_load(&usb_device->endpoint0_ring.pending) && --timeout > 0)
while (atomic_load(&usb_device->endpoint0_ring.pending) && --timeout > 0) {
biglock_unlock();
stall_ms(1);
spin_lock(&xhci->device->lock, lockflags);
biglock_lock();
}
if (timeout == 0) {
DEBUG("timed out\n");
@@ -436,8 +431,7 @@ static bool xhci_endpoint0_ctrl_in(struct xhci* xhci, struct xhci_usb_device* us
static bool xhci_endpoint0_ctrl_out(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint8_t request_type, uint8_t request, uint16_t value,
uint16_t index, uintptr_t data_phys, uint16_t length,
uint64_t* lockflags) {
uint16_t index, uintptr_t data_phys, uint16_t length) {
/* clang-format off */
uint64_t setup = ((uint64_t)length << XHCI_SSTRB_PARAM_WLENGTH)
| ((uint64_t)index << XHCI_SSTRB_PARAM_WINDEX)
@@ -493,14 +487,15 @@ static bool xhci_endpoint0_ctrl_out(struct xhci* xhci, struct xhci_usb_device* u
int timeout = 100;
spin_unlock(&xhci->device->lock, *lockflags);
xhci_write32(xhci->xhci_doorbell_base, usb_device->slot_id * 4, 1);
while (atomic_load(&usb_device->endpoint0_ring.pending) && --timeout > 0)
while (atomic_load(&usb_device->endpoint0_ring.pending) && --timeout > 0) {
biglock_unlock();
stall_ms(1);
spin_lock(&xhci->device->lock, lockflags);
biglock_lock();
}
if (timeout == 0) {
DEBUG("timed out\n");
@@ -510,8 +505,7 @@ static bool xhci_endpoint0_ctrl_out(struct xhci* xhci, struct xhci_usb_device* u
return usb_device->endpoint0_ring.last_cmpl_code == 1;
}
static void xhci_send_cmd(struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl,
uint64_t* lockflags) {
static void xhci_send_cmd(struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl) {
if (xhci->cmd_ring.idx == (xhci->cmd_ring.size - 1)) {
struct xhci_trb* link = &xhci->cmd_ring.trbs[xhci->cmd_ring.idx];
link->param = xhci->cmd_ring.phys;
@@ -541,14 +535,15 @@ static void xhci_send_cmd(struct xhci* xhci, uint64_t param, uint32_t status, ui
int timeout = 100;
spin_unlock(&xhci->device->lock, *lockflags);
xhci_write32(xhci->xhci_doorbell_base, 0, 0);
while (atomic_load(&xhci->event_ring.pending) && --timeout > 0)
while (atomic_load(&xhci->event_ring.pending) && --timeout > 0) {
biglock_unlock();
stall_ms(1);
spin_lock(&xhci->device->lock, lockflags);
biglock_lock();
}
if (timeout == 0)
DEBUG("timed out\n");
@@ -561,8 +556,7 @@ static uint8_t xhci_get_device_ctx_idx(struct usb_endpoint_desc* endpoint) {
}
static bool xhci_usb_device_setup_init_endpoints(struct xhci* xhci,
struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
struct xhci_usb_device* usb_device) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t input_ctx_phys = pmm_alloc(1);
@@ -682,7 +676,7 @@ static bool xhci_usb_device_setup_init_endpoints(struct xhci* xhci,
}
uint32_t ctrl = (usb_device->slot_id << 24) | (XHCI_TRB_CFG_ENDP_CMD << XHCI_GTRB_TRB_TYPE);
xhci_send_cmd(xhci, input_ctx_phys, 0, ctrl, lockflags);
xhci_send_cmd(xhci, input_ctx_phys, 0, ctrl);
pmm_free(input_ctx_phys, 1);
@@ -696,8 +690,8 @@ static bool xhci_usb_device_setup_init_endpoints(struct xhci* xhci,
}
static bool xhci_usb_device_setup_set_config(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint8_t config_val, uint64_t* lockflags) {
bool ok = xhci_endpoint0_ctrl_out(xhci, usb_device, 0x00, 0x09, config_val, 0, 0, 0, lockflags);
uint8_t config_val) {
bool ok = xhci_endpoint0_ctrl_out(xhci, usb_device, 0x00, 0x09, config_val, 0, 0, 0);
if (!ok) {
DEBUG("Failed to set the config!\n");
@@ -709,8 +703,8 @@ static bool xhci_usb_device_setup_set_config(struct xhci* xhci, struct xhci_usb_
return true;
}
static bool xhci_usb_device_setup_addressing(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
static bool xhci_usb_device_setup_addressing(struct xhci* xhci,
struct xhci_usb_device* usb_device) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
struct xhci_port* xhci_port;
@@ -722,7 +716,7 @@ static bool xhci_usb_device_setup_addressing(struct xhci* xhci, struct xhci_usb_
uint32_t speed = (portsc >> XHCI_PORTSC_PORTSPEED) & 0x0F;
xhci->event_ring.last_cmpl_code = 0;
xhci_send_cmd(xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << XHCI_GTRB_TRB_TYPE, lockflags);
xhci_send_cmd(xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << XHCI_GTRB_TRB_TYPE);
if (xhci->event_ring.last_cmpl_code != 1) {
DEBUG("Enable slot failed\n");
@@ -784,7 +778,7 @@ static bool xhci_usb_device_setup_addressing(struct xhci* xhci, struct xhci_usb_
xhci->event_ring.last_cmpl_code = 0;
uint32_t ctrl = (usb_device->slot_id << 24) | (XHCI_TRB_ADDR_DEV_CMD << XHCI_GTRB_TRB_TYPE);
xhci_send_cmd(xhci, input_ctx_phys, 0, ctrl, lockflags);
xhci_send_cmd(xhci, input_ctx_phys, 0, ctrl);
pmm_free(input_ctx_phys, 1);
@@ -799,8 +793,7 @@ static bool xhci_usb_device_setup_addressing(struct xhci* xhci, struct xhci_usb_
}
}
static bool xhci_usb_device_setup_get_info(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
static bool xhci_usb_device_setup_get_info(struct xhci* xhci, struct xhci_usb_device* usb_device) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t response_buf_phys = pmm_alloc(1);
@@ -808,8 +801,7 @@ static bool xhci_usb_device_setup_get_info(struct xhci* xhci, struct xhci_usb_de
void* response_buf = (void*)(response_buf_phys + (uintptr_t)hhdm->offset);
memset(response_buf, 0, PAGE_SIZE);
bool ok = xhci_endpoint0_ctrl_in(xhci, usb_device, 0x80, 6, (1 << 8), 0, response_buf_phys, 18,
lockflags);
bool ok = xhci_endpoint0_ctrl_in(xhci, usb_device, 0x80, 6, (1 << 8), 0, response_buf_phys, 18);
if (!ok) {
pmm_free(response_buf_phys, 1);
@@ -828,8 +820,8 @@ static bool xhci_usb_device_setup_get_info(struct xhci* xhci, struct xhci_usb_de
return true;
}
static bool xhci_usb_device_setup_get_config(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
static bool xhci_usb_device_setup_get_config(struct xhci* xhci,
struct xhci_usb_device* usb_device) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t response_buf_phys = pmm_alloc(1);
@@ -837,8 +829,7 @@ static bool xhci_usb_device_setup_get_config(struct xhci* xhci, struct xhci_usb_
void* response_buf = (void*)(response_buf_phys + (uintptr_t)hhdm->offset);
memset(response_buf, 0, PAGE_SIZE);
bool ok = xhci_endpoint0_ctrl_in(xhci, usb_device, 0x80, 6, (2 << 8), 0, response_buf_phys, 9,
lockflags);
bool ok = xhci_endpoint0_ctrl_in(xhci, usb_device, 0x80, 6, (2 << 8), 0, response_buf_phys, 9);
if (!ok) {
pmm_free(response_buf_phys, 1);
@@ -858,8 +849,7 @@ static bool xhci_usb_device_setup_get_config(struct xhci* xhci, struct xhci_usb_
}
static bool xhci_usb_device_setup_get_config_full(struct xhci* xhci,
struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
struct xhci_usb_device* usb_device) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t response_buf_phys = pmm_alloc(1);
@@ -868,7 +858,7 @@ static bool xhci_usb_device_setup_get_config_full(struct xhci* xhci,
memset(response_buf, 0, PAGE_SIZE);
bool ok = xhci_endpoint0_ctrl_in(xhci, usb_device, 0x80, 6, (2 << 8), 0, response_buf_phys,
usb_device->config_desc.total_length, lockflags);
usb_device->config_desc.total_length);
if (!ok) {
pmm_free(response_buf_phys, 1);
@@ -927,8 +917,7 @@ static bool xhci_usb_device_setup_get_config_full(struct xhci* xhci,
return true;
}
static void xhci_poll_setup_init_ifs(struct xhci* xhci, struct xhci_usb_device* usb_device,
uint64_t* lockflags) {
static void xhci_poll_setup_init_ifs(struct xhci* xhci, struct xhci_usb_device* usb_device) {
struct reschedule_ctx rctx;
memset(&rctx, 0, sizeof(rctx));
@@ -941,11 +930,7 @@ static void xhci_poll_setup_init_ifs(struct xhci* xhci, struct xhci_usb_device*
if (if_->desc.if_class == info->if_class &&
if_->desc.if_subclass == info->if_subclass &&
if_->desc.if_proto == info->if_proto) {
spin_unlock(&xhci->device->lock, *lockflags);
struct device* device = info->init(xhci, usb_device, thiscpu->kproc, &rctx, lockflags);
spin_lock(&xhci->device->lock, lockflags);
struct device* device = info->init(xhci, usb_device, thiscpu->kproc, &rctx);
if (device == NULL)
DEBUG("USB driver failed to initialize. Skipping device!\n");
@@ -956,7 +941,7 @@ static void xhci_poll_setup_init_ifs(struct xhci* xhci, struct xhci_usb_device*
}
}
static void xhci_poll_setup_devices(struct xhci* xhci, uint64_t* lockflags) {
static void xhci_poll_setup_devices(struct xhci* xhci) {
struct list_node_link *usb_device_link, *tmp_usb_device_link;
bool ok;
@@ -968,26 +953,25 @@ static void xhci_poll_setup_devices(struct xhci* xhci, uint64_t* lockflags) {
if (usb_device->slot_id != -1)
continue;
ok = xhci_usb_device_setup_addressing(xhci, usb_device, lockflags);
ok = xhci_usb_device_setup_addressing(xhci, usb_device);
if (ok)
ok = xhci_usb_device_setup_get_info(xhci, usb_device, lockflags);
ok = xhci_usb_device_setup_get_info(xhci, usb_device);
if (ok)
ok = xhci_usb_device_setup_get_config(xhci, usb_device, lockflags);
ok = xhci_usb_device_setup_get_config(xhci, usb_device);
if (ok)
ok = xhci_usb_device_setup_get_config_full(xhci, usb_device, lockflags);
ok = xhci_usb_device_setup_get_config_full(xhci, usb_device);
if (ok)
ok = xhci_usb_device_setup_set_config(xhci, usb_device, usb_device->config_desc.config_value,
lockflags);
ok = xhci_usb_device_setup_set_config(xhci, usb_device, usb_device->config_desc.config_value);
if (ok)
ok = xhci_usb_device_setup_init_endpoints(xhci, usb_device, lockflags);
ok = xhci_usb_device_setup_init_endpoints(xhci, usb_device);
if (ok)
xhci_poll_setup_init_ifs(xhci, usb_device, lockflags);
xhci_poll_setup_init_ifs(xhci, usb_device);
}
}
@@ -1022,7 +1006,7 @@ static void xhci_poll_port_changes(struct xhci* xhci, struct proc* proc,
}
int xhci_bulk_transfer(struct xhci* xhci, struct xhci_usb_device* usb_device, uint8_t endpoint_addr,
uintptr_t buffer_phys, size_t buffer_size, uint64_t* lockflags) {
uintptr_t buffer_phys, size_t buffer_size) {
struct xhci_usb_device_endpoint* endpoint = NULL;
for (size_t ep = 0; ep < usb_device->endpoints_count; ep++) {
@@ -1076,14 +1060,15 @@ int xhci_bulk_transfer(struct xhci* xhci, struct xhci_usb_device* usb_device, ui
int timeout = 100;
spin_unlock(&xhci->device->lock, *lockflags);
xhci_write32(xhci->xhci_doorbell_base, usb_device->slot_id * 4, dci);
while (atomic_load(&endpoint->transfer_ring.pending) && --timeout > 0)
while (atomic_load(&endpoint->transfer_ring.pending) && --timeout > 0) {
biglock_unlock();
stall_ms(1);
spin_lock(&xhci->device->lock, lockflags);
biglock_lock();
}
if (timeout == 0) {
DEBUG("bulk transfer timed out\n");
@@ -1097,7 +1082,7 @@ DEFINE_DEVICE_OP(xhci_poll_driver) {
struct xhci* xhci = device->udata;
xhci_poll_port_changes(xhci, proc, rctx);
xhci_poll_setup_devices(xhci, lockflags);
xhci_poll_setup_devices(xhci);
return ST_OK;
}

View File

@@ -430,7 +430,7 @@ struct xhci {
};
int xhci_bulk_transfer(struct xhci* xhci, struct xhci_usb_device* usb_device, uint8_t endpoint_addr,
uintptr_t buffer_phys, size_t buffer_size, uint64_t* lockflags);
uintptr_t buffer_phys, size_t buffer_size);
DEFINE_DEVICE_INIT(xhci_init);