From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39497) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZUXwR-00031l-VM for qemu-devel@nongnu.org; Wed, 26 Aug 2015 06:28:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZUXwN-0000gz-Sn for qemu-devel@nongnu.org; Wed, 26 Aug 2015 06:28:27 -0400 Received: from mailout1.w1.samsung.com ([210.118.77.11]:17030) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZUXwN-0000gg-Ix for qemu-devel@nongnu.org; Wed, 26 Aug 2015 06:28:23 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NTO0045LQF90060@mailout1.w1.samsung.com> for qemu-devel@nongnu.org; Wed, 26 Aug 2015 11:28:21 +0100 (BST) From: Pavel Fedin Date: Wed, 26 Aug 2015 13:28:14 +0300 Message-id: <5f481e4c8a35808c7e4a511100f9417d75b49670.1440584396.git.p.fedin@samsung.com> In-reply-to: References: In-reply-to: References: Subject: [Qemu-devel] [PATCH v12 2/5] intc/gic: Extract some reusable vGIC code List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Maydell , Shlomo Pongratz , Shlomo Pongratz , Eric Auger Some functions previously used only by vGICv2 are useful also for vGICv3 implementation. Untie them from GICState and make accessible from within other modules: - kvm_arm_gic_set_irq() - kvm_gic_supports_attr() - moved to common code and renamed to kvm_device_check_attr() - kvm_gic_access() - turned into GIC-independent kvm_device_access(). Data pointer changed to void * because some GICv3 registers are 64-bit wide - kvm_gicd_access() - kvm_gicc_access() - actually GICv2-specific, but changed to keep the code style unified with kvm_gicd_access() Some of these changes are not used right now, but they will be helpful for implementing live migration. Actually kvm_dist_get() and kvm_dist_put() could also be made reusable, but they would require two extra parameters (s->dev_fd and s->num_cpu) as well as lots of typecasts of 's' to DeviceState * and back to GICState *. This makes the code very ugly so i decided to stop at this point. I tried also an approach with making a base class for all possible GICs, but it would contain only three variables (dev_fd, cpu_num and irq_num), and accessing them through the rest of the code would be again tedious (either ugly casts or qemu-style separate object pointer). So i disliked it too. Signed-off-by: Pavel Fedin Tested-by: Ashok kumar --- hw/intc/arm_gic_kvm.c | 84 ++++++++++----------------------------------------- hw/intc/vgic_common.h | 49 ++++++++++++++++++++++++++++++ include/sysemu/kvm.h | 26 ++++++++++++++++ kvm-all.c | 33 ++++++++++++++++++++ 4 files changed, 124 insertions(+), 68 deletions(-) create mode 100644 hw/intc/vgic_common.h diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index e5d0f67..e129c90 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -23,6 +23,7 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "gic_internal.h" +#include "vgic_common.h" //#define DEBUG_GIC_KVM @@ -52,7 +53,7 @@ typedef struct KVMARMGICClass { void (*parent_reset)(DeviceState *dev); } KVMARMGICClass; -static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) +void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) { /* Meaning of the 'irq' parameter: * [0..N-1] : external interrupts @@ -63,10 +64,9 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) * has separate fields in the irq number for type, * CPU number and interrupt number. */ - GICState *s = (GICState *)opaque; int kvm_irq, irqtype, cpu; - if (irq < (s->num_irq - GIC_INTERNAL)) { + if (irq < (num_irq - GIC_INTERNAL)) { /* External interrupt. The kernel numbers these like the GIC * hardware, with external interrupt IDs starting after the * internal ones. @@ -77,7 +77,7 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) } else { /* Internal interrupt: decode into (cpu, interrupt id) */ irqtype = KVM_ARM_IRQ_TYPE_PPI; - irq -= (s->num_irq - GIC_INTERNAL); + irq -= (num_irq - GIC_INTERNAL); cpu = irq / GIC_INTERNAL; irq %= GIC_INTERNAL; } @@ -87,69 +87,16 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) kvm_set_irq(kvm_state, kvm_irq, !!level); } -static bool kvm_arm_gic_can_save_restore(GICState *s) -{ - return s->dev_fd >= 0; -} - -static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum) -{ - struct kvm_device_attr attr = { - .group = group, - .attr = attrnum, - .flags = 0, - }; - - if (s->dev_fd == -1) { - return false; - } - - return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0; -} - -static void kvm_gic_access(GICState *s, int group, int offset, - int cpu, uint32_t *val, bool write) +static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level) { - struct kvm_device_attr attr; - int type; - int err; - - cpu = cpu & 0xff; - - attr.flags = 0; - attr.group = group; - attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & - KVM_DEV_ARM_VGIC_CPUID_MASK) | - (((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & - KVM_DEV_ARM_VGIC_OFFSET_MASK); - attr.addr = (uintptr_t)val; - - if (write) { - type = KVM_SET_DEVICE_ATTR; - } else { - type = KVM_GET_DEVICE_ATTR; - } - - err = kvm_device_ioctl(s->dev_fd, type, &attr); - if (err < 0) { - fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n", - strerror(-err)); - abort(); - } -} + GICState *s = (GICState *)opaque; -static void kvm_gicd_access(GICState *s, int offset, int cpu, - uint32_t *val, bool write) -{ - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, - offset, cpu, val, write); + kvm_arm_gic_set_irq(s->num_irq, irq, level); } -static void kvm_gicc_access(GICState *s, int offset, int cpu, - uint32_t *val, bool write) +static bool kvm_arm_gic_can_save_restore(GICState *s) { - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, - offset, cpu, val, write); + return s->dev_fd >= 0; } #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ @@ -559,7 +506,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } - gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL); + gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { qemu_irq irq = qdev_get_gpio_in(dev, i); @@ -576,16 +523,17 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } - if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { uint32_t numirqs = s->num_irq; - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1); + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, + &numirqs, true); } /* Tell the kernel to complete VGIC initialization now */ - if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_CTRL, + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT)) { - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, 0, 0, 1); + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); } /* Distributor */ diff --git a/hw/intc/vgic_common.h b/hw/intc/vgic_common.h new file mode 100644 index 0000000..d52fc30 --- /dev/null +++ b/hw/intc/vgic_common.h @@ -0,0 +1,49 @@ +/* + * ARM KVM vGIC utility functions + * + * Copyright (c) 2015 Samsung Electronics + * Written by Pavel Fedin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_ARM_VGIC_COMMON_H +#define QEMU_ARM_VGIC_COMMON_H + +/** + * kvm_arm_gic_set_irq - Send an IRQ to the in-kernel vGIC + * @num_irq: Total number of IRQs configured for the GIC instance + * @irq: qemu internal IRQ line number: + * [0..N-1] : external interrupts + * [N..N+31] : PPI (internal) interrupts for CPU 0 + * [N+32..N+63] : PPI (internal interrupts for CPU 1 + * @level: level of the IRQ line. + */ +void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level); + +#define KVM_VGIC_ATTR(offset, cpu) \ + ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & \ + KVM_DEV_ARM_VGIC_CPUID_MASK) | \ + (((uint64_t)(offset) << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & \ + KVM_DEV_ARM_VGIC_OFFSET_MASK)) + +#define kvm_gicd_access(s, offset, cpu, val, write) \ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, \ + KVM_VGIC_ATTR(offset, cpu), val, write) + +#define kvm_gicc_access(s, offset, cpu, val, write) \ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, \ + KVM_VGIC_ATTR(offset, cpu), val, write) + +#endif diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 983e99e..2a58b4d 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -240,6 +240,32 @@ int kvm_device_ioctl(int fd, int type, ...); int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr); /** + * kvm_device_check_attr - check for existence of a specific device attribute + * @fd: The device file descriptor + * @group: the group + * @attr: the attribute of that group to query for + * + * Returns: 1 if the attribute exists + * 0 if the attribute either does not exist or if the vm device + * interface is unavailable + */ +int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr); + +/** + * kvm_device_access - set or get value of a specific vm attribute + * @fd: The device file descriptor + * @group: the group + * @attr: the attribute of that group to set or get + * @val: pointer to a storage area for the value + * @write: true for set and false for get operation + * + * This function is not allowed to fail. Use kvm_device_check_attr() + * in order to check for the availability of optional attributes. + */ +void kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write); + +/** * kvm_create_device - create a KVM device for the device control API * @KVMState: The KVMState pointer * @type: The KVM device type (see Documentation/virtual/kvm/devices in the diff --git a/kvm-all.c b/kvm-all.c index 06e06f2..a902fb8 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -24,6 +24,7 @@ #include "qemu/atomic.h" #include "qemu/option.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/pci/msi.h" #include "hw/s390x/adapter.h" @@ -2003,6 +2004,38 @@ int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr) return ret ? 0 : 1; } +int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) +{ + struct kvm_device_attr attribute = { + .group = group, + .attr = attr, + .flags = 0, + }; + + return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1; +} + +void kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write) +{ + struct kvm_device_attr kvmattr; + int err; + + kvmattr.flags = 0; + kvmattr.group = group; + kvmattr.attr = attr; + kvmattr.addr = (uintptr_t)val; + + err = kvm_device_ioctl(fd, + write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, + &kvmattr); + if (err < 0) { + error_report("KVM_%s_DEVICE_ATTR failed: %s", + write ? "SET" : "GET", strerror(-err)); + abort(); + } +} + int kvm_has_sync_mmu(void) { return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU); -- 1.9.5.msysgit.0