From patchwork Tue Jul 14 07:54:44 2015
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pavel Fedin
X-Patchwork-Id: 494911
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])
(using TLSv1 with cipher AES256-SHA (256/256 bits))
(No client certificate requested)
by ozlabs.org (Postfix) with ESMTPS id DB875140319
for ;
Tue, 14 Jul 2015 18:00:02 +1000 (AEST)
Received: from localhost ([::1]:58378 helo=lists.gnu.org)
by lists.gnu.org with esmtp (Exim 4.71) (envelope-from
)
id 1ZEv8C-0001bl-SM
for incoming@patchwork.ozlabs.org; Tue, 14 Jul 2015 04:00:00 -0400
Received: from eggs.gnu.org ([2001:4830:134:3::10]:40479)
by lists.gnu.org with esmtp (Exim 4.71)
(envelope-from ) id 1ZEv3J-0000sb-AK
for qemu-devel@nongnu.org; Tue, 14 Jul 2015 03:54:58 -0400
Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
(envelope-from ) id 1ZEv3E-0002GZ-EX
for qemu-devel@nongnu.org; Tue, 14 Jul 2015 03:54:57 -0400
Received: from mailout4.w1.samsung.com ([210.118.77.14]:9159)
by eggs.gnu.org with esmtp (Exim 4.71)
(envelope-from ) id 1ZEv3E-0002G5-98
for qemu-devel@nongnu.org; Tue, 14 Jul 2015 03:54:52 -0400
Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245])
by mailout4.w1.samsung.com
(Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5
2014)) with ESMTP id <0NRG00G9LWNDIJ20@mailout4.w1.samsung.com> for
qemu-devel@nongnu.org; Tue, 14 Jul 2015 08:54:50 +0100 (BST)
X-AuditID: cbfec7f5-f794b6d000001495-d3-55a4c049a8da
Received: from eusync2.samsung.com ( [203.254.199.212])
by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id 42.05.05269.940C4A55;
Tue, 14 Jul 2015 08:54:49 +0100 (BST)
Received: from localhost ([106.109.131.169])
by eusync2.samsung.com (Oracle Communications Messaging Server
7.0.5.31.0 64bit (built May 5 2014))
with ESMTPA id <0NRG00EOJWNCPV50@eusync2.samsung.com>; Tue,
14 Jul 2015 08:54:49 +0100 (BST)
From: Pavel Fedin
To: qemu-devel@nongnu.org
Date: Tue, 14 Jul 2015 10:54:44 +0300
Message-id:
<0ede255a2d88739990ecb4c39af5732d9d5c58e3.1436859955.git.p.fedin@samsung.com>
X-Mailer: git-send-email 1.9.5.msysgit.0
In-reply-to:
References:
In-reply-to:
References:
X-Brightmail-Tracker:
H4sIAAAAAAAAA+NgFlrMLMWRmVeSWpSXmKPExsVy+t/xK7qeB5aEGhzZqWrx4vU/Rov5W86w
Wsw584DF4njvDhaLts/f2S3uvv7M4sDmsXPWXXaPliNvWT3uXNvD5vHk2mamAJYoLpuU1JzM
stQifbsEroxr5x6zFHxNrLhy9ydLA+Mh9y5GTg4JAROJb0e/M0PYYhIX7q1n62Lk4hASWMoo
cff6O2YI5xujxNvN19lBqtgE1CVOf/3AAmKLCEhK/O46DVbELPCIUeJa2zmwUcIC5hLbF54H
K2IRUJX4+HYDYxcjBwevQLTEotZIiG0aEou+zGEDsTmBymcemwA2X0jATOLWzfvMuMQnMPIv
YGRYxSiaWppcUJyUnmukV5yYW1yal66XnJ+7iRESdF93MC49ZnWIUYCDUYmHd4LlklAh1sSy
4srcQ4wSHMxKIrwWG4FCvCmJlVWpRfnxRaU5qcWHGKU5WJTEeWfueh8iJJCeWJKanZpakFoE
k2Xi4JRqYLSo/yTIELf8gM/i9/08i88sC65+0y+7+Oaz9YqP1upbLFB4sf3mxAecpzqkrsbV
r9ptMXtTdmu5lVDVZ5XzBioXtk+tfvWpP2iO14bGJ+37c9ddOvCwv7V/tgOPdMJHhisn0wTW
TXxdkhP/VnRqTV9y0Ym1jMt+SOgf/2A/4+Dp1S0lp7QuxjxTYinOSDTUYi4qTgQAZk06ETYC AAA=
X-detected-operating-system: by eggs.gnu.org: Genre and OS details not
recognized.
X-Received-From: 210.118.77.14
Cc: Peter Maydell ,
Shlomo Pongratz ,
Shlomo Pongratz ,
Christoffer Dall ,
Eric Auger
Subject: [Qemu-devel] [PATCH v4 2/5] Extract some reusable vGIC code
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
These functions are useful also for vGICv3 implementation. Make them accessible
from within other modules.
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
---
hw/intc/arm_gic_kvm.c | 84 ++++++++++++++++++++++++---------------------------
hw/intc/vgic_common.h | 43 ++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 45 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 f56bff1..9b6d702 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,12 +87,19 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
kvm_set_irq(kvm_state, kvm_irq, !!level);
}
+static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level)
+{
+ GICState *s = (GICState *)opaque;
+
+ kvm_arm_gic_set_irq(s->num_irq, 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)
+bool kvm_gic_supports_attr(int dev_fd, int group, int attrnum)
{
struct kvm_device_attr attr = {
.group = group,
@@ -100,14 +107,14 @@ static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum)
.flags = 0,
};
- if (s->dev_fd == -1) {
+ if (dev_fd == -1) {
return false;
}
- return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0;
+ return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0;
}
-static void kvm_gic_access(GICState *s, int group, int offset,
+void kvm_gic_access(int dev_fd, int group, int offset,
int cpu, uint32_t *val, bool write)
{
struct kvm_device_attr attr;
@@ -130,7 +137,7 @@ static void kvm_gic_access(GICState *s, int group, int offset,
type = KVM_GET_DEVICE_ATTR;
}
- err = kvm_device_ioctl(s->dev_fd, type, &attr);
+ err = kvm_device_ioctl(dev_fd, type, &attr);
if (err < 0) {
fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n",
strerror(-err));
@@ -138,20 +145,6 @@ static void kvm_gic_access(GICState *s, int group, int offset,
}
}
-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);
-}
-
-static void kvm_gicc_access(GICState *s, int offset, int cpu,
- uint32_t *val, bool write)
-{
- kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
- offset, cpu, val, write);
-}
-
#define for_each_irq_reg(_ctr, _max_irq, _field_width) \
for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++)
@@ -291,7 +284,7 @@ static void kvm_dist_get(GICState *s, uint32_t offset, int width,
irq = i * regsz;
cpu = 0;
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
- kvm_gicd_access(s, offset, cpu, ®, false);
+ kvm_gicd_access(s->dev_fd, offset, cpu, ®, false);
for (j = 0; j < regsz; j++) {
field = extract32(reg, j * width, width);
translate_fn(s, irq + j, cpu, &field, false);
@@ -324,7 +317,7 @@ static void kvm_dist_put(GICState *s, uint32_t offset, int width,
translate_fn(s, irq + j, cpu, &field, true);
reg = deposit32(reg, j * width, width, field);
}
- kvm_gicd_access(s, offset, cpu, ®, true);
+ kvm_gicd_access(s->dev_fd, offset, cpu, ®, true);
cpu++;
}
@@ -355,10 +348,10 @@ static void kvm_arm_gic_put(GICState *s)
/* s->ctlr -> GICD_CTLR */
reg = s->ctlr;
- kvm_gicd_access(s, 0x0, 0, ®, true);
+ kvm_gicd_access(s->dev_fd, 0x0, 0, ®, true);
/* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
- kvm_gicd_access(s, 0x4, 0, ®, false);
+ kvm_gicd_access(s->dev_fd, 0x4, 0, ®, false);
num_irq = ((reg & 0x1f) + 1) * 32;
num_cpu = ((reg & 0xe0) >> 5) + 1;
@@ -416,24 +409,24 @@ static void kvm_arm_gic_put(GICState *s)
for (cpu = 0; cpu < s->num_cpu; cpu++) {
/* s->cpu_ctlr[cpu] -> GICC_CTLR */
reg = s->cpu_ctlr[cpu];
- kvm_gicc_access(s, 0x00, cpu, ®, true);
+ kvm_gicc_access(s->dev_fd, 0x00, cpu, ®, true);
/* s->priority_mask[cpu] -> GICC_PMR */
reg = (s->priority_mask[cpu] & 0xff);
- kvm_gicc_access(s, 0x04, cpu, ®, true);
+ kvm_gicc_access(s->dev_fd, 0x04, cpu, ®, true);
/* s->bpr[cpu] -> GICC_BPR */
reg = (s->bpr[cpu] & 0x7);
- kvm_gicc_access(s, 0x08, cpu, ®, true);
+ kvm_gicc_access(s->dev_fd, 0x08, cpu, ®, true);
/* s->abpr[cpu] -> GICC_ABPR */
reg = (s->abpr[cpu] & 0x7);
- kvm_gicc_access(s, 0x1c, cpu, ®, true);
+ kvm_gicc_access(s->dev_fd, 0x1c, cpu, ®, true);
/* s->apr[n][cpu] -> GICC_APRn */
for (i = 0; i < 4; i++) {
reg = s->apr[i][cpu];
- kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, true);
+ kvm_gicc_access(s->dev_fd, 0xd0 + i * 4, cpu, ®, true);
}
}
}
@@ -454,11 +447,11 @@ static void kvm_arm_gic_get(GICState *s)
*/
/* GICD_CTLR -> s->ctlr */
- kvm_gicd_access(s, 0x0, 0, ®, false);
+ kvm_gicd_access(s->dev_fd, 0x0, 0, ®, false);
s->ctlr = reg;
/* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
- kvm_gicd_access(s, 0x4, 0, ®, false);
+ kvm_gicd_access(s->dev_fd, 0x4, 0, ®, false);
s->num_irq = ((reg & 0x1f) + 1) * 32;
s->num_cpu = ((reg & 0xe0) >> 5) + 1;
@@ -469,7 +462,7 @@ static void kvm_arm_gic_get(GICState *s)
}
/* GICD_IIDR -> ? */
- kvm_gicd_access(s, 0x8, 0, ®, false);
+ kvm_gicd_access(s->dev_fd, 0x8, 0, ®, false);
/* Clear all the IRQ settings */
for (i = 0; i < s->num_irq; i++) {
@@ -507,24 +500,24 @@ static void kvm_arm_gic_get(GICState *s)
for (cpu = 0; cpu < s->num_cpu; cpu++) {
/* GICC_CTLR -> s->cpu_ctlr[cpu] */
- kvm_gicc_access(s, 0x00, cpu, ®, false);
+ kvm_gicc_access(s->dev_fd, 0x00, cpu, ®, false);
s->cpu_ctlr[cpu] = reg;
/* GICC_PMR -> s->priority_mask[cpu] */
- kvm_gicc_access(s, 0x04, cpu, ®, false);
+ kvm_gicc_access(s->dev_fd, 0x04, cpu, ®, false);
s->priority_mask[cpu] = (reg & 0xff);
/* GICC_BPR -> s->bpr[cpu] */
- kvm_gicc_access(s, 0x08, cpu, ®, false);
+ kvm_gicc_access(s->dev_fd, 0x08, cpu, ®, false);
s->bpr[cpu] = (reg & 0x7);
/* GICC_ABPR -> s->abpr[cpu] */
- kvm_gicc_access(s, 0x1c, cpu, ®, false);
+ kvm_gicc_access(s->dev_fd, 0x1c, cpu, ®, false);
s->abpr[cpu] = (reg & 0x7);
/* GICC_APRn -> s->apr[n][cpu] */
for (i = 0; i < 4; i++) {
- kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false);
+ kvm_gicc_access(s->dev_fd, 0xd0 + i * 4, cpu, ®, false);
s->apr[i][cpu] = reg;
}
}
@@ -569,7 +562,7 @@ 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);
+ qdev_init_gpio_in(dev, kvm_arm_gicv2_set_irq, i);
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
qemu_irq irq = qdev_get_gpio_in(dev, i);
@@ -596,15 +589,16 @@ 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_gic_supports_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_gic_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0,
+ &numirqs, 1);
}
/* Tell the kernel to complete VGIC initialization now */
- if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ if (kvm_gic_supports_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_gic_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
KVM_DEV_ARM_VGIC_CTRL_INIT, 0, 0, 1);
}
diff --git a/hw/intc/vgic_common.h b/hw/intc/vgic_common.h
new file mode 100644
index 0000000..67241d3
--- /dev/null
+++ b/hw/intc/vgic_common.h
@@ -0,0 +1,43 @@
+/*
+ * 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
+
+void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level);
+bool kvm_gic_supports_attr(int dev_fd, int group, int attrnum);
+void kvm_gic_access(int dev_fd, int group, int offset, int cpu,
+ uint32_t *val, bool write);
+
+static inline void kvm_gicd_access(int dev_fd, int offset, int cpu,
+ uint32_t *val, bool write)
+{
+ kvm_gic_access(dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+ offset, cpu, val, write);
+}
+
+static inline void kvm_gicc_access(int dev_fd, int offset, int cpu,
+ uint32_t *val, bool write)
+{
+ kvm_gic_access(dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
+ offset, cpu, val, write);
+}
+
+#endif