Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1446461 > unrolled thread
| Started by | Eric Auger <eric.auger@redhat.com> |
|---|---|
| First post | 2016-07-19 15:20 +0200 |
| Last post | 2016-07-19 15:20 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v11 0/8] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 3/3: vfio changes Eric Auger <eric.auger@redhat.com> - 2016-07-19 15:20 +0200
[PATCH v11 8/8] vfio/type1: return MSI geometry through VFIO_IOMMU_GET_INFO capability chains Eric Auger <eric.auger@redhat.com> - 2016-07-19 15:20 +0200
[PATCH v11 4/8] vfio/type1: handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots Eric Auger <eric.auger@redhat.com> - 2016-07-19 15:20 +0200
| From | Eric Auger <eric.auger@redhat.com> |
|---|---|
| Date | 2016-07-19 15:20 +0200 |
| Subject | [PATCH v11 0/8] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 3/3: vfio changes |
| Message-ID | <rWD6i-4u7-15@gated-at.bofh.it> |
This series allows the user-space to register a reserved IOVA domain.
This completes the kernel integration of the whole functionality on top
of the 2 previous parts (v11).
We reuse the VFIO DMA MAP ioctl with a new flag to bridge to the
msi-iommu API. The need for provisioning such MSI IOVA range is reported
through capability chain, using VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY.
vfio_iommu_type1 checks if the MSI mapping is safe when attaching the
vfio group to the container (allow_unsafe_interrupts modality). This is
done in a very coarse way, looking at all the registered doorbells and
returning assignment is safe wrt IRQ if all the doorbells are safe.
More details & context can be found at:
http://www.linaro.org/blog/core-dump/kvm-pciemsi-passthrough-armarm64/
Best Regards
Eric
Testing:
- functional on ARM64 AMD Overdrive HW (single GICv2m frame) with
Intel I350T2 (SR-IOV capable, igb/igbvf) and Intel 82574L (e1000e)
- functional on Cavium ThunderX (ARM GICv3 ITS) with Intel 82574L (e1000e)
References:
[1] [RFC 0/2] VFIO: Add virtual MSI doorbell support
(https://lkml.org/lkml/2015/7/24/135)
[2] [RFC PATCH 0/6] vfio: Add interface to map MSI pages
(https://lists.cs.columbia.edu/pipermail/kvmarm/2015-September/016607.html)
[3] [PATCH v2 0/3] Introduce MSI hardware mapping for VFIO
(http://permalink.gmane.org/gmane.comp.emulators.kvm.arm.devel/3858)
Git: complete series available at
https://github.com/eauger/linux/tree/v4.7-rc7-passthrough-v11
the above branch includes a temporary patch to work around a ThunderX pci
bus reset crash (which I think unrelated to this series):
"vfio: pci: HACK! workaround thunderx pci_try_reset_bus crash"
Do not take this for other platforms.
This issue will be handled separately on the ML.
previous version at
https://github.com/eauger/linux/tree/v4.7-rc2-passthrough-v10
History:
v10 -> v11:
- no change to this series, just incremented for consistency
- eventually tested with GICv3 ITS on Cavium
v9 -> v10:
Took into account Alex' comments:
- split "vfio/type1: vfio_find_dma accepting a type argument" into 2 patches
- properly implement replay of MSI DMA slots (by setting the aperture on the
new domain); fixes the assignment of several devices
- rework user api for vfio_iommu_type1_info capability chains (cap_offset
at the end of the struct and fix padding issues)
- VFIO_IOVA_RESERVED renamed into VFIO_IOVA_MSI_RESERVED
- explicit dma->type setting to VFIO_IOVA_USER
v8 -> v9:
- report MSI geometry through capability chain (last patch only);
with the current limitation that an arbitrary number of 16 page
requirement is reported. To be improved later on.
v7 -> v8:
- use renamed msi-iommu API
- VFIO only responsible for setting the IOVA aperture
- use new DOMAIN_ATTR_MSI_GEOMETRY iommu domain attribute
v6 -> v7:
- vfio_find_dma now accepts a dma_type argument.
- should have recovered the capability to unmap the whole user IOVA range
- remove computation of nb IOVA pages -> will post a separate RFC for that
while respinning the QEMU part
RFC v5 -> patch v6:
- split to ease the review process
RFC v4 -> RFC v5:
- take into account Thomas' comments on MSI related patches
- split "msi: IOMMU map the doorbell address when needed"
- increase readability and add comments
- fix style issues
- split "iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute"
- platform ITS now advertises IOMMU_CAP_INTR_REMAP
- fix compilation issue with CONFIG_IOMMU API unset
- arm-smmu-v3 now advertises DOMAIN_ATTR_MSI_MAPPING
RFC v3 -> v4:
- Move doorbell mapping/unmapping in msi.c
- fix ref count issue on set_affinity: in case of a change in the address
the previous address is decremented
- doorbell map/unmap now is done on msi composition. Should allow the use
case for platform MSI controllers
- create dma-reserved-iommu.h/c exposing/implementing a new API dedicated
to reserved IOVA management (looking like dma-iommu glue)
- series reordering to ease the review:
- first part is related to IOMMU
- second related to MSI sub-system
- third related to VFIO (except arm-smmu IOMMU_CAP_INTR_REMAP removal)
- expose the number of requested IOVA pages through VFIO_IOMMU_GET_INFO
[this partially addresses Marc's comments on iommu_get/put_single_reserved
size/alignment problematic - which I did not ignore - but I don't know
how much I can do at the moment]
RFC v2 -> RFC v3:
- should fix wrong handling of some CONFIG combinations:
CONFIG_IOVA, CONFIG_IOMMU_API, CONFIG_PCI_MSI_IRQ_DOMAIN
- fix MSI_FLAG_IRQ_REMAPPING setting in GICv3 ITS (although not tested)
PATCH v1 -> RFC v2:
- reverted to RFC since it looks more reasonable ;-) the code is split
between VFIO, IOMMU, MSI controller and I am not sure I did the right
choices. Also API need to be further discussed.
- iova API usage in arm-smmu.c.
- MSI controller natively programs the MSI addr with either the PA or IOVA.
This is not done anymore in vfio-pci driver as suggested by Alex.
- check irq remapping capability of the group
RFC v1 [2] -> PATCH v1:
- use the existing dma map/unmap ioctl interface with a flag to register a
reserved IOVA range. Use the legacy Rb to store this special vfio_dma.
- a single reserved IOVA contiguous region now is allowed
- use of an RB tree indexed by PA to store allocated reserved slots
- use of a vfio_domain iova_domain to manage iova allocation within the
window provided by the userspace
- vfio alloc_map/unmap_free take a vfio_group handle
- vfio_group handle is cached in vfio_pci_device
- add ref counting to bindings
- user modality enabled at the end of the series
Eric Auger (8):
vfio: introduce a vfio_dma type field
vfio/type1: vfio_find_dma accepting a type argument
vfio/type1: implement recursive vfio_find_dma_from_node
vfio/type1: handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots
vfio: allow reserved msi iova registration
vfio/type1: check doorbell safety
iommu/arm-smmu: do not advertise IOMMU_CAP_INTR_REMAP
vfio/type1: return MSI geometry through VFIO_IOMMU_GET_INFO capability
chains
drivers/iommu/arm-smmu-v3.c | 3 +-
drivers/iommu/arm-smmu.c | 3 +-
drivers/vfio/vfio_iommu_type1.c | 246 +++++++++++++++++++++++++++++++++++++---
include/uapi/linux/vfio.h | 42 ++++++-
4 files changed, 276 insertions(+), 18 deletions(-)
--
1.9.1
[toc] | [next] | [standalone]
| From | Eric Auger <eric.auger@redhat.com> |
|---|---|
| Date | 2016-07-19 15:20 +0200 |
| Subject | [PATCH v11 8/8] vfio/type1: return MSI geometry through VFIO_IOMMU_GET_INFO capability chains |
| Message-ID | <rWD6i-4u7-31@gated-at.bofh.it> |
| In reply to | #1446461 |
This patch allows the user-space to retrieve the MSI geometry. The
implementation is based on capability chains, now also added to
VFIO_IOMMU_GET_INFO.
The returned info comprise:
- whether the MSI IOVA are constrained to a reserved range (x86 case) and
in the positive, the start/end of the aperture,
- or whether the IOVA aperture need to be set by the userspace. In that
case, the size and alignment of the IOVA window to be provided are
returned.
In case the userspace must provide the IOVA aperture, we currently report
a size/alignment based on all the doorbells registered by the host kernel.
This may exceed the actual needs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- move cap_offset after iova_pgsizes
- replace __u64 alignment by __u32 order
- introduce __u32 flags in vfio_iommu_type1_info_cap_msi_geometry and
fix alignment
- call msi-doorbell API to compute the size/alignment
v8 -> v9:
- use iommu_msi_supported flag instead of programmable
- replace IOMMU_INFO_REQUIRE_MSI_MAP flag by a more sophisticated
capability chain, reporting the MSI geometry
v7 -> v8:
- use iommu_domain_msi_geometry
v6 -> v7:
- remove the computation of the number of IOVA pages to be provisionned.
This number depends on the domain/group/device topology which can
dynamically change. Let's rely instead rely on an arbitrary max depending
on the system
v4 -> v5:
- move msi_info and ret declaration within the conditional code
v3 -> v4:
- replace former vfio_domains_require_msi_mapping by
more complex computation of MSI mapping requirements, especially the
number of pages to be provided by the user-space.
- reword patch title
RFC v1 -> v1:
- derived from
[RFC PATCH 3/6] vfio: Extend iommu-info to return MSIs automap state
- renamed allow_msi_reconfig into require_msi_mapping
- fixed VFIO_IOMMU_GET_INFO
---
drivers/vfio/vfio_iommu_type1.c | 78 ++++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 32 ++++++++++++++++-
2 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 7daab53..7e38207 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -38,6 +38,8 @@
#include <linux/workqueue.h>
#include <linux/msi-iommu.h>
#include <linux/msi-doorbell.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -1103,6 +1105,55 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
return ret;
}
+static int compute_msi_geometry_caps(struct vfio_iommu *iommu,
+ struct vfio_info_cap *caps)
+{
+ struct vfio_iommu_type1_info_cap_msi_geometry *vfio_msi_geometry;
+ unsigned long order = __ffs(vfio_pgsize_bitmap(iommu));
+ struct iommu_domain_msi_geometry msi_geometry;
+ struct vfio_info_cap_header *header;
+ struct vfio_domain *d;
+ bool reserved;
+ size_t size;
+
+ mutex_lock(&iommu->lock);
+ /* All domains have same require_msi_map property, pick first */
+ d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
+ iommu_domain_get_attr(d->domain, DOMAIN_ATTR_MSI_GEOMETRY,
+ &msi_geometry);
+ reserved = !msi_geometry.iommu_msi_supported;
+
+ mutex_unlock(&iommu->lock);
+
+ size = sizeof(*vfio_msi_geometry);
+ header = vfio_info_cap_add(caps, size,
+ VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY, 1);
+
+ if (IS_ERR(header))
+ return PTR_ERR(header);
+
+ vfio_msi_geometry = container_of(header,
+ struct vfio_iommu_type1_info_cap_msi_geometry,
+ header);
+
+ vfio_msi_geometry->flags = reserved;
+ if (reserved) {
+ vfio_msi_geometry->aperture_start = msi_geometry.aperture_start;
+ vfio_msi_geometry->aperture_end = msi_geometry.aperture_end;
+ return 0;
+ }
+
+ vfio_msi_geometry->order = order;
+ /*
+ * we compute a system-wide requirement based on all the registered
+ * doorbells
+ */
+ vfio_msi_geometry->size =
+ msi_doorbell_pages(order) * ((uint64_t) 1 << order);
+
+ return 0;
+}
+
static long vfio_iommu_type1_ioctl(void *iommu_data,
unsigned int cmd, unsigned long arg)
{
@@ -1124,8 +1175,10 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
}
} else if (cmd == VFIO_IOMMU_GET_INFO) {
struct vfio_iommu_type1_info info;
+ struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
+ int ret;
- minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes);
+ minsz = offsetofend(struct vfio_iommu_type1_info, cap_offset);
if (copy_from_user(&info, (void __user *)arg, minsz))
return -EFAULT;
@@ -1137,6 +1190,29 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
+ ret = compute_msi_geometry_caps(iommu, &caps);
+ if (ret)
+ return ret;
+
+ if (caps.size) {
+ info.flags |= VFIO_IOMMU_INFO_CAPS;
+ if (info.argsz < sizeof(info) + caps.size) {
+ info.argsz = sizeof(info) + caps.size;
+ info.cap_offset = 0;
+ } else {
+ vfio_info_cap_shift(&caps, sizeof(info));
+ if (copy_to_user((void __user *)arg +
+ sizeof(info), caps.buf,
+ caps.size)) {
+ kfree(caps.buf);
+ return -EFAULT;
+ }
+ info.cap_offset = sizeof(info);
+ }
+
+ kfree(caps.buf);
+ }
+
return copy_to_user((void __user *)arg, &info, minsz) ?
-EFAULT : 0;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 4a9dbc2..8dae013 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -488,7 +488,35 @@ struct vfio_iommu_type1_info {
__u32 argsz;
__u32 flags;
#define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */
- __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+#define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */
+ __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+ __u32 __resv;
+ __u32 cap_offset; /* Offset within info struct of first cap */
+};
+
+#define VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY 1
+
+/*
+ * The MSI geometry capability allows to report the MSI IOVA geometry:
+ * - either the MSI IOVAs are constrained within a reserved IOVA aperture
+ * whose boundaries are given by [@aperture_start, @aperture_end].
+ * this is typically the case on x86 host. The userspace is not allowed
+ * to map userspace memory at IOVAs intersecting this range using
+ * VFIO_IOMMU_MAP_DMA.
+ * - or the MSI IOVAs are not requested to belong to any reserved range;
+ * in that case the userspace must provide an IOVA window characterized by
+ * @size and @alignment using VFIO_IOMMU_MAP_DMA with RESERVED_MSI_IOVA flag.
+ */
+struct vfio_iommu_type1_info_cap_msi_geometry {
+ struct vfio_info_cap_header header;
+ __u32 flags;
+#define VFIO_IOMMU_MSI_GEOMETRY_RESERVED (1 << 0) /* reserved geometry */
+ /* not reserved */
+ __u32 order; /* iommu page order used for aperture alignment*/
+ __u64 size; /* IOVA aperture size (bytes) the userspace must provide */
+ /* reserved */
+ __u64 aperture_start;
+ __u64 aperture_end;
};
#define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
@@ -503,6 +531,8 @@ struct vfio_iommu_type1_info {
* IOVA region that will be used on some platforms to map the host MSI frames.
* In that specific case, vaddr is ignored. Once registered, an MSI reserved
* IOVA region stays until the container is closed.
+ * The requirement for provisioning such reserved IOVA range can be checked by
+ * checking the VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY capability.
*/
struct vfio_iommu_type1_dma_map {
__u32 argsz;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@redhat.com> |
|---|---|
| Date | 2016-07-19 15:20 +0200 |
| Subject | [PATCH v11 4/8] vfio/type1: handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots |
| Message-ID | <rWD6i-4u7-35@gated-at.bofh.it> |
| In reply to | #1446461 |
Before allowing the end-user to create VFIO_IOVA_RESERVED dma slots,
let's implement the expected behavior for removal and replay.
As opposed to user dma slots, reserved IOVAs are not systematically bound
to PAs and PAs are not pinned. VFIO just initializes the IOVA "aperture".
IOVAs are allocated outside of the VFIO framework, by the MSI layer which
is responsible to free and unmap them. The MSI mapping resources are freeed
by the IOMMU driver on domain destruction.
On the creation of a new domain, the "replay" of a reserved slot simply
needs to set the MSI aperture on the new domain.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- replay of a reserved slot sets the MSI aperture on the new domain
- use VFIO_IOVA_RESERVED_MSI enum value instead of VFIO_IOVA_RESERVED
v7 -> v8:
- do no destroy anything anymore, just bypass unmap/unpin and iommu_map
on replay
---
drivers/vfio/vfio_iommu_type1.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 65a4038..69c775e 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -36,6 +36,7 @@
#include <linux/uaccess.h>
#include <linux/vfio.h>
#include <linux/workqueue.h>
+#include <linux/msi-iommu.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -387,7 +388,7 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
struct vfio_domain *domain, *d;
long unlocked = 0;
- if (!dma->size)
+ if (!dma->size || dma->type != VFIO_IOVA_USER)
return;
/*
* We use the IOMMU to track the physical addresses, otherwise we'd
@@ -724,6 +725,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
dma = rb_entry(n, struct vfio_dma, node);
iova = dma->iova;
+ if (dma->type == VFIO_IOVA_RESERVED_MSI) {
+ ret = iommu_msi_set_aperture(domain->domain,
+ dma->iova,
+ iova + dma->size - 1);
+ WARN_ON(ret);
+ continue;
+ }
+
while (iova < dma->iova + dma->size) {
phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
size_t size;
--
1.9.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web