pcid: Use pci_types for parsing capabilties

This commit is contained in:
bjorn3
2024-06-10 17:37:32 +02:00
parent 2ab2fe7b5e
commit 4bd978da7a
5 changed files with 125 additions and 539 deletions
+119 -97
View File
@@ -5,10 +5,10 @@ use std::sync::Arc;
use std::thread;
use log::{error, info};
use pci_types::capability::{MultipleMessageSupport, PciCapability};
use pci_types::{ConfigRegionAccess, PciAddress};
use crate::driver_interface;
use crate::pci::cap::Capability as PciCapability;
use crate::State;
pub struct DriverHandler {
@@ -97,7 +97,6 @@ impl DriverHandler {
request: driver_interface::PcidClientRequest,
args: &driver_interface::SubdriverArguments,
) -> driver_interface::PcidClientResponse {
use crate::pci::cap::{MsiCapability, MsixCapability};
use driver_interface::*;
match request {
@@ -105,7 +104,9 @@ impl DriverHandler {
self.capabilities
.iter()
.filter_map(|capability| match capability {
PciCapability::Vendor(capability) => Some(capability.clone()),
PciCapability::Vendor(addr) => unsafe {
Some(VendorSpecificCapability::parse(*addr, &self.state.pcie))
},
_ => None,
})
.collect::<Vec<_>>(),
@@ -121,85 +122,87 @@ impl DriverHandler {
})
.collect(),
),
PcidClientRequest::EnableFeature(feature) => match feature {
PciFeature::Msi => {
if let Some(msix_capability) = self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msix_mut())
{
// If MSI-X is supported disable it before enabling MSI as they can't be
// active at the same time.
unsafe {
msix_capability.set_msix_enabled(false);
msix_capability.write_a(self.addr, &self.state.pcie);
PcidClientRequest::EnableFeature(feature) => {
match feature {
PciFeature::Msi => {
if let Some(msix_capability) =
self.capabilities
.iter_mut()
.find_map(|capability| match capability {
PciCapability::MsiX(cap) => Some(cap),
_ => None,
})
{
// If MSI-X is supported disable it before enabling MSI as they can't be
// active at the same time.
msix_capability.set_enabled(false, &self.state.pcie);
}
}
let capability: &mut MsiCapability = match self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msi_mut())
{
Some(capability) => capability,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
unsafe {
capability.set_enabled(true);
capability.write_message_control(self.addr, &self.state.pcie);
let capability = match self.capabilities.iter_mut().find_map(|capability| {
match capability {
PciCapability::Msi(cap) => Some(cap),
_ => None,
}
}) {
Some(capability) => capability,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
capability.set_enabled(true, &self.state.pcie);
PcidClientResponse::FeatureEnabled(feature)
}
PcidClientResponse::FeatureEnabled(feature)
}
PciFeature::MsiX => {
if let Some(msi_capability) = self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msi_mut())
{
// If MSI is supported disable it before enabling MSI-X as they can't be
// active at the same time.
unsafe {
msi_capability.set_enabled(false);
msi_capability.write_message_control(self.addr, &self.state.pcie);
PciFeature::MsiX => {
if let Some(msi_capability) =
self.capabilities
.iter_mut()
.find_map(|capability| match capability {
PciCapability::Msi(cap) => Some(cap),
_ => None,
})
{
// If MSI is supported disable it before enabling MSI-X as they can't be
// active at the same time.
msi_capability.set_enabled(false, &self.state.pcie);
}
}
let capability: &mut MsixCapability = match self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msix_mut())
{
Some(capability) => capability,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
unsafe {
capability.set_msix_enabled(true);
capability.write_a(self.addr, &self.state.pcie);
let capability = match self.capabilities.iter_mut().find_map(|capability| {
match capability {
PciCapability::MsiX(cap) => Some(cap),
_ => None,
}
}) {
Some(capability) => capability,
None => {
return PcidClientResponse::Error(
PcidServerResponseError::NonexistentFeature(feature),
)
}
};
capability.set_enabled(true, &self.state.pcie);
PcidClientResponse::FeatureEnabled(feature)
}
PcidClientResponse::FeatureEnabled(feature)
}
},
}
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(
feature,
match feature {
PciFeature::Msi => {
if let Some(info) = self
.capabilities
.iter()
.find_map(|capability| capability.as_msi())
if let Some(info) =
self.capabilities
.iter()
.find_map(|capability| match capability {
PciCapability::Msi(cap) => Some(cap),
_ => None,
})
{
PciFeatureInfo::Msi(msi::MsiInfo {
log2_multiple_message_capable: info.multi_message_capable(),
is_64bit: info.has_64_bit_addr(),
has_per_vector_masking: info.is_pvt_capable(),
log2_multiple_message_capable: info.multiple_message_capable()
as u8,
is_64bit: info.is_64bit(),
has_per_vector_masking: info.has_per_vector_masking(),
})
} else {
return PcidClientResponse::Error(
@@ -208,16 +211,19 @@ impl DriverHandler {
}
}
PciFeature::MsiX => {
if let Some(info) = self
.capabilities
.iter()
.find_map(|capability| capability.as_msix())
if let Some(info) =
self.capabilities
.iter()
.find_map(|capability| match capability {
PciCapability::MsiX(cap) => Some(cap),
_ => None,
})
{
PciFeatureInfo::MsiX(msi::MsixInfo {
table_bar: info.table_bir(),
table_bar: info.table_bar(),
table_offset: info.table_offset(),
table_size: info.table_size(),
pba_bar: info.pba_bir(),
pba_bar: info.pba_bar(),
pba_offset: info.pba_offset(),
})
} else {
@@ -230,18 +236,36 @@ impl DriverHandler {
),
PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set {
SetFeatureInfo::Msi(info_to_set) => {
if let Some(info) = self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msi_mut())
if let Some(info) =
self.capabilities
.iter_mut()
.find_map(|capability| match capability {
PciCapability::Msi(cap) => Some(cap),
_ => None,
})
{
if let Some(mme) = info_to_set.multi_message_enable {
if info.multi_message_capable() < mme || mme > 0b101 {
if (info.multiple_message_capable() as u8) < mme {
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
);
}
info.set_multi_message_enable(mme);
info.set_multiple_message_enable(
match mme {
0 => MultipleMessageSupport::Int1,
1 => MultipleMessageSupport::Int2,
2 => MultipleMessageSupport::Int4,
3 => MultipleMessageSupport::Int8,
4 => MultipleMessageSupport::Int16,
5 => MultipleMessageSupport::Int32,
_ => {
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
)
}
},
&self.state.pcie,
);
}
if let Some(message_addr_and_data) = info_to_set.message_address_and_data {
let message_addr = message_addr_and_data.addr;
@@ -250,27 +274,25 @@ impl DriverHandler {
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)
if message_addr_and_data.data
& ((1 << info.multiple_message_enable(&self.state.pcie) as u8) - 1)
!= 0
{
return PcidClientResponse::Error(
PcidServerResponseError::InvalidBitPattern,
);
}
info.set_message_data(
info.set_message_info(
message_addr,
message_addr_and_data
.data
.try_into()
.expect("pcid: MSI message data too big"),
&self.state.pcie,
);
}
if let Some(mask_bits) = info_to_set.mask_bits {
info.set_mask_bits(mask_bits);
}
unsafe {
info.write_all(self.addr, &self.state.pcie);
info.set_message_mask(mask_bits, &self.state.pcie);
}
PcidClientResponse::SetFeatureInfo(PciFeature::Msi)
} else {
@@ -280,16 +302,16 @@ impl DriverHandler {
}
}
SetFeatureInfo::MsiX { function_mask } => {
if let Some(info) = self
.capabilities
.iter_mut()
.find_map(|capability| capability.as_msix_mut())
if let Some(info) =
self.capabilities
.iter_mut()
.find_map(|capability| match capability {
PciCapability::MsiX(cap) => Some(cap),
_ => None,
})
{
if let Some(mask) = function_mask {
info.set_function_mask(mask);
unsafe {
info.write_a(self.addr, &self.state.pcie);
}
info.set_function_mask(mask, &self.state.pcie);
}
PcidClientResponse::SetFeatureInfo(PciFeature::MsiX)
} else {
+3 -9
View File
@@ -4,7 +4,6 @@ use std::sync::{Arc, Mutex};
use std::thread;
use log::{debug, info, trace, warn};
use pci_types::capability::PciCapabilityAddress;
use pci_types::{CommandRegister, PciAddress};
use redox_log::{OutputBuilder, RedoxLogger};
use structopt::StructOpt;
@@ -98,14 +97,9 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, header: PciEndpointH
};
let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() {
crate::pci::cap::CapabilitiesIter::new(
PciCapabilityAddress {
address: header.address(),
offset: header.cap_pointer(),
},
&state.pcie,
)
.collect::<Vec<_>>()
endpoint_header
.capabilities(&state.pcie)
.collect::<Vec<_>>()
} else {
Vec::new()
};
+3 -167
View File
@@ -2,148 +2,13 @@ use pci_types::capability::PciCapabilityAddress;
use pci_types::ConfigRegionAccess;
use serde::{Serialize, Deserialize};
pub struct CapabilitiesIter<'a> {
addr: PciCapabilityAddress,
access: &'a dyn ConfigRegionAccess,
}
impl<'a> CapabilitiesIter<'a> {
pub fn new(addr: PciCapabilityAddress, access: &'a dyn ConfigRegionAccess) -> Self {
Self { addr, access }
}
}
impl<'a> Iterator for CapabilitiesIter<'a> {
type Item = Capability;
fn next(&mut self) -> Option<Self::Item> {
let addr = unsafe {
// mask RsvdP bits
self.addr.offset = self.addr.offset & 0xFC;
if self.addr.offset == 0 {
return None;
};
let first_dword = self.access.read(self.addr.address, self.addr.offset);
let next = ((first_dword >> 8) & 0xFF) as u16;
let addr = self.addr;
self.addr.offset = next;
addr
};
let cap = unsafe {
Capability::parse(addr, self.access)
};
Some(cap)
}
}
#[repr(u8)]
pub enum CapabilityId {
PwrMgmt = 0x01,
Msi = 0x05,
MsiX = 0x11,
Pcie = 0x10,
Vendor = 0x09,
// function specific
Sata = 0x12, // only on AHCI functions
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum MsiCapability {
_32BitAddress {
cap_offset: u16,
message_control: u32,
message_address: u32,
message_data: u16,
},
_64BitAddress {
cap_offset: u16,
message_control: u32,
message_address_lo: u32,
message_address_hi: u32,
message_data: u16,
},
_32BitAddressWithPvm {
cap_offset: u16,
message_control: u32,
message_address: u32,
message_data: u32,
mask_bits: u32,
pending_bits: u32,
},
_64BitAddressWithPvm {
cap_offset: u16,
message_control: u32,
message_address_lo: u32,
message_address_hi: u32,
message_data: u32,
mask_bits: u32,
pending_bits: u32,
},
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct MsixCapability {
pub cap_offset: u16,
pub a: u32,
pub b: u32,
pub c: u32,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct VendorSpecificCapability {
pub data: Vec<u8>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Capability {
Msi(MsiCapability),
MsiX(MsixCapability),
Vendor(VendorSpecificCapability),
Other(u8),
}
impl Capability {
pub fn as_msi(&self) -> Option<&MsiCapability> {
match self {
&Self::Msi(ref msi) => Some(msi),
_ => None,
}
}
pub fn as_msix(&self) -> Option<&MsixCapability> {
match self {
&Self::MsiX(ref msix) => Some(msix),
_ => None,
}
}
pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> {
match self {
&mut Self::Msi(ref mut msi) => Some(msi),
_ => None,
}
}
pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> {
match self {
&mut Self::MsiX(ref mut msix) => Some(msix),
_ => None,
}
}
unsafe fn parse_msi(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
Self::Msi(MsiCapability::parse(addr, access))
}
unsafe fn parse_msix(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
Self::MsiX(MsixCapability {
cap_offset: addr.offset,
a: access.read(addr.address, addr.offset),
b: access.read(addr.address, addr.offset + 4),
c: access.read(addr.address, addr.offset + 8),
})
}
unsafe fn parse_vendor(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
impl VendorSpecificCapability {
pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
let dword = access.read(addr.address, addr.offset);
let next = (dword >> 8) & 0xFF;
let length = ((dword >> 16) & 0xFF) as u16;
@@ -168,37 +33,8 @@ impl Capability {
log::warn!("Vendor specific capability is invalid");
Vec::new()
};
Self::Vendor(VendorSpecificCapability {
VendorSpecificCapability {
data
})
}
unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
assert_eq!(
addr.offset & 0xFC,
addr.offset,
"capability must be dword aligned"
);
let dword = access.read(addr.address, addr.offset);
let capability_id = (dword & 0xFF) as u8;
if capability_id == CapabilityId::Msi as u8 {
Self::parse_msi(addr, access)
} else if capability_id == CapabilityId::MsiX as u8 {
Self::parse_msix(addr, access)
} else if capability_id == CapabilityId::Vendor as u8 {
Self::parse_vendor(addr, access)
} else {
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)
}
}
}
-256
View File
@@ -1,10 +1,7 @@
use std::fmt;
use super::bar::PciBar;
pub use super::cap::{MsiCapability, MsixCapability};
use pci_types::capability::PciCapabilityAddress;
use pci_types::{ConfigRegionAccess, PciAddress};
use serde::{Deserialize, Serialize};
use syscall::{Io, Mmio};
@@ -31,193 +28,6 @@ pub struct MsiInfo {
pub has_per_vector_masking: bool,
}
impl MsiCapability {
const MC_PVT_CAPABLE_BIT: u16 = 1 << 8;
const MC_64_BIT_ADDR_BIT: u16 = 1 << 7;
const MC_MULTI_MESSAGE_MASK: u16 = 0x000E;
const MC_MULTI_MESSAGE_SHIFT: u8 = 1;
const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070;
const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4;
const MC_MSI_ENABLED_BIT: u16 = 1;
pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self {
let dword = access.read(addr.address, addr.offset);
let message_control = (dword >> 16) as u16;
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
Self::_64BitAddressWithPvm {
cap_offset: addr.offset,
message_control: dword,
message_address_lo: access.read(addr.address, addr.offset + 4),
message_address_hi: access.read(addr.address, addr.offset + 8),
message_data: access.read(addr.address, addr.offset + 12),
mask_bits: access.read(addr.address, addr.offset + 16),
pending_bits: access.read(addr.address, addr.offset + 20),
}
} else {
Self::_32BitAddressWithPvm {
cap_offset: addr.offset,
message_control: dword,
message_address: access.read(addr.address, addr.offset + 4),
message_data: access.read(addr.address, addr.offset + 8),
mask_bits: access.read(addr.address, addr.offset + 12),
pending_bits: access.read(addr.address, addr.offset + 16),
}
}
} else {
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
Self::_64BitAddress {
cap_offset: addr.offset,
message_control: dword,
message_address_lo: access.read(addr.address, addr.offset + 4),
message_address_hi: access.read(addr.address, addr.offset + 8),
message_data: access.read(addr.address, addr.offset + 12) as u16,
}
} else {
Self::_32BitAddress {
cap_offset: addr.offset,
message_control: dword,
message_address: access.read(addr.address, addr.offset + 4),
message_data: access.read(addr.address, addr.offset + 8) as u16,
}
}
}
}
fn cap_offset(&self) -> u16 {
match *self {
MsiCapability::_32BitAddress { cap_offset, .. }
| MsiCapability::_64BitAddress { cap_offset, .. }
| MsiCapability::_32BitAddressWithPvm { cap_offset, .. }
| MsiCapability::_64BitAddressWithPvm { cap_offset, .. } => u16::from(cap_offset),
}
}
fn message_control_raw(&self) -> u32 {
match self {
Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control,
}
}
fn message_control(&self) -> u16 {
(self.message_control_raw() >> 16) as u16
}
pub(crate) fn set_message_control(&mut self, value: u16) {
let mut new_message_control = self.message_control_raw();
new_message_control &= 0x0000_FFFF;
new_message_control |= u32::from(value) << 16;
match self {
Self::_32BitAddress { ref mut message_control, .. }
| Self::_64BitAddress { ref mut message_control, .. }
| Self::_32BitAddressWithPvm { ref mut message_control, .. }
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
}
}
pub(crate) unsafe fn write_message_control(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) {
access.write(addr, self.cap_offset(), self.message_control_raw());
}
pub(crate) fn is_pvt_capable(&self) -> bool {
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
}
pub(crate) fn has_64_bit_addr(&self) -> bool {
self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0
}
pub(crate) fn set_enabled(&mut self, enabled: bool) {
let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT);
new_message_control |= u16::from(enabled);
self.set_message_control(new_message_control);
}
pub(crate) fn multi_message_capable(&self) -> u8 {
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
}
pub(crate) fn multi_message_enable(&self) -> u8 {
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8
}
pub(crate) fn set_multi_message_enable(&mut self, log_mme: u8) {
let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK);
new_message_control |= u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT;
self.set_message_control(new_message_control);
}
fn message_address(&self) -> u32 {
match self {
&Self::_32BitAddress { message_address, .. } | &Self::_32BitAddressWithPvm { message_address, .. } => message_address,
&Self::_64BitAddress { message_address_lo, .. } | &Self::_64BitAddressWithPvm { message_address_lo, .. } => message_address_lo,
}
}
fn message_upper_address(&self) -> Option<u32> {
match self {
&Self::_64BitAddress { message_address_hi, .. } | &Self::_64BitAddressWithPvm { message_address_hi, .. } => Some(message_address_hi),
&Self::_32BitAddress { .. } | &Self::_32BitAddressWithPvm { .. } => None,
}
}
pub(crate) fn set_message_address(&mut self, message_address: u32) {
assert_eq!(message_address & 0xFFFF_FFFC, message_address, "unaligned message address (this should already be validated)");
match self {
&mut Self::_32BitAddress { message_address: ref mut addr, .. } | &mut Self::_32BitAddressWithPvm { message_address: ref mut addr, .. } => *addr = message_address,
&mut Self::_64BitAddress { message_address_lo: ref mut addr, .. } | &mut Self::_64BitAddressWithPvm { message_address_lo: ref mut addr, .. } => *addr = message_address,
}
}
pub(crate) fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> {
match self {
&mut Self::_64BitAddress { ref mut message_address_hi, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_address_hi, .. } => *message_address_hi = message_upper_address,
&mut Self::_32BitAddress { .. } | &mut Self::_32BitAddressWithPvm { .. } => return None,
}
Some(())
}
pub(crate) fn set_message_data(&mut self, value: u16) {
match self {
&mut Self::_32BitAddress { ref mut message_data, .. } | &mut Self::_64BitAddress { ref mut message_data, .. } => *message_data = value,
&mut Self::_32BitAddressWithPvm { ref mut message_data, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_data, .. } => {
*message_data &= 0xFFFF_0000;
*message_data |= u32::from(value);
}
}
}
pub(crate) fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> {
match self {
&mut Self::_32BitAddressWithPvm { mask_bits: ref mut bits, .. } | &mut Self::_64BitAddressWithPvm { mask_bits: ref mut bits, .. } => *bits = mask_bits,
&mut Self::_32BitAddress { .. } | &mut Self::_64BitAddress { .. } => return None,
}
Some(())
}
unsafe fn write_message_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) {
access.write(addr, self.cap_offset() + 4, self.message_address())
}
unsafe fn write_message_upper_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> {
let value = self.message_upper_address()?;
access.write(addr, self.cap_offset() + 8, value);
Some(())
}
unsafe fn write_message_data(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) {
match self {
&Self::_32BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data.into()),
&Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data),
&Self::_64BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data.into()),
&Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data),
}
}
unsafe fn write_mask_bits(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> {
match self {
&Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 12), mask_bits),
&Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 16), mask_bits),
&Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None,
}
Some(())
}
pub(crate) unsafe fn write_all(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) {
self.write_message_control(addr, access);
self.write_message_address(addr, access);
self.write_message_upper_address(addr, access);
self.write_message_data(addr, access);
self.write_mask_bits(addr, access);
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MsixInfo {
pub table_bar: u8,
@@ -268,72 +78,6 @@ impl MsixInfo {
}
}
impl MsixCapability {
const MC_MSIX_ENABLED_BIT: u16 = 1 << 15;
const MC_MSIX_ENABLED_SHIFT: u8 = 15;
const MC_FUNCTION_MASK_BIT: u16 = 1 << 14;
const MC_FUNCTION_MASK_SHIFT: u8 = 14;
const MC_TABLE_SIZE_MASK: u16 = 0x03FF;
/// The Message Control field, containing the enabled and function mask bits, as well as the
/// table size.
const fn message_control(&self) -> u16 {
(self.a >> 16) as u16
}
pub(crate) fn set_message_control(&mut self, message_control: u16) {
self.a &= 0x0000_FFFF;
self.a |= u32::from(message_control) << 16;
}
/// Returns the MSI-X table size.
pub(crate) const fn table_size(&self) -> u16 {
(self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1
}
pub(crate) fn set_msix_enabled(&mut self, enabled: bool) {
let mut new_message_control = self.message_control();
new_message_control &= !(Self::MC_MSIX_ENABLED_BIT);
new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT;
self.set_message_control(new_message_control);
}
pub(crate) fn set_function_mask(&mut self, function_mask: bool) {
let mut new_message_control = self.message_control();
new_message_control &= !(Self::MC_FUNCTION_MASK_BIT);
new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT;
self.set_message_control(new_message_control);
}
const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8;
const TABLE_BIR_MASK: u32 = 0x0000_0007;
/// The table offset is guaranteed to be QWORD aligned (8 bytes).
pub(crate) const fn table_offset(&self) -> u32 {
self.b & Self::TABLE_OFFSET_MASK
}
/// The table BIR, which is used to map the offset to a memory location.
pub(crate) const fn table_bir(&self) -> u8 {
(self.b & Self::TABLE_BIR_MASK) as u8
}
const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8;
const PBA_BIR_MASK: u32 = 0x0000_0007;
/// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes).
pub(crate) const fn pba_offset(&self) -> u32 {
self.c & Self::PBA_OFFSET_MASK
}
/// The Pending Bit Array BIR, which is used to map the offset to a memory location.
pub(crate) const fn pba_bir(&self) -> u8 {
(self.c & Self::PBA_BIR_MASK) as u8
}
/// Write the first DWORD into configuration space (containing the partially modifiable Message
/// Control field).
pub(crate) unsafe fn write_a(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) {
access.write(addr, u16::from(self.cap_offset), self.a)
}
}
#[repr(packed)]
pub struct MsixTableEntry {
pub addr_lo: Mmio<u32>,
-10
View File
@@ -23,7 +23,6 @@ pub struct PciEndpointHeader {
shared: SharedPciHeader,
subsystem_vendor_id: u16,
subsystem_id: u16,
cap_pointer: u16,
}
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -67,15 +66,10 @@ impl PciHeader {
HeaderType::Endpoint => {
let endpoint_header = EndpointHeader::from_header(header, access).unwrap();
let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access);
let cap_pointer = endpoint_header
.capability_pointer(access)
.try_into()
.unwrap();
Ok(PciHeader::General(PciEndpointHeader {
shared,
subsystem_vendor_id,
subsystem_id,
cap_pointer,
}))
}
HeaderType::PciPciBridge => {
@@ -239,10 +233,6 @@ impl PciEndpointHeader {
}
bars
}
pub fn cap_pointer(&self) -> u16 {
self.cap_pointer
}
}
#[cfg(test)]