Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 93 additions & 44 deletions src/device/irqchip/gicv3/gits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use spin::{mutex::Mutex, Once, RwLock};

use crate::{
consts::MAX_ZONE_NUM, cpu_data::this_zone, device::irqchip::gicv3::gicr::enable_one_lpi,
memory::Frame,
memory::Frame, pci::pci_struct::Bdf,
};

use super::host_gits_base;
Expand All @@ -45,6 +45,18 @@ pub const CMDQ_PAGES_NUM: usize = 16; // 16 pages, 64KB
pub const PER_CMD_BYTES: usize = 0x20;
pub const PER_CMD_QWORD: usize = PER_CMD_BYTES >> 3;

pub const ITS_CMD_MOVI: usize = 0x01;
pub const ITS_CMD_INT: usize = 0x03;
pub const ITS_CMD_CLEAR: usize = 0x04;
pub const ITS_CMD_SYNC: usize = 0x05;
pub const ITS_CMD_MAPD: usize = 0x08;
pub const ITS_CMD_MAPC: usize = 0x09;
pub const ITS_CMD_MAPTI: usize = 0x0a;
pub const ITS_CMD_MAPI: usize = 0x0b;
pub const ITS_CMD_INV: usize = 0x0c;
pub const ITS_CMD_INVALL: usize = 0x0d;
pub const ITS_CMD_DISCARD: usize = 0x0f;

