From: Dave Jiang <dave.jiang@intel.com>
To: alex.williamson@redhat.com, kwankhede@nvidia.com,
tglx@linutronix.de, vkoul@kernel.org, jgg@mellanox.com
Cc: Jason Gunthorpe <jgg@nvidia.com>,
megha.dey@intel.com, jacob.jun.pan@intel.com,
ashok.raj@intel.com, yi.l.liu@intel.com, baolu.lu@intel.com,
kevin.tian@intel.com, sanjay.k.kumar@intel.com,
tony.luck@intel.com, dan.j.williams@intel.com,
eric.auger@redhat.com, pbonzini@redhat.com,
dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org,
kvm@vger.kernel.org
Subject: [PATCH v6 05/20] vfio: mdev: common lib code for setting up Interrupt Message Store
Date: Fri, 21 May 2021 17:19:36 -0700 [thread overview]
Message-ID: <162164277624.261970.7989190254803052804.stgit@djiang5-desk3.ch.intel.com> (raw)
In-Reply-To: <162164243591.261970.3439987543338120797.stgit@djiang5-desk3.ch.intel.com>
Add common helper code to setup IMS once the MSI domain has been
setup by the device driver. The main helper function is
mdev_ims_set_msix_trigger() that is called by the VFIO ioctl
VFIO_DEVICE_SET_IRQS. The function deals with the setup and
teardown of emulated and IMS backed eventfd that gets exported
to the guest kernel via VFIO as MSIX vectors.
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/vfio/mdev/Kconfig | 12 ++
drivers/vfio/mdev/Makefile | 3
drivers/vfio/mdev/mdev_irqs.c | 318 +++++++++++++++++++++++++++++++++++++++++
include/linux/mdev.h | 51 +++++++
4 files changed, 384 insertions(+)
create mode 100644 drivers/vfio/mdev/mdev_irqs.c
diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig
index 763c877a1318..82f79d99a7db 100644
--- a/drivers/vfio/mdev/Kconfig
+++ b/drivers/vfio/mdev/Kconfig
@@ -9,3 +9,15 @@ config VFIO_MDEV
See Documentation/driver-api/vfio-mediated-device.rst for more details.
If you don't know what do here, say N.
+
+config VFIO_MDEV_IRQS
+ bool "Mediated device driver common lib code for interrupts"
+ depends on VFIO_MDEV
+ select IMS_MSI_ARRAY
+ select IRQ_BYPASS_MANAGER
+ default n
+ help
+ Provide common library code to deal with IMS interrupts for mediated
+ devices.
+
+ If you don't know what to do here, say N.
diff --git a/drivers/vfio/mdev/Makefile b/drivers/vfio/mdev/Makefile
index 7c236ba1b90e..c3f160cae192 100644
--- a/drivers/vfio/mdev/Makefile
+++ b/drivers/vfio/mdev/Makefile
@@ -2,4 +2,7 @@
mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
+mdev-$(CONFIG_VFIO_MDEV_IRQS) += mdev_irqs.o
+
obj-$(CONFIG_VFIO_MDEV) += mdev.o
+
diff --git a/drivers/vfio/mdev/mdev_irqs.c b/drivers/vfio/mdev/mdev_irqs.c
new file mode 100644
index 000000000000..ed2d11a7c729
--- /dev/null
+++ b/drivers/vfio/mdev/mdev_irqs.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Mediate device IMS library code
+ *
+ * Copyright (c) 2021 Intel Corp. All rights reserved.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/irq-ims-msi.h>
+#include <linux/eventfd.h>
+#include <linux/irqreturn.h>
+#include <linux/msi.h>
+#include <linux/vfio.h>
+#include <linux/irqbypass.h>
+#include <linux/mdev.h>
+
+static irqreturn_t mdev_irq_handler(int irq, void *arg)
+{
+ struct eventfd_ctx *trigger = arg;
+
+ eventfd_signal(trigger, 1);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Common helper routine to send signal to the eventfd that has been setup.
+ *
+ * @mdev_irq [in] : struct mdev_irq context
+ * @vector [in] : vector index for eventfd
+ *
+ * No return value.
+ */
+void mdev_msix_send_signal(struct mdev_device *mdev, int vector)
+{
+ struct mdev_irq *mdev_irq = &mdev->mdev_irq;
+ struct eventfd_ctx *trigger = mdev_irq->irq_entries[vector].trigger;
+
+ if (!mdev_irq->irq_entries || !trigger) {
+ dev_warn(&mdev->dev, "EventFD %d trigger not setup, can't send!\n", vector);
+ return;
+ }
+ mdev_irq_handler(0, (void *)trigger);
+}
+EXPORT_SYMBOL_GPL(mdev_msix_send_signal);
+
+static int mdev_msix_set_vector_signal(struct mdev_irq *mdev_irq, int vector, int fd)
+{
+ int rc, irq;
+ struct mdev_device *mdev = irq_to_mdev(mdev_irq);
+ struct mdev_irq_entry *entry;
+ struct device *dev = &mdev->dev;
+ struct eventfd_ctx *trigger;
+ char *name;
+ bool pasid_en;
+ u32 auxval;
+
+ if (vector < 0 || vector >= mdev_irq->num)
+ return -EINVAL;
+
+ entry = &mdev_irq->irq_entries[vector];
+
+ if (entry->ims)
+ irq = dev_msi_irq_vector(dev, entry->ims_id);
+ else
+ irq = 0;
+
+ pasid_en = mdev_irq->pasid != INVALID_IOASID ? true : false;
+
+ /* IMS and invalid pasid is not a valid configuration */
+ if (entry->ims && !pasid_en)
+ return -EINVAL;
+
+ if (entry->trigger) {
+ if (irq) {
+ irq_bypass_unregister_producer(&entry->producer);
+ free_irq(irq, entry->trigger);
+ if (pasid_en) {
+ auxval = ims_ctrl_pasid_aux(0, false);
+ irq_set_auxdata(irq, IMS_AUXDATA_CONTROL_WORD, auxval);
+ }
+ }
+ kfree(entry->name);
+ eventfd_ctx_put(entry->trigger);
+ entry->trigger = NULL;
+ }
+
+ if (fd < 0)
+ return 0;
+
+ name = kasprintf(GFP_KERNEL, "vfio-mdev-irq[%d](%s)", vector, dev_name(dev));
+ if (!name)
+ return -ENOMEM;
+
+ trigger = eventfd_ctx_fdget(fd);
+ if (IS_ERR(trigger)) {
+ kfree(name);
+ return PTR_ERR(trigger);
+ }
+
+ entry->name = name;
+ entry->trigger = trigger;
+
+ if (!irq)
+ return 0;
+
+ if (pasid_en) {
+ auxval = ims_ctrl_pasid_aux(mdev_irq->pasid, true);
+ rc = irq_set_auxdata(irq, IMS_AUXDATA_CONTROL_WORD, auxval);
+ if (rc < 0)
+ goto err;
+ }
+
+ rc = request_irq(irq, mdev_irq_handler, 0, name, trigger);
+ if (rc < 0)
+ goto irq_err;
+
+ entry->producer.token = trigger;
+ entry->producer.irq = irq;
+ rc = irq_bypass_register_producer(&entry->producer);
+ if (unlikely(rc)) {
+ dev_warn(dev, "irq bypass producer (token %p) registration fails: %d\n",
+ &entry->producer.token, rc);
+ entry->producer.token = NULL;
+ }
+
+ return 0;
+
+ irq_err:
+ if (pasid_en) {
+ auxval = ims_ctrl_pasid_aux(0, false);
+ irq_set_auxdata(irq, IMS_AUXDATA_CONTROL_WORD, auxval);
+ }
+ err:
+ kfree(name);
+ eventfd_ctx_put(trigger);
+ entry->trigger = NULL;
+ return rc;
+}
+
+static int mdev_msix_set_vector_signals(struct mdev_irq *mdev_irq, unsigned int start,
+ unsigned int count, int *fds)
+{
+ int i, j, rc = 0;
+
+ if (start >= mdev_irq->num || start + count > mdev_irq->num)
+ return -EINVAL;
+
+ for (i = 0, j = start; j < count && !rc; i++, j++) {
+ int fd = fds ? fds[i] : -1;
+
+ rc = mdev_msix_set_vector_signal(mdev_irq, j, fd);
+ }
+
+ if (rc) {
+ for (--j; j >= (int)start; j--)
+ mdev_msix_set_vector_signal(mdev_irq, j, -1);
+ }
+
+ return rc;
+}
+
+static int mdev_msix_enable(struct mdev_irq *mdev_irq, int nvec)
+{
+ struct mdev_device *mdev = irq_to_mdev(mdev_irq);
+ struct device *dev;
+ int rc;
+
+ if (nvec != mdev_irq->num)
+ return -EINVAL;
+
+ if (mdev_irq->ims_num) {
+ dev = &mdev->dev;
+ rc = msi_domain_alloc_irqs(dev_get_msi_domain(dev), dev, mdev_irq->ims_num);
+ if (rc < 0)
+ return rc;
+ }
+
+ mdev_irq->irq_type = VFIO_PCI_MSIX_IRQ_INDEX;
+ return 0;
+}
+
+static int mdev_msix_disable(struct mdev_irq *mdev_irq)
+{
+ struct mdev_device *mdev = irq_to_mdev(mdev_irq);
+ struct device *dev = &mdev->dev;
+ struct irq_domain *irq_domain;
+
+ mdev_msix_set_vector_signals(mdev_irq, 0, mdev_irq->num, NULL);
+ irq_domain = dev_get_msi_domain(&mdev->dev);
+ if (irq_domain)
+ msi_domain_free_irqs(irq_domain, dev);
+ mdev_irq->irq_type = VFIO_PCI_NUM_IRQS;
+ return 0;
+}
+
+/*
+ * Common helper function that sets up the MSIX vectors for the mdev device that are
+ * Interrupt Message Store (IMS) backed. Certain mdev devices can have the first
+ * vector emulated rather than backed by IMS.
+ *
+ * @mdev [in] : mdev device
+ * @index [in] : type of VFIO vectors to setup
+ * @start [in] : start position of the vector index
+ * @count [in] : number of vectors
+ * @flags [in] : VFIO_IRQ action to be taken
+ * @data [in] : data accompanied for the call
+ * Return error code on failure or 0 on success.
+ */
+
+int mdev_set_msix_trigger(struct mdev_device *mdev, unsigned int index,
+ unsigned int start, unsigned int count, u32 flags,
+ void *data)
+{
+ struct mdev_irq *mdev_irq = &mdev->mdev_irq;
+ int i, rc = 0;
+
+ if (count > mdev_irq->num)
+ count = mdev_irq->num;
+
+ if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
+ mdev_msix_disable(mdev_irq);
+ return 0;
+ }
+
+ if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+ int *fds = data;
+
+ if (mdev_irq->irq_type == index)
+ return mdev_msix_set_vector_signals(mdev_irq, start, count, fds);
+
+ rc = mdev_msix_enable(mdev_irq, start + count);
+ if (rc < 0)
+ return rc;
+
+ rc = mdev_msix_set_vector_signals(mdev_irq, start, count, fds);
+ if (rc < 0)
+ mdev_msix_disable(mdev_irq);
+
+ return rc;
+ }
+
+ if (start + count > mdev_irq->num)
+ return -EINVAL;
+
+ for (i = start; i < start + count; i++) {
+ if (!mdev_irq->irq_entries[i].trigger)
+ continue;
+ if (flags & VFIO_IRQ_SET_DATA_NONE) {
+ eventfd_signal(mdev_irq->irq_entries[i].trigger, 1);
+ } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+ u8 *bools = data;
+
+ if (bools[i - start])
+ eventfd_signal(mdev_irq->irq_entries[i].trigger, 1);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mdev_set_msix_trigger);
+
+void mdev_irqs_set_pasid(struct mdev_device *mdev, u32 pasid)
+{
+ mdev->mdev_irq.pasid = pasid;
+}
+EXPORT_SYMBOL_GPL(mdev_irqs_set_pasid);
+
+/*
+ * Initialize and setup the mdev_irq context under mdev.
+ *
+ * @mdev [in] : mdev device
+ * @num [in] : number of vectors
+ * @ims_map [in] : bool array that indicates whether a guest MSIX vector is
+ * backed by an IMS vector or emulated
+ * Return error code on failure or 0 on success.
+ */
+int mdev_irqs_init(struct mdev_device *mdev, int num, bool *ims_map)
+{
+ struct mdev_irq *mdev_irq = &mdev->mdev_irq;
+ int i;
+
+ if (num < 1)
+ return -EINVAL;
+
+ mdev_irq->irq_type = VFIO_PCI_NUM_IRQS;
+ mdev_irq->num = num;
+ mdev_irq->pasid = INVALID_IOASID;
+
+ mdev_irq->irq_entries = kcalloc(num, sizeof(*mdev_irq->irq_entries), GFP_KERNEL);
+ if (!mdev_irq->irq_entries)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++) {
+ mdev_irq->irq_entries[i].ims = ims_map[i];
+ if (ims_map[i]) {
+ mdev_irq->irq_entries[i].ims_id = mdev_irq->ims_num;
+ mdev_irq->ims_num++;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mdev_irqs_init);
+
+/*
+ * Free allocated memory in mdev_irq
+ *
+ * @mdev [in] : mdev device
+ */
+void mdev_irqs_free(struct mdev_device *mdev)
+{
+ kfree(mdev->mdev_irq.irq_entries);
+ memset(&mdev->mdev_irq, 0, sizeof(mdev->mdev_irq));
+}
+EXPORT_SYMBOL_GPL(mdev_irqs_free);
diff --git a/include/linux/mdev.h b/include/linux/mdev.h
index 0cd8db2d3422..035c021e8068 100644
--- a/include/linux/mdev.h
+++ b/include/linux/mdev.h
@@ -10,8 +10,26 @@
#ifndef MDEV_H
#define MDEV_H
+#include <linux/irqbypass.h>
+
struct mdev_type;
+struct mdev_irq_entry {
+ struct eventfd_ctx *trigger;
+ struct irq_bypass_producer producer;
+ char *name;
+ bool ims;
+ int ims_id;
+};
+
+struct mdev_irq {
+ struct mdev_irq_entry *irq_entries;
+ int num;
+ int ims_num;
+ int irq_type;
+ int pasid;
+};
+
struct mdev_device {
struct device dev;
guid_t uuid;
@@ -19,8 +37,14 @@ struct mdev_device {
struct mdev_type *type;
struct device *iommu_device;
struct mutex creation_lock;
+ struct mdev_irq mdev_irq;
};
+static inline struct mdev_device *irq_to_mdev(struct mdev_irq *mdev_irq)
+{
+ return container_of(mdev_irq, struct mdev_device, mdev_irq);
+}
+
static inline struct mdev_device *to_mdev_device(struct device *dev)
{
return container_of(dev, struct mdev_device, dev);
@@ -99,4 +123,31 @@ static inline struct mdev_device *mdev_from_dev(struct device *dev)
return dev->bus == &mdev_bus_type ? to_mdev_device(dev) : NULL;
}
+#if IS_ENABLED(CONFIG_VFIO_MDEV_IRQS)
+int mdev_set_msix_trigger(struct mdev_device *mdev, unsigned int index,
+ unsigned int start, unsigned int count, u32 flags,
+ void *data);
+void mdev_msix_send_signal(struct mdev_device *mdev, int vector);
+int mdev_irqs_init(struct mdev_device *mdev, int num, bool *ims_map);
+void mdev_irqs_free(struct mdev_device *mdev);
+void mdev_irqs_set_pasid(struct mdev_device *mdev, u32 pasid);
+#else
+static inline int mdev_set_msix_trigger(struct mdev_device *mdev, unsigned int index,
+ unsigned int start, unsigned int count, u32 flags,
+ void *data)
+{
+ return -EOPNOTSUPP;
+}
+
+void mdev_msix_send_signal(struct mdev_device *mdev, int vector) {}
+
+static inline int mdev_irqs_init(struct mdev_device *mdev, int num, bool *ims_map)
+{
+ return -EOPNOTSUPP;
+}
+
+void mdev_irqs_free(struct mdev_device *mdev) {}
+void mdev_irqs_set_pasid(struct mdev_device *mdev, u32 pasid) {}
+#endif /* CONFIG_VFIO_MDEV_IMS */
+
#endif /* MDEV_H */
next prev parent reply other threads:[~2021-05-22 0:19 UTC|newest]
Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-22 0:19 [PATCH v6 00/20] Add VFIO mediated device support and DEV-MSI support for the idxd driver Dave Jiang
2021-05-22 0:19 ` [PATCH v6 01/20] vfio/mdev: idxd: add theory of operation documentation for idxd mdev Dave Jiang
2021-05-22 0:19 ` [PATCH v6 02/20] dmaengine: idxd: add external module driver support for dsa_bus_type Dave Jiang
2021-05-22 0:19 ` [PATCH v6 03/20] dmaengine: idxd: add IMS offset and size retrieval code Dave Jiang
2021-05-22 0:19 ` [PATCH v6 04/20] dmaengine: idxd: add portal offset for IMS portals Dave Jiang
2021-05-22 0:19 ` Dave Jiang [this message]
2021-05-24 0:02 ` [PATCH v6 05/20] vfio: mdev: common lib code for setting up Interrupt Message Store Jason Gunthorpe
2021-05-28 1:49 ` Dave Jiang
2021-05-28 12:21 ` Jason Gunthorpe
2021-05-28 16:37 ` Dave Jiang
2021-05-28 16:39 ` Jason Gunthorpe
2021-05-31 10:41 ` Thomas Gleixner
2021-05-31 13:48 ` Thomas Gleixner
2021-05-31 15:24 ` Jason Gunthorpe
2021-06-08 15:57 ` Dave Jiang
2021-06-08 17:22 ` Jason Gunthorpe
2021-06-10 13:00 ` Thomas Gleixner
2021-05-22 0:19 ` [PATCH v6 06/20] vfio/mdev: idxd: add PCI config for read/write for mdev Dave Jiang
2021-05-22 0:19 ` [PATCH v6 07/20] vfio/mdev: idxd: Add administrative commands emulation " Dave Jiang
2021-05-22 0:19 ` [PATCH v6 08/20] vfio/mdev: idxd: Add mdev device context initialization Dave Jiang
2021-05-22 0:20 ` [PATCH v6 09/20] vfio/mdev: Add mmio read/write support for mdev Dave Jiang
2021-05-22 0:20 ` [PATCH v6 10/20] vfio/mdev: idxd: add mdev type as a new wq type Dave Jiang
2021-05-22 0:20 ` [PATCH v6 11/20] vfio/mdev: idxd: Add basic driver setup for idxd mdev Dave Jiang
2021-05-23 23:27 ` Jason Gunthorpe
2021-05-23 23:52 ` Jason Gunthorpe
2021-05-22 0:20 ` [PATCH v6 12/20] vfio: move VFIO PCI macros to common header Dave Jiang
2021-06-04 3:47 ` Alex Williamson
2021-05-22 0:20 ` [PATCH v6 13/20] vfio/mdev: idxd: add mdev driver registration and helper functions Dave Jiang
2021-05-23 23:32 ` Jason Gunthorpe
2021-05-23 23:46 ` Jason Gunthorpe
2021-05-22 0:20 ` [PATCH v6 14/20] vfio/mdev: idxd: add 1dwq-v1 mdev type Dave Jiang
2021-05-23 23:47 ` Jason Gunthorpe
2021-05-22 0:20 ` [PATCH v6 15/20] vfio/mdev: idxd: ims domain setup for the vdcm Dave Jiang
2021-05-23 23:50 ` Jason Gunthorpe
2021-05-27 0:22 ` Dave Jiang
2021-05-27 0:54 ` Jason Gunthorpe
2021-05-27 1:15 ` Dave Jiang
2021-05-27 1:41 ` Raj, Ashok
2021-05-27 13:36 ` Jason Gunthorpe
2021-05-31 14:02 ` Thomas Gleixner
2021-05-31 16:57 ` Jason Gunthorpe
2021-05-31 23:55 ` Thomas Gleixner
2021-06-01 12:16 ` Jason Gunthorpe
2021-05-22 0:20 ` [PATCH v6 16/20] vfio/mdev: idxd: add new wq state for mdev Dave Jiang
2021-05-22 0:20 ` [PATCH v6 17/20] vfio/mdev: idxd: add error notification from host driver to mediated device Dave Jiang
2021-05-22 0:20 ` [PATCH v6 18/20] vfio: move vfio_pci_set_ctx_trigger_single to common code Dave Jiang
2021-05-22 0:21 ` [PATCH v6 19/20] vfio: mdev: Add device request interface Dave Jiang
2021-05-23 22:38 ` Jason Gunthorpe
2021-05-22 0:21 ` [PATCH v6 20/20] vfio: mdev: idxd: setup request interrupt Dave Jiang
2021-05-23 23:22 ` [PATCH v6 00/20] Add VFIO mediated device support and DEV-MSI support for the idxd driver Jason Gunthorpe
2021-06-02 15:40 ` Dave Jiang
2021-06-02 23:17 ` Jason Gunthorpe
2021-06-03 1:11 ` Tian, Kevin
2021-06-03 1:49 ` Jason Gunthorpe
2021-06-03 5:52 ` Tian, Kevin
2021-06-03 11:23 ` Jason Gunthorpe
2021-06-04 3:40 ` Alex Williamson
2021-06-07 6:22 ` Tian, Kevin
2021-06-07 18:13 ` Dave Jiang
2021-06-07 19:11 ` Jason Gunthorpe
2021-06-08 16:02 ` Dave Jiang
2021-06-11 18:21 ` Dave Jiang
2021-06-11 18:29 ` Jason Gunthorpe
2021-06-07 18:28 ` Jason Gunthorpe
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=162164277624.261970.7989190254803052804.stgit@djiang5-desk3.ch.intel.com \
--to=dave.jiang@intel.com \
--cc=alex.williamson@redhat.com \
--cc=ashok.raj@intel.com \
--cc=baolu.lu@intel.com \
--cc=dan.j.williams@intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=eric.auger@redhat.com \
--cc=jacob.jun.pan@intel.com \
--cc=jgg@mellanox.com \
--cc=jgg@nvidia.com \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=kwankhede@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=megha.dey@intel.com \
--cc=pbonzini@redhat.com \
--cc=sanjay.k.kumar@intel.com \
--cc=tglx@linutronix.de \
--cc=tony.luck@intel.com \
--cc=vkoul@kernel.org \
--cc=yi.l.liu@intel.com \
/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).