powerpc/powernv: Add iommu DMA bypass support for IODA2
This patch adds the support for to create a direct iommu "bypass" window on IODA2 bridges (such as Power8) allowing to bypass iommu page translation completely for 64-bit DMA capable devices, thus significantly improving DMA performances. Additionally, this adds a hook to the struct iommu_table so that the IOMMU API / VFIO can disable the bypass when external ownership is requested, since in that case, the device will be used by an environment such as userspace or a KVM guest which must not be allowed to bypass translations. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
@@ -191,12 +191,10 @@ EXPORT_SYMBOL(dma_direct_ops);
|
||||
|
||||
#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
|
||||
|
||||
int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
int __dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
if (ppc_md.dma_set_mask)
|
||||
return ppc_md.dma_set_mask(dev, dma_mask);
|
||||
if ((dma_ops != NULL) && (dma_ops->set_dma_mask != NULL))
|
||||
return dma_ops->set_dma_mask(dev, dma_mask);
|
||||
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
||||
@@ -204,6 +202,12 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
*dev->dma_mask = dma_mask;
|
||||
return 0;
|
||||
}
|
||||
int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
{
|
||||
if (ppc_md.dma_set_mask)
|
||||
return ppc_md.dma_set_mask(dev, dma_mask);
|
||||
return __dma_set_mask(dev, dma_mask);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_set_mask);
|
||||
|
||||
u64 dma_get_required_mask(struct device *dev)
|
||||
|
@@ -1088,6 +1088,14 @@ int iommu_take_ownership(struct iommu_table *tbl)
|
||||
memset(tbl->it_map, 0xff, sz);
|
||||
iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
|
||||
|
||||
/*
|
||||
* Disable iommu bypass, otherwise the user can DMA to all of
|
||||
* our physical memory via the bypass window instead of just
|
||||
* the pages that has been explicitly mapped into the iommu
|
||||
*/
|
||||
if (tbl->set_bypass)
|
||||
tbl->set_bypass(tbl, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iommu_take_ownership);
|
||||
@@ -1102,6 +1110,10 @@ void iommu_release_ownership(struct iommu_table *tbl)
|
||||
/* Restore bit#0 set by iommu_init_table() */
|
||||
if (tbl->it_offset == 0)
|
||||
set_bit(0, tbl->it_map);
|
||||
|
||||
/* The kernel owns the device now, we can restore the iommu bypass */
|
||||
if (tbl->set_bypass)
|
||||
tbl->set_bypass(tbl, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iommu_release_ownership);
|
||||
|
||||
|
Verwijs in nieuw issue
Block a user