Merge branch 'pcid_cleanup3' into 'master'
Simplify and refactor handling of MSI/MSI-X See merge request redox-os/drivers!160
This commit is contained in:
+3
-10
@@ -82,17 +82,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File {
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features");
|
||||
log::debug!("PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let has_msi = all_pci_features.iter().any(|feature| feature.is_msi());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
if has_msi && !msi_enabled && !has_msix {
|
||||
msi_enabled = true;
|
||||
}
|
||||
if has_msix && !msix_enabled {
|
||||
msix_enabled = true;
|
||||
}
|
||||
|
||||
if msi_enabled && !msix_enabled {
|
||||
if has_msi && !has_msix {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("ihdad: failed to retrieve the MSI capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(s) => s,
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
|
||||
+15
-22
@@ -13,7 +13,7 @@ use event::{user_data, EventQueue};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi;
|
||||
use pcid_interface::irq_helpers::read_bsp_apic_id;
|
||||
use pcid_interface::msi::{MsixCapability, MsixTableEntry};
|
||||
use pcid_interface::msi::{MsixInfo, MsixTableEntry};
|
||||
use pcid_interface::{
|
||||
MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PcidServerHandle, SetFeatureInfo,
|
||||
SubdriverArguments,
|
||||
@@ -79,17 +79,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MsixInfo {
|
||||
pub struct MappedMsixRegs {
|
||||
pub virt_table_base: NonNull<MsixTableEntry>,
|
||||
pub capability: MsixCapability,
|
||||
pub info: MsixInfo,
|
||||
}
|
||||
|
||||
impl MsixInfo {
|
||||
impl MappedMsixRegs {
|
||||
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
&mut *self.virt_table_base.as_ptr().offset(k as isize)
|
||||
}
|
||||
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
assert!(k < self.info.table_size as usize);
|
||||
unsafe { self.table_entry_pointer_unchecked(k) }
|
||||
}
|
||||
}
|
||||
@@ -101,17 +101,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File {
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features");
|
||||
log::info!("PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let has_msi = all_pci_features.iter().any(|feature| feature.is_msi());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
if has_msi && !msi_enabled && !has_msix {
|
||||
msi_enabled = true;
|
||||
}
|
||||
if has_msix && !msix_enabled {
|
||||
msix_enabled = true;
|
||||
}
|
||||
|
||||
if msi_enabled && !msix_enabled {
|
||||
if has_msi && !has_msix {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(s) => s,
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
@@ -135,21 +128,21 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File {
|
||||
log::info!("Enabled MSI");
|
||||
|
||||
interrupt_handle
|
||||
} else if msix_enabled {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
} else if has_msix {
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(_) => panic!(),
|
||||
PciFeatureInfo::MsiX(s) => s,
|
||||
};
|
||||
capability.validate(pci_config.func.bars);
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
let bar = &pci_config.func.bars[capability.table_bir() as usize];
|
||||
let bar = &pci_config.func.bars[msix_info.table_bar as usize];
|
||||
let bar_address = unsafe { bar.physmap_mem("rtl8139d") } as usize;
|
||||
|
||||
let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry;
|
||||
let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = MsixInfo {
|
||||
let mut info = MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
capability,
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate one msi vector.
|
||||
|
||||
+15
-22
@@ -12,7 +12,7 @@ use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeature
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi;
|
||||
use pcid_interface::irq_helpers::read_bsp_apic_id;
|
||||
use pcid_interface::msi::{MsixCapability, MsixTableEntry};
|
||||
use pcid_interface::msi::{MsixInfo, MsixTableEntry};
|
||||
use redox_log::{RedoxLogger, OutputBuilder};
|
||||
use syscall::EventFlags;
|
||||
|
||||
@@ -74,17 +74,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MsixInfo {
|
||||
pub struct MappedMsixRegs {
|
||||
pub virt_table_base: NonNull<MsixTableEntry>,
|
||||
pub capability: MsixCapability,
|
||||
pub info: MsixInfo,
|
||||
}
|
||||
|
||||
impl MsixInfo {
|
||||
impl MappedMsixRegs {
|
||||
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
&mut *self.virt_table_base.as_ptr().offset(k as isize)
|
||||
}
|
||||
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
assert!(k < self.info.table_size as usize);
|
||||
unsafe { self.table_entry_pointer_unchecked(k) }
|
||||
}
|
||||
}
|
||||
@@ -96,17 +96,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File {
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features");
|
||||
log::info!("PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let has_msi = all_pci_features.iter().any(|feature| feature.is_msi());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
if has_msi && !msi_enabled && !has_msix {
|
||||
msi_enabled = true;
|
||||
}
|
||||
if has_msix && !msix_enabled {
|
||||
msix_enabled = true;
|
||||
}
|
||||
|
||||
if msi_enabled && !msix_enabled {
|
||||
if has_msi && !has_msix {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(s) => s,
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
@@ -130,21 +123,21 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File {
|
||||
log::info!("Enabled MSI");
|
||||
|
||||
interrupt_handle
|
||||
} else if msix_enabled {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
} else if has_msix {
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(_) => panic!(),
|
||||
PciFeatureInfo::MsiX(s) => s,
|
||||
};
|
||||
capability.validate(pci_config.func.bars);
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
let bar = &pci_config.func.bars[capability.table_bir() as usize];
|
||||
let bar = &pci_config.func.bars[msix_info.table_bar as usize];
|
||||
let bar_address = unsafe { bar.physmap_mem("rtl8168d") } as usize;
|
||||
|
||||
let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry;
|
||||
let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = MsixInfo {
|
||||
let mut info = MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
capability,
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate one msi vector.
|
||||
|
||||
+57
-59
@@ -14,7 +14,7 @@ use crate::State;
|
||||
|
||||
pub struct DriverHandler {
|
||||
addr: PciAddress,
|
||||
capabilities: Vec<(u8, PciCapability)>,
|
||||
capabilities: Vec<PciCapability>,
|
||||
|
||||
state: Arc<State>,
|
||||
}
|
||||
@@ -23,7 +23,7 @@ impl DriverHandler {
|
||||
pub fn spawn(
|
||||
state: Arc<State>,
|
||||
func: driver_interface::PciFunction,
|
||||
capabilities: Vec<(u8, PciCapability)>,
|
||||
capabilities: Vec<PciCapability>,
|
||||
args: &[String],
|
||||
) {
|
||||
let subdriver_args = driver_interface::SubdriverArguments { func };
|
||||
@@ -110,34 +110,41 @@ impl DriverHandler {
|
||||
PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities(
|
||||
self.capabilities
|
||||
.iter()
|
||||
.map(|(_, capability)| capability.clone())
|
||||
.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()),
|
||||
)),
|
||||
.filter_map(|capability| match capability {
|
||||
PciCapability::Msi(_) => Some(PciFeature::Msi),
|
||||
PciCapability::MsiX(_) => Some(PciFeature::MsiX),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
PcidClientRequest::EnableFeature(feature) => match feature {
|
||||
PciFeature::Msi => {
|
||||
let (offset, capability): (u8, &mut MsiCapability) = match self
|
||||
if let Some(msix_capability) = self
|
||||
.capabilities
|
||||
.iter_mut()
|
||||
.find_map(|&mut (offset, ref mut capability)| {
|
||||
capability.as_msi_mut().map(|cap| (offset, cap))
|
||||
}) {
|
||||
Some(tuple) => tuple,
|
||||
.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(&func);
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
@@ -146,18 +153,30 @@ impl DriverHandler {
|
||||
};
|
||||
unsafe {
|
||||
capability.set_enabled(true);
|
||||
capability.write_message_control(&func, offset);
|
||||
capability.write_message_control(&func);
|
||||
}
|
||||
PcidClientResponse::FeatureEnabled(feature)
|
||||
}
|
||||
PciFeature::MsiX => {
|
||||
let (offset, capability): (u8, &mut MsixCapability) = match self
|
||||
if let Some(msi_capability) = self
|
||||
.capabilities
|
||||
.iter_mut()
|
||||
.find_map(|&mut (offset, ref mut capability)| {
|
||||
capability.as_msix_mut().map(|cap| (offset, cap))
|
||||
}) {
|
||||
Some(tuple) => tuple,
|
||||
.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(&func);
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
@@ -166,38 +185,11 @@ impl DriverHandler {
|
||||
};
|
||||
unsafe {
|
||||
capability.set_msix_enabled(true);
|
||||
capability.write_a(&func, offset);
|
||||
capability.write_a(&func);
|
||||
}
|
||||
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 {
|
||||
@@ -205,7 +197,7 @@ impl DriverHandler {
|
||||
if let Some(info) = self
|
||||
.capabilities
|
||||
.iter()
|
||||
.find_map(|(_, capability)| capability.as_msi())
|
||||
.find_map(|capability| capability.as_msi())
|
||||
{
|
||||
PciFeatureInfo::Msi(*info)
|
||||
} else {
|
||||
@@ -218,9 +210,15 @@ impl DriverHandler {
|
||||
if let Some(info) = self
|
||||
.capabilities
|
||||
.iter()
|
||||
.find_map(|(_, capability)| capability.as_msix())
|
||||
.find_map(|capability| capability.as_msix())
|
||||
{
|
||||
PciFeatureInfo::MsiX(*info)
|
||||
PciFeatureInfo::MsiX(msi::MsixInfo {
|
||||
table_bar: info.table_bir(),
|
||||
table_offset: info.table_offset(),
|
||||
table_size: info.table_size(),
|
||||
pba_bar: info.pba_bir(),
|
||||
pba_offset: info.pba_offset(),
|
||||
})
|
||||
} else {
|
||||
return PcidClientResponse::Error(
|
||||
PcidServerResponseError::NonexistentFeature(feature),
|
||||
@@ -231,10 +229,10 @@ impl DriverHandler {
|
||||
),
|
||||
PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set {
|
||||
SetFeatureInfo::Msi(info_to_set) => {
|
||||
if let Some((offset, info)) = self
|
||||
if let Some(info) = self
|
||||
.capabilities
|
||||
.iter_mut()
|
||||
.find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?)))
|
||||
.find_map(|capability| capability.as_msi_mut())
|
||||
{
|
||||
if let Some(mme) = info_to_set.multi_message_enable {
|
||||
if info.multi_message_capable() < mme || mme > 0b101 {
|
||||
@@ -271,7 +269,7 @@ impl DriverHandler {
|
||||
info.set_mask_bits(mask_bits);
|
||||
}
|
||||
unsafe {
|
||||
info.write_all(&func, offset);
|
||||
info.write_all(&func);
|
||||
}
|
||||
PcidClientResponse::SetFeatureInfo(PciFeature::Msi)
|
||||
} else {
|
||||
@@ -281,15 +279,15 @@ impl DriverHandler {
|
||||
}
|
||||
}
|
||||
SetFeatureInfo::MsiX { function_mask } => {
|
||||
if let Some((offset, info)) = self
|
||||
if let Some(info) = self
|
||||
.capabilities
|
||||
.iter_mut()
|
||||
.find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?)))
|
||||
.find_map(|capability| capability.as_msix_mut())
|
||||
{
|
||||
if let Some(mask) = function_mask {
|
||||
info.set_function_mask(mask);
|
||||
unsafe {
|
||||
info.write_a(&func, offset);
|
||||
info.write_a(&func);
|
||||
}
|
||||
}
|
||||
PcidClientResponse::SetFeatureInfo(PciFeature::MsiX)
|
||||
|
||||
@@ -133,7 +133,7 @@ impl PciFeature {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum PciFeatureInfo {
|
||||
Msi(msi::MsiCapability),
|
||||
MsiX(msi::MsixCapability),
|
||||
MsiX(msi::MsixInfo),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -194,7 +194,6 @@ pub enum PcidClientRequest {
|
||||
RequestFeatures,
|
||||
RequestCapabilities,
|
||||
EnableFeature(PciFeature),
|
||||
FeatureStatus(PciFeature),
|
||||
FeatureInfo(PciFeature),
|
||||
SetFeatureInfo(SetFeatureInfo),
|
||||
ReadConfig(u16),
|
||||
@@ -213,7 +212,7 @@ pub enum PcidServerResponseError {
|
||||
pub enum PcidClientResponse {
|
||||
Capabilities(Vec<Capability>),
|
||||
Config(SubdriverArguments),
|
||||
AllFeatures(Vec<(PciFeature, FeatureStatus)>),
|
||||
AllFeatures(Vec<PciFeature>),
|
||||
FeatureEnabled(PciFeature),
|
||||
FeatureStatus(PciFeature, FeatureStatus),
|
||||
Error(PcidServerResponseError),
|
||||
@@ -288,20 +287,13 @@ impl PcidServerHandle {
|
||||
}
|
||||
|
||||
// FIXME turn into struct with bool fields
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<PciFeature>> {
|
||||
self.send(&PcidClientRequest::RequestFeatures)?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::AllFeatures(a) => Ok(a),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn feature_status(&mut self, feature: PciFeature) -> Result<FeatureStatus> {
|
||||
self.send(&PcidClientRequest::FeatureStatus(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> {
|
||||
self.send(&PcidClientRequest::EnableFeature(feature))?;
|
||||
match self.recv()? {
|
||||
|
||||
+8
-2
@@ -15,7 +15,7 @@ impl<'a> CapabilitiesIter<'a> {
|
||||
}
|
||||
}
|
||||
impl<'a> Iterator for CapabilitiesIter<'a> {
|
||||
type Item = (u8, Capability);
|
||||
type Item = Capability;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let offset = unsafe {
|
||||
@@ -37,7 +37,7 @@ impl<'a> Iterator for CapabilitiesIter<'a> {
|
||||
Capability::parse(self.func, offset)
|
||||
};
|
||||
|
||||
Some((offset, cap))
|
||||
Some(cap)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,17 +56,20 @@ pub enum CapabilityId {
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MsiCapability {
|
||||
_32BitAddress {
|
||||
cap_offset: u8,
|
||||
message_control: u32,
|
||||
message_address: u32,
|
||||
message_data: u16,
|
||||
},
|
||||
_64BitAddress {
|
||||
cap_offset: u8,
|
||||
message_control: u32,
|
||||
message_address_lo: u32,
|
||||
message_address_hi: u32,
|
||||
message_data: u16,
|
||||
},
|
||||
_32BitAddressWithPvm {
|
||||
cap_offset: u8,
|
||||
message_control: u32,
|
||||
message_address: u32,
|
||||
message_data: u32,
|
||||
@@ -74,6 +77,7 @@ pub enum MsiCapability {
|
||||
pending_bits: u32,
|
||||
},
|
||||
_64BitAddressWithPvm {
|
||||
cap_offset: u8,
|
||||
message_control: u32,
|
||||
message_address_lo: u32,
|
||||
message_address_hi: u32,
|
||||
@@ -85,6 +89,7 @@ pub enum MsiCapability {
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MsixCapability {
|
||||
pub cap_offset: u8,
|
||||
pub a: u32,
|
||||
pub b: u32,
|
||||
pub c: u32,
|
||||
@@ -133,6 +138,7 @@ impl Capability {
|
||||
}
|
||||
unsafe fn parse_msix(func: &PciFunc, offset: u8) -> Self {
|
||||
Self::MsiX(MsixCapability {
|
||||
cap_offset: offset,
|
||||
a: func.read_u32(u16::from(offset)),
|
||||
b: func.read_u32(u16::from(offset + 4)),
|
||||
c: func.read_u32(u16::from(offset + 8)),
|
||||
|
||||
+59
-46
@@ -43,6 +43,7 @@ impl MsiCapability {
|
||||
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddressWithPvm {
|
||||
cap_offset: offset,
|
||||
message_control: dword,
|
||||
message_address_lo: func.read_u32(u16::from(offset + 4)),
|
||||
message_address_hi: func.read_u32(u16::from(offset + 8)),
|
||||
@@ -52,6 +53,7 @@ impl MsiCapability {
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddressWithPvm {
|
||||
cap_offset: offset,
|
||||
message_control: dword,
|
||||
message_address: func.read_u32(u16::from(offset + 4)),
|
||||
message_data: func.read_u32(u16::from(offset + 8)),
|
||||
@@ -62,6 +64,7 @@ impl MsiCapability {
|
||||
} else {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddress {
|
||||
cap_offset: offset,
|
||||
message_control: dword,
|
||||
message_address_lo: func.read_u32(u16::from(offset + 4)),
|
||||
message_address_hi: func.read_u32(u16::from(offset + 8)),
|
||||
@@ -69,6 +72,7 @@ impl MsiCapability {
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddress {
|
||||
cap_offset: offset,
|
||||
message_control: dword,
|
||||
message_address: func.read_u32(u16::from(offset + 4)),
|
||||
message_data: func.read_u32(u16::from(offset + 8)) as u16,
|
||||
@@ -76,6 +80,14 @@ impl MsiCapability {
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
@@ -97,8 +109,8 @@ impl MsiCapability {
|
||||
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
|
||||
}
|
||||
}
|
||||
pub unsafe fn write_message_control(&self, func: &PciFunc, offset: u8) {
|
||||
func.write_u32(u16::from(offset), self.message_control_raw());
|
||||
pub unsafe fn write_message_control(&self, func: &PciFunc) {
|
||||
func.write_u32(self.cap_offset(), self.message_control_raw());
|
||||
}
|
||||
pub fn is_pvt_capable(&self) -> bool {
|
||||
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
|
||||
@@ -186,57 +198,66 @@ impl MsiCapability {
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_message_address(&self, func: &PciFunc, offset: u8) {
|
||||
func.write_u32(u16::from(offset) + 4, self.message_address())
|
||||
pub unsafe fn write_message_address(&self, func: &PciFunc) {
|
||||
func.write_u32(self.cap_offset() + 4, self.message_address())
|
||||
}
|
||||
pub unsafe fn write_message_upper_address(&self, func: &PciFunc, offset: u8) -> Option<()> {
|
||||
pub unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> {
|
||||
let value = self.message_upper_address()?;
|
||||
func.write_u32(u16::from(offset + 8), value);
|
||||
func.write_u32(self.cap_offset() + 8, value);
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_message_data(&self, func: &PciFunc, offset: u8) {
|
||||
pub unsafe fn write_message_data(&self, func: &PciFunc) {
|
||||
match self {
|
||||
&Self::_32BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data.into()),
|
||||
&Self::_32BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data),
|
||||
&Self::_64BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data.into()),
|
||||
&Self::_64BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data),
|
||||
&Self::_32BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data.into()),
|
||||
&Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data),
|
||||
&Self::_64BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data.into()),
|
||||
&Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data),
|
||||
}
|
||||
}
|
||||
pub unsafe fn write_mask_bits(&self, func: &PciFunc, offset: u8) -> Option<()> {
|
||||
pub unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> {
|
||||
match self {
|
||||
&Self::_32BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 12), mask_bits),
|
||||
&Self::_64BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 16), mask_bits),
|
||||
&Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 12), mask_bits),
|
||||
&Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 16), mask_bits),
|
||||
&Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None,
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_all(&self, func: &PciFunc, offset: u8) {
|
||||
self.write_message_control(func, offset);
|
||||
self.write_message_address(func, offset);
|
||||
self.write_message_upper_address(func, offset);
|
||||
self.write_message_data(func, offset);
|
||||
self.write_mask_bits(func, offset);
|
||||
pub unsafe fn write_all(&self, func: &PciFunc) {
|
||||
self.write_message_control(func);
|
||||
self.write_message_address(func);
|
||||
self.write_message_upper_address(func);
|
||||
self.write_message_data(func);
|
||||
self.write_mask_bits(func);
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixCapability {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MsixInfo {
|
||||
pub table_bar: u8,
|
||||
pub table_offset: u32,
|
||||
pub table_size: u16,
|
||||
pub pba_bar: u8,
|
||||
pub pba_offset: u32,
|
||||
}
|
||||
|
||||
impl MsixInfo {
|
||||
pub fn validate(&self, bars: [PciBar; 6]) {
|
||||
if self.table_bir() > 5 {
|
||||
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir());
|
||||
if self.table_bar > 5 {
|
||||
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bar);
|
||||
}
|
||||
if self.pba_bir() > 5 {
|
||||
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir());
|
||||
if self.pba_bar > 5 {
|
||||
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bar);
|
||||
}
|
||||
|
||||
let table_size = self.table_size();
|
||||
let table_offset = self.table_offset() as usize;
|
||||
let table_size = self.table_size;
|
||||
let table_offset = self.table_offset as usize;
|
||||
let table_min_length = table_size * 16;
|
||||
|
||||
let pba_offset = self.pba_offset() as usize;
|
||||
let pba_offset = self.pba_offset as usize;
|
||||
let pba_min_length = table_size.div_ceil(8);
|
||||
|
||||
let (_, table_bar_size) = bars[self.table_bir() as usize].expect_mem();
|
||||
let (_, pba_bar_size) = bars[self.pba_bir() as usize].expect_mem();
|
||||
let (_, table_bar_size) = bars[self.table_bar as usize].expect_mem();
|
||||
let (_, pba_bar_size) = bars[self.pba_bar as usize].expect_mem();
|
||||
|
||||
// Ensure that the table and PBA are within the BAR.
|
||||
|
||||
@@ -258,7 +279,9 @@ impl MsixCapability {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -267,11 +290,11 @@ impl MsixCapability {
|
||||
|
||||
/// The Message Control field, containing the enabled and function mask bits, as well as the
|
||||
/// table size.
|
||||
pub const fn message_control(&self) -> u16 {
|
||||
const fn message_control(&self) -> u16 {
|
||||
(self.a >> 16) as u16
|
||||
}
|
||||
|
||||
pub fn set_message_control(&mut self, message_control: u16) {
|
||||
pub(crate) fn set_message_control(&mut self, message_control: u16) {
|
||||
self.a &= 0x0000_FFFF;
|
||||
self.a |= u32::from(message_control) << 16;
|
||||
}
|
||||
@@ -279,24 +302,14 @@ impl MsixCapability {
|
||||
pub const fn table_size(&self) -> u16 {
|
||||
(self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1
|
||||
}
|
||||
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
|
||||
/// MSI capability structure.
|
||||
pub const fn msix_enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0
|
||||
}
|
||||
/// The MSI-X function mask, which overrides each of the vectors' mask bit, when set.
|
||||
pub const fn function_mask(&self) -> bool {
|
||||
self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0
|
||||
}
|
||||
|
||||
pub fn set_msix_enabled(&mut self, enabled: bool) {
|
||||
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 fn set_function_mask(&mut self, function_mask: bool) {
|
||||
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;
|
||||
@@ -329,8 +342,8 @@ impl MsixCapability {
|
||||
|
||||
/// Write the first DWORD into configuration space (containing the partially modifiable Message
|
||||
/// Control field).
|
||||
pub unsafe fn write_a(&self, func: &PciFunc, offset: u8) {
|
||||
func.write_u32(u16::from(offset), self.a)
|
||||
pub unsafe fn write_a(&self, func: &PciFunc) {
|
||||
func.write_u32(u16::from(self.cap_offset), self.a)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -76,20 +76,20 @@ fn get_int_method(
|
||||
|
||||
let features = pcid_handle.fetch_all_features().unwrap();
|
||||
|
||||
let has_msi = features.iter().any(|(feature, _)| feature.is_msi());
|
||||
let has_msix = features.iter().any(|(feature, _)| feature.is_msix());
|
||||
let has_msi = features.iter().any(|feature| feature.is_msi());
|
||||
let has_msix = features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
// TODO: Allocate more than one vector when possible and useful.
|
||||
if has_msix {
|
||||
// Extended message signaled interrupts.
|
||||
use self::nvme::MsixCfg;
|
||||
use self::nvme::MappedMsixRegs;
|
||||
use pcid_interface::msi::MsixTableEntry;
|
||||
|
||||
let mut capability_struct = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() {
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() {
|
||||
PciFeatureInfo::MsiX(msix) => msix,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
capability_struct.validate(function.bars);
|
||||
msix_info.validate(function.bars);
|
||||
fn bar_base(
|
||||
allocated_bars: &AllocatedBars,
|
||||
function: &PciFunction,
|
||||
@@ -109,11 +109,11 @@ fn get_int_method(
|
||||
}
|
||||
}
|
||||
let table_bar_base: *mut u8 =
|
||||
bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr();
|
||||
bar_base(allocated_bars, function, msix_info.table_bar)?.as_ptr();
|
||||
let table_base =
|
||||
unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) };
|
||||
unsafe { table_bar_base.offset(msix_info.table_offset as isize) };
|
||||
|
||||
let vector_count = capability_struct.table_size();
|
||||
let vector_count = msix_info.table_size;
|
||||
let table_entries: &'static mut [MsixTableEntry] = unsafe {
|
||||
slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize)
|
||||
};
|
||||
@@ -125,7 +125,6 @@ fn get_int_method(
|
||||
}
|
||||
|
||||
pcid_handle.enable_feature(PciFeature::MsiX).unwrap();
|
||||
capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap
|
||||
|
||||
let (msix_vector_number, irq_handle) = {
|
||||
let entry: &mut MsixTableEntry = &mut table_entries[0];
|
||||
@@ -140,8 +139,8 @@ fn get_int_method(
|
||||
(0, irq_handle)
|
||||
};
|
||||
|
||||
let interrupt_method = InterruptMethod::MsiX(MsixCfg {
|
||||
cap: capability_struct,
|
||||
let interrupt_method = InterruptMethod::MsiX(MappedMsixRegs {
|
||||
info: msix_info,
|
||||
table: table_entries,
|
||||
});
|
||||
let interrupt_sources =
|
||||
|
||||
@@ -22,7 +22,7 @@ pub mod queues;
|
||||
use self::cq_reactor::NotifReq;
|
||||
pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue};
|
||||
|
||||
use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry};
|
||||
use pcid_interface::msi::{MsiCapability, MsixInfo, MsixTableEntry};
|
||||
use pcid_interface::PcidServerHandle;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -93,7 +93,7 @@ pub enum InterruptMethod {
|
||||
/// Message signaled interrupts
|
||||
Msi(MsiCapability),
|
||||
/// Extended message signaled interrupts
|
||||
MsiX(MsixCfg),
|
||||
MsiX(MappedMsixRegs),
|
||||
}
|
||||
impl InterruptMethod {
|
||||
fn is_intx(&self) -> bool {
|
||||
@@ -119,8 +119,8 @@ impl InterruptMethod {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MsixCfg {
|
||||
pub cap: MsixCapability,
|
||||
pub struct MappedMsixRegs {
|
||||
pub info: MsixInfo,
|
||||
pub table: &'static mut [MsixTableEntry],
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,7 @@ pub fn probe_legacy_port_transport(
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
|
||||
@@ -4,7 +4,7 @@ use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read
|
||||
use pcid_interface::msi::MsixTableEntry;
|
||||
use std::{fs::File, ptr::NonNull};
|
||||
|
||||
use crate::{probe::MsixInfo, MSIX_PRIMARY_VECTOR};
|
||||
use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR};
|
||||
|
||||
use pcid_interface::*;
|
||||
|
||||
@@ -12,19 +12,19 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
let pci_config = pcid_handle.fetch_config()?;
|
||||
|
||||
// Extended message signaled interrupts.
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX)? {
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? {
|
||||
PciFeatureInfo::MsiX(capability) => capability,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
capability.validate(pci_config.func.bars);
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
let bar = &pci_config.func.bars[capability.table_bir() as usize];
|
||||
let bar = &pci_config.func.bars[msix_info.table_bar as usize];
|
||||
let bar_address = unsafe { bar.physmap_mem("virtio-core") } as usize;
|
||||
let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry;
|
||||
let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = MsixInfo {
|
||||
let mut info = MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
capability,
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate the primary MSI vector.
|
||||
@@ -61,9 +61,7 @@ pub fn probe_legacy_port_transport(
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::fs::File;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Arc;
|
||||
|
||||
use pcid_interface::msi::{MsixCapability, MsixTableEntry};
|
||||
use pcid_interface::msi::{MsixInfo, MsixTableEntry};
|
||||
use pcid_interface::*;
|
||||
|
||||
use crate::spec::*;
|
||||
@@ -20,18 +20,18 @@ pub struct Device {
|
||||
unsafe impl Send for Device {}
|
||||
unsafe impl Sync for Device {}
|
||||
|
||||
pub struct MsixInfo {
|
||||
pub struct MappedMsixRegs {
|
||||
pub virt_table_base: NonNull<MsixTableEntry>,
|
||||
pub capability: MsixCapability,
|
||||
pub info: MsixInfo,
|
||||
}
|
||||
|
||||
impl MsixInfo {
|
||||
impl MappedMsixRegs {
|
||||
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
&mut *self.virt_table_base.as_ptr().add(k)
|
||||
}
|
||||
|
||||
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
assert!(k < self.info.table_size as usize);
|
||||
unsafe { self.table_entry_pointer_unchecked(k) }
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,8 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
// SAFETY: The capability type is `Notify`, so its safe to access
|
||||
// the `notify_multiplier` field.
|
||||
let multiplier = unsafe {
|
||||
(&*(raw_capability.data.as_ptr() as *const PciCapability as *const PciCapabilityNotify))
|
||||
(&*(raw_capability.data.as_ptr() as *const PciCapability
|
||||
as *const PciCapabilityNotify))
|
||||
.notify_off_multiplier()
|
||||
};
|
||||
notify_addr = Some((address, multiplier));
|
||||
@@ -161,9 +162,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
|
||||
+10
-17
@@ -91,17 +91,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features");
|
||||
log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let has_msi = all_pci_features.iter().any(|feature| feature.is_msi());
|
||||
let has_msix = all_pci_features.iter().any(|feature| feature.is_msix());
|
||||
|
||||
if has_msi && !msi_enabled && !has_msix {
|
||||
msi_enabled = true;
|
||||
}
|
||||
if has_msix && !msix_enabled {
|
||||
msix_enabled = true;
|
||||
}
|
||||
|
||||
if msi_enabled && !msix_enabled {
|
||||
if has_msi && !has_msix {
|
||||
let mut capability = match pcid_handle.feature_info(PciFeature::Msi).expect("xhcid: failed to retrieve the MSI capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(s) => s,
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
@@ -125,19 +118,19 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O
|
||||
log::debug!("Enabled MSI");
|
||||
|
||||
(Some(interrupt_handle), InterruptMethod::Msi)
|
||||
} else if msix_enabled {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
} else if has_msix {
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(_) => panic!(),
|
||||
PciFeatureInfo::MsiX(s) => s,
|
||||
};
|
||||
capability.validate(pci_config.func.bars);
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
assert_eq!(capability.table_bir(), 0);
|
||||
let virt_table_base = (bar0_address + capability.table_offset() as usize) as *mut MsixTableEntry;
|
||||
assert_eq!(msix_info.table_bar, 0);
|
||||
let virt_table_base = (bar0_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = xhci::MsixInfo {
|
||||
let mut info = xhci::MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
capability,
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate one msi vector.
|
||||
|
||||
@@ -21,7 +21,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::usb;
|
||||
|
||||
use pcid_interface::msi::{MsixTableEntry, MsixCapability};
|
||||
use pcid_interface::msi::{MsixInfo, MsixTableEntry};
|
||||
use pcid_interface::{PcidServerHandle, PciFeature};
|
||||
|
||||
mod capability;
|
||||
@@ -64,19 +64,19 @@ pub enum InterruptMethod {
|
||||
Msi,
|
||||
|
||||
/// Extended message signaled interrupts.
|
||||
MsiX(Mutex<MsixInfo>),
|
||||
MsiX(Mutex<MappedMsixRegs>),
|
||||
}
|
||||
|
||||
pub struct MsixInfo {
|
||||
pub struct MappedMsixRegs {
|
||||
pub virt_table_base: NonNull<MsixTableEntry>,
|
||||
pub capability: MsixCapability,
|
||||
pub info: MsixInfo,
|
||||
}
|
||||
impl MsixInfo {
|
||||
impl MappedMsixRegs {
|
||||
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
&mut *self.virt_table_base.as_ptr().offset(k as isize)
|
||||
}
|
||||
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
assert!(k < self.info.table_size as usize);
|
||||
unsafe { self.table_entry_pointer_unchecked(k) }
|
||||
}
|
||||
}
|
||||
@@ -774,13 +774,13 @@ impl Xhci {
|
||||
if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false }
|
||||
}
|
||||
// TODO: Perhaps use an rwlock?
|
||||
pub fn msix_info(&self) -> Option<MutexGuard<'_, MsixInfo>> {
|
||||
pub fn msix_info(&self) -> Option<MutexGuard<'_, MappedMsixRegs>> {
|
||||
match self.interrupt_method {
|
||||
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn msix_info_mut(&self) -> Option<MutexGuard<'_, MsixInfo>> {
|
||||
pub fn msix_info_mut(&self) -> Option<MutexGuard<'_, MappedMsixRegs>> {
|
||||
match self.interrupt_method {
|
||||
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
|
||||
_ => None,
|
||||
|
||||
Reference in New Issue
Block a user