From patchwork Thu Apr 17 17:29:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alvise Rigo X-Patchwork-Id: 339989 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 75C041400B8 for ; Fri, 18 Apr 2014 03:31:16 +1000 (EST) Received: from localhost ([::1]:33993 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Waq9a-0007cO-9S for incoming@patchwork.ozlabs.org; Thu, 17 Apr 2014 13:31:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34283) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Waq8i-0006QH-IB for qemu-devel@nongnu.org; Thu, 17 Apr 2014 13:30:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Waq8c-00057O-El for qemu-devel@nongnu.org; Thu, 17 Apr 2014 13:30:20 -0400 Received: from mail-wi0-f169.google.com ([209.85.212.169]:44790) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Waq8c-00057B-5U for qemu-devel@nongnu.org; Thu, 17 Apr 2014 13:30:14 -0400 Received: by mail-wi0-f169.google.com with SMTP id hm4so186283wib.2 for ; Thu, 17 Apr 2014 10:30:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ylSfpfgaYVUazEAmsBHi8lC2P6BYmbl7YraIyEOPJQI=; b=TWG7u9dZLOZjnxFXrV5PAOAB9GyhrJLsZ+5hQQrAa/Dm/KKO12UHXqtAsvn6CoJ8I7 cXDPh0f2yUuYjxIwNrMRxgs7ySMVIpFHDW5xJrMg3KtMXbyit/Q6Ka3H8TyuVN4fVevi L58K+zx0ONhXm/xjoK6OzeInqztIG3linDrAEHKVrjxzjelyLrIvSnCEbLt18ZTM2pES ucWOcYGeVft5gmXbWajXOWlnqR9McXpDAW7Tx6AE45B05zczvpgEqatIMyHxaIdUvelF 1gHnjMTfTNYTfWl24jUQg/2ZGM/IcI7FPQ+jnrsJas3ecafilPABJjeMwvA7MzuTdbhG QFIA== X-Gm-Message-State: ALoCoQln9U/ukBEGV9HV0sm1X5CkN48hmo9RUhjIfL0DkVjLqjb+tE0TxrXrgBR7aiq0RE1jxj4u X-Received: by 10.180.82.7 with SMTP id e7mr13305568wiy.6.1397755813355; Thu, 17 Apr 2014 10:30:13 -0700 (PDT) Received: from localhost.localdomain (AGrenoble-651-1-481-123.w90-42.abo.wanadoo.fr. [90.42.177.123]) by mx.google.com with ESMTPSA id gz1sm5996833wib.14.2014.04.17.10.30.12 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 17 Apr 2014 10:30:12 -0700 (PDT) From: Alvise Rigo To: qemu-devel@nongnu.org, a.motakis@virtualopensystems.com, eric.auger@st.com, kim.phillips@linaro.org Date: Thu, 17 Apr 2014 19:29:35 +0200 Message-Id: <1397755775-23833-5-git-send-email-a.rigo@virtualopensystems.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1397755775-23833-1-git-send-email-a.rigo@virtualopensystems.com> References: <1397755775-23833-1-git-send-email-a.rigo@virtualopensystems.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.212.169 Cc: Alex Williamson , tech@virtualopensystems.com, Alvise Rigo Subject: [Qemu-devel] [RFC 4/4] MemoryRegion with EOI callbacks for VFIO Platform devices 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The user can specify the location of the memory region (register) used by the guest driver to clear the pending interrupt; if enable, this mechanism will substitute the default one (timer based). The region is provided as command line property "intclr-region" of the vfio-platform device. The property is a string "region_index;offset;size" where: region_index: is the index of the memory region where the register lives, offset: offset of the register in the region, size: size of the register. example: -device vfio-platform,...,intclr-region="0;0x2c;4" Signed-off-by: Alvise Rigo --- hw/vfio/platform.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 8 deletions(-) diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index c4a4286..9dae311 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -40,6 +40,7 @@ #include "vfio-common.h" +/*#define DEBUG_VFIO 1*/ #ifdef DEBUG_VFIO #define DPRINTF(fmt, ...) \ do { fprintf(stderr, "vfio: %s: " fmt, __func__, ## __VA_ARGS__); } \ @@ -65,6 +66,7 @@ typedef struct VFIORegion { size_t size; uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ uint8_t nr; /* cache the region number for debug */ + MemoryRegion *intclr; } VFIORegion; @@ -99,6 +101,8 @@ typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; struct VFIOGroup *group; QLIST_HEAD(, VFIOINTp) intp_list; + char *intclr_region_str; /* clear interrupt region string */ + bool has_intclr_region; } VFIODevice; @@ -120,6 +124,48 @@ void vfio_get_props(SysBusDevice *s, char **pname, *psize = vdev->regions[0].size; } +static int parse_clrint_string(const char *intclr_str, uint32_t *id_reg, + hwaddr *off_reg, uint64_t *size_reg) +{ + char *str_ptr = g_strdup(intclr_str); + char *idx, *off, *size; + + if (strlen(intclr_str) < 5) { + return -1; + } + + idx = str_ptr; + str_ptr = strchr(str_ptr, ';'); + if (!str_ptr || idx == str_ptr) { + return -1; + } + *str_ptr = '\0'; + + off = ++str_ptr; + str_ptr = strchr(str_ptr, ';'); + if (!str_ptr || off == str_ptr) { + return -1; + } + *str_ptr = '\0'; + + size = ++str_ptr; + if (!*size) { + return -1; + } + + *id_reg = strtol(idx, NULL, 10); + *off_reg = strtol(off, NULL, 0); + *size_reg = strtol(size, NULL, 10); + + if (errno == EINVAL || errno == ERANGE) { + return -1; + } + + DPRINTF("intclr region - id: %u offset: 0x%"HWADDR_PRIx" size: %"PRIx64"\n", + *id_reg, *off_reg, *size_reg); + return 0; +} + static void vfio_disable_irqindex(VFIODevice *vdev, int index) { struct vfio_irq_set irq_set = { @@ -175,7 +221,7 @@ static void vfio_intp_mmap_enable(void *opaque) /* - * The fd handler + * The fd handlers */ @@ -216,7 +262,22 @@ static void vfio_intp_interrupt(void *opaque) } +static void vfio_clrint_with_region(void *opaque) +{ + int ret; + VFIOINTp *intp = (VFIOINTp *)opaque; + 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; + + /* trigger the virtual IRQ */ + qemu_set_irq(intp->qemuirq, 1); +} static void vfio_irq_eoi(VFIODevice *vdev) { @@ -245,10 +306,57 @@ static void vfio_irq_eoi(VFIODevice *vdev) } return; +} + +static uint64_t vfio_intclr_reg_read(void *opaque, hwaddr addr, unsigned size) +{ + VFIORegion *region = opaque; + + uint32_t data; + + if (size != 4) { + hw_error("unsupported size during intclr read"); + } + if (pread(region->fd, &data, size, region->fd_offset + + region->intclr->addr + addr) != size) { + error_report("(0x%"HWADDR_PRIx", %d) failed: %m", + addr, size); + return (uint64_t)-1; + } + + DPRINTF("(region %d, addr= 0x%"HWADDR_PRIx", data=%d) = 0x%"PRIx32"\n", + region->nr, addr, size, data); + + vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr])); + + return data; } +static void vfio_intclr_reg_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIORegion *region = opaque; + + uint32_t buf = data; + + if (pwrite(region->fd, &buf, size, region->fd_offset + + region->intclr->addr + addr) != size) { + error_report("(0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", + addr, data, size); + } + + DPRINTF("(region %d, addr=0x%"HWADDR_PRIx", data= 0x%"PRIx64", %d)\n", + region->nr, addr, data, size); + vfio_irq_eoi(container_of(region, VFIODevice, regions[region->nr])); +} + +static const struct MemoryRegionOps clrint_ops = { + .read = vfio_intclr_reg_read, + .write = vfio_intclr_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; static int vfio_enable_intp(VFIODevice *vdev, unsigned int index) { @@ -268,6 +376,7 @@ static int vfio_enable_intp(VFIODevice *vdev, unsigned int index) vfio_intp_mmap_enable, intp); /* TO DO: currently each IRQ has the same mmap timeout */ + intp->mmap_timeout = intp->vdev->mmap_timeout; sysbus_init_irq(sbdev, &intp->qemuirq); @@ -302,7 +411,11 @@ static int vfio_enable_intp(VFIODevice *vdev, unsigned int index) DPRINTF("register fd=%d/irq index=%d to kernel\n", *pfd, index); - qemu_set_fd_handler(*pfd, vfio_intp_interrupt, NULL, intp); + if (vdev->has_intclr_region) { + qemu_set_fd_handler(*pfd, vfio_clrint_with_region, NULL, intp); + } else { + 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 @@ -323,7 +436,6 @@ static int vfio_enable_intp(VFIODevice *vdev, unsigned int index) QLIST_INSERT_HEAD(&vdev->intp_list, intp, next); return 0; - } @@ -380,7 +492,7 @@ static int vfio_mmap_region(VFIODevice *vdev, VFIORegion *region, goto error; } - memory_region_init_ram_ptr(submem, OBJECT(vdev), name, size, *map); + memory_region_init_ptr(submem, OBJECT(vdev), name, size, *map); } memory_region_add_subregion(mem, offset, submem); @@ -501,10 +613,10 @@ static void vfio_map_region(VFIODevice *vdev, int nr) static void vfio_unmap_region(VFIODevice *vdev, int nr) { -VFIORegion *region = &vdev->regions[nr]; -memory_region_del_subregion(®ion->mem, ®ion->mmap_mem); -munmap(region->mmap, memory_region_size(®ion->mmap_mem)); -memory_region_destroy(®ion->mmap_mem); + VFIORegion *region = &vdev->regions[nr]; + memory_region_del_subregion(®ion->mem, ®ion->mmap_mem); + munmap(region->mmap, memory_region_size(®ion->mmap_mem)); + memory_region_destroy(®ion->mmap_mem); } @@ -669,6 +781,17 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) } } + hwaddr intclr_off = 0; + uint64_t intclr_size = 0; + uint32_t id = 0; + if (vdev->intclr_region_str) { + ret = parse_clrint_string(vdev->intclr_region_str, &id, &intclr_off, + &intclr_size); + } else { + ret = -1; + } + vdev->has_intclr_region = (!ret) ? true : false; + ret = vfio_get_device(group, path, vdev); if (ret) { error_report("vfio: failed to get device %s", path); @@ -678,6 +801,24 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) for (i = 0; i < vdev->num_regions; i++) { vfio_map_region(vdev, i); + + if (id == i && vdev->has_intclr_region) { + char *clrint_region_name = NULL; + /* add clear interrupt region */ + MemoryRegion *irq_reg = g_new(MemoryRegion, 1); + vdev->regions[i].intclr = irq_reg; + + clrint_region_name = g_strconcat(vdev->name, " intr.reg", NULL); + memory_region_init_io(irq_reg, OBJECT(vdev), &clrint_ops, + &vdev->regions[i], clrint_region_name, + intclr_size); + + memory_region_add_subregion(&vdev->regions[i].mmap_mem, + intclr_off, irq_reg); + + g_free(clrint_region_name); + } + sysbus_init_mmio(sbdev, &vdev->regions[i].mem); } } @@ -729,6 +870,7 @@ typedef struct VFIOPlatformDeviceClass { static Property vfio_platform_dev_properties[] = { DEFINE_PROP_STRING("vfio_device", VFIODevice, name), DEFINE_PROP_STRING("compat", VFIODevice, compat), +DEFINE_PROP_STRING("intclr-region", VFIODevice, intclr_region_str), DEFINE_PROP_UINT32("mmap-timeout-ms", VFIODevice, mmap_timeout, 1100), DEFINE_PROP_END_OF_LIST(), };