summaryrefslogtreecommitdiffstats
path: root/drivers/iommu/io-pgtable-arm-v7s.c
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2017-06-22 11:53:53 -0400
committerWill Deacon <will.deacon@arm.com>2017-06-23 12:58:00 -0400
commit81b3c25218447c65f93adf08b099a322b6803536 (patch)
tree6ba8f9f78dfc2604da3885a1e08060f9bb5cbf09 /drivers/iommu/io-pgtable-arm-v7s.c
parentb9f1ef30ac2e9942b8628d551f4a21e8cec1415c (diff)
iommu/io-pgtable: Introduce explicit coherency
Once we remove the serialising spinlock, a potential race opens up for non-coherent IOMMUs whereby a caller of .map() can be sure that cache maintenance has been performed on their new PTE, but will have no guarantee that such maintenance for table entries above it has actually completed (e.g. if another CPU took an interrupt immediately after writing the table entry, but before initiating the DMA sync). Handling this race safely will add some potentially non-trivial overhead to installing a table entry, which we would much rather avoid on coherent systems where it will be unnecessary, and where we are stirivng to minimise latency by removing the locking in the first place. To that end, let's introduce an explicit notion of cache-coherency to io-pgtable, such that we will be able to avoid penalising IOMMUs which know enough to know when they are coherent. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/io-pgtable-arm-v7s.c')
-rw-r--r--drivers/iommu/io-pgtable-arm-v7s.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c
index dc74631322e4..ec024c75a09e 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -187,7 +187,8 @@ static arm_v7s_iopte *iopte_deref(arm_v7s_iopte pte, int lvl)
187static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, 187static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
188 struct arm_v7s_io_pgtable *data) 188 struct arm_v7s_io_pgtable *data)
189{ 189{
190 struct device *dev = data->iop.cfg.iommu_dev; 190 struct io_pgtable_cfg *cfg = &data->iop.cfg;
191 struct device *dev = cfg->iommu_dev;
191 dma_addr_t dma; 192 dma_addr_t dma;
192 size_t size = ARM_V7S_TABLE_SIZE(lvl); 193 size_t size = ARM_V7S_TABLE_SIZE(lvl);
193 void *table = NULL; 194 void *table = NULL;
@@ -196,7 +197,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
196 table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size)); 197 table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size));
197 else if (lvl == 2) 198 else if (lvl == 2)
198 table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA); 199 table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA);
199 if (table && !selftest_running) { 200 if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) {
200 dma = dma_map_single(dev, table, size, DMA_TO_DEVICE); 201 dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
201 if (dma_mapping_error(dev, dma)) 202 if (dma_mapping_error(dev, dma))
202 goto out_free; 203 goto out_free;
@@ -225,10 +226,11 @@ out_free:
225static void __arm_v7s_free_table(void *table, int lvl, 226static void __arm_v7s_free_table(void *table, int lvl,
226 struct arm_v7s_io_pgtable *data) 227 struct arm_v7s_io_pgtable *data)
227{ 228{
228 struct device *dev = data->iop.cfg.iommu_dev; 229 struct io_pgtable_cfg *cfg = &data->iop.cfg;
230 struct device *dev = cfg->iommu_dev;
229 size_t size = ARM_V7S_TABLE_SIZE(lvl); 231 size_t size = ARM_V7S_TABLE_SIZE(lvl);
230 232
231 if (!selftest_running) 233 if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
232 dma_unmap_single(dev, __arm_v7s_dma_addr(table), size, 234 dma_unmap_single(dev, __arm_v7s_dma_addr(table), size,
233 DMA_TO_DEVICE); 235 DMA_TO_DEVICE);
234 if (lvl == 1) 236 if (lvl == 1)
@@ -240,7 +242,7 @@ static void __arm_v7s_free_table(void *table, int lvl,
240static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries, 242static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries,
241 struct io_pgtable_cfg *cfg) 243 struct io_pgtable_cfg *cfg)
242{ 244{
243 if (selftest_running) 245 if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
244 return; 246 return;
245 247
246 dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep), 248 dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep),
@@ -657,7 +659,8 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
657 if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | 659 if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
658 IO_PGTABLE_QUIRK_NO_PERMS | 660 IO_PGTABLE_QUIRK_NO_PERMS |
659 IO_PGTABLE_QUIRK_TLBI_ON_MAP | 661 IO_PGTABLE_QUIRK_TLBI_ON_MAP |
660 IO_PGTABLE_QUIRK_ARM_MTK_4GB)) 662 IO_PGTABLE_QUIRK_ARM_MTK_4GB |
663 IO_PGTABLE_QUIRK_NO_DMA))
661 return NULL; 664 return NULL;
662 665
663 /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */ 666 /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */
@@ -774,7 +777,7 @@ static int __init arm_v7s_do_selftests(void)
774 .tlb = &dummy_tlb_ops, 777 .tlb = &dummy_tlb_ops,
775 .oas = 32, 778 .oas = 32,
776 .ias = 32, 779 .ias = 32,
777 .quirks = IO_PGTABLE_QUIRK_ARM_NS, 780 .quirks = IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA,
778 .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M, 781 .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
779 }; 782 };
780 unsigned int iova, size, iova_start; 783 unsigned int iova, size, iova_start;