Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20150…
Browse files Browse the repository at this point in the history
…706.0' into staging

VFIO updates for 2.4-rc0
- "real" host page size API (Peter Crosthwaite)
- platform device irqfd support (Eric Auger)
- spapr container disconnect fix (Alexey Kardashevskiy)
- quirk for broken Chelsio hardware (Gabriel Laupre)
- coverity fix (Paolo Bonzini)

# gpg: Signature made Mon Jul  6 19:23:49 2015 BST using RSA key ID 3BB08B22
# gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>"
# gpg:                 aka "Alex Williamson <alex@shazbot.org>"
# gpg:                 aka "Alex Williamson <alwillia@redhat.com>"
# gpg:                 aka "Alex Williamson <alex.l.williamson@gmail.com>"

* remotes/awilliam/tags/vfio-update-20150706.0:
  vfio/pci : Add pba_offset PCI quirk for Chelsio T5 devices
  vfio: Unregister IOMMU notifiers when container is destroyed
  hw/vfio/platform: add irqfd support
  kvm: some fixes to kvm_resamplefds_allowed
  sysbus: add irq_routing_notifier
  intc: arm_gic_kvm: set the qemu_irq/gsi mapping
  kvm-all.c: add qemu_irq/gsi hash table and utility routines
  kvm: rename kvm_irqchip_[add,remove]_irqfd_notifier with gsi suffix
  vfio: cpu: Use "real" page size API
  cpu-all: complete "real" host page size API
  vfio: fix return type of pread

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Conflicts:
	kvm-all.c
  • Loading branch information
pm215 committed Jul 7, 2015
2 parents f6e3035 + 4330296 commit 1452673
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 21 deletions.
6 changes: 6 additions & 0 deletions hw/core/sysbus.c
Expand Up @@ -109,7 +109,13 @@ qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)

void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
{
SysBusDeviceClass *sbd = SYS_BUS_DEVICE_GET_CLASS(dev);

qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);

if (sbd->connect_irq_notifier) {
sbd->connect_irq_notifier(dev, irq);
}
}

/* Check whether an MMIO region exists */
Expand Down
6 changes: 6 additions & 0 deletions hw/intc/arm_gic_kvm.c
Expand Up @@ -570,6 +570,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
*/
i += (GIC_INTERNAL * s->num_cpu);
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);

for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
qemu_irq irq = qdev_get_gpio_in(dev, i);
kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
}

/* We never use our outbound IRQ/FIQ lines but provide them so that
* we maintain the same interface as the non-KVM GIC.
*/
Expand Down
8 changes: 4 additions & 4 deletions hw/s390x/virtio-ccw.c
Expand Up @@ -1316,8 +1316,8 @@ static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
VirtQueue *vq = virtio_get_queue(vdev, n);
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);

return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL,
dev->routes.gsi[n]);
return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, notifier, NULL,
dev->routes.gsi[n]);
}

static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
Expand All @@ -1327,8 +1327,8 @@ static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
int ret;

ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier,
dev->routes.gsi[n]);
ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, notifier,
dev->routes.gsi[n]);
assert(ret == 0);
}

Expand Down
8 changes: 8 additions & 0 deletions hw/vfio/common.c
Expand Up @@ -772,11 +772,19 @@ static void vfio_disconnect_container(VFIOGroup *group)

if (QLIST_EMPTY(&container->group_list)) {
VFIOAddressSpace *space = container->space;
VFIOGuestIOMMU *giommu, *tmp;

if (container->iommu_data.release) {
container->iommu_data.release(container);
}
QLIST_REMOVE(container, next);

QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
memory_region_unregister_iommu_notifier(&giommu->n);
QLIST_REMOVE(giommu, giommu_next);
g_free(giommu);
}

trace_vfio_disconnect_container(container->fd);
close(container->fd);
g_free(container);
Expand Down
42 changes: 35 additions & 7 deletions hw/vfio/pci.c
Expand Up @@ -597,7 +597,7 @@ static void vfio_add_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage *msg,
return;
}

