Merge branch 'pcid_cleanup2' into 'master'

Split up pcid's main.rs and remove parsing for unused capabilities

See merge request redox-os/drivers!159
This commit is contained in:
Jeremy Soller
2024-06-10 17:43:35 +00:00
3 changed files with 389 additions and 307 deletions
+331
View File
@@ -0,0 +1,331 @@
use std::fs::File;
use std::os::unix::io::{FromRawFd, RawFd};
use std::process::Command;
use std::sync::Arc;
use std::thread;
use log::{error, info};
use pci_types::PciAddress;
use crate::driver_interface;
use crate::pci::cap::Capability as PciCapability;
use crate::pci::PciFunc;
use crate::State;
pub struct DriverHandler {
addr: PciAddress,
capabilities: Vec<(u8, PciCapability)>,
state: Arc<State>,
}
impl DriverHandler {
pub fn spawn(
state: Arc<State>,
func: driver_interface::PciFunction,
capabilities: Vec<(u8, PciCapability)>,
args: &[String],
) {
let subdriver_args = driver_interface::SubdriverArguments { func };
let mut args = args.iter();
if let Some(program) = args.next() {
let mut command = Command::new(program);
for arg in args {
if arg.starts_with("$") {
panic!("support for $VARIABLE has been removed. use pcid_interface instead");
}
command.arg(arg);
}
info!("PCID SPAWN {:?}", command);
// TODO: libc wrapper?
let [fds1, fds2] = unsafe {
let mut fds1 = [0 as libc::c_int; 2];
let mut fds2 = [0 as libc::c_int; 2];
assert_eq!(
libc::pipe(fds1.as_mut_ptr()),
0,
"pcid: failed to create pcid->client pipe"
);
assert_eq!(
libc::pipe(fds2.as_mut_ptr()),
0,
"pcid: failed to create client->pcid pipe"
);
[fds1.map(|c| c as usize), fds2.map(|c| c as usize)]
};
let [pcid_to_client_read, pcid_to_client_write] = fds1;
let [pcid_from_client_read, pcid_from_client_write] = fds2;
let envs = vec![
("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)),
("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)),
];
match command.envs(envs).spawn() {
Ok(mut child) => {
let driver_handler = DriverHandler {
addr: func.addr,
state,
capabilities,
};
let _handle = thread::spawn(move || {
driver_handler.handle_spawn(
pcid_to_client_write,
pcid_from_client_read,
subdriver_args,
);
});
// FIXME this currently deadlocks as pcid doesn't daemonize
//state.threads.lock().unwrap().push(handle);
match child.wait() {
Ok(_status) => (),
Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err),
}
}
Err(err) => error!("pcid: failed to execute {:?}: {}", command, err),
}
}
}
fn respond(
&mut self,
request: driver_interface::PcidClientRequest,
args: &driver_interface::SubdriverArguments,
) -> driver_interface::PcidClientResponse {
use crate::pci::cap::{MsiCapability, MsixCapability};
use driver_interface::*;
let func = PciFunc {
pci: &self.state.pcie,
addr: self.addr,
};
match request {
PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities(
self.capabilities
.iter()
.map(|(_, capability)| capability.clone())
.collect::<Vec<_>>(),
),
PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()),
PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures(
self.capabilities
.iter()
.filter_map(|(_, capability)| match capability {
PciCapability::Msi(msi) => {
Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled())))
}
PciCapability::MsiX(msix) => Some((
PciFeature::MsiX,
FeatureStatus::enabled(msix.msix_enabled()),
)),
_ => None,
})
.collect(),
),
PcidClientRequest::EnableFeature(feature) => match feature {
PciFeature::Msi => {
let (offset, capability): (u8, &mut MsiCapability) = match self
.capabilities
.iter_mut()
.find_map(|&mut (offset, ref mut capability)| {
capability.as_msi_mut().map(|cap| (offset, cap))
}) {
Some(tuple) => tuple,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
unsafe {
capability.set_enabled(true);
capability.write_message_control(&func, offset);
}
PcidClientResponse::FeatureEnabled(feature)
}
PciFeature::MsiX => {
let (offset, capability): (u8, &mut MsixCapability) = match self
.capabilities
.iter_mut()
.find_map(|&mut (offset, ref mut capability)| {
capability.as_msix_mut().map(|cap| (offset, cap))
}) {
Some(tuple) => tuple,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
unsafe {
capability.set_msix_enabled(true);
capability.write_a(&func, offset);
}
PcidClientResponse::FeatureEnabled(feature)
}
},
PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(
feature,
match feature {
PciFeature::Msi => self
.capabilities
.iter()
.find_map(|(_, capability)| {
if let PciCapability::Msi(msi) = capability {
Some(FeatureStatus::enabled(msi.enabled()))
} else {
None
}
})
.unwrap_or(FeatureStatus::Disabled),
PciFeature::MsiX => self
.capabilities
.iter()
.find_map(|(_, capability)| {
if let PciCapability::MsiX(msix) = capability {
Some(FeatureStatus::enabled(msix.msix_enabled()))
} else {
None
}
})
.unwrap_or(FeatureStatus::Disabled),
},
),
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(
feature,
match feature {
PciFeature::Msi => {
if let Some(info) = self
.capabilities
.iter()
.find_map(|(_, capability)| capability.as_msi())
{
PciFeatureInfo::Msi(*info)
} else {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
);
}
}
PciFeature::MsiX => {
if let Some(info) = self
.capabilities
.iter()
.find_map(|(_, capability)| capability.as_msix())
{
PciFeatureInfo::MsiX(*info)
} else {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
);
}
}
},
),
PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set {
SetFeatureInfo::Msi(info_to_set) => {
if let Some((offset, info)) = self
.capabilities
.iter_mut()
.find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?)))
{
if let Some(mme) = info_to_set.multi_message_enable {
if info.multi_message_capable() < mme || mme > 0b101 {
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
);
}
info.set_multi_message_enable(mme);
}
if let Some(message_addr_and_data) = info_to_set.message_address_and_data {
let message_addr = message_addr_and_data.addr;
if message_addr & 0b11 != 0 {
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
);
}
info.set_message_address(message_addr as u32);
info.set_message_upper_address((message_addr >> 32) as u32);
if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1)
!= 0
{
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
);
}
info.set_message_data(
message_addr_and_data
.data
.try_into()
.expect("pcid: MSI message data too big"),
);
}
if let Some(mask_bits) = info_to_set.mask_bits {
info.set_mask_bits(mask_bits);
}
unsafe {
info.write_all(&func, offset);
}
PcidClientResponse::SetFeatureInfo(PciFeature::Msi)
} else {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(PciFeature::Msi),
);
}
}
SetFeatureInfo::MsiX { function_mask } => {
if let Some((offset, info)) = self
.capabilities
.iter_mut()
.find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?)))
{
if let Some(mask) = function_mask {
info.set_function_mask(mask);
unsafe {
info.write_a(&func, offset);
}
}
PcidClientResponse::SetFeatureInfo(PciFeature::MsiX)
} else {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(PciFeature::MsiX),
);
}
}
},
PcidClientRequest::ReadConfig(offset) => {
let value = unsafe { func.read_u32(offset) };
return PcidClientResponse::ReadConfig(value);
}
PcidClientRequest::WriteConfig(offset, value) => {
unsafe {
func.write_u32(offset, value);
}
return PcidClientResponse::WriteConfig;
}
}
}
fn handle_spawn(
mut self,
pcid_to_client_write: usize,
pcid_from_client_read: usize,
args: driver_interface::SubdriverArguments,
) {
use driver_interface::*;
let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) };
let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) };
while let Ok(msg) = recv(&mut pcid_from_client) {
let response = self.respond(msg, &args);
send(&mut pcid_to_client, &response).unwrap();
}
}
}
+49 -244
View File
@@ -1,24 +1,22 @@
use std::fs::{File, metadata, read_dir};
use std::fs::{metadata, read_dir, File};
use std::io::prelude::*;
use std::os::unix::io::{FromRawFd, RawFd};
use std::process::Command;
use std::thread;
use std::sync::{Arc, Mutex};
use std::thread;
use log::{debug, info, trace, warn};
use pci_types::{CommandRegister, PciAddress};
use structopt::StructOpt;
use log::{debug, error, info, warn, trace};
use redox_log::{OutputBuilder, RedoxLogger};
use structopt::StructOpt;
use crate::cfg_access::Pcie;
use crate::config::Config;
use crate::driver_interface::LegacyInterruptLine;
use crate::pci::PciFunc;
use crate::pci::cap::Capability as PciCapability;
use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError};
mod cfg_access;
mod config;
mod driver_handler;
mod driver_interface;
mod pci;
mod pci_header;
@@ -26,167 +24,20 @@ mod pci_header;
#[derive(StructOpt)]
#[structopt(about)]
struct Args {
#[structopt(short, long,
help="Increase logging level once for each arg.", parse(from_occurrences))]
#[structopt(
short,
long,
help = "Increase logging level once for each arg.",
parse(from_occurrences)
)]
verbose: u8,
#[structopt(
help="A path to a pcid config file or a directory that contains pcid config files.")]
help = "A path to a pcid config file or a directory that contains pcid config files."
)]
config_path: Option<String>,
}
pub struct DriverHandler {
addr: PciAddress,
capabilities: Vec<(u8, PciCapability)>,
state: Arc<State>,
}
impl DriverHandler {
fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse {
use driver_interface::*;
use crate::pci::cap::{MsiCapability, MsixCapability};
let func = PciFunc {
pci: &self.state.pcie,
addr: self.addr,
};
match request {
PcidClientRequest::RequestCapabilities => {
PcidClientResponse::Capabilities(self.capabilities.iter().map(|(_, capability)| capability.clone()).collect::<Vec<_>>())
}
PcidClientRequest::RequestConfig => {
PcidClientResponse::Config(args.clone())
}
PcidClientRequest::RequestFeatures => {
PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability {
PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))),
PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))),
_ => None,
}).collect())
}
PcidClientRequest::EnableFeature(feature) => match feature {
PciFeature::Msi => {
let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) {
Some(tuple) => tuple,
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
};
unsafe {
capability.set_enabled(true);
capability.write_message_control(&func, offset);
}
PcidClientResponse::FeatureEnabled(feature)
}
PciFeature::MsiX => {
let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) {
Some(tuple) => tuple,
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
};
unsafe {
capability.set_msix_enabled(true);
capability.write_a(&func, offset);
}
PcidClientResponse::FeatureEnabled(feature)
}
}
PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature {
PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability {
Some(FeatureStatus::enabled(msi.enabled()))
} else {
None
}).unwrap_or(FeatureStatus::Disabled),
PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability {
Some(FeatureStatus::enabled(msix.msix_enabled()))
} else {
None
}).unwrap_or(FeatureStatus::Disabled),
}),
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature {
PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) {
PciFeatureInfo::Msi(*info)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
}
PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) {
PciFeatureInfo::MsiX(*info)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
}
}),
PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set {
SetFeatureInfo::Msi(info_to_set) => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) {
if let Some(mme) = info_to_set.multi_message_enable {
if info.multi_message_capable() < mme || mme > 0b101 {
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
}
info.set_multi_message_enable(mme);
}
if let Some(message_addr_and_data) = info_to_set.message_address_and_data {
let message_addr = message_addr_and_data.addr;
if message_addr & 0b11 != 0 {
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
}
info.set_message_address(message_addr as u32);
info.set_message_upper_address((message_addr >> 32) as u32);
if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) != 0 {
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
}
info.set_message_data(
message_addr_and_data
.data
.try_into()
.expect("pcid: MSI message data too big"),
);
}
if let Some(mask_bits) = info_to_set.mask_bits {
info.set_mask_bits(mask_bits);
}
unsafe {
info.write_all(&func, offset);
}
PcidClientResponse::SetFeatureInfo(PciFeature::Msi)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::Msi));
}
SetFeatureInfo::MsiX { function_mask } => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) {
if let Some(mask) = function_mask {
info.set_function_mask(mask);
unsafe {
info.write_a(&func, offset);
}
}
PcidClientResponse::SetFeatureInfo(PciFeature::MsiX)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX));
}
}
PcidClientRequest::ReadConfig(offset) => {
let value = unsafe { func.read_u32(offset) };
return PcidClientResponse::ReadConfig(value);
},
PcidClientRequest::WriteConfig(offset, value) => {
unsafe {
func.write_u32(offset, value);
}
return PcidClientResponse::WriteConfig;
}
}
}
fn handle_spawn(mut self, pcid_to_client_write: usize, pcid_from_client_read: usize, args: driver_interface::SubdriverArguments) {
use driver_interface::*;
let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) };
let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) };
while let Ok(msg) = recv(&mut pcid_from_client) {
let response = self.respond(msg, &args);
send(&mut pcid_to_client, &response).unwrap();
}
}
}
pub struct State {
threads: Mutex<Vec<thread::JoinHandle<()>>>,
pcie: Pcie,
@@ -255,7 +106,14 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, header: PciEndpointH
} else {
Vec::new()
};
debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
debug!(
"PCI DEVICE CAPABILITIES for {}: {:?}",
args.iter()
.map(|string| string.as_ref())
.nth(0)
.unwrap_or("[unknown]"),
capabilities
);
let func = driver_interface::PciFunction {
bars,
@@ -268,64 +126,7 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, header: PciEndpointH
full_device_id: header.full_device_id().clone(),
};
let subdriver_args = driver_interface::SubdriverArguments {
func,
};
let mut args = args.iter();
if let Some(program) = args.next() {
let mut command = Command::new(program);
for arg in args {
if arg.starts_with("$") {
panic!("support for $VARIABLE has been removed. use pcid_interface instead");
}
command.arg(arg);
}
info!("PCID SPAWN {:?}", command);
// TODO: libc wrapper?
let [fds1, fds2] = unsafe {
let mut fds1 = [0 as libc::c_int; 2];
let mut fds2 = [0 as libc::c_int; 2];
assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe");
assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe");
[
fds1.map(|c| c as usize),
fds2.map(|c| c as usize),
]
};
let [pcid_to_client_read, pcid_to_client_write] = fds1;
let [pcid_from_client_read, pcid_from_client_write] = fds2;
let envs = vec![
("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)),
("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)),
];
match command.envs(envs).spawn() {
Ok(mut child) => {
let driver_handler = DriverHandler {
addr: header.address(),
state: Arc::clone(&state),
capabilities,
};
let _handle = thread::spawn(move || {
driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args);
});
// FIXME this currently deadlocks as pcid doesn't daemonize
//state.threads.lock().unwrap().push(handle);
match child.wait() {
Ok(_status) => (),
Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err),
}
}
Err(err) => error!("pcid: failed to execute {:?}: {}", command, err)
}
}
driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args);
}
}
@@ -335,31 +136,35 @@ fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> {
1 => log::LevelFilter::Debug,
_ => log::LevelFilter::Trace,
};
let mut logger = RedoxLogger::new()
.with_output(
OutputBuilder::stderr()
.with_ansi_escape_codes()
.with_filter(log_level)
.flush_on_newline(true)
.build()
);
let mut logger = RedoxLogger::new().with_output(
OutputBuilder::stderr()
.with_ansi_escape_codes()
.with_filter(log_level)
.flush_on_newline(true)
.build(),
);
#[cfg(target_os = "redox")] {
#[cfg(target_os = "redox")]
{
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") {
Ok(b) => logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.flush_on_newline(true)
.build()
),
Ok(b) => {
logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("pcid: failed to open pcid.log"),
}
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") {
Ok(b) => logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build()
),
Ok(b) => {
logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"),
}
}
@@ -442,10 +247,10 @@ fn main(args: Args) {
}
Err(PciHeaderError::NoDevice) => {
if func_addr.function() == 0 {
trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num);
continue 'dev;
trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num);
continue 'dev;
}
},
}
Err(PciHeaderError::UnknownHeaderType(id)) => {
warn!("pcid: unknown header type: {id:?}");
}
+9 -63
View File
@@ -83,32 +83,6 @@ pub enum MsiCapability {
},
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct PcieCapability {
pub pcie_caps: u32,
pub dev_caps: u32,
pub dev_sts_ctl: u32,
pub link_caps: u32,
pub link_sts_ctl: u32,
pub slot_caps: u32,
pub slot_sts_ctl: u32,
pub root_cap_ctl: u32,
pub root_sts: u32,
pub dev_caps2: u32,
pub dev_sts_ctl2: u32,
pub link_caps2: u32,
pub link_sts_ctl2: u32,
pub slot_caps2: u32,
pub slot_sts_ctl2: u32,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct PwrMgmtCapability {
pub a: u32,
pub b: u32,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct MsixCapability {
pub a: u32,
@@ -125,10 +99,7 @@ pub struct VendorSpecificCapability {
pub enum Capability {
Msi(MsiCapability),
MsiX(MsixCapability),
Pcie(PcieCapability),
PwrMgmt(PwrMgmtCapability),
Vendor(VendorSpecificCapability),
FunctionSpecific(u8, Vec<u8>), // TODO: Arrayvec
Other(u8),
}
@@ -167,12 +138,6 @@ impl Capability {
c: func.read_u32(u16::from(offset + 8)),
})
}
unsafe fn parse_pwr(func: &PciFunc, offset: u8) -> Self {
Self::PwrMgmt(PwrMgmtCapability {
a: func.read_u32(u16::from(offset)),
b: func.read_u32(u16::from(offset + 4)),
})
}
unsafe fn parse_vendor(func: &PciFunc, offset: u8) -> Self {
let next = func.read_u8(u16::from(offset+1));
let length = func.read_u8(u16::from(offset+2));
@@ -188,27 +153,6 @@ impl Capability {
data
})
}
unsafe fn parse_pcie(func: &PciFunc, offset: u8) -> Self {
let offset = u16::from(offset);
Self::Pcie(PcieCapability {
pcie_caps: func.read_u32(offset),
dev_caps: func.read_u32(offset + 0x04),
dev_sts_ctl: func.read_u32(offset + 0x08),
link_caps: func.read_u32(offset + 0x0C),
link_sts_ctl: func.read_u32(offset + 0x10),
slot_caps: func.read_u32(offset + 0x14),
slot_sts_ctl: func.read_u32(offset + 0x18),
root_cap_ctl: func.read_u32(offset + 0x1C),
root_sts: func.read_u32(offset + 0x20),
dev_caps2: func.read_u32(offset + 0x24),
dev_sts_ctl2: func.read_u32(offset + 0x28),
link_caps2: func.read_u32(offset + 0x2C),
link_sts_ctl2: func.read_u32(offset + 0x30),
slot_caps2: func.read_u32(offset + 0x34),
slot_sts_ctl2: func.read_u32(offset + 0x38),
})
}
unsafe fn parse(func: &PciFunc, offset: u8) -> Self {
assert_eq!(offset & 0xFC, offset, "capability must be dword aligned");
@@ -219,16 +163,18 @@ impl Capability {
Self::parse_msi(func, offset)
} else if capability_id == CapabilityId::MsiX as u8 {
Self::parse_msix(func, offset)
} else if capability_id == CapabilityId::Pcie as u8 {
Self::parse_pcie(func, offset)
} else if capability_id == CapabilityId::PwrMgmt as u8{
Self::parse_pwr(func, offset)
} else if capability_id == CapabilityId::Vendor as u8 {
Self::parse_vendor(func, offset)
} else if capability_id == CapabilityId::Sata as u8 {
Self::FunctionSpecific(capability_id, func.read_range(offset.into(), 8))
} else {
log::warn!("unimplemented or malformed capability id: {}", capability_id);
if capability_id != CapabilityId::Pcie as u8
&& capability_id != CapabilityId::PwrMgmt as u8
&& capability_id != CapabilityId::Sata as u8
{
log::warn!(
"unimplemented or malformed capability id: {}",
capability_id
);
}
Self::Other(capability_id)
}
}