fn ring_ptr_update(val: usize, page_num: usize) -> usize {
let total_size = CMDQ_PAGE_SIZE * page_num;
if val >= total_size {
Expand Down Expand Up @@ -237,32 +249,65 @@ impl Cmdq {
let binding = this_zone();
let zone = binding.read();
let cpuset_bitmap = zone.cpu_set.bitmap;

let vicid_to_icid_checked = |vicid: u64| -> u64 {
vicid_to_icid(vicid, cpuset_bitmap)
.expect("vicid to icid failed, maybe logical_id out of range")
};
let set_cmd2_icid = |cmd2: &mut u64, icid: u64| {
*cmd2 &= !0xffffu64;
*cmd2 |= icid & 0xffff;
};

// vbdf -> bdf
let id_32 = (value[0] >> 32) as u32;
let domain = (id_32 >> 16) as u8;
let vbus = ((id_32 >> 8) & 0xFF) as u8;
let vdevice = ((id_32 >> 3) & 0x1F) as u8;
let vfunction = (id_32 & 0x07) as u8;

let vbdf = Bdf::new(domain, vbus, vdevice, vfunction);
let bdf = match zone.vpci_bus.get(&vbdf) {
Some(vdev) => vdev.read().get_bdf(),
None => Bdf {
domain,
bus: 0,
device: 0,
function: 0,
},
};

let phys_id_32 = ((bdf.domain as u32) << 16)
| ((bdf.bus as u32) << 8)
| ((bdf.device as u32) << 3)
| (bdf.function as u32);

// new_cmd[0] = cmd0_tmp
// CLEAR DISCARD INT INV MAPD MAPI MAPTI MOVI
let cmd0_tmp = (value[0] & 0xffffffff) | ((phys_id_32 as u64) << 32);

match code {
0x0b => {
let id = value[0] & 0xffffffff00000000;
ITS_CMD_MAPI => {
new_cmd[0] = cmd0_tmp;

let event = value[1] & 0xffffffff;
let vicid = value[2] & 0xffff;
let icid = vicid_to_icid(vicid, cpuset_bitmap)
.expect("vicid to icid failed, maybe logical_id out of range");
new_cmd[2] &= !0xffffu64;
new_cmd[2] |= icid & 0xffff;
let icid = vicid_to_icid_checked(vicid);
set_cmd2_icid(&mut new_cmd[2], icid);
enable_one_lpi((event - 8192) as _);
debug!(
"MAPI cmd, for device {:#x}, event = intid = {:#x} -> vicid {:#x} (icid {:#x})",
id >> 32,
"MAPI cmd, for vbdf {:#x}:{:#x}:{:#x}:{:#x} -> {:#x}:{:#x}:{:#x}:{:#x}, event = intid = {:#x} -> vicid {:#x} (icid {:#x})",
domain, vbus, vdevice, vfunction,
bdf.domain, bdf.bus, bdf.device, bdf.function,
event,
vicid,
icid
);
}
0x08 => {
let id = value[0] & 0xffffffff00000000;
ITS_CMD_MAPD => {
new_cmd[0] = cmd0_tmp;

let itt_base = value[2] & 0x000fffffffffff00; // the lowest 8 bits are zeros
debug!(
"MAPD cmd, for device {:#x}, itt base {:#x}",
id >> 32,
itt_base
);
let phys_itt_base = unsafe {
this_zone()
.read()
Expand All @@ -274,69 +319,73 @@ impl Cmdq {
new_cmd[2] &= !0x000fffffffffff00u64;
new_cmd[2] |= phys_itt_base as u64;
debug!(
"MAPD cmd, set ITT: {:#x} to device {:#x}",
"MAPD cmd, set ITT: {:#x} to vbdf {:#x}:{:#x}:{:#x}:{:#x} -> {:#x}:{:#x}:{:#x}:{:#x}",
phys_itt_base,
id >> 32
domain, vbus, vdevice, vfunction,
bdf.domain, bdf.bus, bdf.device, bdf.function
);
}
0x0a => {
let id = value[0] & 0xffffffff00000000;
ITS_CMD_MAPTI => {
new_cmd[0] = cmd0_tmp;

let event = value[1] & 0xffffffff;
let intid = value[1] >> 32;
let vicid = value[2] & 0xffff;
let icid = vicid_to_icid(vicid, cpuset_bitmap)
.expect("vicid to icid failed, maybe logical_id out of range");
new_cmd[2] &= !0xffffu64;
new_cmd[2] |= icid & 0xffff;
let icid = vicid_to_icid_checked(vicid);
set_cmd2_icid(&mut new_cmd[2], icid);
enable_one_lpi((intid - 8192) as _);
debug!(
"MAPTI cmd, for device {:#x}, event {:#x} -> vicid {:#x} (icid {:#x}) + intid {:#x}",
id >> 32,
"MAPTI cmd, for vbdf {:#x}:{:#x}:{:#x}:{:#x} -> {:#x}:{:#x}:{:#x}:{:#x}, event {:#x} -> vicid {:#x} (icid {:#x}) + intid {:#x}",
domain, vbus, vdevice, vfunction,
bdf.domain, bdf.bus, bdf.device, bdf.function,
event,
vicid,
icid,
intid
);
}
0x09 => {
ITS_CMD_MAPC => {
let vicid = value[2] & 0xffff;
let icid = vicid_to_icid(vicid, cpuset_bitmap)
.expect("vicid to icid failed, maybe logical_id out of range");
new_cmd[2] &= !0xffffu64;
new_cmd[2] |= icid & 0xffff;
let icid = vicid_to_icid_checked(vicid);
set_cmd2_icid(&mut new_cmd[2], icid);
let rd_base = (value[2] >> 16) & 0x7ffffffff;
debug!(
"MAPC cmd, vicid {:#x} (icid {:#x}) -> redist {:#x}",
vicid, icid, rd_base
);
}
0x05 => {
ITS_CMD_SYNC => {
debug!("SYNC cmd");
}
0x04 => {
ITS_CMD_CLEAR => {
new_cmd[0] = cmd0_tmp;
debug!("CLEAR cmd");
}
0x0f => {
ITS_CMD_DISCARD => {
new_cmd[0] = cmd0_tmp;
debug!("DISCARD cmd");
}
0x03 => {
ITS_CMD_INT => {
new_cmd[0] = cmd0_tmp;
debug!("INT cmd");
}
0x0c => {
ITS_CMD_INV => {
new_cmd[0] = cmd0_tmp;
debug!("INV cmd");
}
0x0d => {
ITS_CMD_INVALL => {
debug!("INVALL cmd");
}
0x01 => {
ITS_CMD_MOVI => {
new_cmd[0] = cmd0_tmp;

let vicid = value[2] & 0xffff;
let icid = vicid_to_icid(vicid, cpuset_bitmap)
.expect("vicid to icid failed, maybe logical_id out of range");
new_cmd[2] &= !0xffffu64;
new_cmd[2] |= icid & 0xffff;
let icid = vicid_to_icid_checked(vicid);
set_cmd2_icid(&mut new_cmd[2], icid);
debug!(
"MOVI, for Device {:#x}, new vicid({}) -> icid({})",
value[0] >> 32,
"MOVI, for vbdf {:#x}:{:#x}:{:#x}:{:#x} -> {:#x}:{:#x}:{:#x}:{:#x}, new vicid({}) -> icid({})",
domain, vbus, vdevice, vfunction,
bdf.domain, bdf.bus, bdf.device, bdf.function,
vicid,
icid
);
Expand Down
11 changes: 11 additions & 0 deletions src/hypercall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE};
use crate::cpu_data::{get_cpu_data, PerCpu};
use crate::device::virtio_trampoline::{MAX_DEVS, VIRTIO_BRIDGE, VIRTIO_IRQS};
use crate::error::HvResult;
use crate::pci::pci_config::GLOBAL_PCIE_LIST;
use crate::zone::{
add_zone, all_zones_info, find_zone, is_this_root_zone, remove_zone, zone_create, ZoneInfo,
};
Expand Down Expand Up @@ -272,6 +273,16 @@ impl<'a> HyperCall<'a> {

drop(zone_w);
drop(zone);

// Reset zone_id for all devices allocated to this zone
let pci_list = GLOBAL_PCIE_LIST.lock();
for (_bdf, dev) in pci_list.iter() {
if dev.get_zone_id() == Some(zone_id as u32) {
dev.set_zone_id(None);
}
}
drop(pci_list);

remove_zone(zone_id as _);
info!("zone {} has been shutdown", zone_id);
HyperCallResult::Ok(0)
Expand Down
89 changes: 79 additions & 10 deletions src/pci/pci_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,25 @@ use crate::pci::{
use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex};

#[cfg(feature = "ecam_pcie")]
use crate::pci::pci_handler::mmio_vpci_handler;
use crate::pci::{config_accessors::ecam::EcamConfigAccessor, pci_handler::mmio_vpci_handler};

#[cfg(feature = "dwc_pcie")]
use crate::{
memory::mmio_generic_handler,
pci::{
config_accessors::{dwc::DwcConfigRegionBackend, dwc_atu::AtuConfig, PciRegionMmio},
config_accessors::{
dwc::DwcConfigAccessor, dwc::DwcConfigRegionBackend, dwc_atu::AtuConfig, PciRegionMmio,
},
pci_handler::{mmio_dwc_cfg_handler, mmio_dwc_io_handler, mmio_vpci_handler_dbi},
PciConfigAddress,
},
platform,
};

#[cfg(feature = "loongarch64_pcie")]
use crate::pci::pci_handler::mmio_vpci_direct_handler;
use crate::pci::{
config_accessors::loongarch64::LoongArchConfigAccessor, pci_handler::mmio_vpci_direct_handler,
};

pub static GLOBAL_PCIE_LIST: Lazy<Mutex<BTreeMap<Bdf, ArcRwLockVirtualPciConfigSpace>>> =
Lazy::new(|| {
Expand Down Expand Up @@ -172,7 +177,7 @@ impl Zone {
pci_config: &[HvPciConfig],
_num_pci_config: usize,
) -> HvResult {
let mut guard = GLOBAL_PCIE_LIST.lock();
let guard = GLOBAL_PCIE_LIST.lock();
for target_pci_config in pci_config {
// Skip empty config
if target_pci_config.ecam_base == 0 {
Expand All @@ -184,6 +189,46 @@ impl Zone {
let target_domain = target_pci_config.domain;
let bus_range_begin = target_pci_config.bus_range_begin as u8;

// Create accessor for VirtualRootComplex, similar to RootComplex
#[cfg(feature = "dwc_pcie")]
{
use alloc::sync::Arc;
let atu_config = platform::ROOT_DWC_ATU_CONFIG
.iter()
.find(|atu_cfg| atu_cfg.ecam_base == ecam_base);

match atu_config {
Some(cfg) => {
let root_bus = bus_range_begin;
let accessor = Arc::new(DwcConfigAccessor::new(cfg, root_bus));
self.vpci_bus.set_accessor(accessor);
}
None => {
warn!("No ATU config found for ecam_base 0x{:x}", ecam_base);
continue;
}
}
}

#[cfg(feature = "loongarch64_pcie")]
{
use alloc::sync::Arc;
let root_bus = bus_range_begin;
let accessor = Arc::new(LoongArchConfigAccessor::new(
ecam_base,
target_pci_config.ecam_size,
root_bus,
));
self.vpci_bus.set_accessor(accessor);
}

#[cfg(feature = "ecam_pcie")]
{
use alloc::sync::Arc;
let accessor = Arc::new(EcamConfigAccessor::new(ecam_base));
self.vpci_bus.set_accessor(accessor);
}

let mut filtered_devices: alloc::vec::Vec<HvPciDevConfig> = alloc::vec::Vec::new();
for i in 0..num_pci_devs {
let dev_config = alloc_pci_devs[i as usize];
Expand All @@ -207,6 +252,7 @@ impl Zone {
let mut vbus_pre = bus_range_begin;
let mut bus_pre = bus_range_begin;
let mut device_pre = 0u8;
let mut vdevice_pre = 0u8;

/*
* To allow Linux to successfully recognize the devices we add, hvisor needs
Expand Down Expand Up @@ -246,7 +292,21 @@ impl Zone {
vbus_pre
};

let vbdf = Bdf::new(bdf.domain(), vbus, device, vfunction);
// Remap device number to be contiguous, starting from 0
let vdevice = if bus != bus_pre || device != device_pre {
// New bus or new device, increment device counter
if bus != bus_pre {
vdevice_pre = 0;
} else {
vdevice_pre += 1;
}
vdevice_pre
} else {
// Same bus and device, keep the same virtual device number
vdevice_pre
};

let vbdf = Bdf::new(bdf.domain(), vbus, vdevice, vfunction);

device_pre = device;
bus_pre = bus;
Expand Down Expand Up @@ -276,14 +336,23 @@ impl Zone {
config_value.get_class().0 == 0x6
})
{
let mut vdev = dev.read().clone();
let mut vdev = dev.read().config_space.clone();
vdev.set_vbdf(vbdf);
self.vpci_bus.insert(vbdf, vdev);
} else {
let vdev = guard.remove(&bdf).unwrap();
let mut vdev_inner = vdev.read().clone();
vdev_inner.set_vbdf(vbdf);
self.vpci_bus.insert(vbdf, vdev_inner);
// Check if device is already allocated to another zone
if dev.get_zone_id().is_none() {
dev.set_zone_id(Some(_zone_id as u32));
let mut vdev_inner = dev.read().config_space.clone();
vdev_inner.set_vbdf(vbdf);
self.vpci_bus.insert(vbdf, vdev_inner);
} else {
warn!(
"Device {:#?} is already allocated to zone {:?}",
bdf,
dev.get_zone_id()
);
}
}
} else {
// warn!("can not find dev {:#?}", bdf);
Expand Down
Loading
Loading