intel_iommu: Flush stage-2 cache in PASID-selective PASID-based iotlb invalidation

Per VT-d spec 4.1, 6.5.2.4, "Table 21. PASID-based-IOTLB Invalidation",
PADID-selective PASID-based iotlb invalidation will flush stage-2 iotlb
entries with matching domain id and pasid.

With stage-1 translation introduced, guest could send PASID-selective
PASID-based iotlb invalidation to flush either stage-1 or stage-2 entries.

By this chance, remove old IOTLB related definitions which were unused.

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>
Message-Id: <20241212083757.605022-5-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:
Zhenzhong Duan 2024-12-12 16:37:41 +08:00 committed by Michael S. Tsirkin
parent 791346f93d
commit ad0a7f1e1e
2 changed files with 93 additions and 6 deletions

View file

@ -2692,6 +2692,83 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
return true;
}
static gboolean vtd_hash_remove_by_pasid(gpointer key, gpointer value,
gpointer user_data)
{
VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
return ((entry->domain_id == info->domain_id) &&
(entry->pasid == info->pasid));
}
static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s,
uint16_t domain_id, uint32_t pasid)
{
VTDIOTLBPageInvInfo info;
VTDAddressSpace *vtd_as;
VTDContextEntry ce;
info.domain_id = domain_id;
info.pasid = pasid;
vtd_iommu_lock(s);
g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_pasid,
&info);
vtd_iommu_unlock(s);
QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) {
if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
vtd_as->devfn, &ce) &&
domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {
uint32_t rid2pasid = VTD_CE_GET_RID2PASID(&ce);
if ((vtd_as->pasid != PCI_NO_PASID || pasid != rid2pasid) &&
vtd_as->pasid != pasid) {
continue;
}
if (!s->flts) {
vtd_address_space_sync(vtd_as);
}
}
}
}
static bool vtd_process_piotlb_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
uint16_t domain_id;
uint32_t pasid;
uint64_t mask[4] = {VTD_INV_DESC_PIOTLB_RSVD_VAL0,
VTD_INV_DESC_PIOTLB_RSVD_VAL1,
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, true,
__func__, "piotlb inv")) {
return false;
}
domain_id = VTD_INV_DESC_PIOTLB_DID(inv_desc->val[0]);
pasid = VTD_INV_DESC_PIOTLB_PASID(inv_desc->val[0]);
switch (inv_desc->val[0] & VTD_INV_DESC_PIOTLB_G) {
case VTD_INV_DESC_PIOTLB_ALL_IN_PASID:
vtd_piotlb_pasid_invalidate(s, domain_id, pasid);
break;
case VTD_INV_DESC_PIOTLB_PSI_IN_PASID:
break;
default:
error_report_once("%s: invalid piotlb inv desc: hi=0x%"PRIx64
", lo=0x%"PRIx64" (type mismatch: 0x%llx)",
__func__, inv_desc->val[1], inv_desc->val[0],
inv_desc->val[0] & VTD_INV_DESC_IOTLB_G);
return false;
}
return true;
}
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
@ -2810,6 +2887,13 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
case VTD_INV_DESC_PIOTLB:
trace_vtd_inv_desc("p-iotlb", inv_desc.val[1], inv_desc.val[0]);
if (!vtd_process_piotlb_desc(s, &inv_desc)) {
return false;
}
break;
case VTD_INV_DESC_WAIT:
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
if (!vtd_process_wait_desc(s, &inv_desc)) {
@ -2837,7 +2921,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
* iommu driver) work, just return true is enough so far.
*/
case VTD_INV_DESC_PC:
case VTD_INV_DESC_PIOTLB:
if (s->scalable_mode) {
break;
}

View file

@ -404,11 +404,6 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID(val) (((val) >> 32) & VTD_PASID_ID_MASK)
#define VTD_INV_DESC_IOTLB_PASID_RSVD_LO 0xfff00000000001c0ULL
#define VTD_INV_DESC_IOTLB_PASID_RSVD_HI 0xf80ULL
/* Mask for Device IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
@ -443,6 +438,15 @@ typedef union VTDInvDesc VTDInvDesc;
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
/* Masks for PIOTLB Invalidate Descriptor */
#define VTD_INV_DESC_PIOTLB_G (3ULL << 4)
#define VTD_INV_DESC_PIOTLB_ALL_IN_PASID (2ULL << 4)
#define VTD_INV_DESC_PIOTLB_PSI_IN_PASID (3ULL << 4)
#define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL)
#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000f1c0ULL
#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL
/* Information about page-selective IOTLB invalidate */
struct VTDIOTLBPageInvInfo {
uint16_t domain_id;