Skip to content

Commit

Permalink
Merge tag 'vfio-v6.10-rc1' of https://github.com/awilliam/linux-vfio
Browse files Browse the repository at this point in the history
Pull vfio updates from Alex Williamson:

 - The vfio fsl-mc bus driver has become orphaned. We'll consider
   removing it in future releases if a new maintainer isn't found (Alex
   Williamson)

 - Improved usage of opaque data in vfio-pci INTx handling, avoiding
   lookups of the eventfd through the interrupt and irqfd runtime paths
   (Alex Williamson)

 - Resolve an error path memory leak introduced in vfio-pci interrupt
   code (Ye Bin)

 - Addition of interrupt support for vfio devices exposed on the CDX
   bus, including a new MSI allocation helper and export of existing
   helpers for MSI alloc and free (Nipun Gupta)

 - A new vfio-pci variant driver supporting migration of Intel QAT VF
   devices for the GEN4 PFs (Xin Zeng & Yahui Cao)

 - Resolve a possibly circular locking dependency in vfio-pci by
   avoiding copy_to_user() from a PCI bus walk callback (Alex
   Williamson)

 - Trivial docs update to remove a duplicate semicolon (Foryun Ma)

* tag 'vfio-v6.10-rc1' of https://github.com/awilliam/linux-vfio:
  vfio/pci: Restore zero affected bus reset devices warning
  vfio: remove an extra semicolon
  vfio/pci: Collect hot-reset devices to local buffer
  vfio/qat: Add vfio_pci driver for Intel QAT SR-IOV VF devices
  vfio/cdx: add interrupt support
  genirq/msi: Add MSI allocation helper and export MSI functions
  vfio/pci: fix potential memory leak in vfio_intx_enable()
  vfio/pci: Pass eventfd context object through irqfd
  vfio/pci: Pass eventfd context to IRQ handler
  MAINTAINERS: Orphan vfio fsl-mc bus driver
  • Loading branch information
torvalds committed May 20, 2024
2 parents 70ec81c + cbb325e commit 30aec6e
Show file tree
Hide file tree
Showing 15 changed files with 1,116 additions and 68 deletions.
2 changes: 1 addition & 1 deletion Documentation/driver-api/vfio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ IOMMUFD IOAS/HWPT to enable userspace DMA::
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
map.iova = 0; /* 1MB starting at 0x0 from device view */
map.length = 1024 * 1024;
map.ioas_id = alloc_data.out_ioas_id;;
map.ioas_id = alloc_data.out_ioas_id;

ioctl(iommufd, IOMMU_IOAS_MAP, &map);

Expand Down
11 changes: 9 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -23512,9 +23512,8 @@ F: include/linux/vfio_pci_core.h
F: include/uapi/linux/vfio.h

VFIO FSL-MC DRIVER
M: Diana Craciun <[email protected]>
L: [email protected]
S: Maintained
S: Orphan
F: drivers/vfio/fsl-mc/

VFIO HISILICON PCI DRIVER
Expand Down Expand Up @@ -23568,6 +23567,14 @@ L: [email protected]
S: Maintained
F: drivers/vfio/platform/

VFIO QAT PCI DRIVER
M: Xin Zeng <[email protected]>
M: Giovanni Cabiddu <[email protected]>
L: [email protected]
L: [email protected]
S: Supported
F: drivers/vfio/pci/qat/

VFIO VIRTIO PCI DRIVER
M: Yishai Hadas <[email protected]>
L: [email protected]
Expand Down
2 changes: 1 addition & 1 deletion drivers/vfio/cdx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

obj-$(CONFIG_VFIO_CDX) += vfio-cdx.o

vfio-cdx-objs := main.o
vfio-cdx-objs := main.o intr.o
217 changes: 217 additions & 0 deletions drivers/vfio/cdx/intr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
*/

#include <linux/vfio.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/eventfd.h>
#include <linux/msi.h>
#include <linux/interrupt.h>

#include "linux/cdx/cdx_bus.h"
#include "private.h"

static irqreturn_t vfio_cdx_msihandler(int irq_no, void *arg)
{
struct eventfd_ctx *trigger = arg;

eventfd_signal(trigger);
return IRQ_HANDLED;
}

static int vfio_cdx_msi_enable(struct vfio_cdx_device *vdev, int nvec)
{
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
struct device *dev = vdev->vdev.dev;
int msi_idx, ret;

vdev->cdx_irqs = kcalloc(nvec, sizeof(struct vfio_cdx_irq), GFP_KERNEL);
if (!vdev->cdx_irqs)
return -ENOMEM;

ret = cdx_enable_msi(cdx_dev);
if (ret) {
kfree(vdev->cdx_irqs);
return ret;
}

/* Allocate cdx MSIs */
ret = msi_domain_alloc_irqs(dev, MSI_DEFAULT_DOMAIN, nvec);
if (ret) {
cdx_disable_msi(cdx_dev);
kfree(vdev->cdx_irqs);
return ret;
}

for (msi_idx = 0; msi_idx < nvec; msi_idx++)
vdev->cdx_irqs[msi_idx].irq_no = msi_get_virq(dev, msi_idx);

vdev->msi_count = nvec;
vdev->config_msi = 1;

return 0;
}

static int vfio_cdx_msi_set_vector_signal(struct vfio_cdx_device *vdev,
int vector, int fd)
{
struct eventfd_ctx *trigger;
int irq_no, ret;

if (vector < 0 || vector >= vdev->msi_count)
return -EINVAL;

irq_no = vdev->cdx_irqs[vector].irq_no;

if (vdev->cdx_irqs[vector].trigger) {
free_irq(irq_no, vdev->cdx_irqs[vector].trigger);
kfree(vdev->cdx_irqs[vector].name);
eventfd_ctx_put(vdev->cdx_irqs[vector].trigger);
vdev->cdx_irqs[vector].trigger = NULL;
}

if (fd < 0)
return 0;

vdev->cdx_irqs[vector].name = kasprintf(GFP_KERNEL, "vfio-msi[%d](%s)",
vector, dev_name(vdev->vdev.dev));
if (!vdev->cdx_irqs[vector].name)
return -ENOMEM;

trigger = eventfd_ctx_fdget(fd);
if (IS_ERR(trigger)) {
kfree(vdev->cdx_irqs[vector].name);
return PTR_ERR(trigger);
}

ret = request_irq(irq_no, vfio_cdx_msihandler, 0,
vdev->cdx_irqs[vector].name, trigger);
if (ret) {
kfree(vdev->cdx_irqs[vector].name);
eventfd_ctx_put(trigger);
return ret;
}

vdev->cdx_irqs[vector].trigger = trigger;

return 0;
}

static int vfio_cdx_msi_set_block(struct vfio_cdx_device *vdev,
unsigned int start, unsigned int count,
int32_t *fds)
{
int i, j, ret = 0;

if (start >= vdev->msi_count || start + count > vdev->msi_count)
return -EINVAL;

for (i = 0, j = start; i < count && !ret; i++, j++) {
int fd = fds ? fds[i] : -1;

ret = vfio_cdx_msi_set_vector_signal(vdev, j, fd);
}

if (ret) {
for (--j; j >= (int)start; j--)
vfio_cdx_msi_set_vector_signal(vdev, j, -1);
}

return ret;
}

static void vfio_cdx_msi_disable(struct vfio_cdx_device *vdev)
{
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
struct device *dev = vdev->vdev.dev;

vfio_cdx_msi_set_block(vdev, 0, vdev->msi_count, NULL);

if (!vdev->config_msi)
return;

msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
cdx_disable_msi(cdx_dev);
kfree(vdev->cdx_irqs);

vdev->cdx_irqs = NULL;
vdev->msi_count = 0;
vdev->config_msi = 0;
}

static int vfio_cdx_set_msi_trigger(struct vfio_cdx_device *vdev,
unsigned int index, unsigned int start,
unsigned int count, u32 flags,
void *data)
{
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
int i;

if (start + count > cdx_dev->num_msi)
return -EINVAL;

if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
vfio_cdx_msi_disable(vdev);
return 0;
}

if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
s32 *fds = data;
int ret;

if (vdev->config_msi)
return vfio_cdx_msi_set_block(vdev, start, count,
fds);
ret = vfio_cdx_msi_enable(vdev, cdx_dev->num_msi);
if (ret)
return ret;

ret = vfio_cdx_msi_set_block(vdev, start, count, fds);
if (ret)
vfio_cdx_msi_disable(vdev);

return ret;
}

for (i = start; i < start + count; i++) {
if (!vdev->cdx_irqs[i].trigger)
continue;
if (flags & VFIO_IRQ_SET_DATA_NONE) {
eventfd_signal(vdev->cdx_irqs[i].trigger);
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
u8 *bools = data;

if (bools[i - start])
eventfd_signal(vdev->cdx_irqs[i].trigger);
}
}

return 0;
}

int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev,
u32 flags, unsigned int index,
unsigned int start, unsigned int count,
void *data)
{
if (flags & VFIO_IRQ_SET_ACTION_TRIGGER)
return vfio_cdx_set_msi_trigger(vdev, index, start,
count, flags, data);
else
return -EINVAL;
}

/* Free All IRQs for the given device */
void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev)
{
/*
* Device does not support any interrupt or the interrupts
* were not configured
*/
if (!vdev->cdx_irqs)
return;

vfio_cdx_set_msi_trigger(vdev, 0, 0, 0, VFIO_IRQ_SET_DATA_NONE, NULL);
}
63 changes: 62 additions & 1 deletion drivers/vfio/cdx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static void vfio_cdx_close_device(struct vfio_device *core_vdev)

kfree(vdev->regions);
cdx_dev_reset(core_vdev->dev);
vfio_cdx_irqs_cleanup(vdev);
}

static int vfio_cdx_bm_ctrl(struct vfio_device *core_vdev, u32 flags,
Expand Down Expand Up @@ -123,7 +124,7 @@ static int vfio_cdx_ioctl_get_info(struct vfio_cdx_device *vdev,
info.flags |= VFIO_DEVICE_FLAGS_RESET;

info.num_regions = cdx_dev->res_count;
info.num_irqs = 0;
info.num_irqs = cdx_dev->num_msi ? 1 : 0;

return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
}
Expand Down Expand Up @@ -152,6 +153,62 @@ static int vfio_cdx_ioctl_get_region_info(struct vfio_cdx_device *vdev,
return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
}

static int vfio_cdx_ioctl_get_irq_info(struct vfio_cdx_device *vdev,
struct vfio_irq_info __user *arg)
{
unsigned long minsz = offsetofend(struct vfio_irq_info, count);
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
struct vfio_irq_info info;

if (copy_from_user(&info, arg, minsz))
return -EFAULT;

if (info.argsz < minsz)
return -EINVAL;

if (info.index >= 1)
return -EINVAL;

if (!cdx_dev->num_msi)
return -EINVAL;

info.flags = VFIO_IRQ_INFO_EVENTFD | VFIO_IRQ_INFO_NORESIZE;
info.count = cdx_dev->num_msi;

return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
}

static int vfio_cdx_ioctl_set_irqs(struct vfio_cdx_device *vdev,
struct vfio_irq_set __user *arg)
{
unsigned long minsz = offsetofend(struct vfio_irq_set, count);
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
struct vfio_irq_set hdr;
size_t data_size = 0;
u8 *data = NULL;
int ret = 0;

if (copy_from_user(&hdr, arg, minsz))
return -EFAULT;

ret = vfio_set_irqs_validate_and_prepare(&hdr, cdx_dev->num_msi,
1, &data_size);
if (ret)
return ret;

if (data_size) {
data = memdup_user(arg->data, data_size);
if (IS_ERR(data))
return PTR_ERR(data);
}

ret = vfio_cdx_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
hdr.start, hdr.count, data);
kfree(data);

return ret;
}

static long vfio_cdx_ioctl(struct vfio_device *core_vdev,
unsigned int cmd, unsigned long arg)
{
Expand All @@ -164,6 +221,10 @@ static long vfio_cdx_ioctl(struct vfio_device *core_vdev,
return vfio_cdx_ioctl_get_info(vdev, uarg);
case VFIO_DEVICE_GET_REGION_INFO:
return vfio_cdx_ioctl_get_region_info(vdev, uarg);
case VFIO_DEVICE_GET_IRQ_INFO:
return vfio_cdx_ioctl_get_irq_info(vdev, uarg);
case VFIO_DEVICE_SET_IRQS:
return vfio_cdx_ioctl_set_irqs(vdev, uarg);
case VFIO_DEVICE_RESET:
return cdx_dev_reset(core_vdev->dev);
default:
Expand Down
18 changes: 18 additions & 0 deletions drivers/vfio/cdx/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ static inline u64 vfio_cdx_index_to_offset(u32 index)
return ((u64)(index) << VFIO_CDX_OFFSET_SHIFT);
}

struct vfio_cdx_irq {
u32 flags;
u32 count;
int irq_no;
struct eventfd_ctx *trigger;
char *name;
};

struct vfio_cdx_region {
u32 flags;
u32 type;
Expand All @@ -23,8 +31,18 @@ struct vfio_cdx_region {
struct vfio_cdx_device {
struct vfio_device vdev;
struct vfio_cdx_region *regions;
struct vfio_cdx_irq *cdx_irqs;
u32 flags;
#define BME_SUPPORT BIT(0)
u32 msi_count;
u8 config_msi;
};

int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev,
u32 flags, unsigned int index,
unsigned int start, unsigned int count,
void *data);

void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev);

#endif /* VFIO_CDX_PRIVATE_H */
2 changes: 2 additions & 0 deletions drivers/vfio/pci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ source "drivers/vfio/pci/virtio/Kconfig"

source "drivers/vfio/pci/nvgrace-gpu/Kconfig"

source "drivers/vfio/pci/qat/Kconfig"

endmenu
2 changes: 2 additions & 0 deletions drivers/vfio/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ obj-$(CONFIG_PDS_VFIO_PCI) += pds/
obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio/

obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu/

obj-$(CONFIG_QAT_VFIO_PCI) += qat/
Loading

0 comments on commit 30aec6e

Please sign in to comment.