summaryrefslogtreecommitdiffstats
path: root/drivers/vfio
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2015-06-05 02:35:23 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2015-06-11 01:16:54 -0400
commit46d3e1e16294c587a74093b1f5474c1b33b72381 (patch)
tree6d10c41510f2d4f5c809d0838860f9b9d6a881c2 /drivers/vfio
parent0054719386d96984153ad31d714a8be4ec7eba80 (diff)
vfio: powerpc/spapr: powerpc/powernv/ioda2: Use DMA windows API in ownership control
Before the IOMMU user (VFIO) would take control over the IOMMU table belonging to a specific IOMMU group. This approach did not allow sharing tables between IOMMU groups attached to the same container. This introduces a new IOMMU ownership flavour when the user can not just control the existing IOMMU table but remove/create tables on demand. If an IOMMU implements take/release_ownership() callbacks, this lets the user have full control over the IOMMU group. When the ownership is taken, the platform code removes all the windows so the caller must create them. Before returning the ownership back to the platform code, VFIO unprograms and removes all the tables it created. This changes IODA2's onwership handler to remove the existing table rather than manipulating with the existing one. From now on, iommu_take_ownership() and iommu_release_ownership() are only called from the vfio_iommu_spapr_tce driver. Old-style ownership is still supported allowing VFIO to run on older P5IOC2 and IODA IO controllers. No change in userspace-visible behaviour is expected. Since it recreates TCE tables on each ownership change, related kernel traces will appear more often. This adds a pnv_pci_ioda2_setup_default_config() which is called when PE is being configured at boot time and when the ownership is passed from VFIO to the platform code. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> [aw: for the vfio related changes] Acked-by: Alex Williamson <alex.williamson@redhat.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.c88
1 files changed, 87 insertions, 1 deletions
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 6d919eb4251f..203caacf2242 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -333,6 +333,45 @@ static long tce_iommu_build(struct tce_container *container,
333 return ret; 333 return ret;
334} 334}
335 335
336static long tce_iommu_create_table(struct tce_container *container,
337 struct iommu_table_group *table_group,
338 int num,
339 __u32 page_shift,
340 __u64 window_size,
341 __u32 levels,
342 struct iommu_table **ptbl)
343{
344 long ret, table_size;
345
346 table_size = table_group->ops->get_table_size(page_shift, window_size,
347 levels);
348 if (!table_size)
349 return -EINVAL;
350
351 ret = try_increment_locked_vm(table_size >> PAGE_SHIFT);
352 if (ret)
353 return ret;
354
355 ret = table_group->ops->create_table(table_group, num,
356 page_shift, window_size, levels, ptbl);
357
358 WARN_ON(!ret && !(*ptbl)->it_ops->free);
359 WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size));
360
361 if (ret)
362 decrement_locked_vm(table_size >> PAGE_SHIFT);
363
364 return ret;
365}
366
367static void tce_iommu_free_table(struct iommu_table *tbl)
368{
369 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
370
371 tbl->it_ops->free(tbl);
372 decrement_locked_vm(pages);
373}
374
336static long tce_iommu_ioctl(void *iommu_data, 375static long tce_iommu_ioctl(void *iommu_data,
337 unsigned int cmd, unsigned long arg) 376 unsigned int cmd, unsigned long arg)
338{ 377{
@@ -546,15 +585,62 @@ static int tce_iommu_take_ownership(struct tce_container *container,
546static void tce_iommu_release_ownership_ddw(struct tce_container *container, 585static void tce_iommu_release_ownership_ddw(struct tce_container *container,
547 struct iommu_table_group *table_group) 586 struct iommu_table_group *table_group)
548{ 587{
588 long i;
589
590 if (!table_group->ops->unset_window) {
591 WARN_ON_ONCE(1);
592 return;
593 }
594
595 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
596 /* Store table pointer as unset_window resets it */
597 struct iommu_table *tbl = table_group->tables[i];
598
599 if (!tbl)
600 continue;
601
602 table_group->ops->unset_window(table_group, i);
603 tce_iommu_clear(container, tbl,
604 tbl->it_offset, tbl->it_size);
605 tce_iommu_free_table(tbl);
606 }
607
549 table_group->ops->release_ownership(table_group); 608 table_group->ops->release_ownership(table_group);
550} 609}
551 610
552static long tce_iommu_take_ownership_ddw(struct tce_container *container, 611static long tce_iommu_take_ownership_ddw(struct tce_container *container,
553 struct iommu_table_group *table_group) 612 struct iommu_table_group *table_group)
554{ 613{
614 long ret;
615 struct iommu_table *tbl = NULL;
616
617 if (!table_group->ops->create_table || !table_group->ops->set_window ||
618 !table_group->ops->release_ownership) {
619 WARN_ON_ONCE(1);
620 return -EFAULT;
621 }
622
555 table_group->ops->take_ownership(table_group); 623 table_group->ops->take_ownership(table_group);
556 624
557 return 0; 625 ret = tce_iommu_create_table(container,
626 table_group,
627 0, /* window number */
628 IOMMU_PAGE_SHIFT_4K,
629 table_group->tce32_size,
630 1, /* default levels */
631 &tbl);
632 if (!ret) {
633 ret = table_group->ops->set_window(table_group, 0, tbl);
634 if (ret)
635 tce_iommu_free_table(tbl);
636 else
637 table_group->tables[0] = tbl;
638 }
639
640 if (ret)
641 table_group->ops->release_ownership(table_group);
642
643 return ret;
558} 644}
559 645
560static int tce_iommu_attach_group(void *iommu_data, 646static int tce_iommu_attach_group(void *iommu_data,