Inter-revision diff: patch 24

Comparing v5 (message) to v3 (message)

--- v5
+++ v3
@@ -1,66 +1,242 @@
-This changes few functions to receive a iommu_table_group pointer
-rather than PE as they are going to be a part of upcoming
-iommu_table_group_ops callback set.
+This adds create/remove window ioctls to create and remove DMA windows.
+
+This changes VFIO_IOMMU_SPAPR_TCE_GET_INFO handler to return additional
+information such as a number of supported windows and maximum number
+levels of TCE tables.
 
 Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
 ---
- arch/powerpc/platforms/powernv/pci-ioda.c | 13 ++++++++-----
- 1 file changed, 8 insertions(+), 5 deletions(-)
-
-diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
-index 19b5f36..ed60b38 100644
---- a/arch/powerpc/platforms/powernv/pci-ioda.c
-+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
-@@ -1400,10 +1400,12 @@ static __be64 *pnv_alloc_tce_table(int nid,
- 	return addr;
+ arch/powerpc/include/asm/iommu.h    |   2 +-
+ drivers/vfio/vfio_iommu_spapr_tce.c | 137 +++++++++++++++++++++++++++++++++++-
+ include/uapi/linux/vfio.h           |  24 ++++++-
+ 3 files changed, 160 insertions(+), 3 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
+index 33009f9..7ca1c8c 100644
+--- a/arch/powerpc/include/asm/iommu.h
++++ b/arch/powerpc/include/asm/iommu.h
+@@ -133,7 +133,7 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name);
+ extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
+ 					    int nid);
+ 
+-#define POWERPC_IOMMU_MAX_TABLES	1
++#define POWERPC_IOMMU_MAX_TABLES	2
+ 
+ #define POWERPC_IOMMU_DEFAULT_LEVELS	1
+ 
+diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
+index 8bcafb7..d3a1cc9 100644
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -300,6 +300,20 @@ static struct iommu_table *spapr_tce_find_table(
+ 	return ret;
  }
  
