From patchwork Wed Apr 9 15:33:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Auger Eric X-Patchwork-Id: 28099 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-oa0-f72.google.com (mail-oa0-f72.google.com [209.85.219.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 372EB2145A for ; Wed, 9 Apr 2014 15:37:15 +0000 (UTC) Received: by mail-oa0-f72.google.com with SMTP id eb12sf11724434oac.7 for ; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:date :message-id:in-reply-to:references:cc:subject:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list; bh=AxWrO5X+evxHmbdXr9NK22+vT0jlNOYqRWtuXdilmis=; b=UiI5326rC+Pz2Q/rYIik+wUdEl4enoVVLIV+PIWZjIV7rgObIAhQm51RNMIuh25XpR ne845xBwXM9737RCZIAmJgMXXJPG0juZz8zNNDJq7eGpKgK9lJzXqrTb4FbsHueIwQDf jeOWDRS/OVqNyykiChpAI9ZKtUJCGVGVazRNbmigwPonpxCzmVI4FJFCkMf9o0c2AZH7 xhdoKXlQ/6b6qFmqY4lgJer+Q9PYI/vz1oFQ+QoGn6P0Lx5KysqlPLMaaPRuGO7rLQ4T mczyYNmXrQ5rZswHobykk/0KHwRlA6CsoDBpoj3VqjD5NxbkrpSMKDKyGT1tcK79fmV4 3Afg== X-Gm-Message-State: ALoCoQnvk600JUoMehbO806NOtrXTYCYjvPJb7HDaj1dGMBpM27vt9iYHTU+LN3moh7OJUJwRpSK X-Received: by 10.182.28.99 with SMTP id a3mr5399877obh.40.1397057834724; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.41.212 with SMTP id z78ls318100qgz.93.gmail; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) X-Received: by 10.220.109.138 with SMTP id j10mr952830vcp.54.1397057834514; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) Received: from mail-vc0-f179.google.com (mail-vc0-f179.google.com [209.85.220.179]) by mx.google.com with ESMTPS id dz10si192196vcb.195.2014.04.09.08.37.14 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 09 Apr 2014 08:37:14 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.179 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.179; Received: by mail-vc0-f179.google.com with SMTP id ij19so2177636vcb.24 for ; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) X-Received: by 10.52.173.165 with SMTP id bl5mr7741141vdc.13.1397057834431; Wed, 09 Apr 2014 08:37:14 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.12.8 with SMTP id v8csp339925vcv; Wed, 9 Apr 2014 08:37:13 -0700 (PDT) X-Received: by 10.224.54.4 with SMTP id o4mr13661047qag.74.1397057833712; Wed, 09 Apr 2014 08:37:13 -0700 (PDT) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id g2si561280qab.176.2014.04.09.08.37.13 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 09 Apr 2014 08:37:13 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Received: from localhost ([::1]:46766 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WXuYr-0004Kn-7j for patch@linaro.org; Wed, 09 Apr 2014 11:37:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46269) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WXuVw-000092-9q for qemu-devel@nongnu.org; Wed, 09 Apr 2014 11:34:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WXuVq-0000G3-5B for qemu-devel@nongnu.org; Wed, 09 Apr 2014 11:34:12 -0400 Received: from mail-wi0-f173.google.com ([209.85.212.173]:46906) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WXuVp-0000Fo-S3 for qemu-devel@nongnu.org; Wed, 09 Apr 2014 11:34:06 -0400 Received: by mail-wi0-f173.google.com with SMTP id z2so9128795wiv.6 for ; Wed, 09 Apr 2014 08:34:05 -0700 (PDT) X-Received: by 10.194.174.197 with SMTP id bu5mr3075607wjc.71.1397057645044; Wed, 09 Apr 2014 08:34:05 -0700 (PDT) Received: from midway01-04-00.lavalab ([88.98.47.97]) by mx.google.com with ESMTPSA id ga10sm2170061wjb.23.2014.04.09.08.34.04 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 09 Apr 2014 08:34:04 -0700 (PDT) From: Eric Auger To: eric.auger@st.com, christoffer.dall@linaro.org, qemu-devel@nongnu.org Date: Wed, 9 Apr 2014 16:33:07 +0100 Message-Id: <1397057589-11779-5-git-send-email-eric.auger@linaro.org> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1397057589-11779-1-git-send-email-eric.auger@linaro.org> References: <1397057589-11779-1-git-send-email-eric.auger@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.212.173 Cc: peter.maydell@linaro.org, kim.phillips@freescale.com, Eric Auger , agraf@suse.de, stuart.yoder@freescale.com, alex.williamson@redhat.com, christophe.barnichon@st.com, a.motakis@virtualopensystems.com, kvmarm@lists.cs.columbia.edu Subject: [Qemu-devel] [RFC v2 4/6] vfio: Add initial IRQ support in QEMU platform device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: eric.auger@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.179 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 This work is inspired of PCI INTx. The code was prepared to support multiple IRQs but this was not tested at that stage. Similarly to what is done on PCI, the device register space is RAM unmapped on IRQ hit in order to trap the end of interrupt (EOI). On mmap timer hit, if the EOI was trapped, the mmapping is restored. the physical interrupt is unmasked on the first read/write with the MMIO register space. Tested on Calxeda Midway xgmac which can be directly assigned to one virt VM. Acknowledgements: - vfio device name, guest physical address and IRQ indexes are hardcoded. This will be improved in another patch - currently tested on a single IRQ (xgmac main IRQ) - a KVM patch is required to invalidate stage2 entries on RAM memory region destruction (see [PATCH] ARM: KVM: Handle IPA unmapping on memory region deletion) Signed-off-by: Eric Auger --- hw/arm/virt.c | 13 ++- hw/vfio/platform.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 304 insertions(+), 25 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 5d43cf0..31ae7d2 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -108,12 +108,13 @@ static const MemMapEntry a15memmap[] = { /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ /* 0x10000000 .. 0x40000000 reserved for PCI */ [VIRT_MEM] = { 0x40000000, 1ULL * 1024 * 1024 * 1024 }, - [VIRT_ETHERNET] = { 0xfff51000, 0x1000 }, + [VIRT_ETHERNET] = { 0xfff41000, 0x1000 }, }; static const int a15irqmap[] = { [VIRT_UART] = 1, [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ + [VIRT_ETHERNET] = 77, }; static VirtBoardInfo machines[] = { @@ -299,8 +300,12 @@ static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic) hwaddr base = vbi->memmap[VIRT_ETHERNET].base; hwaddr size = vbi->memmap[VIRT_ETHERNET].size; const char compat[] = "calxeda,hb-xgmac"; + int irqm = vbi->irqmap[VIRT_ETHERNET]; + int irqp = irqm+1; + int irqlp = irqm+2; - sysbus_create_simple("vfio-platform", base, NULL); + sysbus_create_varargs("vfio-platform", base, + pic[irqm], pic[irqp], pic[irqlp], NULL); nodename = g_strdup_printf("/ethernet@%" PRIx64, base); qemu_fdt_add_subnode(vbi->fdt, nodename); @@ -308,6 +313,10 @@ static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic) /* Note that we can't use setprop_string because of the embedded NUL */ qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + 0x0, irqm, 0x4, + 0x0, irqp, 0x4, + 0x0, irqlp, 0x4); g_free(nodename); } diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 138fb13..f148edd 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -24,6 +24,7 @@ #include "config.h" #include "exec/address-spaces.h" #include "exec/memory.h" + #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/event_notifier.h" @@ -31,6 +32,7 @@ #include "qemu/range.h" #include "sysemu/kvm.h" #include "sysemu/sysemu.h" + #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/hw.h" @@ -41,12 +43,15 @@ #define DEBUG_VFIO #ifdef DEBUG_VFIO #define DPRINTF(fmt, ...) \ - do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0) + do { fprintf(stderr, "vfio: %s: " fmt, __func__, ## __VA_ARGS__); } \ + while (0) #else #define DPRINTF(fmt, ...) \ do { } while (0) #endif +#define PLATFORM_NUM_REGIONS 10 + /* Extra debugging, trap acceleration paths for more logging */ #define VFIO_ALLOW_MMAP 1 @@ -63,16 +68,240 @@ typedef struct VFIORegion { uint8_t nr; /* cache the region number for debug */ } VFIORegion; + +#define VFIO_INT_INTp 4 + +typedef struct VFIOINTp { + QLIST_ENTRY(VFIOINTp) next; + EventNotifier interrupt; /* eventfd triggered on interrupt */ + EventNotifier unmask; /* eventfd for unmask on QEMU bypass */ + qemu_irq qemuirq; + struct VFIODevice *vdev; /* back pointer to device */ + bool pending; /* interrupt pending */ + bool kvm_accel; /* set when QEMU bypass through KVM enabled */ + uint8_t pin; /* index */ + uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */ + QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */ +} VFIOINTp; + + + typedef struct VFIODevice { SysBusDevice sbdev; int fd; int num_regions; - VFIORegion *regions; + int num_irqs; + int interrupt; /* type of the interrupt, might disappear */ + char *name; + uint32_t mmap_timeout; /* mmap timeout value in ms */ + VFIORegion regions[PLATFORM_NUM_REGIONS]; QLIST_ENTRY(VFIODevice) next; struct VFIOGroup *group; - char *name; + QLIST_HEAD(, VFIOINTp) intp_list; } VFIODevice; + + +static void vfio_unmask_intp(VFIODevice *vdev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, + .index = index, + .start = 0, + .count = 1, + }; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + + + + +static void vfio_intp_mmap_enable(void *opaque) +{ + VFIOINTp * intp = (VFIOINTp *)opaque; + VFIODevice *vdev = intp->vdev; + + if (intp->pending) { + DPRINTF("IRQ still pending, re-schedule the mmap timer\n"); + timer_mod(intp->mmap_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + intp->mmap_timeout); + return; + } + + DPRINTF("IRQ EOI'ed sets mmap again\n"); + VFIORegion *region = &vdev->regions[0]; + memory_region_set_enabled(®ion->mmap_mem, true); +} + + + +static void vfio_intp_interrupt(void *opaque) +{ + int ret; + VFIOINTp *intp = (VFIOINTp *)opaque; + VFIODevice *vdev = intp->vdev; + + DPRINTF("pin = %d fd = %d\n", + intp->pin, event_notifier_get_fd(&intp->interrupt)); + + ret = event_notifier_test_and_clear(&intp->interrupt); + if (!ret) { + DPRINTF("Error when clearing fd=%d\n", + event_notifier_get_fd(&intp->interrupt)); + } + + intp->pending = true; + + /* TODO: fix this number of regions, + * currently a single region is handled + */ + + VFIORegion *region = &vdev->regions[0]; + memory_region_set_enabled(®ion->mmap_mem, false); + + qemu_set_irq(intp->qemuirq, 1); + + /* schedule the mmap timer which will restote mmap path after EOI*/ + if (intp->mmap_timeout) { + timer_mod(intp->mmap_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + intp->mmap_timeout); + } + +} + + + +static void vfio_irq_eoi(VFIODevice *vdev) +{ + + VFIOINTp *intp; + bool eoi_done = false; + + QLIST_FOREACH(intp, &vdev->intp_list, next) { + if (intp->pending) { + if (eoi_done) { + DPRINTF("several IRQ pending simultaneously: \ + this is not a supported case yet\n"); + } + DPRINTF("EOI IRQ #%d fd=%d\n", + intp->pin, event_notifier_get_fd(&intp->interrupt)); + intp->pending = false; + qemu_set_irq(intp->qemuirq, 0); + vfio_unmask_intp(vdev, intp->pin); + eoi_done = true; + } + } + + return; + +} + + + +#if 0 +static void vfio_list_intp(VFIODevice *vdev) +{ + VFIOINTp *intp; + int i = 0; + QLIST_FOREACH(intp, &vdev->intp_list, next) { + DPRINTF("IRQ #%d\n", i); + DPRINTF("- pin = %d\n", intp->pin); + DPRINTF("- fd = %d\n", event_notifier_get_fd(&intp->interrupt)); + DPRINTF("- pending = %d\n", (int)intp->pending); + DPRINTF("- kvm_accel = %d\n", (int)intp->kvm_accel); + i++; + } +} +#endif + +static int vfio_enable_intp(VFIODevice *vdev, unsigned int index) +{ + struct vfio_irq_set *irq_set; /* irq structure passed to vfio kernel */ + int32_t *pfd; /* pointer to the eventfd */ + int ret, argsz; + + int device = vdev->fd; + SysBusDevice *sbdev = SYS_BUS_DEVICE(vdev); + + vdev->interrupt = VFIO_INT_INTp; + + /* allocate and populate a new VFIOINTp structure put in a queue list */ + VFIOINTp *intp = g_malloc0(sizeof(*intp)); + intp->vdev = vdev; + intp->pin = index; + intp->pending = false; + intp->mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + vfio_intp_mmap_enable, intp); + intp->mmap_timeout = 1100; + /* TO DO: timeout as parameter */ + + /* incr sysbus num_irq and sets sysbus->irqp[n] = &intp->qemuirq + * only the address of the qemu_irq is set here + */ + + sysbus_init_irq(sbdev, &intp->qemuirq); + + /* content is set in sysbus_connect_irq (currently in machine definition) */ + + ret = event_notifier_init(&intp->interrupt, 0); + if (ret) { + error_report("vfio: Error: event_notifier_init failed "); + return ret; + } + + /* build the irq_set to be passed to the vfio kernel driver */ + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + + if (!irq_set) { + DPRINTF("failure while allocating memory for irq\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "VFIO platform: failure while allocating memory for irq"); + return -errno; + } + + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = index; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&intp->interrupt); + + DPRINTF("register fd=%d/irq index=%d to kernel\n", *pfd, index); + + qemu_set_fd_handler(*pfd, vfio_intp_interrupt, NULL, intp); + + /* pass the index/fd binding to the kernel driver so that it + * triggers this fd on HW IRQ + */ + ret = ioctl(device, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); + + if (ret) { + error_report("vfio: Error: Failed to pass Int fd to the driver: %m"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); + close(*pfd); /* TO DO : replace by event_notifier_cleanup */ + return -errno; + } + + /* store the new intp in qlist */ + + QLIST_INSERT_HEAD(&vdev->intp_list, intp, next); + + return 0; + +} + + + + static int vfio_mmap_region(VFIODevice *vdev, VFIORegion *region, MemoryRegion *mem, MemoryRegion *submem, void **map, size_t size, off_t offset, @@ -112,6 +341,7 @@ error: /* * IO Port/MMIO - Beware of the endians, VFIO is always little endian */ + static void vfio_region_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { @@ -139,12 +369,15 @@ static void vfio_region_write(void *opaque, hwaddr addr, } if (pwrite(region->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", - __func__, addr, data, size); + error_report("(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", + addr, data, size); } - DPRINTF("%s(region %d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", - __func__, region->nr, addr, data, size); + DPRINTF("(region %d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", + region->nr, addr, data, size); + + vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr])); + } static uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size) @@ -159,8 +392,8 @@ static uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size) uint64_t data = 0; if (pread(region->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m", - __func__, addr, size); + error_report("(,0x%"HWADDR_PRIx", %d) failed: %m", + addr, size); return (uint64_t)-1; } @@ -179,18 +412,22 @@ static uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size) break; } - DPRINTF("%s(region %d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", - __func__, region->nr, addr, size, data); + DPRINTF("(region %d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", + region->nr, addr, size, data); + + vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr])); return data; } + static const MemoryRegionOps vfio_region_ops = { .read = vfio_region_read, .write = vfio_region_write, .endianness = DEVICE_NATIVE_ENDIAN, }; + static void vfio_map_region(VFIODevice *vdev, int nr) { VFIORegion *region = &vdev->regions[nr]; @@ -242,14 +479,6 @@ static int vfio_get_device(VFIOGroup *group, const char *name, DPRINTF("Device %s flags: %u, regions: %u, irqs: %u\n", name, dev_info.flags, dev_info.num_regions, dev_info.num_irqs); - vdev->regions = g_malloc0(sizeof(VFIORegion) * dev_info.num_regions); - if (!vdev->regions) { - error_report("vfio: Error allocating space for %d regions", - dev_info.num_regions); - ret = -ENOMEM; - goto error; - } - vdev->num_regions = dev_info.num_regions; for (i = 0; i < dev_info.num_regions; i++) { @@ -273,6 +502,38 @@ static int vfio_get_device(VFIOGroup *group, const char *name, vdev->regions[i].nr = i; } + /* IRQ */ + + DPRINTF("Num IRQS: %d\n", dev_info.num_irqs); + + vdev->num_irqs = dev_info.num_irqs; + + for (i = 0; i < dev_info.num_irqs; i++) { + + struct vfio_irq_info irq = { .argsz = sizeof(irq) }; + + irq.index = i; + + DPRINTF("Retrieve IRQ info from vfio platform driver ...\n"); + + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq); + + if (ret) { + error_report("vfio: error getting device %s irq info", + name); + error_printf("vfio: error getting device %s irq info", + name); + } + + DPRINTF("- IRQ index %d: count %d, flags=0x%x\n", + irq.index, + irq.count, + irq.flags); + + vfio_enable_intp(vdev, irq.index); + + } + error: if (ret) { g_free(vdev->regions); @@ -286,13 +547,16 @@ error: static void vfio_platform_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbdev = SYS_BUS_DEVICE(dev); - VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, sbdev, sbdev); + VFIODevice *vdev = DO_UPCAST(VFIODevice, sbdev, sbdev); + VFIODevice *pvdev; + VFIOGroup *group; char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; ssize_t len; struct stat st; int groupid, i, ret; + /* TODO: pass device name on command line */ vdev->name = malloc(PATH_MAX); strcpy(vdev->name, "fff51000.ethernet"); @@ -320,24 +584,29 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) return; } - DPRINTF("%s(%s) group %d\n", __func__, vdev->name, groupid); + DPRINTF("%s belongs to VFIO group %d\n", vdev->name, groupid); group = vfio_get_group(groupid, NULL); if (!group) { error_report("vfio: failed to get group %d", groupid); return; } - snprintf(path, sizeof(path), "%s", vdev->name); QLIST_FOREACH(pvdev, &group->device_list, next) { + DPRINTF("compare %s versus %s\n", pvdev->name, vdev->name); if (strcmp(pvdev->name, vdev->name) == 0) { - error_report("vfio: error: device %s is already attached", path); + + DPRINTF("vfio device %s already is attached to group %d\n", + vdev->name, groupid); + vfio_put_group(group, NULL); return; } } + DPRINTF("Calling vfio_get_device ...\n"); + ret = vfio_get_device(group, path, vdev); if (ret) { error_report("vfio: failed to get device %s", path); @@ -363,6 +632,7 @@ static void vfio_platform_dev_class_init(ObjectClass *klass, void *data) dc->realize = vfio_platform_realize; dc->vmsd = &vfio_platform_vmstate; dc->desc = "VFIO-based platform device assignment"; + dc->cannot_instantiate_with_device_add_yet = true; set_bit(DEVICE_CATEGORY_MISC, dc->categories); }