Files
RedBear-OS/local/patches/base/P2-xhcid-remaining.patch
vasilito 76b75d80b4 fix: absorb redundant base daemon and driver patches
Consolidate ~30 absorbed base patches into surviving carriers. Add
new init service files, driver sources, and network/storage modules
for the base recipe. Move absorbed patches to local/patches/base/absorbed/.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-11 10:09:25 +01:00

374 lines
14 KiB
Diff

--- a/drivers/usb/xhcid/src/main.rs
+++ b/drivers/usb/xhcid/src/main.rs
@@ -33,7 +33,7 @@
use pcid_interface::irq_helpers::read_bsp_apic_id;
#[cfg(target_arch = "x86_64")]
use pcid_interface::irq_helpers::{
- allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi,
+ try_allocate_first_msi_interrupt_on_bsp, try_allocate_single_interrupt_vector_for_msi,
};
use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle};
@@ -61,11 +61,24 @@
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
if has_msix {
- let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) {
- PciFeatureInfo::Msi(_) => panic!(),
- PciFeatureInfo::MsiX(s) => s,
+ let msix_info = match pcid_handle.try_feature_info(PciFeature::MsiX) {
+ Ok(PciFeatureInfo::MsiX(s)) => s,
+ Ok(PciFeatureInfo::Msi(_)) => {
+ log::error!("xhcid: invalid MSI-X feature response payload");
+ return (None, InterruptMethod::Polling);
+ }
+ Err(err) => {
+ log::error!("xhcid: failed to fetch MSI-X feature info: {err}");
+ return (None, InterruptMethod::Polling);
+ }
};
- let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) };
+ let mut info = match unsafe { msix_info.try_map_and_mask_all(pcid_handle) } {
+ Ok(info) => info,
+ Err(err) => {
+ log::error!("xhcid: failed to map MSI-X registers: {err}");
+ return (None, InterruptMethod::Polling);
+ }
+ };
// Allocate one msi vector.
@@ -75,27 +88,53 @@
let table_entry_pointer = info.table_entry_pointer(k);
- let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id");
+ let destination_id = match read_bsp_apic_id() {
+ Ok(id) => id,
+ Err(err) => {
+ log::error!("xhcid: failed to read BSP APIC ID: {err}");
+ return (None, InterruptMethod::Polling);
+ }
+ };
let (msg_addr_and_data, interrupt_handle) =
- allocate_single_interrupt_vector_for_msi(destination_id);
+ match try_allocate_single_interrupt_vector_for_msi(destination_id) {
+ Ok(result) => result,
+ Err(err) => {
+ log::error!("xhcid: failed to allocate MSI-X vector: {err}");
+ return (None, InterruptMethod::Polling);
+ }
+ };
table_entry_pointer.write_addr_and_data(msg_addr_and_data);
table_entry_pointer.unmask();
(Some(interrupt_handle), InterruptMethod::Msi)
};
- pcid_handle.enable_feature(PciFeature::MsiX);
+ if let Err(err) = pcid_handle.try_enable_feature(PciFeature::MsiX) {
+ log::error!("xhcid: failed to enable MSI-X: {err}");
+ return (None, InterruptMethod::Polling);
+ }
log::debug!("Enabled MSI-X");
method
} else if has_msi {
- let interrupt_handle = allocate_first_msi_interrupt_on_bsp(pcid_handle);
- (Some(interrupt_handle), InterruptMethod::Msi)
+ match try_allocate_first_msi_interrupt_on_bsp(pcid_handle) {
+ Ok(interrupt_handle) => (Some(interrupt_handle), InterruptMethod::Msi),
+ Err(err) => {
+ log::error!("xhcid: failed to allocate MSI interrupt: {err}");
+ (None, InterruptMethod::Polling)
+ }
+ }
} else if let Some(irq) = pci_config.func.legacy_interrupt_line {
log::debug!("Legacy IRQ {}", irq);
// legacy INTx# interrupt pins.
- (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx)
+ match irq.try_irq_handle("xhcid") {
+ Ok(file) => (Some(file), InterruptMethod::Intx),
+ Err(err) => {
+ log::error!("xhcid: failed to open legacy IRQ handle: {err}");
+ (None, InterruptMethod::Polling)
+ }
+ }
} else {
// no interrupts at all
(None, InterruptMethod::Polling)
@@ -109,7 +148,13 @@
if let Some(irq) = pci_config.func.legacy_interrupt_line {
// legacy INTx# interrupt pins.
- (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx)
+ match irq.try_irq_handle("xhcid") {
+ Ok(file) => (Some(file), InterruptMethod::Intx),
+ Err(err) => {
+ log::error!("xhcid: failed to open legacy IRQ handle: {err}");
+ (None, InterruptMethod::Polling)
+ }
+ }
} else {
// no interrupts at all
(None, InterruptMethod::Polling)
@@ -136,23 +181,48 @@
log::debug!("XHCI PCI CONFIG: {:?}", pci_config);
- let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize;
-
- let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle);
- //TODO: Fix interrupts.
+ let address = match unsafe { pcid_handle.try_map_bar(0) } {
+ Ok(bar) => bar.ptr.as_ptr() as usize,
+ Err(err) => {
+ log::error!("xhcid: failed to map BAR0: {err}");
+ std::process::exit(1);
+ }
+ };
+
+ let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle);
+
+ match interrupt_method {
+ InterruptMethod::Msi => log::info!("xhcid: using MSI/MSI-X interrupt delivery"),
+ InterruptMethod::Intx => log::info!("xhcid: using legacy INTx interrupt delivery"),
+ InterruptMethod::Polling => log::warn!("xhcid: falling back to polling mode"),
+ }
log::info!("XHCI {}", pci_config.func.display());
let scheme_name = format!("usb.{}", name);
- let socket = Socket::create().expect("xhcid: failed to create usb scheme");
+ let socket = match Socket::create() {
+ Ok(socket) => socket,
+ Err(err) => {
+ log::error!("xhcid: failed to create usb scheme: {err}");
+ std::process::exit(1);
+ }
+ };
let handler = Blocking::new(&socket, 16);
let hci = Arc::new(
- Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle)
- .expect("xhcid: failed to allocate device"),
+ match Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle) {
+ Ok(hci) => hci,
+ Err(err) => {
+ log::error!("xhcid: failed to allocate device: {err}");
+ std::process::exit(1);
+ }
+ },
);
register_sync_scheme(&socket, &scheme_name, &mut &*hci)
- .expect("xhcid: failed to regsiter scheme to namespace");
+ .unwrap_or_else(|err| {
+ log::error!("xhcid: failed to register scheme to namespace: {err}");
+ std::process::exit(1);
+ });
daemon.ready();
@@ -163,7 +233,10 @@
handler
.process_requests_blocking(&*hci)
- .expect("xhcid: failed to process requests");
+ .unwrap_or_else(|err| {
+ log::error!("xhcid: failed to process requests: {err}");
+ std::process::exit(1);
+ });
}
fn main() {
@@ -171,7 +244,13 @@
}
fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
- let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize;
+ let address = match unsafe { pcid_handle.try_map_bar(0) } {
+ Ok(bar) => bar.ptr.as_ptr() as usize,
+ Err(err) => {
+ log::error!("xhcid: failed to map BAR0: {err}");
+ std::process::exit(1);
+ }
+ };
let cap = unsafe { &mut *(address as *mut xhci::CapabilityRegs) };
if cap.csz() {
daemon_with_context_size::<{ xhci::CONTEXT_64 }>(daemon, pcid_handle)
--- a/drivers/usb/xhcid/src/xhci/device_enumerator.rs
+++ b/drivers/usb/xhcid/src/xhci/device_enumerator.rs
@@ -4,8 +4,10 @@
use crossbeam_channel;
use log::{debug, info, warn};
use std::sync::Arc;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use syscall::EAGAIN;
+
+const DEFAULT_PORT_RESET_SETTLE_MS: u64 = 16;
pub struct DeviceEnumerationRequest {
pub port_id: PortId,
@@ -28,7 +30,11 @@
let request = match self.request_queue.recv() {
Ok(req) => req,
Err(err) => {
- panic!("Failed to received an enumeration request! error: {}", err)
+ warn!(
+ "device enumerator stopping after request queue closed: {}",
+ err
+ );
+ break;
}
};
@@ -38,7 +44,11 @@
debug!("Device Enumerator request for port {}", port_id);
let (len, flags) = {
- let ports = self.hci.ports.lock().unwrap();
+ let ports = self
+ .hci
+ .ports
+ .lock()
+ .unwrap_or_else(|poisoned| poisoned.into_inner());
let len = ports.len();
@@ -62,43 +72,52 @@
//A USB3 port won't generate a Connect Status Change until it's already enabled, so this check
//will always be skipped for USB3 ports
if !flags.contains(PortFlags::PED) {
- let disabled_state = flags.contains(PortFlags::PP)
- && flags.contains(PortFlags::CCS)
- && !flags.contains(PortFlags::PED)
- && !flags.contains(PortFlags::PR);
+ let disabled_state = Self::port_is_disabled(&flags);
if !disabled_state {
- panic!(
- "Port {} isn't in the disabled state! Current flags: {:?}",
+ warn!(
+ "Port {} never reached the disabled state before reset-driven enumeration; current flags: {:?}",
port_id, flags
);
+ continue;
} else {
debug!("Port {} has entered the disabled state.", port_id);
}
//THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT
debug!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id);
- let _ = self.hci.reset_port(port_id);
-
- let mut ports = self.hci.ports.lock().unwrap();
+ if let Err(err) = self.hci.reset_port(port_id) {
+ warn!(
+ "failed to reset port {} before enumeration; skipping attach: {}",
+ port_id, err
+ );
+ continue;
+ }
+
+ let mut ports = self
+ .hci
+ .ports
+ .lock()
+ .unwrap_or_else(|poisoned| poisoned.into_inner());
let port = &mut ports[port_array_index];
port.clear_prc();
- std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition.
-
- let flags = port.flags();
-
- let enabled_state = flags.contains(PortFlags::PP)
- && flags.contains(PortFlags::CCS)
- && flags.contains(PortFlags::PED)
- && !flags.contains(PortFlags::PR);
+ drop(ports);
+
+ let flags = self.wait_for_port_enabled_state(
+ port_array_index,
+ Duration::from_millis(DEFAULT_PORT_RESET_SETTLE_MS),
+ );
+
+ let enabled_state = Self::port_is_enabled(&flags);
if !enabled_state {
warn!(
- "Port {} isn't in the enabled state! Current flags: {:?}",
+ "Port {} isn't in the enabled state after bounded reset settle; current flags: {:?}",
port_id, flags
);
+ continue;
} else {
debug!(
"Port {} is in the enabled state. Proceeding with enumeration",
@@ -131,13 +150,60 @@
Ok(was_connected) => {
if was_connected {
info!("Device on port {} was detached", port_id);
+ } else {
+ debug!(
+ "Ignoring duplicate or out-of-order detach event for unattached port {}",
+ port_id
+ );
}
}
Err(err) => {
- warn!("processing of device attach request failed! Error: {}", err);
+ warn!("processing of device detach request failed! Error: {}", err);
}
}
}
}
}
+
+ fn port_is_disabled(flags: &PortFlags) -> bool {
+ flags.contains(PortFlags::PP)
+ && flags.contains(PortFlags::CCS)
+ && !flags.contains(PortFlags::PED)
+ && !flags.contains(PortFlags::PR)
+ }
+
+ fn port_is_enabled(flags: &PortFlags) -> bool {
+ flags.contains(PortFlags::PP)
+ && flags.contains(PortFlags::CCS)
+ && flags.contains(PortFlags::PED)
+ && !flags.contains(PortFlags::PR)
+ }
+
+ fn wait_for_port_enabled_state(
+ &self,
+ port_array_index: usize,
+ settle_timeout: Duration,
+ ) -> PortFlags {
+ let start = Instant::now();
+
+ loop {
+ let flags = {
+ let ports = self
+ .hci
+ .ports
+ .lock()
+ .unwrap_or_else(|poisoned| poisoned.into_inner());
+ ports[port_array_index].flags()
+ };
+
+ if Self::port_is_enabled(&flags)
+ || !flags.contains(PortFlags::PR)
+ || start.elapsed() >= settle_timeout
+ {
+ return flags;
+ }
+
+ std::thread::sleep(Duration::from_millis(1));
+ }
+ }
}