Skip to content

Commit 08955af

Browse files
niklas88joergroedel
authored andcommitted
iommu/s390: Optimize IOMMU table walking
When invalidating existing table entries for unmap there is no need to know the physical address beforehand so don't do an extra walk of the IOMMU table to get it. Also when invalidating entries not finding an entry indicates an invalid unmap and not a lack of memory we also don't need to undo updates in this case. Implement this by splitting s390_iommu_update_trans() in a variant for validating and one for invalidating translations. Signed-off-by: Niklas Schnelle <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 2ba8336 commit 08955af

File tree

1 file changed

+43
-26
lines changed

1 file changed

+43
-26
lines changed

drivers/iommu/s390-iommu.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -260,42 +260,66 @@ static void s390_iommu_iotlb_sync_map(struct iommu_domain *domain,
260260
rcu_read_unlock();
261261
}
262262

263-
static int s390_iommu_update_trans(struct s390_domain *s390_domain,
264-
phys_addr_t pa, dma_addr_t dma_addr,
265-
unsigned long nr_pages, int flags)
263+
static int s390_iommu_validate_trans(struct s390_domain *s390_domain,
264+
phys_addr_t pa, dma_addr_t dma_addr,
265+
unsigned long nr_pages, int flags)
266266
{
267267
phys_addr_t page_addr = pa & PAGE_MASK;
268268
unsigned long irq_flags, i;
269269
unsigned long *entry;
270-
int rc = 0;
270+
int rc;
271271

272272
if (!nr_pages)
273273
return 0;
274274

275275
spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags);
276276
for (i = 0; i < nr_pages; i++) {
277277
entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
278-
if (!entry) {
278+
if (unlikely(!entry)) {
279279
rc = -ENOMEM;
280280
goto undo_cpu_trans;
281281
}
282282
dma_update_cpu_trans(entry, page_addr, flags);
283283
page_addr += PAGE_SIZE;
284284
dma_addr += PAGE_SIZE;
285285
}
286+
spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
287+
288+
return 0;
286289

287290
undo_cpu_trans:
288-
if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
289-
flags = ZPCI_PTE_INVALID;
290-
while (i-- > 0) {
291-
page_addr -= PAGE_SIZE;
292-
dma_addr -= PAGE_SIZE;
293-
entry = dma_walk_cpu_trans(s390_domain->dma_table,
294-
dma_addr);
295-
if (!entry)
296-
break;
297-
dma_update_cpu_trans(entry, page_addr, flags);
291+
while (i-- > 0) {
292+
dma_addr -= PAGE_SIZE;
293+
entry = dma_walk_cpu_trans(s390_domain->dma_table,
294+
dma_addr);
295+
if (!entry)
296+
break;
297+
dma_update_cpu_trans(entry, 0, ZPCI_PTE_INVALID);
298+
}
299+
spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
300+
301+
return rc;
302+
}
303+
304+
static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain,
305+
dma_addr_t dma_addr, unsigned long nr_pages)
306+
{
307+
unsigned long irq_flags, i;
308+
unsigned long *entry;
309+
int rc = 0;
310+
311+
if (!nr_pages)
312+
return 0;
313+
314+
spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags);
315+
for (i = 0; i < nr_pages; i++) {
316+
entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
317+
if (unlikely(!entry)) {
318+
rc = -EINVAL;
319+
break;
298320
}
321+
dma_update_cpu_trans(entry, 0, ZPCI_PTE_INVALID);
322+
dma_addr += PAGE_SIZE;
299323
}
300324
spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
301325

@@ -308,8 +332,8 @@ static int s390_iommu_map_pages(struct iommu_domain *domain,
308332
int prot, gfp_t gfp, size_t *mapped)
309333
{
310334
struct s390_domain *s390_domain = to_s390_domain(domain);
311-
int flags = ZPCI_PTE_VALID, rc = 0;
312335
size_t size = pgcount << __ffs(pgsize);
336+
int flags = ZPCI_PTE_VALID, rc = 0;
313337

314338
if (pgsize != SZ_4K)
315339
return -EINVAL;
@@ -327,8 +351,8 @@ static int s390_iommu_map_pages(struct iommu_domain *domain,
327351
if (!(prot & IOMMU_WRITE))
328352
flags |= ZPCI_TABLE_PROTECTED;
329353

330-
rc = s390_iommu_update_trans(s390_domain, paddr, iova,
331-
pgcount, flags);
354+
rc = s390_iommu_validate_trans(s390_domain, paddr, iova,
355+
pgcount, flags);
332356
if (!rc)
333357
*mapped = size;
334358

@@ -373,20 +397,13 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain,
373397
{
374398
struct s390_domain *s390_domain = to_s390_domain(domain);
375399
size_t size = pgcount << __ffs(pgsize);
376-
int flags = ZPCI_PTE_INVALID;
377-
phys_addr_t paddr;
378400
int rc;
379401

380402
if (WARN_ON(iova < s390_domain->domain.geometry.aperture_start ||
381403
(iova + size - 1) > s390_domain->domain.geometry.aperture_end))
382404
return 0;
383405

384-
paddr = s390_iommu_iova_to_phys(domain, iova);
385-
if (!paddr)
386-
return 0;
387-
388-
rc = s390_iommu_update_trans(s390_domain, paddr, iova,
389-
pgcount, flags);
406+
rc = s390_iommu_invalidate_trans(s390_domain, iova, pgcount);
390407
if (rc)
391408
return 0;
392409

0 commit comments

Comments
 (0)