diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs index 25be5a88c7..b452e3a4ec 100644 --- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs +++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs @@ -376,12 +376,15 @@ impl IrqReactor { trace!("Updated ERDP to {:#0x}", dequeue_pointer); - self.hci.run.lock().unwrap_or_else(|e| e.into_inner()).ints[0] - .erdp_low - .write(dequeue_pointer as u32); - self.hci.run.lock().unwrap_or_else(|e| e.into_inner()).ints[0] - .erdp_high - .write((dequeue_pointer >> 32) as u32); + let zero_64b = self.hci.quirks.contains(crate::xhci::quirks::XhciQuirks::ZERO_64B_REGS); + let mut run = self.hci.run.lock().unwrap_or_else(|e| e.into_inner()); + if zero_64b { + run.ints[0].erdp_high.write((dequeue_pointer >> 32) as u32); + run.ints[0].erdp_low.write(dequeue_pointer as u32); + } else { + run.ints[0].erdp_low.write(dequeue_pointer as u32); + run.ints[0].erdp_high.write((dequeue_pointer >> 32) as u32); + } } fn handle_requests(&mut self) { self.states.extend( diff --git a/drivers/usb/xhcid/src/xhci/mod.rs b/drivers/usb/xhcid/src/xhci/mod.rs index b27de564ff..8dd967932e 100644 --- a/drivers/usb/xhcid/src/xhci/mod.rs +++ b/drivers/usb/xhcid/src/xhci/mod.rs @@ -552,23 +552,21 @@ impl Xhci { // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); debug!("Writing DCBAAP: {:X}", dcbaap); - self.op.get_mut().unwrap().dcbaap_low.write(dcbaap as u32); - self.op - .get_mut() - .unwrap() - .dcbaap_high - .write((dcbaap as u64 >> 32) as u32); + { + let zero_64b = self.quirks.contains(crate::xhci::quirks::XhciQuirks::ZERO_64B_REGS); + let mut op = self.op.get_mut().unwrap(); + Self::write_64bit_reg(&mut op.dcbaap_low, &mut op.dcbaap_high, dcbaap as u64, zero_64b); + } // Set command ring control register let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); debug!("Writing CRCR: {:X}", crcr); - self.op.get_mut().unwrap().crcr_low.write(crcr as u32); - self.op - .get_mut() - .unwrap() - .crcr_high - .write((crcr as u64 >> 32) as u32); + { + let zero_64b = self.quirks.contains(crate::xhci::quirks::XhciQuirks::ZERO_64B_REGS); + let mut op = self.op.get_mut().unwrap(); + Self::write_64bit_reg(&mut op.crcr_low, &mut op.crcr_high, crcr, zero_64b); + } // Set event ring segment table registers debug!( @@ -584,8 +582,8 @@ impl Xhci { let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); debug!("Writing ERDP: {:X}", erdp); - int.erdp_low.write(erdp as u32 | (1 << 3)); - int.erdp_high.write((erdp as u64 >> 32) as u32); + let zero_64b = self.quirks.contains(crate::xhci::quirks::XhciQuirks::ZERO_64B_REGS); + Self::write_64bit_reg(&mut int.erdp_low, &mut int.erdp_high, erdp | (1 << 3), zero_64b); let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); debug!("Writing ERSTBA: {:X}", erstba); @@ -1030,6 +1028,19 @@ impl Xhci { ((self.dev_ctx.contexts[slot].slot.d.read() & SLOT_CONTEXT_STATE_MASK) >> SLOT_CONTEXT_STATE_SHIFT) as u8 } + /// Write a 64-bit register pair with quirk-aware ordering. + /// ZERO_64B_REGS (Renesas uPD720202): write HIGH first, then LOW. + /// Normal path: write LOW first, then HIGH. + fn write_64bit_reg(low: &mut common::io::Mmio, high: &mut common::io::Mmio, value: u64, zero_64b: bool) { + if zero_64b { + high.write((value >> 32) as u32); + low.write(value as u32); + } else { + low.write(value as u32); + high.write((value >> 32) as u32); + } + } + /// Returns effective 64-bit addressing capability, respecting NO_64BIT_SUPPORT quirk. fn ac64_effective(&self) -> bool { if self.quirks.contains(crate::xhci::quirks::XhciQuirks::NO_64BIT_SUPPORT) {