pcid: Use pci_types for parsing capabilties
This commit is contained in:
+119
-97
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user