Re: [PATCH v4 11/16] powerpc/powernv: Release replaced TCE
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: 2014-08-06 06:27:16
On Wed, 2014-07-30 at 19:31 +1000, Alexey Kardashevskiy wrote:
quoted hunk ↗ jump to hunk
static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction, + unsigned long uaddr, unsigned long *old_tces, + enum dma_data_direction direction, struct dma_attrs *attrs, bool rm) { u64 proto_tce; __be64 *tcep, *tces; u64 rpn; + long i; proto_tce = TCE_PCI_READ; // Read allowed@@ -587,9 +589,13 @@ static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, tces = tcep = ((__be64 *)tbl->it_base) + index - tbl->it_offset; rpn = __pa(uaddr) >> tbl->it_page_shift; - while (npages--) - *(tcep++) = cpu_to_be64(proto_tce | - (rpn++ << tbl->it_page_shift)); + for (i = 0; i < npages; i++) { + unsigned long oldtce = xchg(tcep, cpu_to_be64(proto_tce | + (rpn++ << tbl->it_page_shift))); + if (old_tces) + old_tces[i] = (unsigned long) __va(oldtce); + tcep++; + }
xchg() is slow, please keep separate implementation for build and set_and_get() to avoid the performance loss on normal TCE host operations. Cheers, Ben.
quoted hunk ↗ jump to hunk
pnv_tce_invalidate(tbl, tces, tcep - 1, rm);@@ -601,8 +607,18 @@ static int pnv_tce_build_vm(struct iommu_table *tbl, long index, long npages, enum dma_data_direction direction, struct dma_attrs *attrs) { - return pnv_tce_build(tbl, index, npages, uaddr, direction, attrs, - false); + return pnv_tce_build(tbl, index, npages, uaddr, NULL, direction, + attrs, false); +} + +static int pnv_tce_set_and_get_vm(struct iommu_table *tbl, long index, + long npages, + unsigned long uaddr, unsigned long *old_tces, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + return pnv_tce_build(tbl, index, npages, uaddr, old_tces, direction, + attrs, false); } static void pnv_tce_free(struct iommu_table *tbl, long index, long npages,@@ -630,6 +646,7 @@ static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) struct iommu_table_ops pnv_iommu_ops = { .set = pnv_tce_build_vm, + .set_and_get = pnv_tce_set_and_get_vm, .clear = pnv_tce_free_vm, .get = pnv_tce_get,