From 9a4f9ddd05fe84b473c9b1f4557dabfa9562f8d7 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Tue, 7 Jul 2026 12:49:05 +0300 Subject: [PATCH] =?UTF-8?q?xhcid:=20P7-B=20slice=201=20=E2=80=94=20USB=203?= =?UTF-8?q?.0=20U1/U2/U3=20link=20states=20+=20timeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add USB 3.0 port link power management definitions and controls, cross-referenced with Linux 7.1 drivers/usb/host/xhci-port.h. Link state constants (PORTSC PLS field, bits 8:5): - XDEV_U0..XDEV_U3 (Active, U1, U2, Suspend) - XDEV_DISABLED, XDEV_RXDETECT, XDEV_INACTIVE - XDEV_POLLING, XDEV_RECOVERY, XDEV_HOT_RESET - XDEV_COMPLIANCE, XDEV_TEST_MODE, XDEV_RESUME Port PM Control (portpmsc): - PORT_U1_TIMEOUT_MASK (bits 7:0) - PORT_U2_TIMEOUT_MASK (bits 15:8) - PORT_FORCE_LINK_PM_ACCEPT (bit 19) Methods: - Port::set_u1_u2_timeout(u1, u2): programs U1/U2 inactivity timeout values with FORCE_LINK_PM_ACCEPT - Port::link_state(): reads current PLS value from PORTSC Cross-reference: Linux 7.1 - drivers/usb/host/xhci-port.h:18-28 (link states) - drivers/usb/host/xhci-port.h:128-132 (U1/U2 timeout masks) - drivers/usb/host/xhci-hub.c: xhci_set_link_state() --- drivers/usb/xhcid/src/xhci/port.rs | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/usb/xhcid/src/xhci/port.rs b/drivers/usb/xhcid/src/xhci/port.rs index c7624ab667..70f619102f 100644 --- a/drivers/usb/xhcid/src/xhci/port.rs +++ b/drivers/usb/xhcid/src/xhci/port.rs @@ -65,6 +65,30 @@ pub const PORT_HIRDM_MASK: u32 = 0x3u32; // Host Initiated Resume Durat pub const XHCI_DEFAULT_BESL: u32 = 4; pub const XHCI_L1_TIMEOUT: u32 = 512; // microseconds +// USB 3.0 Port Link States (PORTSC PLS field, bits 8:5). +// Cross-referenced with Linux 7.1 drivers/usb/host/xhci-port.h:18-21. +pub const XDEV_U0: u32 = 0x0 << 5; // Active +pub const XDEV_U1: u32 = 0x1 << 5; // Fast exit (<10us) +pub const XDEV_U2: u32 = 0x2 << 5; // Slower exit (>100us) +pub const XDEV_U3: u32 = 0x3 << 5; // Suspend +pub const XDEV_DISABLED: u32 = 0x4 << 5; +pub const XDEV_RXDETECT: u32 = 0x5 << 5; +pub const XDEV_INACTIVE: u32 = 0x6 << 5; +pub const XDEV_POLLING: u32 = 0x7 << 5; +pub const XDEV_RECOVERY: u32 = 0x8 << 5; +pub const XDEV_HOT_RESET: u32 = 0x9 << 5; +pub const XDEV_COMPLIANCE: u32 = 0xA << 5; +pub const XDEV_TEST_MODE: u32 = 0xB << 5; +pub const XDEV_RESUME: u32 = 0xF << 5; + +// Port PM Control (portpmsc) register bits (xHCI 1.1+). +// U1/U2 timeout values control how quickly the port transitions from +// U0 to U1/U2 after idling. See Linux xhci-port.h:128-132. +pub const PORT_U1_TIMEOUT_MASK: u32 = 0x0000_00FF; +pub const PORT_U2_TIMEOUT_SHIFT: u32 = 8; +pub const PORT_U2_TIMEOUT_MASK: u32 = 0x0000_FF00; +pub const PORT_FORCE_LINK_PM_ACCEPT: u32 = 1u32 << 19; // xHCI 1.1+ + impl Port { pub fn read(&self) -> u32 { self.portsc.read() @@ -135,4 +159,20 @@ impl Port { pub fn disable_lpm(&mut self) { self.porthlpmc.write(0); } + + /// Program U1/U2 inactivity timeout for USB 3.0 ports. + /// `u1_timeout` is multiplied by 256ns. + /// `u2_timeout` is multiplied by 1us. + /// Linux 7.1: xhci-hub.c computes these from device descriptors. + pub fn set_u1_u2_timeout(&mut self, u1_timeout: u8, u2_timeout: u8) { + let val = (u32::from(u1_timeout) & PORT_U1_TIMEOUT_MASK) + | ((u32::from(u2_timeout) << PORT_U2_TIMEOUT_SHIFT) & PORT_U2_TIMEOUT_MASK) + | PORT_FORCE_LINK_PM_ACCEPT; + self.portpmsc.write(val); + } + + /// Get the current port link state from PLS bits. + pub fn link_state(&self) -> u8 { + ((self.read() >> 5) & 0xF) as u8 + } }