|
@@ -2692,6 +2692,83 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
|
return true;
|
|
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,
|
|
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
|
|
VTDInvDesc *inv_desc)
|
|
VTDInvDesc *inv_desc)
|
|
{
|
|
{
|
|
@@ -2810,6 +2887,13 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
|
|
}
|
|
}
|
|
break;
|
|
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:
|
|
case VTD_INV_DESC_WAIT:
|
|
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
|
|
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
|
|
if (!vtd_process_wait_desc(s, &inv_desc)) {
|
|
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.
|
|
* iommu driver) work, just return true is enough so far.
|
|
*/
|
|
*/
|
|
case VTD_INV_DESC_PC:
|
|
case VTD_INV_DESC_PC:
|
|
- case VTD_INV_DESC_PIOTLB:
|
|
|
|
if (s->scalable_mode) {
|
|
if (s->scalable_mode) {
|
|
break;
|
|
break;
|
|
}
|
|
}
|