xhcid: gate xHCI 1.1+ features on HCCPARAMS2 + protocol-caps bits (P2-B)
Gate xHCI 1.1+ features on their capability bits, cross-referenced with
Linux 7.1 xhci driver behavior:
LEC (HCC2_LEC, scheme.rs):
- lec now uses Linux xhci-mem.c:1350 exact condition:
hci_version > 0x100 && hcc_params2 & HCC2_LEC (HCCPARAMS2 register
space is reserved on 1.0 controllers).
- Max ESIT Payload Hi zeroed when LEC=0 (spec Table 6-8 RsvdZ).
U3C (HCC2_U3C, mod.rs suspend_port):
- Refuse SuperSpeed U3 entry with ENOSYS when hci_ver >= 0x110 and
HCC2_U3C=0 (spec 4.15.1). USB2 suspend unaffected. Linux 7.1 defines
but never gates this bit; xhcid follows the spec.
CIC (HCC2_CIC): CIE gate pre-existing (set_cie from cic()); added the
hci_ver > 0x100 version guard. HCC2 capability log block similarly
guarded.
HW LPM (extended.rs, mod.rs, port.rs):
- New SupportedProtoCap::{l1_capable,hw_lpm_capable,besl_lpm_capable}
reading protocol-defined bits (Linux xhci-ext-caps.h:62-66 L1C/HLC/BLC).
- Xhci::hw_lpm_support computed per Linux xhci-mem.c:2137:
hci_ver >= 0x100 && !HW_LPM_DISABLE && any USB2 protocol cap has HLC.
- attach_device(): defensive LPM clear on USB 2.0 protocol ports
(rev_major() != 3) when hw_lpm_support is false — Linux xhci.c:4725
disable path; USB3 excluded because PORTPMSC L1DS aliases U2 timeout.
- Port::enable_lpm/disable_lpm register targets fixed: HLE/HIRD/RWE/
L1DS belong in PORTPMSC (offset 0x04), not PORTHLPMC (0x0C, bit 16
RsvdZ) — spec Tables 5-21/5-23, Linux xhci-port.h:135-158. Helpers
rewritten to Linux xhci.c:4686-4737 two-register sequence.
- Per-device L1 enablement (BESL, MEL Evaluate Context) defers to P3.
Bug fix: removed bogus CapabilityRegs::hlc() + HCC_PARAMS1_HLC_BIT —
they read xECP pointer bits 16-31 of HCCPARAMS1 (spec Table 5-13), not
HLC. HLC lives in the Supported Protocol capability port_info DWORD.
Verification: cargo check clean (138 warnings, -2 vs baseline: the new
disable_lpm call site also revived PORT_HLE/PORT_HIRD_MASK), 43/43
tests pass.
This commit is contained in:
@@ -146,9 +146,14 @@ pub const HCC_PARAMS1_NSS_BIT: u32 = 1u32 << 7;
|
||||
pub const HCC_PARAMS1_SPC_BIT: u32 = 1u32 << 9;
|
||||
/// Bit 11 — Contiguous Frame ID Capability (HCC_CFC).
|
||||
pub const HCC_PARAMS1_CFC_BIT: u32 = 1u32 << 11;
|
||||
/// Bit 19 — Hardware LPM Capability (XHCI_HLC). xHCI 1.1+.
|
||||
/// When set, the controller supports USB 2.0 Link Power Management.
|
||||
pub const HCC_PARAMS1_HLC_BIT: u32 = 1u32 << 19;
|
||||
|
||||
// NOTE: HCCPARAMS1 has NO Hardware LPM bit — bits 16-31 are the xECP
|
||||
// pointer (xHCI spec Table 5-13). USB 2.0 Hardware LPM Capability (HLC)
|
||||
// is protocol-defined bit 3 of the Supported Protocol extended
|
||||
// capability port_info DWORD (xHCI spec §7.2.2.1.3.2); see
|
||||
// `SupportedProtoCap::hw_lpm_capable()` in extended.rs. An earlier
|
||||
// revision mistakenly defined an HLC accessor reading bit 19 of this
|
||||
// register (i.e. an xECP pointer bit) — removed.
|
||||
|
||||
/// The mask to use to get the LEC bit from HCCParams2. See [CapabilityRegs]
|
||||
pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4;
|
||||
@@ -272,10 +277,6 @@ impl CapabilityRegs {
|
||||
pub fn spc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_SPC_BIT) }
|
||||
/// Contiguous Frame ID Capability (bit 11).
|
||||
pub fn cfc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_CFC_BIT) }
|
||||
/// USB 2.0 Hardware LPM Capability (bit 19, xHCI 1.1+).
|
||||
/// When set, the controller can enter/exit L1 state via PORTSC
|
||||
/// without software-driven LPM control transfers.
|
||||
pub fn hlc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_HLC_BIT) }
|
||||
|
||||
// -- HCSPARAMS3: U1/U2 exit latencies (xhci 1.1+ root-hub bos). --
|
||||
/// Maximum U1 device exit latency in microseconds. Used by the root
|
||||
|
||||
@@ -268,6 +268,25 @@ impl SupportedProtoCap {
|
||||
pub fn proto_defined(&self) -> u16 {
|
||||
((self.c.read() & SUPP_PROTO_CAP_PROTO_DEF_MASK) >> SUPP_PROTO_CAP_PROTO_DEF_SHIFT) as u16
|
||||
}
|
||||
/// USB 2.0 L1 Capability (L1C) — protocol-defined bit 0 of the
|
||||
/// Supported Protocol capability port_info DWORD.
|
||||
/// Linux 7.1 xhci-ext-caps.h:62 `XHCI_L1C (1 << 16)`.
|
||||
pub fn l1_capable(&self) -> bool {
|
||||
self.proto_defined() & 0x1 != 0
|
||||
}
|
||||
/// USB 2.0 Hardware LPM Capability (HLC) — protocol-defined bit 3.
|
||||
/// Meaningful only on USB 2.0 protocol entries (rev_major() != 3);
|
||||
/// USB3 ports use U1/U2 LPM instead.
|
||||
/// Linux 7.1 xhci-ext-caps.h:65 `XHCI_HLC (1 << 19)` and
|
||||
/// xhci-mem.c:2137 hw_lpm_support detection.
|
||||
pub fn hw_lpm_capable(&self) -> bool {
|
||||
self.proto_defined() & 0x8 != 0
|
||||
}
|
||||
/// USB 2.0 BESL LPM Capability (BLC) — protocol-defined bit 4.
|
||||
/// Linux 7.1 xhci-ext-caps.h:66 `XHCI_BLC (1 << 20)`.
|
||||
pub fn besl_lpm_capable(&self) -> bool {
|
||||
self.proto_defined() & 0x10 != 0
|
||||
}
|
||||
pub fn psic(&self) -> u8 {
|
||||
((self.c.read() & SUPP_PROTO_CAP_PSIC_MASK) >> SUPP_PROTO_CAP_PSIC_SHIFT) as u8
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use std::{mem, process, slice, thread};
|
||||
use syscall::error::{Error, Result, EBADF, EBADFD, EBADMSG, EINVAL, EIO, ENOENT};
|
||||
use syscall::error::{Error, Result, EBADF, EBADFD, EBADMSG, EINVAL, EIO, ENOENT, ENOSYS};
|
||||
use syscall::{EAGAIN, PAGE_SIZE};
|
||||
|
||||
use chashmap::CHashMap;
|
||||
@@ -261,6 +261,13 @@ pub struct Xhci<const N: usize> {
|
||||
/// Per-controller hardware quirks ported from Linux 7.1 xhci-pci.c.
|
||||
/// Set once at construction and read by hot paths to decide workarounds.
|
||||
pub quirks: crate::xhci::quirks::XhciQuirks,
|
||||
/// Whether USB 2.0 hardware Link Power Management (L1) is usable on
|
||||
/// this controller. Computed at init from
|
||||
/// `hci_version >= 0x100 && !HW_LPM_DISABLE && any USB 2.0 Supported
|
||||
/// Protocol cap has HLC set` — mirrors Linux 7.1 xhci-mem.c:2137
|
||||
/// `hw_lpm_support` detection. Consumed by per-device LPM enablement
|
||||
/// at attach time (hub work, P3).
|
||||
hw_lpm_support: bool,
|
||||
//page_size: usize,
|
||||
|
||||
// XXX: It would be really useful to be able to mutably access individual elements of a slice,
|
||||
@@ -476,6 +483,7 @@ impl<const N: usize> Xhci<N> {
|
||||
|
||||
cap,
|
||||
quirks,
|
||||
hw_lpm_support: false, // computed in init()
|
||||
//page_size,
|
||||
op: Mutex::new(op),
|
||||
ports: Mutex::new(ports),
|
||||
@@ -540,19 +548,33 @@ impl<const N: usize> Xhci<N> {
|
||||
self.op.get_mut().unwrap().config.read() & 0xFF
|
||||
);
|
||||
|
||||
// Log HCC2/HCS3 features the controller advertises. These are
|
||||
// xHCI 1.1+ extensions; on a 1.0 controller all are zero.
|
||||
// Future phases (P2-C, P3, P7) gate behavior on these bits.
|
||||
if self.cap.hcc2_u3c() { log::info!("xhcid: HCC2: U3 entry supported"); }
|
||||
if self.cap.hcc2_cmc() { log::info!("xhcid: HCC2: Configure Endpoint MaxExitLat too-large supported"); }
|
||||
if self.cap.hcc2_fsc() { log::info!("xhcid: HCC2: Force Save Context supported"); }
|
||||
if self.cap.hcc2_etc() { log::info!("xhcid: HCC2: Extended TBC supported"); }
|
||||
if self.cap.hcc2_gsc() { log::info!("xhcid: HCC2: Get/Set Extended Property supported"); }
|
||||
if self.cap.hcc2_vtc() { log::info!("xhcid: HCC2: Virtualization-based Trusted I/O supported"); }
|
||||
if self.cap.hcc2_e2v2c() { log::info!("xhcid: HCC2: eUSB2V2 supported"); }
|
||||
// HCCPARAMS1: USB 2.0 Hardware LPM (xHCI 1.1+).
|
||||
if self.cap.hlc() {
|
||||
log::info!("xhcid: HCC1: USB 2.0 Hardware LPM supported");
|
||||
// HCCPARAMS2 exists only on xHCI 1.1+; on 1.0 controllers its
|
||||
// register space is reserved, so every hcc2_* read is gated on
|
||||
// the version. Linux uses the same guard (xhci-mem.c:1350:
|
||||
// `hci_version > 0x100 && hcc_params2 & HCC2_LEC`).
|
||||
let hci_version = self.cap.hci_ver.read();
|
||||
|
||||
// USB 2.0 hardware LPM availability (Linux 7.1 xhci-mem.c:2137):
|
||||
// xHCI 1.0+ required, HW_LPM_DISABLE quirk vetoes, and at least
|
||||
// one USB 2.0 Supported Protocol capability must advertise HLC.
|
||||
self.hw_lpm_support = hci_version >= 0x100
|
||||
&& !self.quirks.contains(crate::xhci::quirks::XhciQuirks::HW_LPM_DISABLE)
|
||||
&& self
|
||||
.supported_protocols_iter()
|
||||
.any(|proto| proto.rev_major() != 3 && proto.hw_lpm_capable());
|
||||
|
||||
// Log HCC2/HCS3 features the controller advertises.
|
||||
if hci_version > 0x100 {
|
||||
if self.cap.hcc2_u3c() { log::info!("xhcid: HCC2: U3 entry supported"); }
|
||||
if self.cap.hcc2_cmc() { log::info!("xhcid: HCC2: Configure Endpoint MaxExitLat too-large supported"); }
|
||||
if self.cap.hcc2_fsc() { log::info!("xhcid: HCC2: Force Save Context supported"); }
|
||||
if self.cap.hcc2_etc() { log::info!("xhcid: HCC2: Extended TBC supported"); }
|
||||
if self.cap.hcc2_gsc() { log::info!("xhcid: HCC2: Get/Set Extended Property supported"); }
|
||||
if self.cap.hcc2_vtc() { log::info!("xhcid: HCC2: Virtualization-based Trusted I/O supported"); }
|
||||
if self.cap.hcc2_e2v2c() { log::info!("xhcid: HCC2: eUSB2V2 supported"); }
|
||||
}
|
||||
if self.hw_lpm_support {
|
||||
log::info!("xhcid: USB 2.0 Hardware LPM supported (HLC in protocol caps)");
|
||||
}
|
||||
log::info!(
|
||||
"xhcid: HCS3 U1_dev_exit_lat={}us U2_dev_exit_lat={}us",
|
||||
@@ -637,7 +659,13 @@ impl<const N: usize> Xhci<N> {
|
||||
|
||||
debug!("XHCI initialized.");
|
||||
|
||||
self.op.get_mut().unwrap().set_cie(self.cap.cic());
|
||||
// CIE enables Configuration Information in the input control
|
||||
// context (xHCI 1.1 §6.2.5.1); HCCPARAMS2.CIC is only defined on
|
||||
// xHCI 1.1+, hence the version guard.
|
||||
self.op
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.set_cie(hci_version > 0x100 && self.cap.cic());
|
||||
|
||||
self.print_port_capabilities();
|
||||
|
||||
@@ -649,13 +677,20 @@ impl<const N: usize> Xhci<N> {
|
||||
log::info!("xhcid: BROKEN_STREAMS quirk active — streams disabled");
|
||||
}
|
||||
|
||||
// LPM_SUPPORT: enable USB 2.0 Hardware Link Power Management.
|
||||
// Required for Intel host controllers. HW_LPM_DISABLE
|
||||
// overrides: some AMD/ASMedia controllers have broken LPM.
|
||||
// USB 2.0 hardware LPM state was computed above into
|
||||
// self.hw_lpm_support (mirrors Linux 7.1 xhci-mem.c:2137).
|
||||
// LPM_SUPPORT (Intel Panther Point and later) means the
|
||||
// controller is expected to advertise HLC; HW_LPM_DISABLE
|
||||
// (broken AMD/ASMedia LPM) vetoes it unconditionally. Actual
|
||||
// per-device L1 enablement happens at attach time once the
|
||||
// device BOS descriptor (lpm_capable) and BESL parameters are
|
||||
// known — hub-level work tracked as P3.
|
||||
if self.quirks.contains(crate::xhci::quirks::XhciQuirks::HW_LPM_DISABLE) {
|
||||
log::info!("xhcid: HW_LPM_DISABLE quirk active — LPM disabled");
|
||||
} else if self.quirks.contains(crate::xhci::quirks::XhciQuirks::LPM_SUPPORT) {
|
||||
log::info!("xhcid: LPM_SUPPORT quirk active — USB 2.0 LPM enabled");
|
||||
log::info!("xhcid: HW_LPM_DISABLE quirk active — hw_lpm_support=false");
|
||||
} else if self.quirks.contains(crate::xhci::quirks::XhciQuirks::LPM_SUPPORT)
|
||||
&& self.hw_lpm_support
|
||||
{
|
||||
log::info!("xhcid: LPM_SUPPORT quirk + HLC capability — USB 2.0 HW LPM available");
|
||||
}
|
||||
|
||||
// U2_DISABLE_WAKE: skip U2 wake configuration.
|
||||
@@ -945,6 +980,17 @@ impl<const N: usize> Xhci<N> {
|
||||
// The port speed field (bits 13:10) gives the current link speed.
|
||||
let speed = port.speed();
|
||||
let usb3 = speed >= 4; // SuperSpeed (4) or SuperSpeedPlus (5+)
|
||||
// HCC2_U3C (xHCI 1.1+, spec §4.15.1): when clear, the controller
|
||||
// does not support U3 entry on the SuperSpeed link. Refusing the
|
||||
// transition here is the spec-correct behavior; USB 2.0 port
|
||||
// suspend uses the bus-level suspended state and is unaffected.
|
||||
if usb3 && self.cap.hci_ver.read() >= 0x110 && !self.cap.hcc2_u3c() {
|
||||
log::warn!(
|
||||
"xhcid: refusing U3 suspend on port {} — controller is xHCI 1.1+ without U3 Entry Capability (HCC2_U3C=0)",
|
||||
port_id
|
||||
);
|
||||
return Err(Error::new(ENOSYS));
|
||||
}
|
||||
log::info!("xhcid: suspend port {} to U3 (USB3={})", port_id, usb3);
|
||||
port.suspend(usb3);
|
||||
Ok(())
|
||||
@@ -1113,7 +1159,8 @@ impl<const N: usize> Xhci<N> {
|
||||
);
|
||||
|
||||
if flags.contains(port::PortFlags::CCS) {
|
||||
let slot_ty = match self.supported_protocol(port_id) {
|
||||
let protocol = self.supported_protocol(port_id);
|
||||
let slot_ty = match protocol {
|
||||
Some(protocol) => protocol.proto_slot_ty(),
|
||||
None => {
|
||||
warn!("Failed to find supported protocol information for port");
|
||||
@@ -1121,6 +1168,30 @@ impl<const N: usize> Xhci<N> {
|
||||
}
|
||||
};
|
||||
|
||||
// Defensive LPM clear (Linux 7.1 xhci.c:4725 disable path):
|
||||
// when the controller lacks HW LPM support — or HW_LPM_DISABLE
|
||||
// vetoed it — scrub any firmware-leftover HLE state on USB 2.0
|
||||
// ports. USB 2.0 protocol ports only (rev_major() != 3, the
|
||||
// Linux test): on USB 3.0 ports the PORTPMSC L1DS field
|
||||
// aliases the U2 timeout field, so a blanket clear would
|
||||
// corrupt U2 LPM configuration.
|
||||
if !self.hw_lpm_support {
|
||||
if let Some(proto) = protocol {
|
||||
if proto.rev_major() != 3 {
|
||||
let mut ports = self.ports.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if let Some(idx) = port_id.root_hub_port_index() {
|
||||
if let Some(port) = ports.get_mut(idx) {
|
||||
port.disable_lpm();
|
||||
log::debug!(
|
||||
"xhcid: port {} HW LPM explicitly disabled (hw_lpm_support=false)",
|
||||
port_id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Slot type: {}", slot_ty);
|
||||
debug!("Enabling slot.");
|
||||
let slot = match self.enable_port_slot(slot_ty).await {
|
||||
|
||||
@@ -55,15 +55,23 @@ pub struct Port {
|
||||
pub porthlpmc: Mmio<u32>,
|
||||
}
|
||||
|
||||
// PORTHLPMC register bits (USB 2.0 LPM).
|
||||
// Cross-referenced with Linux 7.1 drivers/usb/host/xhci-port.h:135-173.
|
||||
pub const PORT_HLE: u32 = 1u32 << 16; // Hardware LPM Enable
|
||||
pub const PORT_HIRD_MASK: u32 = 0xFu32 << 4; // Host Initiated Resume Duration
|
||||
pub const PORT_L1_TIMEOUT_MASK: u32 = 0xFFu32 << 2;
|
||||
pub const PORT_BESLD_MASK: u32 = 0xFu32 << 10; // Best Effort Service Latency Deep
|
||||
pub const PORT_HIRDM_MASK: u32 = 0x3u32; // Host Initiated Resume Duration Mode
|
||||
// PORTPMSC register bits for USB 2.0 hardware LPM (xHCI spec Table 5-21;
|
||||
// Linux 7.1 xhci-port.h:135-143). HLE/HIRD/L1DS/RWE live in PORTPMSC
|
||||
// (offset 0x04), NOT in PORTHLPMC — an earlier revision of this file
|
||||
// wrote them to PORTHLPMC (offset 0x0C), where bit 16 is RsvdZ.
|
||||
pub const PORT_RWE: u32 = 1u32 << 3; // Remote Wake Enable
|
||||
pub const PORT_HIRD_MASK: u32 = 0xFu32 << 4; // Host Initiated Resume Duration (bits 7:4)
|
||||
pub const PORT_L1DS_MASK: u32 = 0xFFu32 << 8; // L1 Device Slot (bits 15:8)
|
||||
pub const PORT_HLE: u32 = 1u32 << 16; // Hardware LPM Enable
|
||||
|
||||
// PORTHLPMC register bits for USB 2.0 hardware LPM (xHCI spec Table 5-23;
|
||||
// Linux 7.1 xhci-port.h:156-158).
|
||||
pub const PORT_HIRDM_MASK: u32 = 0x3u32; // Host Initiated Resume Duration Mode (bits 1:0)
|
||||
pub const PORT_L1_TIMEOUT_MASK: u32 = 0xFFu32 << 2; // L1 timeout (bits 9:2)
|
||||
pub const PORT_BESLD_MASK: u32 = 0xFu32 << 10; // Best Effort Service Latency Deep (bits 13:10)
|
||||
|
||||
pub const XHCI_DEFAULT_BESL: u32 = 4;
|
||||
pub const XHCI_L1_TIMEOUT: u32 = 512; // microseconds
|
||||
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.
|
||||
@@ -146,18 +154,33 @@ impl Port {
|
||||
self.flags() & preserved
|
||||
}
|
||||
|
||||
/// Enable USB 2.0 Hardware LPM on this port.
|
||||
/// Linux 7.1: xhci_set_usb2_hardware_lpm() → sets PORT_HLE.
|
||||
pub fn enable_lpm(&mut self, hird: u32, l1_timeout: u32) {
|
||||
let val = PORT_HLE
|
||||
| ((hird & 0xF) << 4) // PORT_HIRD
|
||||
| ((l1_timeout & 0xFF) << 2); // PORT_L1_TIMEOUT
|
||||
self.porthlpmc.write(val);
|
||||
/// Enable USB 2.0 Hardware LPM (L1) on this port.
|
||||
/// Linux 7.1 xhci.c:4686-4722 xhci_set_usb2_hardware_lpm() enable
|
||||
/// path: PORTHLPMC ← HIRDM | L1_TIMEOUT | BESLD, then PORTPMSC ←
|
||||
/// HIRD | RWE | L1DS(slot), then PORTPMSC |= HLE to commit.
|
||||
pub fn enable_lpm(&mut self, slot_id: u8, hird: u32, besld: u32, l1_timeout: u32, hirdm: u32) {
|
||||
let hlpmc = (hirdm & PORT_HIRDM_MASK)
|
||||
| ((l1_timeout << 2) & PORT_L1_TIMEOUT_MASK)
|
||||
| ((besld << 10) & PORT_BESLD_MASK);
|
||||
self.porthlpmc.write(hlpmc);
|
||||
|
||||
let mut pm = self.portpmsc.read();
|
||||
pm &= !(PORT_HIRD_MASK | PORT_RWE | PORT_L1DS_MASK);
|
||||
pm |= ((hird << 4) & PORT_HIRD_MASK)
|
||||
| PORT_RWE
|
||||
| ((u32::from(slot_id) << 8) & PORT_L1DS_MASK);
|
||||
self.portpmsc.write(pm);
|
||||
self.portpmsc.write(pm | PORT_HLE);
|
||||
}
|
||||
|
||||
/// Disable USB 2.0 Hardware LPM on this port.
|
||||
/// Linux 7.1 xhci.c:4725-4737 disable path: clear HLE, RWE, HIRD
|
||||
/// and L1DS in PORTPMSC. PORTHLPMC contents are don't-care once
|
||||
/// HLE is clear.
|
||||
pub fn disable_lpm(&mut self) {
|
||||
self.porthlpmc.write(0);
|
||||
let pm =
|
||||
self.portpmsc.read() & !(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK);
|
||||
self.portpmsc.write(pm);
|
||||
}
|
||||
|
||||
/// Program U1/U2 inactivity timeout for USB 3.0 ports.
|
||||
|
||||
@@ -1570,7 +1570,12 @@ impl<const N: usize> Xhci<N> {
|
||||
config_desc.configuration_value,
|
||||
)
|
||||
};
|
||||
let lec = self.cap.lec();
|
||||
// LEC gates both the isoch Mult field and the Max ESIT Payload
|
||||
// Hi byte. Linux 7.1 xhci-mem.c:1350 xhci_get_endpoint_mult():
|
||||
// `lec = hci_version > 0x100 && (hcc_params2 & HCC2_LEC)` — the
|
||||
// version guard is required because HCCPARAMS2 is reserved space
|
||||
// on xHCI 1.0 controllers.
|
||||
let lec = self.cap.hci_ver.read() > 0x100 && self.cap.lec();
|
||||
let log_max_psa_size = self.cap.max_psa_size();
|
||||
|
||||
let port_speed_id = port.root_hub_port_index()
|
||||
@@ -1671,7 +1676,15 @@ impl<const N: usize> Xhci<N> {
|
||||
max_burst_size,
|
||||
);
|
||||
let max_esit_payload_lo = max_esit_payload as u16;
|
||||
let max_esit_payload_hi = ((max_esit_payload & 0x00FF_0000) >> 16) as u8;
|
||||
// xHCI 1.1 spec Table 6-8: Max ESIT Payload Hi (Endpoint
|
||||
// Context dw0 bits 31:24) is RsvdZ when LEC=0 — must be
|
||||
// zeroed on 1.0 controllers and 1.1+ controllers without the
|
||||
// Large ESIT Payload Capability.
|
||||
let max_esit_payload_hi = if lec {
|
||||
((max_esit_payload & 0x00FF_0000) >> 16) as u8
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let interval = Self::endp_ctx_interval(speed_id, endp_desc);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user