--static long pnv_pci_ioda2_create_table(struct pnv_ioda_pe *pe,
-+static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
- 		__u32 page_shift, __u64 window_size, __u32 levels,
- 		struct iommu_table *tbl)
++static int spapr_tce_find_free_table(struct tce_container *container)
++{
++	int i;
++
++	for (i = 0; i < POWERPC_IOMMU_MAX_TABLES; ++i) {
++		struct iommu_table *tbl = &container->tables[i];
++
++		if (!tbl->it_size)
++			return i;
++	}
++
++	return -1;
++}
++
+ static unsigned long tce_default_winsize(struct tce_container *container)
  {
-+	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
-+						table_group);
- 	int nid = pe->phb->hose->node;
- 	void *addr;
- 	unsigned long tce_table_size, left;
-@@ -1459,9 +1461,11 @@ static void pnv_pci_free_table(struct iommu_table *tbl)
- 	iommu_reset_table(tbl, "ioda2");
- }
- 
--static long pnv_pci_ioda2_set_window(struct pnv_ioda_pe *pe,
-+static long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,
- 		struct iommu_table *tbl)
+ 	struct tce_iommu_group *tcegrp;
+@@ -594,7 +608,7 @@ static long tce_iommu_ioctl(void *iommu_data,
+ 				 unsigned int cmd, unsigned long arg)
  {
-+	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
-+			table_group);
- 	struct pnv_phb *phb = pe->phb;
- 	const __be64 *swinvp;
- 	int64_t rc;
-@@ -1594,12 +1598,11 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
- 
- 	/* The PE will reserve all possible 32-bits space */
- 	pe->tce32_seg = 0;
--
- 	end = (1 << ilog2(phb->ioda.m32_pci_base));
- 	pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n",
- 		end);
- 
--	rc = pnv_pci_ioda2_create_table(pe, IOMMU_PAGE_SHIFT_4K,
-+	rc = pnv_pci_ioda2_create_table(&pe->table_group, IOMMU_PAGE_SHIFT_4K,
- 			phb->ioda.m32_pci_base,
- 			POWERNV_IOMMU_DEFAULT_LEVELS, tbl);
- 	if (rc) {
-@@ -1611,7 +1614,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
- 	pe->table_group.tables[0].it_group = &pe->table_group;
- 	pe->table_group.ops = &pnv_pci_ioda2_ops;
- 
--	rc = pnv_pci_ioda2_set_window(pe, tbl);
-+	rc = pnv_pci_ioda2_set_window(&pe->table_group, tbl);
- 	if (rc) {
- 		pe_err(pe, "Failed to configure 32-bit TCE table,"
- 		       " err %ld\n", rc);
+ 	struct tce_container *container = iommu_data;
+-	unsigned long minsz;
++	unsigned long minsz, ddwsz;
+ 	long ret;
+ 
+ 	switch (cmd) {
+@@ -636,6 +650,15 @@ static long tce_iommu_ioctl(void *iommu_data,
+ 
+ 		info.dma32_window_start = iommu->tce32_start;
+ 		info.dma32_window_size = iommu->tce32_size;
++		info.windows_supported = iommu->windows_supported;
++		info.levels = iommu->levels;
++		info.flags = iommu->flags;
++
++		ddwsz = offsetofend(struct vfio_iommu_spapr_tce_info,
++				levels);
++
++		if (info.argsz == ddwsz)
++			minsz = ddwsz;
+ 
+ 		if (copy_to_user((void __user *)arg, &info, minsz))
+ 			return -EFAULT;
+@@ -800,6 +823,118 @@ static long tce_iommu_ioctl(void *iommu_data,
+ 		return ret;
+ 	}
+ 
++	case VFIO_IOMMU_SPAPR_TCE_CREATE: {
++		struct vfio_iommu_spapr_tce_create create;
++		struct powerpc_iommu *iommu;
++		struct tce_iommu_group *tcegrp;
++		int num;
++
++		if (!tce_preregistered(container))
++			return -ENXIO;
++
++		minsz = offsetofend(struct vfio_iommu_spapr_tce_create,
++				start_addr);
++
++		if (copy_from_user(&create, (void __user *)arg, minsz))
++			return -EFAULT;
++
++		if (create.argsz < minsz)
++			return -EINVAL;
++
++		if (create.flags)
++			return -EINVAL;
++
++		num = spapr_tce_find_free_table(container);
++		if (num < 0)
++			return -ENOSYS;
++
++		tcegrp = list_first_entry(&container->group_list,
++				struct tce_iommu_group, next);
++		iommu = iommu_group_get_iommudata(tcegrp->grp);
++
++		ret = iommu->ops->create_table(iommu, num,
++				create.page_shift, create.window_shift,
++				create.levels,
++				&container->tables[num]);
++		if (ret)
++			return ret;
++
++		list_for_each_entry(tcegrp, &container->group_list, next) {
++			struct powerpc_iommu *iommutmp =
++					iommu_group_get_iommudata(tcegrp->grp);
++
++			if (WARN_ON_ONCE(iommutmp->ops != iommu->ops))
++				return -EFAULT;
++
++			ret = iommu->ops->set_window(iommutmp, num,
++					&container->tables[num]);
++			if (ret)
++				return ret;
++		}
++
++		create.start_addr =
++				container->tables[num].it_offset <<
++				container->tables[num].it_page_shift;
++
++		if (copy_to_user((void __user *)arg, &create, minsz))
++			return -EFAULT;
++
++		mutex_lock(&container->lock);
++		mutex_unlock(&container->lock);
++
++		return ret;
++	}
++	case VFIO_IOMMU_SPAPR_TCE_REMOVE: {
++		struct vfio_iommu_spapr_tce_remove remove;
++		struct powerpc_iommu *iommu = NULL;
++		struct iommu_table *tbl;
++		struct tce_iommu_group *tcegrp;
++		int num;
++
++		if (!tce_preregistered(container))
++			return -ENXIO;
++
++		minsz = offsetofend(struct vfio_iommu_spapr_tce_remove,
++				start_addr);
++
++		if (copy_from_user(&remove, (void __user *)arg, minsz))
++			return -EFAULT;
++
++		if (remove.argsz < minsz)
++			return -EINVAL;
++
++		if (remove.flags)
++			return -EINVAL;
++
++
++		tbl = spapr_tce_find_table(container, remove.start_addr);
++		if (!tbl)
++			return -EINVAL;
++
++		/* Detach windows from IOMMUs */
++		mutex_lock(&container->lock);
++
++		/* Detach groups from IOMMUs */
++		num = tbl - container->tables;
++		list_for_each_entry(tcegrp, &container->group_list, next) {
++			iommu = iommu_group_get_iommudata(tcegrp->grp);
++			if (container->tables[num].it_size)
++				iommu->ops->unset_window(iommu, num);
++		}
++
++		/* Free table */
++		tcegrp = list_first_entry(&container->group_list,
++				struct tce_iommu_group, next);
++		iommu = iommu_group_get_iommudata(tcegrp->grp);
++
++		tce_iommu_clear(container, tbl,
++				tbl->it_offset, tbl->it_size);
++		iommu->ops->free_table(tbl);
++
++		mutex_unlock(&container->lock);
++
++		return 0;
++	}
+ 	}
+ 
+ 	return -ENOTTY;
+diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
+index 2bb0c9b..7ed7000 100644
+--- a/include/uapi/linux/vfio.h
++++ b/include/uapi/linux/vfio.h
+@@ -483,9 +483,11 @@ struct vfio_iommu_type1_unregister_memory {
+  */
+ struct vfio_iommu_spapr_tce_info {
+ 	__u32 argsz;
+-	__u32 flags;			/* reserved for future use */
++	__u32 flags;
+ 	__u32 dma32_window_start;	/* 32 bit window start (bytes) */
+ 	__u32 dma32_window_size;	/* 32 bit window size (bytes) */
++	__u32 windows_supported;
++	__u32 levels;
+ };
+ 
+ #define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
+@@ -521,6 +523,26 @@ struct vfio_eeh_pe_op {
+ 
+ #define VFIO_EEH_PE_OP			_IO(VFIO_TYPE, VFIO_BASE + 21)
+ 
++struct vfio_iommu_spapr_tce_create {
++	__u32 argsz;
++	__u32 flags;
++	/* in */
++	__u32 page_shift;
++	__u32 window_shift;
++	__u32 levels;
++	/* out */
++	__u64 start_addr;
++};
++#define VFIO_IOMMU_SPAPR_TCE_CREATE	_IO(VFIO_TYPE, VFIO_BASE + 19)
++
++struct vfio_iommu_spapr_tce_remove {
++	__u32 argsz;
++	__u32 flags;
++	/* in */
++	__u64 start_addr;
++};
++#define VFIO_IOMMU_SPAPR_TCE_REMOVE	_IO(VFIO_TYPE, VFIO_BASE + 20)
++
+ /* ***************************************************************** */
+ 
+ #endif /* _UAPIVFIO_H */
 -- 
 2.0.0
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help