xhci: some quirks for Intel chipsets

This commit is contained in:
Mark Poliakov 2025-02-09 19:04:27 +02:00
parent 3e5f3fc6cd
commit f1becafaaf
4 changed files with 56 additions and 3 deletions

View File

@ -519,6 +519,16 @@ impl MsiXVectorTable<'_> {
}
impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> {
pub fn set_enabled(&mut self, enabled: bool) {
let mut w0 = self.space.read_u16(self.offset + 2);
if enabled {
w0 |= 1 << 0;
} else {
w0 &= !(1 << 0);
}
self.space.write_u16(self.offset + 2, w0);
}
pub fn register(
&mut self,
ic: &Arc<dyn MessageInterruptController>,

View File

@ -144,6 +144,10 @@ impl PciDeviceInfo {
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
{
if let Ok(mut vt) = msix.vector_table() {
if let Some(mut msi) = self.config_space.capability::<MsiCapability>() {
msi.set_enabled(false);
}
vt.mask_all();
msix.set_function_mask(false);

View File

@ -23,7 +23,7 @@ use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
LocalRegisterCopy,
};
use ygg_driver_pci::device::PciDeviceInfo;
use ygg_driver_pci::{device::PciDeviceInfo, PciConfigurationSpace};
use ygg_driver_usb::{
bus::UsbBusManager,
device::{UsbBusAddress, UsbDeviceAccess, UsbSpeed},
@ -32,6 +32,7 @@ use ygg_driver_usb::{
pipe::control::UsbControlPipeAccess,
UsbHostController,
};
use yggdrasil_abi::bitflags;
use crate::{
context::{XhciDeviceContext, XhciInputContext},
@ -52,6 +53,13 @@ use crate::{
util::EventBitmap,
};
bitflags! {
pub struct Quirks: u32 {
const INTEL: bit 0;
const INTEL_PANTHER_POINT: bit 1;
}
}
#[allow(unused)]
struct ScratchpadArray {
buffers: Vec<DmaBuffer<[MaybeUninit<u8>]>>,
@ -68,6 +76,7 @@ pub struct Xhci {
#[allow(unused)]
pci: PciDeviceInfo,
pub(crate) dma: Arc<dyn DmaAllocator>,
quirks: Quirks,
dcbaa: IrqSafeRwLock<DmaBuffer<[BusAddress]>>,
#[allow(unused)]
@ -106,10 +115,19 @@ impl Xhci {
pci: PciDeviceInfo,
regs: Regs,
) -> Result<Self, UsbError> {
let mut quirks = Quirks::empty();
if pci.vendor_id == 0x8086 {
quirks |= Quirks::INTEL;
if pci.device_id == 0x1E31 {
quirks |= Quirks::INTEL_PANTHER_POINT;
}
}
let mut dcbaa = DmaBuffer::new_slice(&*dma, BusAddress::ZERO, regs.slot_count + 1)
.map_err(UsbError::MemoryError)?;
let command_ring = CommandRing::new(&*dma, 128)?;
let event_ring = EventRing::new(&*dma, 128)?;
let event_ring = EventRing::new(&*dma, 64)?;
let erst = EventRingSegmentTable::for_event_rings(&*dma, &[&event_ring])?;
// Setup scratch buffers
@ -146,6 +164,18 @@ impl Xhci {
}
}
// TODO this is only needed if there's an EHCI controller as well
if quirks.contains(Quirks::INTEL_PANTHER_POINT) {
log::info!("quirk: intel pantherpoint xhci/ehci port switchover");
const INTEL_USB3PSSEN: usize = 0xD8;
const INTEL_XUSB2PR: usize = 0xD0;
let space = &pci.config_space;
space.write_u32(INTEL_USB3PSSEN, 0xFFFFFFFF);
space.write_u32(INTEL_XUSB2PR, 0xFFFFFFFF);
}
let port_slot_map = (0..regs.port_count).map(|_| AtomicU8::new(0)).collect();
let slots = (0..regs.slot_count)
.map(|_| IrqSafeRwLock::new(None))
@ -155,6 +185,7 @@ impl Xhci {
regs,
pci,
dma,
quirks,
dcbaa: IrqSafeRwLock::new(dcbaa),
scratchpads,
@ -483,6 +514,13 @@ impl Device for Xhci {
log::info!("xhci: start HC");
op.USBCMD.modify(USBCMD::INTE::SET + USBCMD::HSEE::SET);
op.USBCMD.modify(USBCMD::RS::SET);
if self.quirks.contains(Quirks::INTEL) {
for _ in 0..100000000 {
core::hint::spin_loop();
}
}
op.wait_usbsts_bit(USBSTS::CNR::CLEAR, 100000000)?;
let bus = UsbBusManager::register_bus(self.clone());
@ -500,6 +538,7 @@ impl Device for Xhci {
impl InterruptHandler for Xhci {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
log::info!("xhci irq");
let status = self.regs.handle_interrupt(0);
if status.matches_all(USBSTS::HSE::SET) {

View File

@ -59,7 +59,7 @@ impl RuntimeRegs {
interrupter.ERSTSZ.set(erst.capacity() as u32);
interrupter.ERSTBA.set(erstba);
interrupter.ERDP.set(erdp);
interrupter.IMAN.write(IMAN::IE::SET);
interrupter.IMAN.write(IMAN::IE::SET + IMAN::IP::SET);
}
pub fn set_interrupter_dequeue_pointer(&self, index: usize, erdp: BusAddress) {