memory: Fix IOMMU replay base address
Since a788f227 "memory: Allow replay of IOMMU mapping notifications" when new VFIO listener is added, all existing IOMMU mappings are replayed. However there is a problem that the base address of an IOMMU memory region (IOMMU MR) is ignored which is not a problem for the existing user (which is pseries) with its default 32bit DMA window starting at 0 but it is if there is another DMA window. This stores the IOMMU's offset_within_address_space and adjusts the IOVA before calling vfio_dma_map/vfio_dma_unmap. As the IOMMU notifier expects IOVA offset rather than the absolute address, this also adjusts IOVA in sPAPR H_PUT_TCE handler before calling notifier(s). Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
		
							parent
							
								
									7a057b4fb9
								
							
						
					
					
						commit
						d78c19b5cf
					
				@ -278,7 +278,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
 | 
				
			|||||||
    tcet->table[index] = tce;
 | 
					    tcet->table[index] = tce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    entry.target_as = &address_space_memory,
 | 
					    entry.target_as = &address_space_memory,
 | 
				
			||||||
    entry.iova = ioba & page_mask;
 | 
					    entry.iova = (ioba - tcet->bus_offset) & page_mask;
 | 
				
			||||||
    entry.translated_addr = tce & page_mask;
 | 
					    entry.translated_addr = tce & page_mask;
 | 
				
			||||||
    entry.addr_mask = ~page_mask;
 | 
					    entry.addr_mask = ~page_mask;
 | 
				
			||||||
    entry.perm = spapr_tce_iommu_access_flags(tce);
 | 
					    entry.perm = spapr_tce_iommu_access_flags(tce);
 | 
				
			||||||
 | 
				
			|||||||
@ -260,14 +260,14 @@ static void vfio_iommu_map_notify(Notifier *n, void *data)
 | 
				
			|||||||
    VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
 | 
					    VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
 | 
				
			||||||
    VFIOContainer *container = giommu->container;
 | 
					    VFIOContainer *container = giommu->container;
 | 
				
			||||||
    IOMMUTLBEntry *iotlb = data;
 | 
					    IOMMUTLBEntry *iotlb = data;
 | 
				
			||||||
 | 
					    hwaddr iova = iotlb->iova + giommu->iommu_offset;
 | 
				
			||||||
    MemoryRegion *mr;
 | 
					    MemoryRegion *mr;
 | 
				
			||||||
    hwaddr xlat;
 | 
					    hwaddr xlat;
 | 
				
			||||||
    hwaddr len = iotlb->addr_mask + 1;
 | 
					    hwaddr len = iotlb->addr_mask + 1;
 | 
				
			||||||
    void *vaddr;
 | 
					    void *vaddr;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    trace_vfio_iommu_map_notify(iotlb->iova,
 | 
					    trace_vfio_iommu_map_notify(iova, iova + iotlb->addr_mask);
 | 
				
			||||||
                                iotlb->iova + iotlb->addr_mask);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * The IOMMU TLB entry we have just covers translation through
 | 
					     * The IOMMU TLB entry we have just covers translation through
 | 
				
			||||||
@ -294,21 +294,21 @@ static void vfio_iommu_map_notify(Notifier *n, void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
 | 
					    if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
 | 
				
			||||||
        vaddr = memory_region_get_ram_ptr(mr) + xlat;
 | 
					        vaddr = memory_region_get_ram_ptr(mr) + xlat;
 | 
				
			||||||
        ret = vfio_dma_map(container, iotlb->iova,
 | 
					        ret = vfio_dma_map(container, iova,
 | 
				
			||||||
                           iotlb->addr_mask + 1, vaddr,
 | 
					                           iotlb->addr_mask + 1, vaddr,
 | 
				
			||||||
                           !(iotlb->perm & IOMMU_WO) || mr->readonly);
 | 
					                           !(iotlb->perm & IOMMU_WO) || mr->readonly);
 | 
				
			||||||
        if (ret) {
 | 
					        if (ret) {
 | 
				
			||||||
            error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
 | 
					            error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
 | 
				
			||||||
                         "0x%"HWADDR_PRIx", %p) = %d (%m)",
 | 
					                         "0x%"HWADDR_PRIx", %p) = %d (%m)",
 | 
				
			||||||
                         container, iotlb->iova,
 | 
					                         container, iova,
 | 
				
			||||||
                         iotlb->addr_mask + 1, vaddr, ret);
 | 
					                         iotlb->addr_mask + 1, vaddr, ret);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1);
 | 
					        ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1);
 | 
				
			||||||
        if (ret) {
 | 
					        if (ret) {
 | 
				
			||||||
            error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
 | 
					            error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
 | 
				
			||||||
                         "0x%"HWADDR_PRIx") = %d (%m)",
 | 
					                         "0x%"HWADDR_PRIx") = %d (%m)",
 | 
				
			||||||
                         container, iotlb->iova,
 | 
					                         container, iova,
 | 
				
			||||||
                         iotlb->addr_mask + 1, ret);
 | 
					                         iotlb->addr_mask + 1, ret);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -380,6 +380,8 @@ static void vfio_listener_region_add(MemoryListener *listener,
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        giommu = g_malloc0(sizeof(*giommu));
 | 
					        giommu = g_malloc0(sizeof(*giommu));
 | 
				
			||||||
        giommu->iommu = section->mr;
 | 
					        giommu->iommu = section->mr;
 | 
				
			||||||
 | 
					        giommu->iommu_offset = section->offset_within_address_space -
 | 
				
			||||||
 | 
					                               section->offset_within_region;
 | 
				
			||||||
        giommu->container = container;
 | 
					        giommu->container = container;
 | 
				
			||||||
        giommu->n.notify = vfio_iommu_map_notify;
 | 
					        giommu->n.notify = vfio_iommu_map_notify;
 | 
				
			||||||
        QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
 | 
					        QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
 | 
				
			||||||
 | 
				
			|||||||
@ -90,6 +90,7 @@ typedef struct VFIOContainer {
 | 
				
			|||||||
typedef struct VFIOGuestIOMMU {
 | 
					typedef struct VFIOGuestIOMMU {
 | 
				
			||||||
    VFIOContainer *container;
 | 
					    VFIOContainer *container;
 | 
				
			||||||
    MemoryRegion *iommu;
 | 
					    MemoryRegion *iommu;
 | 
				
			||||||
 | 
					    hwaddr iommu_offset;
 | 
				
			||||||
    Notifier n;
 | 
					    Notifier n;
 | 
				
			||||||
    QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
 | 
					    QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
 | 
				
			||||||
} VFIOGuestIOMMU;
 | 
					} VFIOGuestIOMMU;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user