mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: iommu: Support multiple endpoints per domain
Based on the VIRTIO specification, we must be able to support multiple endpoints per domain. This is fixed along with the introduction of some simplification regarding how we can retrieve the external mapping directly based on the endpoint. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
@@ -346,7 +346,6 @@ impl Request {
|
|||||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||||
mapping: &Arc<IommuMapping>,
|
mapping: &Arc<IommuMapping>,
|
||||||
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||||
ext_domain_mapping: &mut BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
|
||||||
msi_iova_space: (u64, u64),
|
msi_iova_space: (u64, u64),
|
||||||
) -> result::Result<usize, Error> {
|
) -> result::Result<usize, Error> {
|
||||||
let desc = desc_chain
|
let desc = desc_chain
|
||||||
@@ -402,13 +401,6 @@ impl Request {
|
|||||||
// Add endpoint associated with specific domain
|
// Add endpoint associated with specific domain
|
||||||
mapping.endpoints.write().unwrap().insert(endpoint, domain);
|
mapping.endpoints.write().unwrap().insert(endpoint, domain);
|
||||||
|
|
||||||
// If the endpoint is part of the list of devices with an
|
|
||||||
// external mapping, insert a new entry for the corresponding
|
|
||||||
// domain, with the same reference to the trait.
|
|
||||||
if let Some(map) = ext_mapping.get(&endpoint) {
|
|
||||||
ext_domain_mapping.insert(domain, map.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new domain with no mapping if the entry didn't exist yet
|
// Add new domain with no mapping if the entry didn't exist yet
|
||||||
let mut mappings = mapping.mappings.write().unwrap();
|
let mut mappings = mapping.mappings.write().unwrap();
|
||||||
mappings.entry(domain).or_insert_with(BTreeMap::new);
|
mappings.entry(domain).or_insert_with(BTreeMap::new);
|
||||||
@@ -430,16 +422,24 @@ impl Request {
|
|||||||
let domain = req.domain;
|
let domain = req.domain;
|
||||||
let endpoint = req.endpoint;
|
let endpoint = req.endpoint;
|
||||||
|
|
||||||
// If the endpoint is part of the list of devices with an
|
|
||||||
// external mapping, remove the entry for the corresponding
|
|
||||||
// domain.
|
|
||||||
if ext_mapping.contains_key(&endpoint) {
|
|
||||||
ext_domain_mapping.remove(&domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove endpoint associated with specific domain
|
// Remove endpoint associated with specific domain
|
||||||
mapping.endpoints.write().unwrap().remove(&endpoint);
|
mapping.endpoints.write().unwrap().remove(&endpoint);
|
||||||
|
|
||||||
|
// After all endpoints have been successfully detached from a
|
||||||
|
// domain, the domain can be removed. This means we must remove
|
||||||
|
// the mappings associated with this domain.
|
||||||
|
if mapping
|
||||||
|
.endpoints
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, &d)| d == domain)
|
||||||
|
.count()
|
||||||
|
== 0
|
||||||
|
{
|
||||||
|
mapping.mappings.write().unwrap().remove(&domain);
|
||||||
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
VIRTIO_IOMMU_T_MAP => {
|
VIRTIO_IOMMU_T_MAP => {
|
||||||
@@ -455,13 +455,24 @@ impl Request {
|
|||||||
|
|
||||||
// Copy the value to use it as a proper reference.
|
// Copy the value to use it as a proper reference.
|
||||||
let domain = req.domain;
|
let domain = req.domain;
|
||||||
|
// Find the list of endpoints attached to the given domain.
|
||||||
|
let endpoints: Vec<u32> = mapping
|
||||||
|
.endpoints
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, &d)| d == domain)
|
||||||
|
.map(|(&e, _)| e)
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Trigger external mapping if necessary.
|
// Trigger external mapping if necessary.
|
||||||
if let Some(ext_map) = ext_domain_mapping.get(&domain) {
|
for endpoint in endpoints {
|
||||||
let size = req.virt_end - req.virt_start + 1;
|
if let Some(ext_map) = ext_mapping.get(&endpoint) {
|
||||||
ext_map
|
let size = req.virt_end - req.virt_start + 1;
|
||||||
.map(req.virt_start, req.phys_start, size)
|
ext_map
|
||||||
.map_err(Error::ExternalMapping)?;
|
.map(req.virt_start, req.phys_start, size)
|
||||||
|
.map_err(Error::ExternalMapping)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new mapping associated with the domain
|
// Add new mapping associated with the domain
|
||||||
@@ -493,16 +504,27 @@ impl Request {
|
|||||||
// Copy the value to use it as a proper reference.
|
// Copy the value to use it as a proper reference.
|
||||||
let domain = req.domain;
|
let domain = req.domain;
|
||||||
let virt_start = req.virt_start;
|
let virt_start = req.virt_start;
|
||||||
|
// Find the list of endpoints attached to the given domain.
|
||||||
|
let endpoints: Vec<u32> = mapping
|
||||||
|
.endpoints
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, &d)| d == domain)
|
||||||
|
.map(|(&e, _)| e)
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Trigger external unmapping if necessary.
|
// Trigger external unmapping if necessary.
|
||||||
if let Some(ext_map) = ext_domain_mapping.get(&domain) {
|
for endpoint in endpoints {
|
||||||
let size = req.virt_end - virt_start + 1;
|
if let Some(ext_map) = ext_mapping.get(&endpoint) {
|
||||||
ext_map
|
let size = req.virt_end - virt_start + 1;
|
||||||
.unmap(virt_start, size)
|
ext_map
|
||||||
.map_err(Error::ExternalUnmapping)?;
|
.unmap(virt_start, size)
|
||||||
|
.map_err(Error::ExternalUnmapping)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new mapping associated with the domain
|
// Remove mapping associated with the domain
|
||||||
if let Some(entry) = mapping.mappings.write().unwrap().get_mut(&domain) {
|
if let Some(entry) = mapping.mappings.write().unwrap().get_mut(&domain) {
|
||||||
entry.remove(&virt_start);
|
entry.remove(&virt_start);
|
||||||
}
|
}
|
||||||
@@ -573,7 +595,6 @@ struct IommuEpollHandler {
|
|||||||
pause_evt: EventFd,
|
pause_evt: EventFd,
|
||||||
mapping: Arc<IommuMapping>,
|
mapping: Arc<IommuMapping>,
|
||||||
ext_mapping: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
|
ext_mapping: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
|
||||||
ext_domain_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
|
||||||
msi_iova_space: (u64, u64),
|
msi_iova_space: (u64, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +607,6 @@ impl IommuEpollHandler {
|
|||||||
&mut desc_chain,
|
&mut desc_chain,
|
||||||
&self.mapping,
|
&self.mapping,
|
||||||
&self.ext_mapping.lock().unwrap(),
|
&self.ext_mapping.lock().unwrap(),
|
||||||
&mut self.ext_domain_mapping,
|
|
||||||
self.msi_iova_space,
|
self.msi_iova_space,
|
||||||
) {
|
) {
|
||||||
Ok(len) => len as u32,
|
Ok(len) => len as u32,
|
||||||
@@ -900,7 +920,6 @@ impl VirtioDevice for Iommu {
|
|||||||
pause_evt,
|
pause_evt,
|
||||||
mapping: self.mapping.clone(),
|
mapping: self.mapping.clone(),
|
||||||
ext_mapping: self.ext_mapping.clone(),
|
ext_mapping: self.ext_mapping.clone(),
|
||||||
ext_domain_mapping: BTreeMap::new(),
|
|
||||||
msi_iova_space: self.msi_iova_space,
|
msi_iova_space: self.msi_iova_space,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user