1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2018 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt::Display; 7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::str::FromStr; 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted; 11*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 12*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserializer; 13*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 14*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serializer; 15*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError; 16*bb4ee6a4SAndroid Build Coastguard Worker 17*bb4ee6a4SAndroid Build Coastguard Worker /// Identifies a single component of a [`PciAddress`]. 18*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)] 19*bb4ee6a4SAndroid Build Coastguard Worker pub enum PciAddressComponent { 20*bb4ee6a4SAndroid Build Coastguard Worker Domain, 21*bb4ee6a4SAndroid Build Coastguard Worker Bus, 22*bb4ee6a4SAndroid Build Coastguard Worker Device, 23*bb4ee6a4SAndroid Build Coastguard Worker Function, 24*bb4ee6a4SAndroid Build Coastguard Worker } 25*bb4ee6a4SAndroid Build Coastguard Worker 26*bb4ee6a4SAndroid Build Coastguard Worker /// PCI address parsing and conversion errors. 27*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug, PartialEq, Eq)] 28*bb4ee6a4SAndroid Build Coastguard Worker #[sorted] 29*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error { 30*bb4ee6a4SAndroid Build Coastguard Worker /// The specified component was outside the valid range. 31*bb4ee6a4SAndroid Build Coastguard Worker #[error("{0:?} out of range")] 32*bb4ee6a4SAndroid Build Coastguard Worker ComponentOutOfRange(PciAddressComponent), 33*bb4ee6a4SAndroid Build Coastguard Worker /// The specified component could not be parsed as a hexadecimal number. 34*bb4ee6a4SAndroid Build Coastguard Worker #[error("{0:?} failed to parse as hex")] 35*bb4ee6a4SAndroid Build Coastguard Worker InvalidHex(PciAddressComponent), 36*bb4ee6a4SAndroid Build Coastguard Worker /// The given PCI device path is invalid 37*bb4ee6a4SAndroid Build Coastguard Worker #[error("Invalid PCI device path")] 38*bb4ee6a4SAndroid Build Coastguard Worker InvalidHostPath, 39*bb4ee6a4SAndroid Build Coastguard Worker /// A delimiter (`:` or `.`) between the two specified components was missing or incorrect. 40*bb4ee6a4SAndroid Build Coastguard Worker #[error("Missing delimiter between {0:?} and {1:?}")] 41*bb4ee6a4SAndroid Build Coastguard Worker MissingDelimiter(PciAddressComponent, PciAddressComponent), 42*bb4ee6a4SAndroid Build Coastguard Worker /// The PCI address contained more than the expected number of components. 43*bb4ee6a4SAndroid Build Coastguard Worker #[error("Too many components in PCI address")] 44*bb4ee6a4SAndroid Build Coastguard Worker TooManyComponents, 45*bb4ee6a4SAndroid Build Coastguard Worker } 46*bb4ee6a4SAndroid Build Coastguard Worker 47*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>; 48*bb4ee6a4SAndroid Build Coastguard Worker 49*bb4ee6a4SAndroid Build Coastguard Worker /// PCI Device Address, AKA Bus:Device.Function 50*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 51*bb4ee6a4SAndroid Build Coastguard Worker pub struct PciAddress { 52*bb4ee6a4SAndroid Build Coastguard Worker /// Bus number, in the range `0..=255`. 53*bb4ee6a4SAndroid Build Coastguard Worker pub bus: u8, 54*bb4ee6a4SAndroid Build Coastguard Worker /// Device number, in the range `0..=31`. 55*bb4ee6a4SAndroid Build Coastguard Worker pub dev: u8, 56*bb4ee6a4SAndroid Build Coastguard Worker /// Function number, in the range `0..=7`. 57*bb4ee6a4SAndroid Build Coastguard Worker pub func: u8, 58*bb4ee6a4SAndroid Build Coastguard Worker } 59*bb4ee6a4SAndroid Build Coastguard Worker 60*bb4ee6a4SAndroid Build Coastguard Worker impl Serialize for PciAddress { serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,61*bb4ee6a4SAndroid Build Coastguard Worker fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> 62*bb4ee6a4SAndroid Build Coastguard Worker where 63*bb4ee6a4SAndroid Build Coastguard Worker S: Serializer, 64*bb4ee6a4SAndroid Build Coastguard Worker { 65*bb4ee6a4SAndroid Build Coastguard Worker serializer.serialize_str(&self.to_string()) 66*bb4ee6a4SAndroid Build Coastguard Worker } 67*bb4ee6a4SAndroid Build Coastguard Worker } 68*bb4ee6a4SAndroid Build Coastguard Worker 69*bb4ee6a4SAndroid Build Coastguard Worker impl<'de> Deserialize<'de> for PciAddress { deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> where D: Deserializer<'de>,70*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> 71*bb4ee6a4SAndroid Build Coastguard Worker where 72*bb4ee6a4SAndroid Build Coastguard Worker D: Deserializer<'de>, 73*bb4ee6a4SAndroid Build Coastguard Worker { 74*bb4ee6a4SAndroid Build Coastguard Worker let s = String::deserialize(deserializer)?; 75*bb4ee6a4SAndroid Build Coastguard Worker FromStr::from_str(&s).map_err(serde::de::Error::custom) 76*bb4ee6a4SAndroid Build Coastguard Worker } 77*bb4ee6a4SAndroid Build Coastguard Worker } 78*bb4ee6a4SAndroid Build Coastguard Worker 79*bb4ee6a4SAndroid Build Coastguard Worker /// Convert `PciAddress` to a human-readable string format. 80*bb4ee6a4SAndroid Build Coastguard Worker /// 81*bb4ee6a4SAndroid Build Coastguard Worker /// The display format will always include the domain component, even if it is zero. 82*bb4ee6a4SAndroid Build Coastguard Worker /// 83*bb4ee6a4SAndroid Build Coastguard Worker /// # Example 84*bb4ee6a4SAndroid Build Coastguard Worker /// 85*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 86*bb4ee6a4SAndroid Build Coastguard Worker /// use devices::PciAddress; 87*bb4ee6a4SAndroid Build Coastguard Worker /// 88*bb4ee6a4SAndroid Build Coastguard Worker /// let pci_address = PciAddress::new(0x0000, 0x03, 0x14, 0x1)?; 89*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.to_string(), "0000:03:14.1"); 90*bb4ee6a4SAndroid Build Coastguard Worker /// # Ok::<(), devices::PciAddressError>(()) 91*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 92*bb4ee6a4SAndroid Build Coastguard Worker impl Display for PciAddress { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94*bb4ee6a4SAndroid Build Coastguard Worker let domain = 0; 95*bb4ee6a4SAndroid Build Coastguard Worker write!( 96*bb4ee6a4SAndroid Build Coastguard Worker f, 97*bb4ee6a4SAndroid Build Coastguard Worker "{:04x}:{:02x}:{:02x}.{:0x}", 98*bb4ee6a4SAndroid Build Coastguard Worker domain, self.bus, self.dev, self.func, 99*bb4ee6a4SAndroid Build Coastguard Worker ) 100*bb4ee6a4SAndroid Build Coastguard Worker } 101*bb4ee6a4SAndroid Build Coastguard Worker } 102*bb4ee6a4SAndroid Build Coastguard Worker 103*bb4ee6a4SAndroid Build Coastguard Worker /// Construct `PciAddress` from string "\[domain:\]bus:device.function". 104*bb4ee6a4SAndroid Build Coastguard Worker /// Each component of the address is unprefixed hexadecimal. 105*bb4ee6a4SAndroid Build Coastguard Worker /// 106*bb4ee6a4SAndroid Build Coastguard Worker /// # Example 107*bb4ee6a4SAndroid Build Coastguard Worker /// 108*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 109*bb4ee6a4SAndroid Build Coastguard Worker /// use std::str::FromStr; 110*bb4ee6a4SAndroid Build Coastguard Worker /// use devices::PciAddress; 111*bb4ee6a4SAndroid Build Coastguard Worker /// 112*bb4ee6a4SAndroid Build Coastguard Worker /// let pci_address = PciAddress::from_str("d7:15.4")?; 113*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.bus, 0xd7); 114*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.dev, 0x15); 115*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.func, 0x4); 116*bb4ee6a4SAndroid Build Coastguard Worker /// # Ok::<(), devices::PciAddressError>(()) 117*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 118*bb4ee6a4SAndroid Build Coastguard Worker impl FromStr for PciAddress { 119*bb4ee6a4SAndroid Build Coastguard Worker type Err = Error; 120*bb4ee6a4SAndroid Build Coastguard Worker from_str(address: &str) -> std::result::Result<Self, Self::Err>121*bb4ee6a4SAndroid Build Coastguard Worker fn from_str(address: &str) -> std::result::Result<Self, Self::Err> { 122*bb4ee6a4SAndroid Build Coastguard Worker let (dev_bus_domain, func) = address.rsplit_once('.').ok_or(Error::MissingDelimiter( 123*bb4ee6a4SAndroid Build Coastguard Worker PciAddressComponent::Device, 124*bb4ee6a4SAndroid Build Coastguard Worker PciAddressComponent::Function, 125*bb4ee6a4SAndroid Build Coastguard Worker ))?; 126*bb4ee6a4SAndroid Build Coastguard Worker let func = u32::from_str_radix(func, 16) 127*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::InvalidHex(PciAddressComponent::Function))?; 128*bb4ee6a4SAndroid Build Coastguard Worker 129*bb4ee6a4SAndroid Build Coastguard Worker let (bus_domain, dev) = dev_bus_domain 130*bb4ee6a4SAndroid Build Coastguard Worker .rsplit_once(':') 131*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(Error::MissingDelimiter( 132*bb4ee6a4SAndroid Build Coastguard Worker PciAddressComponent::Bus, 133*bb4ee6a4SAndroid Build Coastguard Worker PciAddressComponent::Device, 134*bb4ee6a4SAndroid Build Coastguard Worker ))?; 135*bb4ee6a4SAndroid Build Coastguard Worker let dev = u32::from_str_radix(dev, 16) 136*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::InvalidHex(PciAddressComponent::Device))?; 137*bb4ee6a4SAndroid Build Coastguard Worker 138*bb4ee6a4SAndroid Build Coastguard Worker // Domain is optional; if unspecified, the rest of the string is the bus, and domain 139*bb4ee6a4SAndroid Build Coastguard Worker // defaults to 0. 140*bb4ee6a4SAndroid Build Coastguard Worker let (domain, bus) = bus_domain.rsplit_once(':').unwrap_or(("0", bus_domain)); 141*bb4ee6a4SAndroid Build Coastguard Worker let bus = u32::from_str_radix(bus, 16) 142*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::InvalidHex(PciAddressComponent::Bus))?; 143*bb4ee6a4SAndroid Build Coastguard Worker 144*bb4ee6a4SAndroid Build Coastguard Worker if domain.contains(':') { 145*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::TooManyComponents); 146*bb4ee6a4SAndroid Build Coastguard Worker } 147*bb4ee6a4SAndroid Build Coastguard Worker 148*bb4ee6a4SAndroid Build Coastguard Worker let domain = u32::from_str_radix(domain, 16) 149*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::InvalidHex(PciAddressComponent::Domain))?; 150*bb4ee6a4SAndroid Build Coastguard Worker 151*bb4ee6a4SAndroid Build Coastguard Worker Self::new(domain, bus, dev, func) 152*bb4ee6a4SAndroid Build Coastguard Worker } 153*bb4ee6a4SAndroid Build Coastguard Worker } 154*bb4ee6a4SAndroid Build Coastguard Worker 155*bb4ee6a4SAndroid Build Coastguard Worker impl PciAddress { 156*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 157*bb4ee6a4SAndroid Build Coastguard Worker const BUS_MASK: u32 = 0x00ff; 158*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 159*bb4ee6a4SAndroid Build Coastguard Worker const DEVICE_BITS_NUM: usize = 5; 160*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 161*bb4ee6a4SAndroid Build Coastguard Worker const DEVICE_MASK: u32 = 0x1f; 162*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 163*bb4ee6a4SAndroid Build Coastguard Worker const FUNCTION_BITS_NUM: usize = 3; 164*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 165*bb4ee6a4SAndroid Build Coastguard Worker const FUNCTION_MASK: u32 = 0x07; 166*bb4ee6a4SAndroid Build Coastguard Worker #[doc(hidden)] 167*bb4ee6a4SAndroid Build Coastguard Worker const REGISTER_OFFSET: usize = 2; 168*bb4ee6a4SAndroid Build Coastguard Worker 169*bb4ee6a4SAndroid Build Coastguard Worker /// Construct [`PciAddress`] from separate domain, bus, device, and function numbers. 170*bb4ee6a4SAndroid Build Coastguard Worker /// 171*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 172*bb4ee6a4SAndroid Build Coastguard Worker /// 173*bb4ee6a4SAndroid Build Coastguard Worker /// * `domain` - The PCI domain number. Must be `0` in the current implementation. 174*bb4ee6a4SAndroid Build Coastguard Worker /// * `bus` - The PCI bus number. Must be in the range `0..=255`. 175*bb4ee6a4SAndroid Build Coastguard Worker /// * `dev` - The PCI device number. Must be in the range `0..=31`. 176*bb4ee6a4SAndroid Build Coastguard Worker /// * `func` - The PCI function number. Must be in the range `0..=7`. 177*bb4ee6a4SAndroid Build Coastguard Worker /// 178*bb4ee6a4SAndroid Build Coastguard Worker /// # Errors 179*bb4ee6a4SAndroid Build Coastguard Worker /// 180*bb4ee6a4SAndroid Build Coastguard Worker /// If any component is out of the valid range, this function will return 181*bb4ee6a4SAndroid Build Coastguard Worker /// [`Error::ComponentOutOfRange`]. new(domain: u32, bus: u32, dev: u32, func: u32) -> Result<Self>182*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(domain: u32, bus: u32, dev: u32, func: u32) -> Result<Self> { 183*bb4ee6a4SAndroid Build Coastguard Worker if bus > Self::BUS_MASK { 184*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::ComponentOutOfRange(PciAddressComponent::Bus)); 185*bb4ee6a4SAndroid Build Coastguard Worker } 186*bb4ee6a4SAndroid Build Coastguard Worker 187*bb4ee6a4SAndroid Build Coastguard Worker if dev > Self::DEVICE_MASK { 188*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::ComponentOutOfRange(PciAddressComponent::Device)); 189*bb4ee6a4SAndroid Build Coastguard Worker } 190*bb4ee6a4SAndroid Build Coastguard Worker 191*bb4ee6a4SAndroid Build Coastguard Worker if func > Self::FUNCTION_MASK { 192*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::ComponentOutOfRange(PciAddressComponent::Function)); 193*bb4ee6a4SAndroid Build Coastguard Worker } 194*bb4ee6a4SAndroid Build Coastguard Worker 195*bb4ee6a4SAndroid Build Coastguard Worker // PciAddress does not store domain for now, so disallow anything other than domain 0. 196*bb4ee6a4SAndroid Build Coastguard Worker if domain > 0 { 197*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::ComponentOutOfRange(PciAddressComponent::Domain)); 198*bb4ee6a4SAndroid Build Coastguard Worker } 199*bb4ee6a4SAndroid Build Coastguard Worker 200*bb4ee6a4SAndroid Build Coastguard Worker Ok(PciAddress { 201*bb4ee6a4SAndroid Build Coastguard Worker bus: bus as u8, 202*bb4ee6a4SAndroid Build Coastguard Worker dev: dev as u8, 203*bb4ee6a4SAndroid Build Coastguard Worker func: func as u8, 204*bb4ee6a4SAndroid Build Coastguard Worker }) 205*bb4ee6a4SAndroid Build Coastguard Worker } 206*bb4ee6a4SAndroid Build Coastguard Worker 207*bb4ee6a4SAndroid Build Coastguard Worker /// Decode a [`PciAddress`] and register index from a CONFIG_ADDRESS value. 208*bb4ee6a4SAndroid Build Coastguard Worker /// 209*bb4ee6a4SAndroid Build Coastguard Worker /// The configuration address should be in the format used with the PCI CAM or ECAM 210*bb4ee6a4SAndroid Build Coastguard Worker /// configuration space access mechanisms, with the lowest bits encoding a register index and 211*bb4ee6a4SAndroid Build Coastguard Worker /// the bits above that encoding the PCI function (3 bits), device (5 bits), and bus (8 bits). 212*bb4ee6a4SAndroid Build Coastguard Worker /// The low two bits of the configuration address, which are technically part of the register 213*bb4ee6a4SAndroid Build Coastguard Worker /// number, are ignored, since PCI configuration space accesses must be DWORD (4-byte) aligned. 214*bb4ee6a4SAndroid Build Coastguard Worker /// 215*bb4ee6a4SAndroid Build Coastguard Worker /// On success, returns a [`PciAddress`] and the extracted register index in DWORDs. 216*bb4ee6a4SAndroid Build Coastguard Worker /// 217*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 218*bb4ee6a4SAndroid Build Coastguard Worker /// 219*bb4ee6a4SAndroid Build Coastguard Worker /// * `config_address` - The PCI configuration address. 220*bb4ee6a4SAndroid Build Coastguard Worker /// * `register_bits_num` - The size of the register value in bits. 221*bb4ee6a4SAndroid Build Coastguard Worker /// 222*bb4ee6a4SAndroid Build Coastguard Worker /// # Example 223*bb4ee6a4SAndroid Build Coastguard Worker /// 224*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 225*bb4ee6a4SAndroid Build Coastguard Worker /// use devices::PciAddress; 226*bb4ee6a4SAndroid Build Coastguard Worker /// 227*bb4ee6a4SAndroid Build Coastguard Worker /// let (pci_address, register_index) = PciAddress::from_config_address(0x32a354, 8); 228*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.bus, 0x32); 229*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.dev, 0x14); 230*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(pci_address.func, 0x3); 231*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(register_index, 0x15); 232*bb4ee6a4SAndroid Build Coastguard Worker /// ``` from_config_address(config_address: u32, register_bits_num: usize) -> (Self, usize)233*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_config_address(config_address: u32, register_bits_num: usize) -> (Self, usize) { 234*bb4ee6a4SAndroid Build Coastguard Worker let bus_offset = register_bits_num + Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM; 235*bb4ee6a4SAndroid Build Coastguard Worker let bus = ((config_address >> bus_offset) & Self::BUS_MASK) as u8; 236*bb4ee6a4SAndroid Build Coastguard Worker let dev_offset = register_bits_num + Self::FUNCTION_BITS_NUM; 237*bb4ee6a4SAndroid Build Coastguard Worker let dev = ((config_address >> dev_offset) & Self::DEVICE_MASK) as u8; 238*bb4ee6a4SAndroid Build Coastguard Worker let func = ((config_address >> register_bits_num) & Self::FUNCTION_MASK) as u8; 239*bb4ee6a4SAndroid Build Coastguard Worker let register_mask: u32 = (1_u32 << (register_bits_num - Self::REGISTER_OFFSET)) - 1; 240*bb4ee6a4SAndroid Build Coastguard Worker let register = ((config_address >> Self::REGISTER_OFFSET) & register_mask) as usize; 241*bb4ee6a4SAndroid Build Coastguard Worker 242*bb4ee6a4SAndroid Build Coastguard Worker (PciAddress { bus, dev, func }, register) 243*bb4ee6a4SAndroid Build Coastguard Worker } 244*bb4ee6a4SAndroid Build Coastguard Worker 245*bb4ee6a4SAndroid Build Coastguard Worker /// Construct [`PciAddress`] from a system PCI path 246*bb4ee6a4SAndroid Build Coastguard Worker /// 247*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 248*bb4ee6a4SAndroid Build Coastguard Worker /// 249*bb4ee6a4SAndroid Build Coastguard Worker /// * `path` - The system PCI path. The file name of this path must be a valid PCI address. 250*bb4ee6a4SAndroid Build Coastguard Worker /// 251*bb4ee6a4SAndroid Build Coastguard Worker /// # Errors 252*bb4ee6a4SAndroid Build Coastguard Worker /// 253*bb4ee6a4SAndroid Build Coastguard Worker /// If the path given is invalid or filename is an invalid PCI address, this function will 254*bb4ee6a4SAndroid Build Coastguard Worker /// return error. from_path(path: &Path) -> Result<Self>255*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_path(path: &Path) -> Result<Self> { 256*bb4ee6a4SAndroid Build Coastguard Worker let os_str = path.file_name().ok_or(Error::InvalidHostPath)?; 257*bb4ee6a4SAndroid Build Coastguard Worker let pci_str = os_str.to_str().ok_or(Error::InvalidHostPath)?; 258*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str(pci_str) 259*bb4ee6a4SAndroid Build Coastguard Worker } 260*bb4ee6a4SAndroid Build Coastguard Worker 261*bb4ee6a4SAndroid Build Coastguard Worker /// Encode [`PciAddress`] into CONFIG_ADDRESS value. 262*bb4ee6a4SAndroid Build Coastguard Worker /// 263*bb4ee6a4SAndroid Build Coastguard Worker /// See [`PciAddress::from_config_address()`] for details of the encoding. 264*bb4ee6a4SAndroid Build Coastguard Worker /// 265*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 266*bb4ee6a4SAndroid Build Coastguard Worker /// 267*bb4ee6a4SAndroid Build Coastguard Worker /// * `register` - The register index in DWORDs. 268*bb4ee6a4SAndroid Build Coastguard Worker /// * `register_bits_num` - The width of the register field, not including the two lowest bits. 269*bb4ee6a4SAndroid Build Coastguard Worker /// 270*bb4ee6a4SAndroid Build Coastguard Worker /// # Example 271*bb4ee6a4SAndroid Build Coastguard Worker /// 272*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 273*bb4ee6a4SAndroid Build Coastguard Worker /// use devices::PciAddress; 274*bb4ee6a4SAndroid Build Coastguard Worker /// 275*bb4ee6a4SAndroid Build Coastguard Worker /// let pci_address = PciAddress::new(0x0000, 0x32, 0x14, 0x3)?; 276*bb4ee6a4SAndroid Build Coastguard Worker /// let config_address = pci_address.to_config_address(0x15, 8); 277*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(config_address, 0x32a354); 278*bb4ee6a4SAndroid Build Coastguard Worker /// # Ok::<(), devices::PciAddressError>(()) 279*bb4ee6a4SAndroid Build Coastguard Worker /// ``` to_config_address(&self, register: usize, register_bits_num: usize) -> u32280*bb4ee6a4SAndroid Build Coastguard Worker pub fn to_config_address(&self, register: usize, register_bits_num: usize) -> u32 { 281*bb4ee6a4SAndroid Build Coastguard Worker let bus_offset = register_bits_num + Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM; 282*bb4ee6a4SAndroid Build Coastguard Worker let dev_offset = register_bits_num + Self::FUNCTION_BITS_NUM; 283*bb4ee6a4SAndroid Build Coastguard Worker let register_mask: u32 = (1_u32 << (register_bits_num - Self::REGISTER_OFFSET)) - 1; 284*bb4ee6a4SAndroid Build Coastguard Worker ((Self::BUS_MASK & self.bus as u32) << bus_offset) 285*bb4ee6a4SAndroid Build Coastguard Worker | ((Self::DEVICE_MASK & self.dev as u32) << dev_offset) 286*bb4ee6a4SAndroid Build Coastguard Worker | ((Self::FUNCTION_MASK & self.func as u32) << register_bits_num) 287*bb4ee6a4SAndroid Build Coastguard Worker | ((register_mask & register as u32) << Self::REGISTER_OFFSET) 288*bb4ee6a4SAndroid Build Coastguard Worker } 289*bb4ee6a4SAndroid Build Coastguard Worker 290*bb4ee6a4SAndroid Build Coastguard Worker /// Convert B:D:F PCI address to unsigned 32 bit integer. 291*bb4ee6a4SAndroid Build Coastguard Worker /// 292*bb4ee6a4SAndroid Build Coastguard Worker /// The bus, device, and function numbers are packed into an integer as follows: 293*bb4ee6a4SAndroid Build Coastguard Worker /// 294*bb4ee6a4SAndroid Build Coastguard Worker /// | Bits 15-8 | Bits 7-3 | Bits 2-0 | 295*bb4ee6a4SAndroid Build Coastguard Worker /// |-----------|----------|----------| 296*bb4ee6a4SAndroid Build Coastguard Worker /// | Bus | Device | Function | to_u32(&self) -> u32297*bb4ee6a4SAndroid Build Coastguard Worker pub fn to_u32(&self) -> u32 { 298*bb4ee6a4SAndroid Build Coastguard Worker ((Self::BUS_MASK & self.bus as u32) << (Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM)) 299*bb4ee6a4SAndroid Build Coastguard Worker | ((Self::DEVICE_MASK & self.dev as u32) << Self::FUNCTION_BITS_NUM) 300*bb4ee6a4SAndroid Build Coastguard Worker | (Self::FUNCTION_MASK & self.func as u32) 301*bb4ee6a4SAndroid Build Coastguard Worker } 302*bb4ee6a4SAndroid Build Coastguard Worker 303*bb4ee6a4SAndroid Build Coastguard Worker /// Convert D:F PCI address to a linux style devfn. 304*bb4ee6a4SAndroid Build Coastguard Worker /// 305*bb4ee6a4SAndroid Build Coastguard Worker /// The device and function numbers are packed into an u8 as follows: 306*bb4ee6a4SAndroid Build Coastguard Worker /// 307*bb4ee6a4SAndroid Build Coastguard Worker /// | Bits 7-3 | Bits 2-0 | 308*bb4ee6a4SAndroid Build Coastguard Worker /// |----------|----------| 309*bb4ee6a4SAndroid Build Coastguard Worker /// | Device | Function | devfn(&self) -> u8310*bb4ee6a4SAndroid Build Coastguard Worker pub fn devfn(&self) -> u8 { 311*bb4ee6a4SAndroid Build Coastguard Worker (self.dev << Self::FUNCTION_BITS_NUM) | self.func 312*bb4ee6a4SAndroid Build Coastguard Worker } 313*bb4ee6a4SAndroid Build Coastguard Worker 314*bb4ee6a4SAndroid Build Coastguard Worker /// Convert D:F PCI address to an ACPI _ADR. 315*bb4ee6a4SAndroid Build Coastguard Worker /// 316*bb4ee6a4SAndroid Build Coastguard Worker /// The device and function numbers are packed into an u32 as follows: 317*bb4ee6a4SAndroid Build Coastguard Worker /// 318*bb4ee6a4SAndroid Build Coastguard Worker /// | Bits 31-16 | Bits 15-0 | 319*bb4ee6a4SAndroid Build Coastguard Worker /// |------------|-----------| 320*bb4ee6a4SAndroid Build Coastguard Worker /// | Device | Function | acpi_adr(&self) -> u32321*bb4ee6a4SAndroid Build Coastguard Worker pub fn acpi_adr(&self) -> u32 { 322*bb4ee6a4SAndroid Build Coastguard Worker ((Self::DEVICE_MASK & self.dev as u32) << 16) | (Self::FUNCTION_MASK & self.func as u32) 323*bb4ee6a4SAndroid Build Coastguard Worker } 324*bb4ee6a4SAndroid Build Coastguard Worker 325*bb4ee6a4SAndroid Build Coastguard Worker /// Convert B:D:F PCI address to a PCI PME Requester ID. 326*bb4ee6a4SAndroid Build Coastguard Worker /// 327*bb4ee6a4SAndroid Build Coastguard Worker /// The output is identical to `to_u32()` except that only the lower 16 bits are needed pme_requester_id(&self) -> u16328*bb4ee6a4SAndroid Build Coastguard Worker pub fn pme_requester_id(&self) -> u16 { 329*bb4ee6a4SAndroid Build Coastguard Worker self.to_u32() as u16 330*bb4ee6a4SAndroid Build Coastguard Worker } 331*bb4ee6a4SAndroid Build Coastguard Worker 332*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true if the address points to PCI root host-bridge. 333*bb4ee6a4SAndroid Build Coastguard Worker /// 334*bb4ee6a4SAndroid Build Coastguard Worker /// This is true if and only if this is the all-zero address (`00:0.0`). is_root(&self) -> bool335*bb4ee6a4SAndroid Build Coastguard Worker pub fn is_root(&self) -> bool { 336*bb4ee6a4SAndroid Build Coastguard Worker matches!( 337*bb4ee6a4SAndroid Build Coastguard Worker &self, 338*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 339*bb4ee6a4SAndroid Build Coastguard Worker bus: 0, 340*bb4ee6a4SAndroid Build Coastguard Worker dev: 0, 341*bb4ee6a4SAndroid Build Coastguard Worker func: 0 342*bb4ee6a4SAndroid Build Coastguard Worker } 343*bb4ee6a4SAndroid Build Coastguard Worker ) 344*bb4ee6a4SAndroid Build Coastguard Worker } 345*bb4ee6a4SAndroid Build Coastguard Worker } 346*bb4ee6a4SAndroid Build Coastguard Worker 347*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 348*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 349*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 350*bb4ee6a4SAndroid Build Coastguard Worker 351*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string()352*bb4ee6a4SAndroid Build Coastguard Worker fn from_string() { 353*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 354*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:00:00.0").unwrap(), 355*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 356*bb4ee6a4SAndroid Build Coastguard Worker bus: 0, 357*bb4ee6a4SAndroid Build Coastguard Worker dev: 0, 358*bb4ee6a4SAndroid Build Coastguard Worker func: 0 359*bb4ee6a4SAndroid Build Coastguard Worker } 360*bb4ee6a4SAndroid Build Coastguard Worker ); 361*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 362*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("00:00.0").unwrap(), 363*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 364*bb4ee6a4SAndroid Build Coastguard Worker bus: 0, 365*bb4ee6a4SAndroid Build Coastguard Worker dev: 0, 366*bb4ee6a4SAndroid Build Coastguard Worker func: 0 367*bb4ee6a4SAndroid Build Coastguard Worker } 368*bb4ee6a4SAndroid Build Coastguard Worker ); 369*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 370*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("01:02.3").unwrap(), 371*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 372*bb4ee6a4SAndroid Build Coastguard Worker bus: 1, 373*bb4ee6a4SAndroid Build Coastguard Worker dev: 2, 374*bb4ee6a4SAndroid Build Coastguard Worker func: 3 375*bb4ee6a4SAndroid Build Coastguard Worker } 376*bb4ee6a4SAndroid Build Coastguard Worker ); 377*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 378*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("ff:1f.7").unwrap(), 379*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 380*bb4ee6a4SAndroid Build Coastguard Worker bus: 0xff, 381*bb4ee6a4SAndroid Build Coastguard Worker dev: 0x1f, 382*bb4ee6a4SAndroid Build Coastguard Worker func: 7, 383*bb4ee6a4SAndroid Build Coastguard Worker } 384*bb4ee6a4SAndroid Build Coastguard Worker ); 385*bb4ee6a4SAndroid Build Coastguard Worker } 386*bb4ee6a4SAndroid Build Coastguard Worker 387*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_missing_func_delim()388*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_missing_func_delim() { 389*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 390*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("1").expect_err("parse should fail"), 391*bb4ee6a4SAndroid Build Coastguard Worker Error::MissingDelimiter(PciAddressComponent::Device, PciAddressComponent::Function) 392*bb4ee6a4SAndroid Build Coastguard Worker ); 393*bb4ee6a4SAndroid Build Coastguard Worker } 394*bb4ee6a4SAndroid Build Coastguard Worker 395*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_missing_dev_delim()396*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_missing_dev_delim() { 397*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 398*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("2.1").expect_err("parse should fail"), 399*bb4ee6a4SAndroid Build Coastguard Worker Error::MissingDelimiter(PciAddressComponent::Bus, PciAddressComponent::Device) 400*bb4ee6a4SAndroid Build Coastguard Worker ); 401*bb4ee6a4SAndroid Build Coastguard Worker } 402*bb4ee6a4SAndroid Build Coastguard Worker 403*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_extra_components()404*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_extra_components() { 405*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 406*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0:0:0:0.0").expect_err("parse should fail"), 407*bb4ee6a4SAndroid Build Coastguard Worker Error::TooManyComponents 408*bb4ee6a4SAndroid Build Coastguard Worker ); 409*bb4ee6a4SAndroid Build Coastguard Worker } 410*bb4ee6a4SAndroid Build Coastguard Worker 411*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_func_hex()412*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_func_hex() { 413*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 414*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:00:00.g").expect_err("parse should fail"), 415*bb4ee6a4SAndroid Build Coastguard Worker Error::InvalidHex(PciAddressComponent::Function) 416*bb4ee6a4SAndroid Build Coastguard Worker ); 417*bb4ee6a4SAndroid Build Coastguard Worker } 418*bb4ee6a4SAndroid Build Coastguard Worker 419*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_func_range()420*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_func_range() { 421*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 422*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:00:00.8").expect_err("parse should fail"), 423*bb4ee6a4SAndroid Build Coastguard Worker Error::ComponentOutOfRange(PciAddressComponent::Function) 424*bb4ee6a4SAndroid Build Coastguard Worker ); 425*bb4ee6a4SAndroid Build Coastguard Worker } 426*bb4ee6a4SAndroid Build Coastguard Worker 427*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_dev_hex()428*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_dev_hex() { 429*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 430*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:00:gg.0").expect_err("parse should fail"), 431*bb4ee6a4SAndroid Build Coastguard Worker Error::InvalidHex(PciAddressComponent::Device) 432*bb4ee6a4SAndroid Build Coastguard Worker ); 433*bb4ee6a4SAndroid Build Coastguard Worker } 434*bb4ee6a4SAndroid Build Coastguard Worker 435*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_dev_range()436*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_dev_range() { 437*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 438*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:00:20.0").expect_err("parse should fail"), 439*bb4ee6a4SAndroid Build Coastguard Worker Error::ComponentOutOfRange(PciAddressComponent::Device) 440*bb4ee6a4SAndroid Build Coastguard Worker ); 441*bb4ee6a4SAndroid Build Coastguard Worker } 442*bb4ee6a4SAndroid Build Coastguard Worker 443*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_bus_hex()444*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_bus_hex() { 445*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 446*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:gg:00.0").expect_err("parse should fail"), 447*bb4ee6a4SAndroid Build Coastguard Worker Error::InvalidHex(PciAddressComponent::Bus) 448*bb4ee6a4SAndroid Build Coastguard Worker ); 449*bb4ee6a4SAndroid Build Coastguard Worker } 450*bb4ee6a4SAndroid Build Coastguard Worker 451*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_bus_range()452*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_bus_range() { 453*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 454*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0000:100:00.0").expect_err("parse should fail"), 455*bb4ee6a4SAndroid Build Coastguard Worker Error::ComponentOutOfRange(PciAddressComponent::Bus) 456*bb4ee6a4SAndroid Build Coastguard Worker ); 457*bb4ee6a4SAndroid Build Coastguard Worker } 458*bb4ee6a4SAndroid Build Coastguard Worker 459*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_domain_hex()460*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_domain_hex() { 461*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 462*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("gggg:00:00.0").expect_err("parse should fail"), 463*bb4ee6a4SAndroid Build Coastguard Worker Error::InvalidHex(PciAddressComponent::Domain) 464*bb4ee6a4SAndroid Build Coastguard Worker ); 465*bb4ee6a4SAndroid Build Coastguard Worker } 466*bb4ee6a4SAndroid Build Coastguard Worker 467*bb4ee6a4SAndroid Build Coastguard Worker #[test] from_string_invalid_domain_range()468*bb4ee6a4SAndroid Build Coastguard Worker fn from_string_invalid_domain_range() { 469*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 470*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::from_str("0001:00:00.0").expect_err("parse should fail"), 471*bb4ee6a4SAndroid Build Coastguard Worker Error::ComponentOutOfRange(PciAddressComponent::Domain) 472*bb4ee6a4SAndroid Build Coastguard Worker ); 473*bb4ee6a4SAndroid Build Coastguard Worker } 474*bb4ee6a4SAndroid Build Coastguard Worker 475*bb4ee6a4SAndroid Build Coastguard Worker #[test] format_simple()476*bb4ee6a4SAndroid Build Coastguard Worker fn format_simple() { 477*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 478*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::new(0, 1, 2, 3).unwrap().to_string(), 479*bb4ee6a4SAndroid Build Coastguard Worker "0000:01:02.3" 480*bb4ee6a4SAndroid Build Coastguard Worker ); 481*bb4ee6a4SAndroid Build Coastguard Worker } 482*bb4ee6a4SAndroid Build Coastguard Worker 483*bb4ee6a4SAndroid Build Coastguard Worker #[test] format_max()484*bb4ee6a4SAndroid Build Coastguard Worker fn format_max() { 485*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 486*bb4ee6a4SAndroid Build Coastguard Worker PciAddress::new(0, 0xff, 0x1f, 7).unwrap().to_string(), 487*bb4ee6a4SAndroid Build Coastguard Worker "0000:ff:1f.7" 488*bb4ee6a4SAndroid Build Coastguard Worker ); 489*bb4ee6a4SAndroid Build Coastguard Worker } 490*bb4ee6a4SAndroid Build Coastguard Worker 491*bb4ee6a4SAndroid Build Coastguard Worker #[test] serialize_json()492*bb4ee6a4SAndroid Build Coastguard Worker fn serialize_json() { 493*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 494*bb4ee6a4SAndroid Build Coastguard Worker serde_json::to_string(&PciAddress::new(0, 0xa5, 0x1f, 3).unwrap()).unwrap(), 495*bb4ee6a4SAndroid Build Coastguard Worker "\"0000:a5:1f.3\"" 496*bb4ee6a4SAndroid Build Coastguard Worker ); 497*bb4ee6a4SAndroid Build Coastguard Worker } 498*bb4ee6a4SAndroid Build Coastguard Worker 499*bb4ee6a4SAndroid Build Coastguard Worker #[test] deserialize_json()500*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_json() { 501*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 502*bb4ee6a4SAndroid Build Coastguard Worker serde_json::from_str::<PciAddress>("\"0000:a5:1f.3\"").unwrap(), 503*bb4ee6a4SAndroid Build Coastguard Worker PciAddress { 504*bb4ee6a4SAndroid Build Coastguard Worker bus: 0xa5, 505*bb4ee6a4SAndroid Build Coastguard Worker dev: 0x1f, 506*bb4ee6a4SAndroid Build Coastguard Worker func: 3, 507*bb4ee6a4SAndroid Build Coastguard Worker } 508*bb4ee6a4SAndroid Build Coastguard Worker ); 509*bb4ee6a4SAndroid Build Coastguard Worker } 510*bb4ee6a4SAndroid Build Coastguard Worker } 511