aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2017-03-22 00:21:50 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2017-03-30 06:42:11 -0400
commite5afdf9dd515a9446c009f44f99f9bc2f91b89a7 (patch)
tree21683e5afe296b2a6cf32e22f5471b1da1a7a18e
parent11edf116e3a6352cfee6b1437d41603c9aff79c9 (diff)
powerpc/vfio_spapr_tce: Add reference counting to iommu_table
So far iommu_table obejcts were only used in virtual mode and had a single owner. We are going to change this by implementing in-kernel acceleration of DMA mapping requests. The proposed acceleration will handle requests in real mode and KVM will keep references to tables. This adds a kref to iommu_table and defines new helpers to update it. This replaces iommu_free_table() with iommu_tce_table_put() and makes iommu_free_table() static. iommu_tce_table_get() is not used in this patch but it will be in the following patch. Since this touches prototypes, this also removes @node_name parameter as it has never been really useful on powernv and carrying it for the pseries platform code to iommu_free_table() seems to be quite useless as well. This should cause no behavioral change. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Acked-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/iommu.h5
-rw-r--r--arch/powerpc/kernel/iommu.c27
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c14
-rw-r--r--arch/powerpc/platforms/powernv/pci.c1
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c3
-rw-r--r--arch/powerpc/platforms/pseries/vio.c2
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c2
7 files changed, 37 insertions, 17 deletions
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 4554699aec02..d96142572e6d 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -119,6 +119,7 @@ struct iommu_table {
119 struct list_head it_group_list;/* List of iommu_table_group_link */ 119 struct list_head it_group_list;/* List of iommu_table_group_link */
120 unsigned long *it_userspace; /* userspace view of the table */ 120 unsigned long *it_userspace; /* userspace view of the table */
121 struct iommu_table_ops *it_ops; 121 struct iommu_table_ops *it_ops;
122 struct kref it_kref;
122}; 123};
123 124
124#define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \ 125#define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \
@@ -151,8 +152,8 @@ static inline void *get_iommu_table_base(struct device *dev)
151 152
152extern int dma_iommu_dma_supported(struct device *dev, u64 mask); 153extern int dma_iommu_dma_supported(struct device *dev, u64 mask);
153 154
154/* Frees table for an individual device node */ 155extern struct iommu_table *iommu_tce_table_get(struct iommu_table *tbl);
155extern void iommu_free_table(struct iommu_table *tbl, const char *node_name); 156extern int iommu_tce_table_put(struct iommu_table *tbl);
156 157
157/* Initializes an iommu_table based in values set in the passed-in 158/* Initializes an iommu_table based in values set in the passed-in
158 * structure 159 * structure
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index a3689fdedd4a..5a3231fedf08 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -711,13 +711,13 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
711 return tbl; 711 return tbl;
712} 712}
713 713
714void iommu_free_table(struct iommu_table *tbl, const char *node_name) 714static void iommu_table_free(struct kref *kref)
715{ 715{
716 unsigned long bitmap_sz; 716 unsigned long bitmap_sz;
717 unsigned int order; 717 unsigned int order;
718 struct iommu_table *tbl;
718 719
719 if (!tbl) 720 tbl = container_of(kref, struct iommu_table, it_kref);
720 return;
721 721
722 if (tbl->it_ops->free) 722 if (tbl->it_ops->free)
723 tbl->it_ops->free(tbl); 723 tbl->it_ops->free(tbl);
@@ -736,7 +736,7 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
736 736
737 /* verify that table contains no entries */ 737 /* verify that table contains no entries */
738 if (!bitmap_empty(tbl->it_map, tbl->it_size)) 738 if (!bitmap_empty(tbl->it_map, tbl->it_size))
739 pr_warn("%s: Unexpected TCEs for %s\n", __func__, node_name); 739 pr_warn("%s: Unexpected TCEs\n", __func__);
740 740
741 /* calculate bitmap size in bytes */ 741 /* calculate bitmap size in bytes */
742 bitmap_sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long); 742 bitmap_sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
@@ -748,7 +748,24 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
748 /* free table */ 748 /* free table */
749 kfree(tbl); 749 kfree(tbl);
750} 750}
751EXPORT_SYMBOL_GPL(iommu_free_table); 751
752struct iommu_table *iommu_tce_table_get(struct iommu_table *tbl)
753{
754 if (kref_get_unless_zero(&tbl->it_kref))
755 return tbl;
756
757 return NULL;
758}
759EXPORT_SYMBOL_GPL(iommu_tce_table_get);
760
761int iommu_tce_table_put(struct iommu_table *tbl)
762{
763 if (WARN_ON(!tbl))
764 return 0;
765
766 return kref_put(&tbl->it_kref, iommu_table_free);
767}
768EXPORT_SYMBOL_GPL(iommu_tce_table_put);
752 769
753/* Creates TCEs for a user provided buffer. The user buffer must be 770/* Creates TCEs for a user provided buffer. The user buffer must be
754 * contiguous real kernel storage (not vmalloc). The address passed here 771 * contiguous real kernel storage (not vmalloc). The address passed here
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 5dae54cb11e3..ee4cdb5b893f 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1424,7 +1424,7 @@ static void pnv_pci_ioda2_release_dma_pe(struct pci_dev *dev, struct pnv_ioda_pe
1424 iommu_group_put(pe->table_group.group); 1424 iommu_group_put(pe->table_group.group);
1425 BUG_ON(pe->table_group.group); 1425 BUG_ON(pe->table_group.group);
1426 } 1426 }
1427 iommu_free_table(tbl, of_node_full_name(dev->dev.of_node)); 1427 iommu_tce_table_put(tbl);
1428} 1428}
1429 1429
1430static void pnv_ioda_release_vf_PE(struct pci_dev *pdev) 1430static void pnv_ioda_release_vf_PE(struct pci_dev *pdev)
@@ -2225,7 +2225,7 @@ found:
2225 __free_pages(tce_mem, get_order(tce32_segsz * segs)); 2225 __free_pages(tce_mem, get_order(tce32_segsz * segs));
2226 if (tbl) { 2226 if (tbl) {
2227 pnv_pci_unlink_table_and_group(tbl, &pe->table_group); 2227 pnv_pci_unlink_table_and_group(tbl, &pe->table_group);
2228 iommu_free_table(tbl, "pnv"); 2228 iommu_tce_table_put(tbl);
2229 } 2229 }
2230} 2230}
2231 2231
@@ -2321,7 +2321,7 @@ static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
2321 bus_offset, page_shift, window_size, 2321 bus_offset, page_shift, window_size,
2322 levels, tbl); 2322 levels, tbl);
2323 if (ret) { 2323 if (ret) {
2324 iommu_free_table(tbl, "pnv"); 2324 iommu_tce_table_put(tbl);
2325 return ret; 2325 return ret;
2326 } 2326 }
2327 2327
@@ -2365,7 +2365,7 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe)
2365 if (rc) { 2365 if (rc) {
2366 pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n", 2366 pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n",
2367 rc); 2367 rc);
2368 iommu_free_table(tbl, ""); 2368 iommu_tce_table_put(tbl);
2369 return rc; 2369 return rc;
2370 } 2370 }
2371 2371
@@ -2453,7 +2453,7 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
2453 pnv_pci_ioda2_unset_window(&pe->table_group, 0); 2453 pnv_pci_ioda2_unset_window(&pe->table_group, 0);
2454 if (pe->pbus) 2454 if (pe->pbus)
2455 pnv_ioda_setup_bus_dma(pe, pe->pbus, false); 2455 pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
2456 iommu_free_table(tbl, "pnv"); 2456 iommu_tce_table_put(tbl);
2457} 2457}
2458 2458
2459static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) 2459static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
@@ -3428,7 +3428,7 @@ static void pnv_pci_ioda1_release_pe_dma(struct pnv_ioda_pe *pe)
3428 } 3428 }
3429 3429
3430 free_pages(tbl->it_base, get_order(tbl->it_size << 3)); 3430 free_pages(tbl->it_base, get_order(tbl->it_size << 3));
3431 iommu_free_table(tbl, "pnv"); 3431 iommu_tce_table_put(tbl);
3432} 3432}
3433 3433
3434static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe) 3434static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
@@ -3455,7 +3455,7 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
3455 } 3455 }
3456 3456
3457 pnv_pci_ioda2_table_free_pages(tbl); 3457 pnv_pci_ioda2_table_free_pages(tbl);
3458 iommu_free_table(tbl, "pnv"); 3458 iommu_tce_table_put(tbl);
3459} 3459}
3460 3460
3461static void pnv_ioda_free_pe_seg(struct pnv_ioda_pe *pe, 3461static void pnv_ioda_free_pe_seg(struct pnv_ioda_pe *pe,
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index eb835e977e33..204a829ff506 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -767,6 +767,7 @@ struct iommu_table *pnv_pci_table_alloc(int nid)
767 767
768 tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, nid); 768 tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, nid);
769 INIT_LIST_HEAD_RCU(&tbl->it_group_list); 769 INIT_LIST_HEAD_RCU(&tbl->it_group_list);
770 kref_init(&tbl->it_kref);
770 771
771 return tbl; 772 return tbl;
772} 773}
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 4d757eaa46bf..7ce5db209abf 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -74,6 +74,7 @@ static struct iommu_table_group *iommu_pseries_alloc_group(int node)
74 goto fail_exit; 74 goto fail_exit;
75 75
76 INIT_LIST_HEAD_RCU(&tbl->it_group_list); 76 INIT_LIST_HEAD_RCU(&tbl->it_group_list);
77 kref_init(&tbl->it_kref);
77 tgl->table_group = table_group; 78 tgl->table_group = table_group;
78 list_add_rcu(&tgl->next, &tbl->it_group_list); 79 list_add_rcu(&tgl->next, &tbl->it_group_list);
79 80
@@ -115,7 +116,7 @@ static void iommu_pseries_free_group(struct iommu_table_group *table_group,
115 BUG_ON(table_group->group); 116 BUG_ON(table_group->group);
116 } 117 }
117#endif 118#endif
118 iommu_free_table(tbl, node_name); 119 iommu_tce_table_put(tbl);
119 120
120 kfree(table_group); 121 kfree(table_group);
121} 122}
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
index 720493932486..28b09fd797ec 100644
--- a/arch/powerpc/platforms/pseries/vio.c
+++ b/arch/powerpc/platforms/pseries/vio.c
@@ -1318,7 +1318,7 @@ static void vio_dev_release(struct device *dev)
1318 struct iommu_table *tbl = get_iommu_table_base(dev); 1318 struct iommu_table *tbl = get_iommu_table_base(dev);
1319 1319
1320 if (tbl) 1320 if (tbl)
1321 iommu_free_table(tbl, of_node_full_name(dev->of_node)); 1321 iommu_tce_table_put(tbl);
1322 of_node_put(dev->of_node); 1322 of_node_put(dev->of_node);
1323 kfree(to_vio_dev(dev)); 1323 kfree(to_vio_dev(dev));
1324} 1324}
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index fbec7348a7e5..8031d3a55a17 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -680,7 +680,7 @@ static void tce_iommu_free_table(struct tce_container *container,
680 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT; 680 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
681 681
682 tce_iommu_userspace_view_free(tbl, container->mm); 682 tce_iommu_userspace_view_free(tbl, container->mm);
683 iommu_free_table(tbl, ""); 683 iommu_tce_table_put(tbl);
684 decrement_locked_vm(container->mm, pages); 684 decrement_locked_vm(container->mm, pages);
685} 685}
686 686