if (kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->kvm_interrupt,
if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
NULL, virq) < 0) {
kvm_irqchip_release_virq(kvm_state, virq);
event_notifier_cleanup(&vector->kvm_interrupt);
Expand All @@ -609,8 +609,8 @@ static void vfio_add_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage *msg,

static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
{
kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->kvm_interrupt,
vector->virq);
kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
vector->virq);
kvm_irqchip_release_virq(kvm_state, vector->virq);
vector->virq = -1;
event_notifier_cleanup(&vector->kvm_interrupt);
Expand Down Expand Up @@ -939,7 +939,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
};
uint64_t size;
off_t off = 0;
size_t bytes;
ssize_t bytes;

if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info)) {
error_report("vfio: Error getting ROM info: %m");
Expand Down Expand Up @@ -2252,6 +2252,33 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev)
vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;

/*
* Test the size of the pba_offset variable and catch if it extends outside
* of the specified BAR. If it is the case, we need to apply a hardware
* specific quirk if the device is known or we have a broken configuration.
*/
if (vdev->msix->pba_offset >=
vdev->bars[vdev->msix->pba_bar].region.size) {

PCIDevice *pdev = &vdev->pdev;
uint16_t vendor = pci_get_word(pdev->config + PCI_VENDOR_ID);
uint16_t device = pci_get_word(pdev->config + PCI_DEVICE_ID);

/*
* Chelsio T5 Virtual Function devices are encoded as 0x58xx for T5
* adapters. The T5 hardware returns an incorrect value of 0x8000 for
* the VF PBA offset while the BAR itself is only 8k. The correct value
* is 0x1000, so we hard code that here.
*/
if (vendor == PCI_VENDOR_ID_CHELSIO && (device & 0xff00) == 0x5800) {
vdev->msix->pba_offset = 0x1000;
} else {
error_report("vfio: Hardware reports invalid configuration, "
"MSIX PBA outside of specified BAR");
return -EINVAL;
}
}

trace_vfio_early_setup_msix(vdev->vbasedev.name, pos,
vdev->msix->table_bar,
vdev->msix->table_offset,
Expand Down Expand Up @@ -2388,7 +2415,7 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr)
* potentially insert a direct-mapped subregion before and after it.
*/
if (vdev->msix && vdev->msix->table_bar == nr) {
size = vdev->msix->table_offset & qemu_host_page_mask;
size = vdev->msix->table_offset & qemu_real_host_page_mask;
}

strncat(name, " mmap", sizeof(name) - strlen(name) - 1);
Expand All @@ -2401,8 +2428,9 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr)
if (vdev->msix && vdev->msix->table_bar == nr) {
uint64_t start;

start = HOST_PAGE_ALIGN((uint64_t)vdev->msix->table_offset +
(vdev->msix->entries * PCI_MSIX_ENTRY_SIZE));
start = REAL_HOST_PAGE_ALIGN((uint64_t)vdev->msix->table_offset +
(vdev->msix->entries *
PCI_MSIX_ENTRY_SIZE));

size = start < bar->region.size ? bar->region.size - start : 0;
strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1);
Expand Down
100 changes: 100 additions & 0 deletions hw/vfio/platform.c
Expand Up @@ -26,6 +26,7 @@
#include "hw/sysbus.h"
#include "trace.h"
#include "hw/platform-bus.h"
#include "sysemu/kvm.h"

/*
* Functions used whatever the injection method
Expand All @@ -51,6 +52,7 @@ static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
intp->pin = info.index;
intp->flags = info.flags;
intp->state = VFIO_IRQ_INACTIVE;
intp->kvm_accel = false;

sysbus_init_irq(sbdev, &intp->qemuirq);

Expand All @@ -61,6 +63,13 @@ static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
error_report("vfio: Error: trigger event_notifier_init failed ");
return NULL;
}
/* Get an eventfd for resample/unmask */
ret = event_notifier_init(&intp->unmask, 0);
if (ret) {
g_free(intp);
error_report("vfio: Error: resamplefd event_notifier_init failed");
return NULL;
}

