mirror of https://github.com/proxmox/mirror_qemu
spapr: make IOMMU translation go through IOMMUTLBEntry
The next step is to introduce the translation code that will be used for IOMMU MemoryRegions, but still do the actual translation in a DMAContext. Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>master
parent
2b7dc949e2
commit
a71bfbfe9d
|
@ -68,15 +68,8 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_tce_translate(DMAContext *dma,
|
static IOMMUTLBEntry spapr_tce_translate_iommu(sPAPRTCETable *tcet, hwaddr addr)
|
||||||
dma_addr_t addr,
|
|
||||||
hwaddr *paddr,
|
|
||||||
hwaddr *len,
|
|
||||||
DMADirection dir)
|
|
||||||
{
|
{
|
||||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
|
||||||
enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE)
|
|
||||||
? SPAPR_TCE_WO : SPAPR_TCE_RO;
|
|
||||||
uint64_t tce;
|
uint64_t tce;
|
||||||
|
|
||||||
#ifdef DEBUG_TCE
|
#ifdef DEBUG_TCE
|
||||||
|
@ -85,9 +78,13 @@ static int spapr_tce_translate(DMAContext *dma,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (tcet->bypass) {
|
if (tcet->bypass) {
|
||||||
*paddr = addr;
|
return (IOMMUTLBEntry) {
|
||||||
*len = (hwaddr)-1;
|
.target_as = &address_space_memory,
|
||||||
return 0;
|
.iova = 0,
|
||||||
|
.translated_addr = 0,
|
||||||
|
.addr_mask = ~(hwaddr)0,
|
||||||
|
.perm = IOMMU_RW,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we are in bound */
|
/* Check if we are in bound */
|
||||||
|
@ -95,28 +92,41 @@ static int spapr_tce_translate(DMAContext *dma,
|
||||||
#ifdef DEBUG_TCE
|
#ifdef DEBUG_TCE
|
||||||
fprintf(stderr, "spapr_tce_translate out of bounds\n");
|
fprintf(stderr, "spapr_tce_translate out of bounds\n");
|
||||||
#endif
|
#endif
|
||||||
return -EFAULT;
|
return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
|
||||||
}
|
}
|
||||||
|
|
||||||
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce;
|
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce;
|
||||||
|
|
||||||
/* Check TCE */
|
#ifdef DEBUG_TCE
|
||||||
if (!(tce & access)) {
|
fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
|
||||||
|
(tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (IOMMUTLBEntry) {
|
||||||
|
.target_as = &address_space_memory,
|
||||||
|
.iova = addr & ~SPAPR_TCE_PAGE_MASK,
|
||||||
|
.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
|
||||||
|
.addr_mask = SPAPR_TCE_PAGE_MASK,
|
||||||
|
.perm = tce,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spapr_tce_translate(DMAContext *dma,
|
||||||
|
dma_addr_t addr,
|
||||||
|
hwaddr *paddr,
|
||||||
|
hwaddr *len,
|
||||||
|
DMADirection dir)
|
||||||
|
{
|
||||||
|
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||||
|
bool is_write = (dir == DMA_DIRECTION_FROM_DEVICE);
|
||||||
|
IOMMUTLBEntry entry = spapr_tce_translate_iommu(tcet, addr);
|
||||||
|
if (!(entry.perm & (1 << is_write))) {
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* How much til end of page ? */
|
|
||||||
*len = ((~addr) & SPAPR_TCE_PAGE_MASK) + 1;
|
|
||||||
|
|
||||||
/* Translate */
|
/* Translate */
|
||||||
*paddr = (tce & ~SPAPR_TCE_PAGE_MASK) |
|
*paddr = entry.translated_addr | (addr & entry.addr_mask);
|
||||||
(addr & SPAPR_TCE_PAGE_MASK);
|
*len = (addr | entry.addr_mask) - addr + 1;
|
||||||
|
|
||||||
#ifdef DEBUG_TCE
|
|
||||||
fprintf(stderr, " -> *paddr=0x" TARGET_FMT_plx ", *len=0x"
|
|
||||||
TARGET_FMT_plx "\n", *paddr, *len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue