Merge branch 'x86_virtio_modern_transport' into 'master'
Support the modern virtio transport on x86 See merge request redox-os/drivers!173
This commit is contained in:
@@ -178,21 +178,21 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result<Option<(u8,
|
||||
Ok(Some((base, files.pop().unwrap())))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndData, File) {
|
||||
use crate::pci::msi::x86_64 as x86_64_msix;
|
||||
use crate::pci::msi::x86 as x86_msix;
|
||||
|
||||
// FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping
|
||||
let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8");
|
||||
let rh = false;
|
||||
let dm = false;
|
||||
let addr = x86_64_msix::message_address(lapic_id, rh, dm);
|
||||
let addr = x86_msix::message_address(lapic_id, rh, dm);
|
||||
|
||||
let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id)
|
||||
.expect("failed to allocate interrupt vector")
|
||||
.expect("no interrupt vectors left");
|
||||
let msg_data =
|
||||
x86_64_msix::message_data_edge_triggered(x86_64_msix::DeliveryMode::Fixed, vector);
|
||||
x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector);
|
||||
|
||||
(MsiAddrAndData::new(addr, msg_data), interrupt_handle)
|
||||
}
|
||||
|
||||
+2
-2
@@ -92,8 +92,8 @@ pub struct MsixTableEntry {
|
||||
pub vec_ctl: Mmio<u32>,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod x86_64 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub mod x86 {
|
||||
#[repr(u8)]
|
||||
pub enum TriggerMode {
|
||||
Edge = 0,
|
||||
|
||||
@@ -1,15 +1,57 @@
|
||||
use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device};
|
||||
use std::fs::File;
|
||||
|
||||
use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id};
|
||||
use pcid_interface::msi::MsixTableEntry;
|
||||
use std::{fs::File, ptr::NonNull};
|
||||
|
||||
use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR};
|
||||
|
||||
use pcid_interface::*;
|
||||
|
||||
pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
panic!("virtio-core: x86 doesn't support enable_msix")
|
||||
pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result<File, Error> {
|
||||
let pci_config = pcid_handle.config();
|
||||
|
||||
// Extended message signaled interrupts.
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? {
|
||||
PciFeatureInfo::MsiX(capability) => capability,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? }
|
||||
.ptr
|
||||
.as_ptr() as usize;
|
||||
let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate the primary MSI vector.
|
||||
// FIXME allow the driver to register multiple MSI-X vectors
|
||||
// FIXME move this MSI-X registering code into pcid_interface or pcid itself
|
||||
let interrupt_handle = {
|
||||
let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize);
|
||||
|
||||
let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed");
|
||||
let (msg_addr_and_data, interrupt_handle) =
|
||||
allocate_single_interrupt_vector_for_msi(destination_id);
|
||||
table_entry_pointer.write_addr_and_data(msg_addr_and_data);
|
||||
table_entry_pointer.unmask();
|
||||
|
||||
interrupt_handle
|
||||
};
|
||||
|
||||
pcid_handle.enable_feature(PciFeature::MsiX)?;
|
||||
|
||||
log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})");
|
||||
Ok(interrupt_handle)
|
||||
}
|
||||
|
||||
pub fn probe_legacy_port_transport(
|
||||
pci_config: &SubdriverArguments,
|
||||
pcid_handle: &mut PcidServerHandle,
|
||||
pcid_handle: &mut PciFunctionHandle,
|
||||
) -> Result<Device, Error> {
|
||||
let port = pci_config.func.bars[0].expect_port();
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device};
|
||||
|
||||
use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id};
|
||||
use pcid_interface::msi::MsixTableEntry;
|
||||
use std::{fs::File, ptr::NonNull};
|
||||
|
||||
use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR};
|
||||
|
||||
use pcid_interface::*;
|
||||
|
||||
pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result<File, Error> {
|
||||
let pci_config = pcid_handle.config();
|
||||
|
||||
// Extended message signaled interrupts.
|
||||
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? {
|
||||
PciFeatureInfo::MsiX(capability) => capability,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
msix_info.validate(pci_config.func.bars);
|
||||
|
||||
let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? }
|
||||
.ptr
|
||||
.as_ptr() as usize;
|
||||
let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry;
|
||||
|
||||
let mut info = MappedMsixRegs {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
info: msix_info,
|
||||
};
|
||||
|
||||
// Allocate the primary MSI vector.
|
||||
// FIXME allow the driver to register multiple MSI-X vectors
|
||||
// FIXME move this MSI-X registering code into pcid_interface or pcid itself
|
||||
let interrupt_handle = {
|
||||
let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize);
|
||||
|
||||
let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed");
|
||||
let (msg_addr_and_data, interrupt_handle) =
|
||||
allocate_single_interrupt_vector_for_msi(destination_id);
|
||||
table_entry_pointer.write_addr_and_data(msg_addr_and_data);
|
||||
table_entry_pointer.unmask();
|
||||
|
||||
interrupt_handle
|
||||
};
|
||||
|
||||
pcid_handle.enable_feature(PciFeature::MsiX)?;
|
||||
|
||||
log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})");
|
||||
Ok(interrupt_handle)
|
||||
}
|
||||
|
||||
pub fn probe_legacy_port_transport(
|
||||
pci_config: &SubdriverArguments,
|
||||
pcid_handle: &mut PciFunctionHandle,
|
||||
) -> Result<Device, Error> {
|
||||
let port = pci_config.func.bars[0].expect_port();
|
||||
|
||||
common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level");
|
||||
log::warn!("virtio: using legacy transport");
|
||||
|
||||
let transport = LegacyTransport::new(port);
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
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");
|
||||
let irq_handle = enable_msix(pcid_handle)?;
|
||||
|
||||
let device = Device {
|
||||
transport,
|
||||
irq_handle,
|
||||
device_space: core::ptr::null_mut(),
|
||||
};
|
||||
|
||||
device.transport.reset();
|
||||
reinit(&device)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
@@ -10,14 +10,10 @@ mod probe;
|
||||
#[path="arch/aarch64.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[path="arch/x86.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[path="arch/x86_64.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod legacy_transport;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user