QLIST_INSERT_HEAD(&vdev->intp_list, intp, next);
return intp;
Expand Down Expand Up @@ -315,6 +324,94 @@ static int vfio_start_eventfd_injection(VFIOINTp *intp)
return ret;
}

/*
* Functions used for irqfd
*/

/**
* vfio_set_resample_eventfd - sets the resamplefd for an IRQ
* @intp: the IRQ struct handle
* programs the VFIO driver to unmask this IRQ when the
* intp->unmask eventfd is triggered
*/
static int vfio_set_resample_eventfd(VFIOINTp *intp)
{
VFIODevice *vbasedev = &intp->vdev->vbasedev;
struct vfio_irq_set *irq_set;
int argsz, ret;
int32_t *pfd;

argsz = sizeof(*irq_set) + sizeof(*pfd);
irq_set = g_malloc0(argsz);
irq_set->argsz = argsz;
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
irq_set->index = intp->pin;
irq_set->start = 0;
irq_set->count = 1;
pfd = (int32_t *)&irq_set->data;
*pfd = event_notifier_get_fd(&intp->unmask);
qemu_set_fd_handler(*pfd, NULL, NULL, NULL);
ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret < 0) {
error_report("vfio: Failed to set resample eventfd: %m");
}
return ret;
}

static void vfio_start_irqfd_injection(SysBusDevice *sbdev, qemu_irq irq)
{
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
VFIOINTp *intp;

if (!kvm_irqfds_enabled() || !kvm_resamplefds_enabled() ||
!vdev->irqfd_allowed) {
return;
}

QLIST_FOREACH(intp, &vdev->intp_list, next) {
if (intp->qemuirq == irq) {
break;
}
}
assert(intp);

/* Get to a known interrupt state */
qemu_set_fd_handler(event_notifier_get_fd(&intp->interrupt),
NULL, NULL, vdev);

vfio_mask_single_irqindex(&vdev->vbasedev, intp->pin);
qemu_set_irq(intp->qemuirq, 0);

if (kvm_irqchip_add_irqfd_notifier(kvm_state, &intp->interrupt,
&intp->unmask, irq) < 0) {
goto fail_irqfd;
}

if (vfio_set_trigger_eventfd(intp, NULL) < 0) {
goto fail_vfio;
}
if (vfio_set_resample_eventfd(intp) < 0) {
goto fail_vfio;
}

/* Let's resume injection with irqfd setup */
vfio_unmask_single_irqindex(&vdev->vbasedev, intp->pin);

intp->kvm_accel = true;

trace_vfio_platform_start_irqfd_injection(intp->pin,
event_notifier_get_fd(&intp->interrupt),
event_notifier_get_fd(&intp->unmask));
return;
fail_vfio:
kvm_irqchip_remove_irqfd_notifier(kvm_state, &intp->interrupt, irq);
fail_irqfd:
vfio_start_eventfd_injection(intp);
vfio_unmask_single_irqindex(&vdev->vbasedev, intp->pin);
return;
}

/* VFIO skeleton */

static void vfio_platform_compute_needs_reset(VFIODevice *vbasedev)
Expand Down Expand Up @@ -584,17 +681,20 @@ static Property vfio_platform_dev_properties[] = {
DEFINE_PROP_BOOL("x-mmap", VFIOPlatformDevice, vbasedev.allow_mmap, true),
DEFINE_PROP_UINT32("mmap-timeout-ms", VFIOPlatformDevice,
mmap_timeout, 1100),
DEFINE_PROP_BOOL("x-irqfd", VFIOPlatformDevice, irqfd_allowed, true),
DEFINE_PROP_END_OF_LIST(),
};

static void vfio_platform_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);

dc->realize = vfio_platform_realize;
dc->props = vfio_platform_dev_properties;
dc->vmsd = &vfio_platform_vmstate;
dc->desc = "VFIO-based platform device assignment";
sbc->connect_irq_notifier = vfio_start_irqfd_injection;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}

