From: Alexey Kardashevskiy <aik@ozlabs.ru>
To: linuxppc-dev@lists.ozlabs.org
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>,
Benjamin Herrenschmidt <benh@kernel.crashing.org>,
Paul Mackerras <paulus@samba.org>,
Alex Williamson <alex.williamson@redhat.com>,
Gavin Shan <gwshan@linux.vnet.ibm.com>,
Alexander Graf <agraf@suse.de>,
linux-kernel@vger.kernel.org
Subject: [PATCH v4 28/28] vfio: powerpc/spapr: Support Dynamic DMA windows
Date: Mon, 16 Feb 2015 21:06:20 +1100 [thread overview]
Message-ID: <1424081180-4494-29-git-send-email-aik@ozlabs.ru> (raw)
In-Reply-To: <1424081180-4494-1-git-send-email-aik@ozlabs.ru>
This adds create/remove window ioctls to create and remove DMA windows.
sPAPR defines a Dynamic DMA windows capability which allows
para-virtualized guests to create additional DMA windows on a PCI bus.
The existing linux kernels use this new window to map the entire guest
memory and switch to the direct DMA operations saving time on map/unmap
requests which would normally happen in a big amounts.
This adds 2 ioctl handlers - VFIO_IOMMU_SPAPR_TCE_CREATE and
VFIO_IOMMU_SPAPR_TCE_REMOVE - to create and remove windows.
Up to 2 windows are supported now by the hardware and by this driver.
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>
---
Changes:
v4:
* moved code to tce_iommu_create_window()/tce_iommu_remove_window()
helpers
* added docs
---
Documentation/vfio.txt | 6 ++
arch/powerpc/include/asm/iommu.h | 2 +-
drivers/vfio/vfio_iommu_spapr_tce.c | 156 +++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 24 +++++-
4 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
index 791e85c..11628f1 100644
--- a/Documentation/vfio.txt
+++ b/Documentation/vfio.txt
@@ -446,6 +446,12 @@ the memory block.
The user space is not expected to call these often and the block descriptors
are stored in a linked list in the kernel.
+6) sPAPR specification allows guests to have an ddditional DMA window(s) on
+a PCI bus with a variable page size. Two ioctls have been added to support
+this: VFIO_IOMMU_SPAPR_TCE_CREATE and VFIO_IOMMU_SPAPR_TCE_REMOVE.
+The platform has to support the functionality or error will be returned to
+the userspace.
+
-------------------------------------------------------------------------------
[1] VFIO was originally an acronym for "Virtual Function I/O" in its
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 8393822..6f34b82 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 ee91d51..d5de7c6 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -333,6 +333,20 @@ static struct iommu_table *spapr_tce_find_table(
return ret;
}
+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 int tce_iommu_enable(struct tce_container *container)
{
int ret = 0;
@@ -620,11 +634,85 @@ static long tce_iommu_build(struct tce_container *container,
return ret;
}
+static long tce_iommu_create_window(struct tce_container *container,
+ __u32 page_shift, __u32 window_shift, __u32 levels,
+ __u64 *start_addr)
+{
+ struct powerpc_iommu *iommu;
+ struct tce_iommu_group *tcegrp;
+ int num;
+ long ret;
+
+ 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,
+ page_shift, window_shift, 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;
+ }
+
+ *start_addr = container->tables[num].it_offset <<
+ container->tables[num].it_page_shift;
+
+ return 0;
+}
+
+static long tce_iommu_remove_window(struct tce_container *container,
+ __u64 start_addr)
+{
+ struct powerpc_iommu *iommu = NULL;
+ struct iommu_table *tbl;
+ struct tce_iommu_group *tcegrp;
+ int num;
+
+ tbl = spapr_tce_find_table(container, start_addr);
+ if (!tbl)
+ return -EINVAL;
+
+ /* 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);
+
+ return 0;
+}
+
static long tce_iommu_ioctl(void *iommu_data,
unsigned int cmd, unsigned long arg)
{
struct tce_container *container = iommu_data;
- unsigned long minsz;
+ unsigned long minsz, ddwsz;
long ret;
switch (cmd) {
@@ -666,6 +754,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;
@@ -828,6 +925,63 @@ static long tce_iommu_ioctl(void *iommu_data,
return ret;
}
+ case VFIO_IOMMU_SPAPR_TCE_CREATE: {
+ struct vfio_iommu_spapr_tce_create create;
+
+ if (!tce_preregistered(container))
+ return -EPERM;
+
+ 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;
+
+ mutex_lock(&container->lock);
+
+ ret = tce_iommu_create_window(container, create.page_shift,
+ create.window_shift, create.levels,
+ &create.start_addr);
+
+ if (!ret && copy_to_user((void __user *)arg, &create, minsz))
+ return -EFAULT;
+
+ mutex_unlock(&container->lock);
+
+ return ret;
+ }
+ case VFIO_IOMMU_SPAPR_TCE_REMOVE: {
+ struct vfio_iommu_spapr_tce_remove remove;
+
+ if (!tce_preregistered(container))
+ return -EPERM;
+
+ 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;
+
+ mutex_lock(&container->lock);
+
+ ret = tce_iommu_remove_window(container, remove.start_addr);
+
+ mutex_unlock(&container->lock);
+
+ return ret;
+ }
}
return -ENOTTY;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 0f55c08..0f4b219 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -454,9 +454,11 @@ struct vfio_iommu_type1_dma_unmap {
*/
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)
@@ -517,6 +519,26 @@ struct vfio_iommu_spapr_register_memory {
*/
#define VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY _IO(VFIO_TYPE, VFIO_BASE + 18)
+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
prev parent reply other threads:[~2015-02-16 10:11 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-16 10:05 [PATCH v4 00/28] powerpc/iommu/vfio: Enable Dynamic DMA windows Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 01/28] vfio: powerpc/spapr: Move page pinning from arch code to VFIO IOMMU driver Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 02/28] vfio: powerpc/spapr: Do cleanup when releasing the group Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 03/28] vfio: powerpc/spapr: Check that TCE page size is equal to it_page_size Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 04/28] vfio: powerpc/spapr: Use it_page_size Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 05/28] vfio: powerpc/spapr: Move locked_vm accounting to helpers Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 06/28] vfio: powerpc/spapr: Disable DMA mappings on disabled container Alexey Kardashevskiy
2015-02-16 10:05 ` [PATCH v4 07/28] vfio: powerpc/spapr: Moving pinning/unpinning to helpers Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 08/28] vfio: powerpc/spapr: Register memory Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 09/28] powerpc/powernv: Do not set "read" flag if direction==DMA_NONE Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 10/28] powerpc/iommu: Move tce_xxx callbacks from ppc_md to iommu_table Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 11/28] powerpc/iommu: Introduce iommu_table_alloc() helper Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 12/28] powerpc/spapr: vfio: Switch from iommu_table to new powerpc_iommu Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 13/28] powerpc/iommu: Fix IOMMU ownership control functions Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 14/28] vfio: powerpc/spapr: powerpc/powernv/ioda2: Rework IOMMU ownership control Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 15/28] powerpc/powernv/ioda/ioda2: Rework tce_build()/tce_free() Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 16/28] powerpc/iommu/powernv: Release replaced TCE Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 17/28] powerpc/pseries/lpar: Enable VFIO Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 18/28] poweppc/powernv/ioda2: Rework iommu_table creation Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 19/28] powerpc/powernv/ioda2: Introduce pnv_pci_ioda2_create_table Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 20/28] powerpc/powernv/ioda2: Introduce pnv_pci_ioda2_set_window Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 21/28] powerpc/iommu: Split iommu_free_table into 2 helpers Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 22/28] powerpc/powernv: Implement multilevel TCE tables Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 23/28] powerpc/powernv: Change prototypes to receive iommu Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 24/28] powerpc/powernv/ioda: Define and implement DMA table/window management callbacks Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 25/28] vfio: powerpc/spapr: powerpc/powernv/ioda2: Rework ownership Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 26/28] vfio: powerpc/spapr: Rework an IOMMU group attach/detach Alexey Kardashevskiy
2015-02-16 10:06 ` [PATCH v4 27/28] vfio: powerpc/spapr: Register memory Alexey Kardashevskiy
2015-02-20 2:18 ` Alexey Kardashevskiy
2015-02-16 10:06 ` Alexey Kardashevskiy [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1424081180-4494-29-git-send-email-aik@ozlabs.ru \
--to=aik@ozlabs.ru \
--cc=agraf@suse.de \
--cc=alex.williamson@redhat.com \
--cc=benh@kernel.crashing.org \
--cc=gwshan@linux.vnet.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=paulus@samba.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).