intel_iommu: Add support for ATS

Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@eviden.com>
Message-Id: <20250628180226.133285-11-clement.mathieu--drif@eviden.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
CLEMENT MATHIEU--DRIF 2025-06-28 18:04:10 +00:00 committed by Michael S. Tsirkin
parent 580b926344
commit c049bf5bb9

View file

@ -4738,6 +4738,68 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &vtd_as->as;
}
static IOMMUTLBEntry vtd_iommu_ats_do_translate(IOMMUMemoryRegion *iommu,
hwaddr addr,
IOMMUAccessFlags flags)
{
IOMMUTLBEntry entry;
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
if (vtd_is_interrupt_addr(addr)) {
vtd_report_ir_illegal_access(vtd_as, addr, flags & IOMMU_WO);
entry.target_as = &address_space_memory;
entry.iova = 0;
entry.translated_addr = 0;
entry.addr_mask = ~VTD_PAGE_MASK_4K;
entry.perm = IOMMU_NONE;
entry.pasid = PCI_NO_PASID;
} else {
entry = vtd_iommu_translate(iommu, addr, flags, 0);
}
return entry;
}
static ssize_t vtd_ats_request_translation(PCIBus *bus, void *opaque,
int devfn, uint32_t pasid,
bool priv_req, bool exec_req,
hwaddr addr, size_t length,
bool no_write, IOMMUTLBEntry *result,
size_t result_length,
uint32_t *err_count)
{
IntelIOMMUState *s = opaque;
VTDAddressSpace *vtd_as;
IOMMUAccessFlags flags = IOMMU_ACCESS_FLAG_FULL(true, !no_write, exec_req,
priv_req, false, false);
ssize_t res_index = 0;
hwaddr target_address = addr + length;
IOMMUTLBEntry entry;
vtd_as = vtd_find_add_as(s, bus, devfn, pasid);
*err_count = 0;
while ((addr < target_address) && (res_index < result_length)) {
entry = vtd_iommu_ats_do_translate(&vtd_as->iommu, addr, flags);
entry.perm &= ~IOMMU_GLOBAL; /* Spec 4.1.2: Global Mapping never set */
if ((entry.perm & flags) != flags) {
*err_count += 1; /* Less than expected */
}
result[res_index] = entry;
res_index += 1;
addr = (addr & (~entry.addr_mask)) + (entry.addr_mask + 1);
}
/* Buffer too small */
if (addr < target_address) {
return -ENOMEM;
}
return res_index;
}
static void vtd_init_iotlb_notifier(PCIBus *bus, void *opaque, int devfn,
IOMMUNotifier *n, IOMMUNotify fn,
void *user_opaque)
@ -4787,6 +4849,7 @@ static PCIIOMMUOps vtd_iommu_ops = {
.init_iotlb_notifier = vtd_init_iotlb_notifier,
.register_iotlb_notifier = vtd_register_iotlb_notifier,
.unregister_iotlb_notifier = vtd_unregister_iotlb_notifier,
.ats_request_translation = vtd_ats_request_translation,
};
static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)