Expand Down
4 changes: 2 additions & 2 deletions hw/virtio/virtio-pci.c
Expand Up @@ -495,7 +495,7 @@ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
int ret;
ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq);
return ret;
}

Expand All @@ -509,7 +509,7 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int ret;

ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq);
assert(ret == 0);
}

Expand Down
3 changes: 3 additions & 0 deletions include/exec/cpu-all.h
Expand Up @@ -183,10 +183,13 @@ extern unsigned long reserved_va;

/* ??? These should be the larger of uintptr_t and target_ulong. */
extern uintptr_t qemu_real_host_page_size;
extern uintptr_t qemu_real_host_page_mask;
extern uintptr_t qemu_host_page_size;
extern uintptr_t qemu_host_page_mask;

#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
#define REAL_HOST_PAGE_ALIGN(addr) (((addr) + qemu_real_host_page_size - 1) & \
qemu_real_host_page_mask)

/* same as PROT_xxx */
#define PAGE_READ 0x0001
Expand Down
2 changes: 2 additions & 0 deletions include/hw/pci/pci_ids.h
Expand Up @@ -114,6 +114,8 @@
#define PCI_VENDOR_ID_ENSONIQ 0x1274
#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000

#define PCI_VENDOR_ID_CHELSIO 0x1425

#define PCI_VENDOR_ID_FREESCALE 0x1957
#define PCI_DEVICE_ID_MPC8533E 0x0030

Expand Down
1 change: 1 addition & 0 deletions include/hw/sysbus.h
Expand Up @@ -58,6 +58,7 @@ typedef struct SysBusDeviceClass {
* omitted then. (This is not considered a fatal error.)
*/
char *(*explicit_ofw_unit_address)(const SysBusDevice *dev);
void (*connect_irq_notifier)(SysBusDevice *dev, qemu_irq irq);
} SysBusDeviceClass;

struct SysBusDevice {
Expand Down
2 changes: 2 additions & 0 deletions include/hw/vfio/vfio-platform.h
Expand Up @@ -41,6 +41,7 @@ typedef struct VFIOINTp {
int state; /* inactive, pending, active */
uint8_t pin; /* index */
uint32_t flags; /* IRQ info flags */
bool kvm_accel; /* set when QEMU bypass through KVM enabled */
} VFIOINTp;

/* function type for user side eventfd handler */
Expand All @@ -57,6 +58,7 @@ typedef struct VFIOPlatformDevice {
uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */
QEMUTimer *mmap_timer; /* allows fast-path resume after IRQ hit */
QemuMutex intp_mutex; /* protect the intp_list IRQ state */
bool irqfd_allowed; /* debug option to force irqfd on/off */
} VFIOPlatformDevice;

typedef struct VFIOPlatformDeviceClass {
Expand Down
12 changes: 10 additions & 2 deletions include/sysemu/kvm.h
Expand Up @@ -19,6 +19,7 @@
#include "qemu/queue.h"
#include "qom/cpu.h"
#include "exec/memattrs.h"
#include "hw/irq.h"

#ifdef CONFIG_KVM
#include <linux/kvm.h>
Expand Down Expand Up @@ -151,6 +152,7 @@ extern bool kvm_readonly_mem_allowed;
#define kvm_halt_in_kernel() (false)
#define kvm_eventfds_enabled() (false)
#define kvm_irqfds_enabled() (false)
#define kvm_resamplefds_enabled() (false)
#define kvm_msi_via_irqfd_enabled() (false)
#define kvm_gsi_routing_allowed() (false)
#define kvm_gsi_direct_mapping() (false)
Expand Down Expand Up @@ -416,9 +418,15 @@ void kvm_irqchip_release_virq(KVMState *s, int virq);

int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter);

int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq);
int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
int virq);
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq);
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
EventNotifier *rn, qemu_irq irq);
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n,
qemu_irq irq);
void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi);
void kvm_pc_gsi_handler(void *opaque, int n, int level);
void kvm_pc_setup_irq_routing(bool pci_enabled);
void kvm_init_irq_routing(KVMState *s);
Expand Down

0 comments on commit 1452673

Please sign in to comment.