aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2013-04-16 15:05:06 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2013-06-20 16:32:47 +0200
commita71bfbfe9d0bb74912170435d687f3c5de86a9f6 (patch)
tree6688314dba9b5de2861cbf01b886a023361ade82 /hw/ppc
parent2b7dc949e241ac2b069d2d6183c1346cad792662 (diff)
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>
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/spapr_iommu.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 7a507e045e..cf5ccb17ed 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -68,15 +68,8 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
return NULL;
}
-static int spapr_tce_translate(DMAContext *dma,
- dma_addr_t addr,
- hwaddr *paddr,
- hwaddr *len,
- DMADirection dir)
+static IOMMUTLBEntry spapr_tce_translate_iommu(sPAPRTCETable *tcet, hwaddr addr)
{
- sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
- enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE)
- ? SPAPR_TCE_WO : SPAPR_TCE_RO;
uint64_t tce;
#ifdef DEBUG_TCE
@@ -85,9 +78,13 @@ static int spapr_tce_translate(DMAContext *dma,
#endif
if (tcet->bypass) {
- *paddr = addr;
- *len = (hwaddr)-1;
- return 0;
+ return (IOMMUTLBEntry) {
+ .target_as = &address_space_memory,
+ .iova = 0,
+ .translated_addr = 0,
+ .addr_mask = ~(hwaddr)0,
+ .perm = IOMMU_RW,
+ };
}
/* Check if we are in bound */
@@ -95,28 +92,41 @@ static int spapr_tce_translate(DMAContext *dma,
#ifdef DEBUG_TCE
fprintf(stderr, "spapr_tce_translate out of bounds\n");
#endif
- return -EFAULT;
+ return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
}
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce;
- /* Check TCE */
- if (!(tce & access)) {
+#ifdef DEBUG_TCE
+ 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;
}
- /* How much til end of page ? */
- *len = ((~addr) & SPAPR_TCE_PAGE_MASK) + 1;
-
/* Translate */
- *paddr = (tce & ~SPAPR_TCE_PAGE_MASK) |
- (addr & SPAPR_TCE_PAGE_MASK);
-
-#ifdef DEBUG_TCE
- fprintf(stderr, " -> *paddr=0x" TARGET_FMT_plx ", *len=0x"
- TARGET_FMT_plx "\n", *paddr, *len);
-#endif
-
+ *paddr = entry.translated_addr | (addr & entry.addr_mask);
+ *len = (addr | entry.addr_mask) - addr + 1;
return 0;
}