Skip to content

Commit 13954fd

Browse files
Sebastian OttMartin Schwidefsky
authored andcommitted
s390/pci_dma: improve lazy flush for unmap
Lazy unmap (defer tlb flush after unmap until dma address reuse) can greatly reduce the number of RPCIT instructions in the best case. In reality we are often far away from the best case scenario because our implementation suffers from the following problem: To create dma addresses we maintain an iommu bitmap and a pointer into that bitmap to mark the start of the next search. That pointer moves from the start to the end of that bitmap and we issue a global tlb flush once that pointer wraps around. To prevent address reuse before we issue the tlb flush we even have to move the next pointer during unmaps - when clearing a bit > next. This could lead to a situation where we only use the rear part of that bitmap and issue more tlb flushes than expected. To fix this we no longer clear bits during unmap but maintain a 2nd bitmap which we use to mark addresses that can't be reused until we issue the global tlb flush after wrap around. Signed-off-by: Sebastian Ott <[email protected]> Reviewed-by: Gerald Schaefer <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 1f166e9 commit 13954fd

File tree

2 files changed

+34
-14
lines changed

2 files changed

+34
-14
lines changed

arch/s390/include/asm/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct zpci_dev {
118118

119119
spinlock_t iommu_bitmap_lock;
120120
unsigned long *iommu_bitmap;
121+
unsigned long *lazy_bitmap;
121122
unsigned long iommu_size;
122123
unsigned long iommu_pages;
123124
unsigned int next_bit;

arch/s390/pci/pci_dma.c

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -257,20 +257,28 @@ static dma_addr_t dma_alloc_address(struct device *dev, int size)
257257
spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
258258
offset = __dma_alloc_iommu(dev, zdev->next_bit, size);
259259
if (offset == -1) {
260+
if (!zdev->tlb_refresh && !s390_iommu_strict) {
261+
/* global flush before DMA addresses are reused */
262+
if (zpci_refresh_global(zdev))
263+
goto out_error;
264+
265+
bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap,
266+
zdev->lazy_bitmap, zdev->iommu_pages);
267+
bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages);
268+
}
260269
/* wrap-around */
261270
offset = __dma_alloc_iommu(dev, 0, size);
262-
if (offset == -1) {
263-
spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
264-
return DMA_ERROR_CODE;
265-
}
266-
if (!zdev->tlb_refresh && !s390_iommu_strict)
267-
/* global flush after wrap-around with lazy unmap */
268-
zpci_refresh_global(zdev);
271+
if (offset == -1)
272+
goto out_error;
269273
}
270274
zdev->next_bit = offset + size;
271275
spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
272276

273277
return zdev->start_dma + offset * PAGE_SIZE;
278+
279+
out_error:
280+
spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
281+
return DMA_ERROR_CODE;
274282
}
275283

276284
static void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size)
@@ -283,13 +291,12 @@ static void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size)
283291
spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
284292
if (!zdev->iommu_bitmap)
285293
goto out;
286-
bitmap_clear(zdev->iommu_bitmap, offset, size);
287-
/*
288-
* Lazy flush for unmap: need to move next_bit to avoid address re-use
289-
* until wrap-around.
290-
*/
291-
if (!s390_iommu_strict && offset >= zdev->next_bit)
292-
zdev->next_bit = offset + size;
294+
295+
if (zdev->tlb_refresh || s390_iommu_strict)
296+
bitmap_clear(zdev->iommu_bitmap, offset, size);
297+
else
298+
bitmap_set(zdev->lazy_bitmap, offset, size);
299+
293300
out:
294301
spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
295302
}
@@ -557,7 +564,14 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
557564
rc = -ENOMEM;
558565
goto free_dma_table;
559566
}
567+
if (!zdev->tlb_refresh && !s390_iommu_strict) {
568+
zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8);
569+
if (!zdev->lazy_bitmap) {
570+
rc = -ENOMEM;
571+
goto free_bitmap;
572+
}
560573

574+
}
561575
rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
562576
(u64) zdev->dma_table);
563577
if (rc)
@@ -567,6 +581,8 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
567581
free_bitmap:
568582
vfree(zdev->iommu_bitmap);
569583
zdev->iommu_bitmap = NULL;
584+
vfree(zdev->lazy_bitmap);
585+
zdev->lazy_bitmap = NULL;
570586
free_dma_table:
571587
dma_free_cpu_table(zdev->dma_table);
572588
zdev->dma_table = NULL;
@@ -588,6 +604,9 @@ void zpci_dma_exit_device(struct zpci_dev *zdev)
588604
zdev->dma_table = NULL;
589605
vfree(zdev->iommu_bitmap);
590606
zdev->iommu_bitmap = NULL;
607+
vfree(zdev->lazy_bitmap);
608+
zdev->lazy_bitmap = NULL;
609+
591610
zdev->next_bit = 0;
592611
}
593612

0 commit comments

Comments
 (0)