diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2015-06-05 02:35:10 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-06-11 01:16:47 -0400 |
commit | f87a88642e660edd8912ad39fe77848c6f9927a2 (patch) | |
tree | 728433c0ca8d3aa52fc4b75676131d2935e77bd6 /drivers/vfio | |
parent | 0eaf4defc7c44ed5dd33a03cab12a5f88c9b4b86 (diff) |
vfio: powerpc/spapr/iommu/powernv/ioda2: Rework IOMMU ownership control
This adds tce_iommu_take_ownership() and tce_iommu_release_ownership
which call in a loop iommu_take_ownership()/iommu_release_ownership()
for every table on the group. As there is just one now, no change in
behaviour is expected.
At the moment the iommu_table struct has a set_bypass() which enables/
disables DMA bypass on IODA2 PHB. This is exposed to POWERPC IOMMU code
which calls this callback when external IOMMU users such as VFIO are
about to get over a PHB.
The set_bypass() callback is not really an iommu_table function but
IOMMU/PE function. This introduces a iommu_table_group_ops struct and
adds take_ownership()/release_ownership() callbacks to it which are
called when an external user takes/releases control over the IOMMU.
This replaces set_bypass() with ownership callbacks as it is not
necessarily just bypass enabling, it can be something else/more
so let's give it more generic name.
The callbacks is implemented for IODA2 only. Other platforms (P5IOC2,
IODA1) will use the old iommu_take_ownership/iommu_release_ownership API.
The following patches will replace iommu_take_ownership/
iommu_release_ownership calls in IODA2 with full IOMMU table release/
create.
As we here and touching bypass control, this removes
pnv_pci_ioda2_setup_bypass_pe() as it does not do much
more compared to pnv_pci_ioda2_set_bypass. This moves tce_bypass_base
initialization to pnv_pci_ioda2_setup_dma_pe.
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
[aw: for the vfio related changes]
Acked-by: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/vfio')
-rw-r--r-- | drivers/vfio/vfio_iommu_spapr_tce.c | 70 |
1 files changed, 65 insertions, 5 deletions
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index ffc634a75dba..9c720de46c33 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c | |||
@@ -486,6 +486,61 @@ static long tce_iommu_ioctl(void *iommu_data, | |||
486 | return -ENOTTY; | 486 | return -ENOTTY; |
487 | } | 487 | } |
488 | 488 | ||
489 | static void tce_iommu_release_ownership(struct tce_container *container, | ||
490 | struct iommu_table_group *table_group) | ||
491 | { | ||
492 | int i; | ||
493 | |||
494 | for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { | ||
495 | struct iommu_table *tbl = table_group->tables[i]; | ||
496 | |||
497 | if (!tbl) | ||
498 | continue; | ||
499 | |||
500 | tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); | ||
501 | if (tbl->it_map) | ||
502 | iommu_release_ownership(tbl); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | static int tce_iommu_take_ownership(struct tce_container *container, | ||
507 | struct iommu_table_group *table_group) | ||
508 | { | ||
509 | int i, j, rc = 0; | ||
510 | |||
511 | for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { | ||
512 | struct iommu_table *tbl = table_group->tables[i]; | ||
513 | |||
514 | if (!tbl || !tbl->it_map) | ||
515 | continue; | ||
516 | |||
517 | rc = iommu_take_ownership(tbl); | ||
518 | if (rc) { | ||
519 | for (j = 0; j < i; ++j) | ||
520 | iommu_release_ownership( | ||
521 | table_group->tables[j]); | ||
522 | |||
523 | return rc; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static void tce_iommu_release_ownership_ddw(struct tce_container *container, | ||
531 | struct iommu_table_group *table_group) | ||
532 | { | ||
533 | table_group->ops->release_ownership(table_group); | ||
534 | } | ||
535 | |||
536 | static long tce_iommu_take_ownership_ddw(struct tce_container *container, | ||
537 | struct iommu_table_group *table_group) | ||
538 | { | ||
539 | table_group->ops->take_ownership(table_group); | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
489 | static int tce_iommu_attach_group(void *iommu_data, | 544 | static int tce_iommu_attach_group(void *iommu_data, |
490 | struct iommu_group *iommu_group) | 545 | struct iommu_group *iommu_group) |
491 | { | 546 | { |
@@ -518,7 +573,12 @@ static int tce_iommu_attach_group(void *iommu_data, | |||
518 | goto unlock_exit; | 573 | goto unlock_exit; |
519 | } | 574 | } |
520 | 575 | ||
521 | ret = iommu_take_ownership(table_group->tables[0]); | 576 | if (!table_group->ops || !table_group->ops->take_ownership || |
577 | !table_group->ops->release_ownership) | ||
578 | ret = tce_iommu_take_ownership(container, table_group); | ||
579 | else | ||
580 | ret = tce_iommu_take_ownership_ddw(container, table_group); | ||
581 | |||
522 | if (!ret) | 582 | if (!ret) |
523 | container->grp = iommu_group; | 583 | container->grp = iommu_group; |
524 | 584 | ||
@@ -533,7 +593,6 @@ static void tce_iommu_detach_group(void *iommu_data, | |||
533 | { | 593 | { |
534 | struct tce_container *container = iommu_data; | 594 | struct tce_container *container = iommu_data; |
535 | struct iommu_table_group *table_group; | 595 | struct iommu_table_group *table_group; |
536 | struct iommu_table *tbl; | ||
537 | 596 | ||
538 | mutex_lock(&container->lock); | 597 | mutex_lock(&container->lock); |
539 | if (iommu_group != container->grp) { | 598 | if (iommu_group != container->grp) { |
@@ -556,9 +615,10 @@ static void tce_iommu_detach_group(void *iommu_data, | |||
556 | table_group = iommu_group_get_iommudata(iommu_group); | 615 | table_group = iommu_group_get_iommudata(iommu_group); |
557 | BUG_ON(!table_group); | 616 | BUG_ON(!table_group); |
558 | 617 | ||
559 | tbl = table_group->tables[0]; | 618 | if (!table_group->ops || !table_group->ops->release_ownership) |
560 | tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); | 619 | tce_iommu_release_ownership(container, table_group); |
561 | iommu_release_ownership(tbl); | 620 | else |
621 | tce_iommu_release_ownership_ddw(container, table_group); | ||
562 | 622 | ||
563 | unlock_exit: | 623 | unlock_exit: |
564 | mutex_unlock(&container->lock); | 624 | mutex_unlock(&container->lock); |