intel_iommu: Flush stage-1 cache in iotlb invalidation
According to spec, Page-Selective-within-Domain Invalidation (11b): 1. IOTLB entries caching second-stage mappings (PGTT=010b) or pass-through (PGTT=100b) mappings associated with the specified domain-id and the input-address range are invalidated. 2. IOTLB entries caching first-stage (PGTT=001b) or nested (PGTT=011b) mapping associated with specified domain-id are invalidated. So per spec definition the Page-Selective-within-Domain Invalidation needs to flush first stage and nested cached IOTLB entries as well. We don't support nested yet and pass-through mapping is never cached, so what in iotlb cache are only first-stage and second-stage mappings. Add a tag pgtt in VTDIOTLBEntry to mark PGTT type of the mapping and invalidate entries based on PGTT type. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Clément Mathieu--Drif<clement.mathieu--drif@eviden.com> Acked-by: Jason Wang <jasowang@redhat.com> Reviewed-by: Yi Liu <yi.l.liu@intel.com> Message-Id: <20241212083757.605022-11-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
65c4f09999
commit
16d4e418e9
@ -305,9 +305,21 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
|
|||||||
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
|
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
|
||||||
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
|
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
|
||||||
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
|
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
|
||||||
return (entry->domain_id == info->domain_id) &&
|
|
||||||
(((entry->gfn & info->mask) == gfn) ||
|
if (entry->domain_id != info->domain_id) {
|
||||||
(entry->gfn == gfn_tlb));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to spec, IOTLB entries caching first-stage (PGTT=001b) or
|
||||||
|
* nested (PGTT=011b) mapping associated with specified domain-id are
|
||||||
|
* invalidated. Nested isn't supported yet, so only need to check 001b.
|
||||||
|
*/
|
||||||
|
if (entry->pgtt == VTD_SM_PASID_ENTRY_FLT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
|
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
|
||||||
@ -382,7 +394,7 @@ out:
|
|||||||
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
||||||
uint16_t domain_id, hwaddr addr, uint64_t pte,
|
uint16_t domain_id, hwaddr addr, uint64_t pte,
|
||||||
uint8_t access_flags, uint32_t level,
|
uint8_t access_flags, uint32_t level,
|
||||||
uint32_t pasid)
|
uint32_t pasid, uint8_t pgtt)
|
||||||
{
|
{
|
||||||
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
||||||
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
||||||
@ -400,6 +412,7 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
|||||||
entry->access_flags = access_flags;
|
entry->access_flags = access_flags;
|
||||||
entry->mask = vtd_pt_level_page_mask(level);
|
entry->mask = vtd_pt_level_page_mask(level);
|
||||||
entry->pasid = pasid;
|
entry->pasid = pasid;
|
||||||
|
entry->pgtt = pgtt;
|
||||||
|
|
||||||
key->gfn = gfn;
|
key->gfn = gfn;
|
||||||
key->sid = source_id;
|
key->sid = source_id;
|
||||||
@ -2062,7 +2075,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|||||||
bool is_fpd_set = false;
|
bool is_fpd_set = false;
|
||||||
bool reads = true;
|
bool reads = true;
|
||||||
bool writes = true;
|
bool writes = true;
|
||||||
uint8_t access_flags;
|
uint8_t access_flags, pgtt;
|
||||||
bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable;
|
bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable;
|
||||||
VTDIOTLBEntry *iotlb_entry;
|
VTDIOTLBEntry *iotlb_entry;
|
||||||
uint64_t xlat, size;
|
uint64_t xlat, size;
|
||||||
@ -2171,9 +2184,11 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|||||||
if (s->flts && s->root_scalable) {
|
if (s->flts && s->root_scalable) {
|
||||||
ret_fr = vtd_iova_to_flpte(s, &ce, addr, is_write, &pte, &level,
|
ret_fr = vtd_iova_to_flpte(s, &ce, addr, is_write, &pte, &level,
|
||||||
&reads, &writes, s->aw_bits, pasid);
|
&reads, &writes, s->aw_bits, pasid);
|
||||||
|
pgtt = VTD_SM_PASID_ENTRY_FLT;
|
||||||
} else {
|
} else {
|
||||||
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
|
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
|
||||||
&reads, &writes, s->aw_bits, pasid);
|
&reads, &writes, s->aw_bits, pasid);
|
||||||
|
pgtt = VTD_SM_PASID_ENTRY_SLT;
|
||||||
}
|
}
|
||||||
if (!ret_fr) {
|
if (!ret_fr) {
|
||||||
xlat = vtd_get_pte_addr(pte, s->aw_bits);
|
xlat = vtd_get_pte_addr(pte, s->aw_bits);
|
||||||
@ -2207,7 +2222,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|||||||
page_mask = vtd_pt_level_page_mask(level);
|
page_mask = vtd_pt_level_page_mask(level);
|
||||||
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
||||||
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
||||||
addr, pte, access_flags, level, pasid);
|
addr, pte, access_flags, level, pasid, pgtt);
|
||||||
out:
|
out:
|
||||||
vtd_iommu_unlock(s);
|
vtd_iommu_unlock(s);
|
||||||
entry->iova = addr & page_mask;
|
entry->iova = addr & page_mask;
|
||||||
|
@ -155,6 +155,7 @@ struct VTDIOTLBEntry {
|
|||||||
uint64_t pte;
|
uint64_t pte;
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
uint8_t access_flags;
|
uint8_t access_flags;
|
||||||
|
uint8_t pgtt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VT-d Source-ID Qualifier types */
|
/* VT-d Source-ID Qualifier types */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user