aboutsummaryrefslogtreecommitdiff
path: root/hw/spapr_iommu.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2012-09-12 16:57:20 +0000
committerAlexander Graf <agraf@suse.de>2012-10-04 15:54:18 +0200
commit53724ee565565f69560dbe17553bede8c0169379 (patch)
treeef73b2b50f6b30ee1c55c24da8ff858632ca9e3f /hw/spapr_iommu.c
parent490d4a2b6edafb27cd688ded7fdb1290453d71b0 (diff)
pseries: Rework implementation of TCE bypass
On the pseries machine the IOMMU (aka TCE tables) is always active for all PCI and VIO devices. Mostly to simplify the SLOF firmware, we implement an extension which allows the IOMMU to be temporarily disabled for certain devices. Currently this is implemented by setting the device's DMAContext pointer to NULL (thus reverting to qemu's default no-IOMMU DMA behaviour), then replacing it when bypass mode is disabled. This approach causes a bunch of complications though. It complexifies the management of the DMAContext lifetimes, it's problematic for savevm/loadvm, and it means that while bypass is active we have nowhere to store the device's LIOBN (Logical IO Bus Number, used to identify DMA address spaces). At present we regenerate the LIOBN from other address information but this restricts how we can allocate LIOBNs. This patch gives up on this approach, replacing it with the much simpler one of having a 'bypass' boolean flag in the TCE state structure. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr_iommu.c')
-rw-r--r--hw/spapr_iommu.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c
index 216aa06809..38034c07bd 100644
--- a/hw/spapr_iommu.c
+++ b/hw/spapr_iommu.c
@@ -42,6 +42,7 @@ struct sPAPRTCETable {
uint32_t liobn;
uint32_t window_size;
sPAPRTCE *table;
+ bool bypass;
int fd;
QLIST_ENTRY(sPAPRTCETable) list;
};
@@ -78,6 +79,12 @@ static int spapr_tce_translate(DMAContext *dma,
DMA_ADDR_FMT "\n", tcet->liobn, addr);
#endif
+ if (tcet->bypass) {
+ *paddr = addr;
+ *len = (target_phys_addr_t)-1;
+ return 0;
+ }
+
/* Check if we are in bound */
if (addr >= tcet->window_size) {
#ifdef DEBUG_TCE
@@ -162,15 +169,21 @@ void spapr_tce_free(DMAContext *dma)
}
}
+void spapr_tce_set_bypass(DMAContext *dma, bool bypass)
+{
+ sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
+
+ tcet->bypass = bypass;
+}
+
void spapr_tce_reset(DMAContext *dma)
{
- if (dma) {
- sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
- size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
- * sizeof(sPAPRTCE);
+ sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
+ size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
+ * sizeof(sPAPRTCE);
- memset(tcet->table, 0, table_size);
- }
+ tcet->bypass = false;
+ memset(tcet->table, 0, table_size);
}
static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,