* [PATCH 0/3] Introduce MSI hardware mapping for VFIO
@ 2015-11-24 7:48 Pavel Fedin
2015-11-24 7:48 ` [PATCH 1/3] vfio: Introduce map and unmap operations Pavel Fedin
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-11-24 7:48 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Alex Williamson, Marc Zyngier, Thomas Gleixner, Jason Cooper,
Manish Jaggi
On some architectures (e.g. ARM64) if the device is behind an IOMMU, and
is being mapped by VFIO, it is necessary to also add mappings for MSI
translation register for interrupts to work. This series implements the
necessary API to do this, and makes use of this API for GICv3 ITS on
ARM64.
Pavel Fedin (3):
vfio: Introduce map and unmap operations
gicv3, its: Introduce VFIO map and unmap operations
vfio: Introduce generic MSI mapping operations
drivers/irqchip/irq-gic-v3-its.c | 31 ++++++++++
drivers/vfio/pci/vfio_pci_intrs.c | 11 ++++
drivers/vfio/vfio.c | 112 +++++++++++++++++++++++++++++++++++++
drivers/vfio/vfio_iommu_type1.c | 29 ++++++++++
include/linux/irqchip/arm-gic-v3.h | 2 +
include/linux/msi.h | 12 ++++
include/linux/vfio.h | 6 +-
7 files changed, 202 insertions(+), 1 deletion(-)
--
2.4.4
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] vfio: Introduce map and unmap operations
2015-11-24 7:48 [PATCH 0/3] Introduce MSI hardware mapping for VFIO Pavel Fedin
@ 2015-11-24 7:48 ` Pavel Fedin
2015-11-24 7:48 ` [PATCH 2/3] gicv3, its: Introduce VFIO " Pavel Fedin
2015-11-24 7:48 ` [PATCH 3/3] vfio: Introduce generic MSI mapping operations Pavel Fedin
2 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-11-24 7:48 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Marc Zyngier, Alex Williamson, Manish Jaggi, Thomas Gleixner,
Jason Cooper
These new functions allow direct mapping and unmapping of addresses on the
given IOMMU. They will be used for mapping MSI hardware.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
drivers/vfio/vfio_iommu_type1.c | 29 +++++++++++++++++++++++++++++
include/linux/vfio.h | 4 +++-
2 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 59d47cb..17506eb 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -558,6 +558,33 @@ unwind:
return ret;
}
+static int vfio_iommu_type1_map(void *iommu_data, dma_addr_t iova,
+ phys_addr_t paddr, long npage, int prot)
+{
+ struct vfio_iommu *iommu = iommu_data;
+ int ret;
+
+ mutex_lock(&iommu->lock);
+ ret = vfio_iommu_map(iommu, iova, paddr >> PAGE_SHIFT, npage, prot);
+ mutex_unlock(&iommu->lock);
+
+ return ret;
+}
+
+static void vfio_iommu_type1_unmap(void *iommu_data, dma_addr_t iova,
+ long npage)
+{
+ struct vfio_iommu *iommu = iommu_data;
+ struct vfio_domain *d;
+
+ mutex_lock(&iommu->lock);
+
+ list_for_each_entry_reverse(d, &iommu->domain_list, next)
+ iommu_unmap(d->domain, iova, npage << PAGE_SHIFT);
+
+ mutex_unlock(&iommu->lock);
+}
+
static int vfio_dma_do_map(struct vfio_iommu *iommu,
struct vfio_iommu_type1_dma_map *map)
{
@@ -1046,6 +1073,8 @@ static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
.ioctl = vfio_iommu_type1_ioctl,
.attach_group = vfio_iommu_type1_attach_group,
.detach_group = vfio_iommu_type1_detach_group,
+ .map = vfio_iommu_type1_map,
+ .unmap = vfio_iommu_type1_unmap,
};
static int __init vfio_iommu_type1_init(void)
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 610a86a..061038a 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -75,7 +75,9 @@ struct vfio_iommu_driver_ops {
struct iommu_group *group);
void (*detach_group)(void *iommu_data,
struct iommu_group *group);
-
+ int (*map)(void *iommu_data, dma_addr_t iova,
+ phys_addr_t paddr, long npage, int prot);
+ void (*unmap)(void *iommu_data, dma_addr_t iova, long npage);
};
extern int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops);
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] gicv3, its: Introduce VFIO map and unmap operations
2015-11-24 7:48 [PATCH 0/3] Introduce MSI hardware mapping for VFIO Pavel Fedin
2015-11-24 7:48 ` [PATCH 1/3] vfio: Introduce map and unmap operations Pavel Fedin
@ 2015-11-24 7:48 ` Pavel Fedin
2015-11-24 7:48 ` [PATCH 3/3] vfio: Introduce generic MSI mapping operations Pavel Fedin
2 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-11-24 7:48 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Marc Zyngier, Alex Williamson, Manish Jaggi, Thomas Gleixner,
Jason Cooper
These new functions use the supplied IOMMU in order to map and unmap MSI
translation register(s).
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
drivers/irqchip/irq-gic-v3-its.c | 31 +++++++++++++++++++++++++++++++
include/linux/irqchip/arm-gic-v3.h | 2 ++
include/linux/msi.h | 12 ++++++++++++
3 files changed, 45 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index e23d1d1..b97dfd7 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -29,6 +29,7 @@
#include <linux/of_platform.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/vfio.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
@@ -1257,8 +1258,38 @@ out:
return 0;
}
+#if IS_ENABLED(CONFIG_VFIO)
+
+static int its_vfio_map(struct irq_domain *domain,
+ const struct vfio_iommu_driver_ops *ops,
+ void *iommu_data)
+{
+ struct msi_domain_info *msi_info = msi_get_domain_info(domain);
+ struct its_node *its = msi_info->data;
+ u64 addr = its->phys_base + GIC_V3_ITS_CONTROL_SIZE;
+
+ return ops->map(iommu_data, addr, addr, 1, IOMMU_READ|IOMMU_WRITE);
+}
+
+static void its_vfio_unmap(struct irq_domain *domain,
+ const struct vfio_iommu_driver_ops *ops,
+ void *iommu_data)
+{
+ struct msi_domain_info *msi_info = msi_get_domain_info(domain);
+ struct its_node *its = msi_info->data;
+ u64 addr = its->phys_base + GIC_V3_ITS_CONTROL_SIZE;
+
+ ops->unmap(iommu_data, addr, 1);
+}
+
+#endif
+
static struct msi_domain_ops its_msi_domain_ops = {
.msi_prepare = its_msi_prepare,
+#if IS_ENABLED(CONFIG_VFIO)
+ .vfio_map = its_vfio_map,
+ .vfio_unmap = its_vfio_unmap,
+#endif
};
static int its_irq_gic_domain_alloc(struct irq_domain *domain,
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c9ae0c6..95388a7 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -240,6 +240,8 @@
#define GITS_BASER_TYPE_RESERVED6 6
#define GITS_BASER_TYPE_RESERVED7 7
+#define GIC_V3_ITS_CONTROL_SIZE 0x10000
+
/*
* ITS commands
*/
diff --git a/include/linux/msi.h b/include/linux/msi.h
index f71a25e..48faea9 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -155,6 +155,8 @@ void arch_restore_msi_irqs(struct pci_dev *dev);
void default_teardown_msi_irqs(struct pci_dev *dev);
void default_restore_msi_irqs(struct pci_dev *dev);
+struct vfio_iommu_driver_ops;
+
struct msi_controller {
struct module *owner;
struct device *dev;
@@ -189,6 +191,8 @@ struct msi_domain_info;
* @msi_finish: Optional callbacl to finalize the allocation
* @set_desc: Set the msi descriptor for an interrupt
* @handle_error: Optional error handler if the allocation fails
+ * @vfio_map: Map the MSI hardware for VFIO
+ * @vfio_unmap: Unmap the MSI hardware for VFIO
*
* @get_hwirq, @msi_init and @msi_free are callbacks used by
* msi_create_irq_domain() and related interfaces
@@ -218,6 +222,14 @@ struct msi_domain_ops {
struct msi_desc *desc);
int (*handle_error)(struct irq_domain *domain,
struct msi_desc *desc, int error);
+#if IS_ENABLED(CONFIG_VFIO)
+ int (*vfio_map)(struct irq_domain *domain,
+ const struct vfio_iommu_driver_ops *ops,
+ void *iommu_data);
+ void (*vfio_unmap)(struct irq_domain *domain,
+ const struct vfio_iommu_driver_ops *ops,
+ void *iommu_data);
+#endif
};
/**
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] vfio: Introduce generic MSI mapping operations
2015-11-24 7:48 [PATCH 0/3] Introduce MSI hardware mapping for VFIO Pavel Fedin
2015-11-24 7:48 ` [PATCH 1/3] vfio: Introduce map and unmap operations Pavel Fedin
2015-11-24 7:48 ` [PATCH 2/3] gicv3, its: Introduce VFIO " Pavel Fedin
@ 2015-11-24 7:48 ` Pavel Fedin
2015-11-24 12:42 ` kbuild test robot
2 siblings, 1 reply; 5+ messages in thread
From: Pavel Fedin @ 2015-11-24 7:48 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Marc Zyngier, Alex Williamson, Manish Jaggi, Thomas Gleixner,
Jason Cooper
These operations are used in order to map and unmap MSI translation
registers for the device, allowing it to send MSIs to the host while being
mapped via IOMMU.
Usage of MSI controllers is tracked on a per-device basis using reference
counting. An MSI controller remains mapped as long as there's at least one
device referring to it using MSI.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
drivers/vfio/pci/vfio_pci_intrs.c | 11 ++++
drivers/vfio/vfio.c | 112 ++++++++++++++++++++++++++++++++++++++
include/linux/vfio.h | 2 +
3 files changed, 125 insertions(+)
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 3b3ba15..3c8be59 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -259,12 +259,19 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
if (!vdev->ctx)
return -ENOMEM;
+ ret = vfio_device_map_msi(&pdev->dev);
+ if (ret) {
+ kfree(vdev->ctx);
+ return ret;
+ }
+
if (msix) {
int i;
vdev->msix = kzalloc(nvec * sizeof(struct msix_entry),
GFP_KERNEL);
if (!vdev->msix) {
+ vfio_device_unmap_msi(&pdev->dev);
kfree(vdev->ctx);
return -ENOMEM;
}
@@ -277,6 +284,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
if (ret > 0)
pci_disable_msix(pdev);
kfree(vdev->msix);
+ vfio_device_unmap_msi(&pdev->dev);
kfree(vdev->ctx);
return ret;
}
@@ -285,6 +293,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
if (ret < nvec) {
if (ret > 0)
pci_disable_msi(pdev);
+ vfio_device_unmap_msi(&pdev->dev);
kfree(vdev->ctx);
return ret;
}
@@ -413,6 +422,8 @@ static void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix)
} else
pci_disable_msi(pdev);
+ vfio_device_unmap_msi(&pdev->dev);
+
vdev->irq_type = VFIO_PCI_NUM_IRQS;
vdev->num_ctx = 0;
kfree(vdev->ctx);
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index de632da..09de246 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -21,9 +21,11 @@
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/iommu.h>
+#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
+#include <linux/msi.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/rwsem.h>
@@ -63,6 +65,8 @@ struct vfio_container {
struct vfio_iommu_driver *iommu_driver;
void *iommu_data;
bool noiommu;
+ struct list_head msi_list;
+ struct mutex msi_lock;
};
struct vfio_unbound_dev {
@@ -97,6 +101,13 @@ struct vfio_device {
void *device_data;
};
+struct vfio_msi {
+ struct kref kref;
+ struct list_head msi_next;
+ struct vfio_container *container;
+ struct irq_domain *domain;
+};
+
#ifdef CONFIG_VFIO_NOIOMMU
static bool noiommu __read_mostly;
module_param_named(enable_unsafe_noiommu_support,
@@ -882,6 +893,105 @@ void *vfio_device_data(struct vfio_device *device)
}
EXPORT_SYMBOL_GPL(vfio_device_data);
+int vfio_device_map_msi(struct device *dev)
+{
+ struct irq_domain *msi_domain = dev_get_msi_domain(dev);
+ struct msi_domain_info *info;
+ struct vfio_device *device;
+ struct vfio_container *container;
+ struct vfio_msi *vmsi;
+ int ret;
+
+ if (!msi_domain)
+ return 0;
+ info = msi_domain->host_data;
+ if (!info->ops->vfio_map)
+ return 0;
+
+ device = dev_get_drvdata(dev);
+ container = device->group->container;
+
+ if (!container->iommu_driver->ops->map)
+ return -EINVAL;
+
+ mutex_lock(&container->msi_lock);
+
+ list_for_each_entry(vmsi, &container->msi_list, msi_next) {
+ if (vmsi->domain == msi_domain) {
+ kref_get(&vmsi->kref);
+ mutex_unlock(&container->msi_lock);
+ return 0;
+ }
+ }
+
+ vmsi = kmalloc(sizeof(*vmsi), GFP_KERNEL);
+ if (!vmsi) {
+ mutex_unlock(&container->msi_lock);
+ return -ENOMEM;
+ }
+
+ ret = info->ops->vfio_map(msi_domain, container->iommu_driver->ops,
+ container->iommu_data);
+ if (ret) {
+ mutex_unlock(&container->msi_lock);
+ kfree(vmsi);
+ return ret;
+ }
+
+ kref_init(&vmsi->kref);
+ vmsi->container = container;
+ vmsi->domain = msi_domain;
+ list_add(&vmsi->msi_next, &container->msi_list);
+
+ mutex_unlock(&container->msi_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(vfio_device_map_msi);
+
+static void msi_release(struct kref *kref)
+{
+ struct vfio_msi *vmsi = container_of(kref, struct vfio_msi, kref);
+ struct vfio_container *container = vmsi->container;
+ struct msi_domain_info *info = vmsi->domain->host_data;
+
+ info->ops->vfio_unmap(vmsi->domain, container->iommu_driver->ops,
+ container->iommu_data);
+
+ list_del(&vmsi->msi_next);
+ kfree(vmsi);
+}
+
+void vfio_device_unmap_msi(struct device *dev)
+{
+ struct irq_domain *msi_domain = dev_get_msi_domain(dev);
+ struct msi_domain_info *info;
+ struct vfio_device *device;
+ struct vfio_container *container;
+ struct vfio_msi *vmsi;
+
+ if (!msi_domain)
+ return;
+ info = msi_domain->host_data;
+ if (!info->ops->vfio_unmap)
+ return;
+
+ device = dev_get_drvdata(dev);
+ container = device->group->container;
+
+ mutex_lock(&container->msi_lock);
+
+ list_for_each_entry(vmsi, &container->msi_list, msi_next) {
+ if (vmsi->domain == msi_domain) {
+ kref_put(&vmsi->kref, msi_release);
+ break;
+ }
+ }
+
+ mutex_unlock(&container->msi_lock);
+}
+EXPORT_SYMBOL(vfio_device_unmap_msi);
+
/* Given a referenced group, check if it contains the device */
static bool vfio_dev_present(struct vfio_group *group, struct device *dev)
{
@@ -1170,6 +1280,8 @@ static int vfio_fops_open(struct inode *inode, struct file *filep)
INIT_LIST_HEAD(&container->group_list);
init_rwsem(&container->group_lock);
+ INIT_LIST_HEAD(&container->msi_list);
+ mutex_init(&container->msi_lock);
kref_init(&container->kref);
filep->private_data = container;
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 061038a..faa3dbc 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -93,6 +93,8 @@ extern void vfio_group_put_external_user(struct vfio_group *group);
extern int vfio_external_user_iommu_id(struct vfio_group *group);
extern long vfio_external_check_extension(struct vfio_group *group,
unsigned long arg);
+int vfio_device_map_msi(struct device *dev);
+void vfio_device_unmap_msi(struct device *dev);
struct pci_dev;
#ifdef CONFIG_EEH
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 3/3] vfio: Introduce generic MSI mapping operations
2015-11-24 7:48 ` [PATCH 3/3] vfio: Introduce generic MSI mapping operations Pavel Fedin
@ 2015-11-24 12:42 ` kbuild test robot
0 siblings, 0 replies; 5+ messages in thread
From: kbuild test robot @ 2015-11-24 12:42 UTC (permalink / raw)
To: Pavel Fedin
Cc: Jason Cooper, kvm, Manish Jaggi, Marc Zyngier, Alex Williamson,
kbuild-all, Thomas Gleixner, kvmarm
[-- Attachment #1: Type: text/plain, Size: 1652 bytes --]
Hi Pavel,
[auto build test ERROR on tip/irq/core]
[also build test ERROR on v4.4-rc2 next-20151124]
url: https://github.com/0day-ci/linux/commits/Pavel-Fedin/Introduce-MSI-hardware-mapping-for-VFIO/20151124-155050
config: powerpc-allmodconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=powerpc
All errors (new ones prefixed by >>):
drivers/vfio/vfio.c: In function 'vfio_device_map_msi':
>> drivers/vfio/vfio.c:908:11: error: dereferencing pointer to incomplete type 'struct msi_domain_info'
if (!info->ops->vfio_map)
^
drivers/vfio/vfio.c: In function 'msi_release':
drivers/vfio/vfio.c:958:6: error: dereferencing pointer to incomplete type 'struct msi_domain_info'
info->ops->vfio_unmap(vmsi->domain, container->iommu_driver->ops,
^
drivers/vfio/vfio.c: In function 'vfio_device_unmap_msi':
drivers/vfio/vfio.c:976:11: error: dereferencing pointer to incomplete type 'struct msi_domain_info'
if (!info->ops->vfio_unmap)
^
vim +908 drivers/vfio/vfio.c
902 struct vfio_msi *vmsi;
903 int ret;
904
905 if (!msi_domain)
906 return 0;
907 info = msi_domain->host_data;
> 908 if (!info->ops->vfio_map)
909 return 0;
910
911 device = dev_get_drvdata(dev);
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 46895 bytes --]
[-- Attachment #3: Type: text/plain, Size: 151 bytes --]
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-11-24 12:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-24 7:48 [PATCH 0/3] Introduce MSI hardware mapping for VFIO Pavel Fedin
2015-11-24 7:48 ` [PATCH 1/3] vfio: Introduce map and unmap operations Pavel Fedin
2015-11-24 7:48 ` [PATCH 2/3] gicv3, its: Introduce VFIO " Pavel Fedin
2015-11-24 7:48 ` [PATCH 3/3] vfio: Introduce generic MSI mapping operations Pavel Fedin
2015-11-24 12:42 ` kbuild test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.