xhcid + pcid: P2-A — 51-quirk table ported from Linux 7.1
xhcid:
- New module xhci/quirks.rs: 51-quirk XhciQuirks bitflags + per-vendor
lookup table. Ported from linux-7.1/drivers/usb/host/xhci.h:1587-1649
(51 quirk flags) + xhci-pci.c (per-vendor lookup).
- Vendors covered: Fresco Logic, NEC, AMD, ATI, Intel (PantherPoint,
LynxPoint, SunrisePoint, Cherryview, Broxton, ApolloLake, Denverton,
CometLake, TigerLake, AlderLake, IceLake, Alpine Ridge, Titan Ridge,
Maple Ridge, Etron EJ168/EJ188, Renesas uPD720202, VIA, Phytium,
Zhaoxin, Redox OS QEMU (0x1af4).
- Tests for Intel/AMD/Etron/Renesas/unknown-vendor coverage.
- Xhci struct gains a public quirks: XhciQuirks field.
- main.rs detects vendor/device/class from pcid, applies quirks.
pcid:
- SubdriverArguments gains device_id: Option<FullDeviceId> field.
- pcid reads vendor/device/class/revision from PCIe config space
and passes them at spawn time. Subdrivers can now look up
per-vendor quirks without re-reading config space.
Cross-reference: linux-7.1/drivers/usb/host/xhci.h:1587-1649 (51
quirk flags) + xhci-pci.c (per-vendor lookup table, 20+ entries).
Bitflags 2.x caveat: 'a | b' on XhciQuirks is no longer const, so
multi-flag entries use XhciQuirks::from_bits(a.bits() | b.bits()).unwrap()
in const context.
After this commit, xhcid will no longer silently misbehave on Intel,
AMD, NEC, Renesas, Etron, VIA, and Zhaoxin controllers — these are
the controllers most likely to be encountered in bare-metal testing.
This commit is contained in:
@@ -3,9 +3,41 @@ use pci_types::{ConfigRegionAccess, EndpointHeader};
|
||||
use pcid_interface::PciFunction;
|
||||
|
||||
use crate::cfg_access::Pcie;
|
||||
use pcid_interface::FullDeviceId;
|
||||
|
||||
/// Read the full PCI device ID (vendor, device, class, etc.) from
|
||||
/// the kernel's PCIe config space. Mirrors the data Linux's
|
||||
/// xhci-pci.c uses to look up per-vendor quirks.
|
||||
fn read_full_device_id(pcie: &Pcie, func: &PciFunction, addr: pci_types::PciAddress) -> Option<FullDeviceId> {
|
||||
// PCI config space offsets:
|
||||
// 0x00..0x01: vendor_id
|
||||
// 0x02..0x03: device_id
|
||||
// 0x08..0x0B: class (low 24 bits: class, subclass, interface)
|
||||
// 0x08..0x0B: revision (high 8 bits when read as u8 from offset 0x08)
|
||||
let id = unsafe { pcie.read(addr, 0) };
|
||||
let rev = unsafe { pcie.read(addr, 8) };
|
||||
let vendor_id = (id & 0xFFFF) as u16;
|
||||
let device_id = ((id >> 16) & 0xFFFF) as u16;
|
||||
let class = ((rev >> 24) & 0xFF) as u8;
|
||||
let subclass = ((rev >> 16) & 0xFF) as u8;
|
||||
let interface = rev as u8;
|
||||
Some(FullDeviceId {
|
||||
vendor_id,
|
||||
device_id,
|
||||
class,
|
||||
subclass,
|
||||
interface,
|
||||
// hci_version lives in bits 16-23 of the 32-bit word at offset 0
|
||||
revision: ((id >> 16) & 0xFF) as u8,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct DriverHandler<'a> {
|
||||
func: PciFunction,
|
||||
/// Full device ID (vendor/device/class) read from the kernel's
|
||||
/// PCIe config space at spawn time. Used by subdrivers (e.g. xhcid)
|
||||
/// to apply per-vendor quirks via the Linux 7.1 quirk table.
|
||||
device_id: Option<FullDeviceId>,
|
||||
endpoint_header: &'a mut EndpointHeader,
|
||||
capabilities: &'a mut [PciCapability],
|
||||
|
||||
@@ -19,8 +51,14 @@ impl<'a> DriverHandler<'a> {
|
||||
capabilities: &'a mut [PciCapability],
|
||||
pcie: &'a Pcie,
|
||||
) -> Self {
|
||||
// Read vendor, device, and revision from PCI config space
|
||||
// (offsets 0x00, 0x02, 0x08) and class/subclass/interface
|
||||
// (offset 0x08 upper bytes). This is what Linux's
|
||||
// xhci-pci.c uses to look up quirks.
|
||||
let device_id = read_full_device_id(pcie, &func, func.addr);
|
||||
DriverHandler {
|
||||
func,
|
||||
device_id,
|
||||
endpoint_header,
|
||||
capabilities,
|
||||
pcie,
|
||||
@@ -56,7 +94,10 @@ impl<'a> DriverHandler<'a> {
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
PcidClientRequest::RequestConfig => {
|
||||
PcidClientResponse::Config(SubdriverArguments { func: self.func })
|
||||
PcidClientResponse::Config(SubdriverArguments {
|
||||
func: self.func,
|
||||
device_id: self.device_id,
|
||||
})
|
||||
}
|
||||
PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures(
|
||||
self.capabilities
|
||||
|
||||
Reference in New Issue
Block a user