From 07e2034d0817b8006ae4eff07d9d67169d52855a Mon Sep 17 00:00:00 2001
From: Pavel Fedin
Date: Fri, 17 Jun 2016 15:23:46 +0100
Subject: hw/intc/arm_gicv3: Add state information
Add state information to GICv3 object structure and implement
arm_gicv3_common_reset().
This commit includes accessor functions for the fields which are
stored as bitmaps in uint32_t arrays.
Signed-off-by: Pavel Fedin
Reviewed-by: Shannon Zhao
Tested-by: Shannon Zhao
Signed-off-by: Peter Maydell
Message-id: 1465915112-29272-7-git-send-email-peter.maydell@linaro.org
[PMM: significantly overhauled:
* Add missing qom/cpu.h include
* Remove legacy-only state fields (we can add them later if/when we add
legacy emulation)
* Use arrays of uint32_t to store the various distributor bitmaps,
and provide accessor functions for the various set/test/etc operations
* Add various missing register offset #defines
* Accessor macros which combine distributor and redistributor behaviour
removed
* Fields in state structures renamed to match architectural register names
* Corrected the reset value for GICR_IENABLER0 since we don't support
legacy mode
* Added ARM_LINUX_BOOT_IF interface for "we are directly booting a kernel in
non-secure" so that we can fake up the firmware-mandated reconfiguration
only when we need it
]
Signed-off-by: Peter Maydell
Reviewed-by: Shannon Zhao
---
include/hw/intc/arm_gicv3_common.h | 192 ++++++++++++++++++++++++++++++++++++-
1 file changed, 189 insertions(+), 3 deletions(-)
(limited to 'include/hw')
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c2fd8da4ef..bd364a7e02 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -3,8 +3,9 @@
*
* Copyright (c) 2012 Linaro Limited
* Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
+ * Reworked for GICv3 by Shlomo Pongratz and 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
@@ -26,7 +27,143 @@
#include "hw/sysbus.h"
#include "hw/intc/arm_gic_common.h"
-typedef struct GICv3State {
+/*
+ * Maximum number of possible interrupts, determined by the GIC architecture.
+ * Note that this does not include LPIs. When implemented, these should be
+ * dealt with separately.
+ */
+#define GICV3_MAXIRQ 1020
+#define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL)
+
+/* Minimum BPR for Secure, or when security not enabled */
+#define GIC_MIN_BPR 0
+/* Minimum BPR for Nonsecure when security is enabled */
+#define GIC_MIN_BPR_NS (GIC_MIN_BPR + 1)
+
+/* For some distributor fields we want to model the array of 32-bit
+ * register values which hold various bitmaps corresponding to enabled,
+ * pending, etc bits. These macros and functions facilitate that; the
+ * APIs are generally modelled on the generic bitmap.h functions
+ * (which are unsuitable here because they use 'unsigned long' as the
+ * underlying storage type, which is very awkward when you need to
+ * access the data as 32-bit values.)
+ * Each bitmap contains a bit for each interrupt. Although there is
+ * space for the PPIs and SGIs, those bits (the first 32) are never
+ * used as that state lives in the redistributor. The unused bits are
+ * provided purely so that interrupt X's state is always in bit X; this
+ * avoids bugs where we forget to subtract GIC_INTERNAL from an
+ * interrupt number.
+ */
+#define GICV3_BMP_SIZE (DIV_ROUND_UP(GICV3_MAXIRQ, 32))
+
+#define GIC_DECLARE_BITMAP(name) \
+ uint32_t name[GICV3_BMP_SIZE]
+
+#define GIC_BIT_MASK(nr) (1U << ((nr) % 32))
+#define GIC_BIT_WORD(nr) ((nr) / 32)
+
+static inline void gic_bmp_set_bit(int nr, uint32_t *addr)
+{
+ uint32_t mask = GIC_BIT_MASK(nr);
+ uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+static inline void gic_bmp_clear_bit(int nr, uint32_t *addr)
+{
+ uint32_t mask = GIC_BIT_MASK(nr);
+ uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+ *p &= ~mask;
+}
+
+static inline int gic_bmp_test_bit(int nr, const uint32_t *addr)
+{
+ return 1U & (addr[GIC_BIT_WORD(nr)] >> (nr & 31));
+}
+
+static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val)
+{
+ uint32_t mask = GIC_BIT_MASK(nr);
+ uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+ *p &= ~mask;
+ *p |= (val & 1U) << (nr % 32);
+}
+
+/* Return a pointer to the 32-bit word containing the specified bit. */
+static inline uint32_t *gic_bmp_ptr32(uint32_t *addr, int nr)
+{
+ return addr + GIC_BIT_WORD(nr);
+}
+
+typedef struct GICv3State GICv3State;
+typedef struct GICv3CPUState GICv3CPUState;
+
+/* Some CPU interface registers come in three flavours:
+ * Group0, Group1 (Secure) and Group1 (NonSecure)
+ * (where the latter two are exposed as a single banked system register).
+ * In the state struct they are implemented as a 3-element array which
+ * can be indexed into by the GICV3_G0, GICV3_G1 and GICV3_G1NS constants.
+ * If the CPU doesn't support EL3 then the G1 element is unused.
+ *
+ * These constants are also used to communicate the group to use for
+ * an interrupt or SGI when it is passed between the cpu interface and
+ * the redistributor or distributor. For those purposes the receiving end
+ * must be prepared to cope with a Group 1 Secure interrupt even if it does
+ * not have security support enabled, because security can be disabled
+ * independently in the CPU and in the GIC. In that case the receiver should
+ * treat an incoming Group 1 Secure interrupt as if it were Group 0.
+ * (This architectural requirement is why the _G1 element is the unused one
+ * in a no-EL3 CPU: we would otherwise have to translate back and forth
+ * between (G0, G1NS) from the distributor and (G0, G1) in the CPU i/f.)
+ */
+#define GICV3_G0 0
+#define GICV3_G1 1
+#define GICV3_G1NS 2
+
+/* ICC_CTLR_EL1, GICD_STATUSR and GICR_STATUSR are banked but not
+ * group-related, so those indices are just 0 for S and 1 for NS.
+ * (If the CPU or the GIC, respectively, don't support the Security
+ * extensions then the S element is unused.)
+ */
+#define GICV3_S 0
+#define GICV3_NS 1
+
+struct GICv3CPUState {
+ GICv3State *gic;
+ CPUState *cpu;
+
+ /* Redistributor */
+ uint32_t level; /* Current IRQ level */
+ /* RD_base page registers */
+ uint32_t gicr_ctlr;
+ uint64_t gicr_typer;
+ uint32_t gicr_statusr[2];
+ uint32_t gicr_waker;
+ uint64_t gicr_propbaser;
+ uint64_t gicr_pendbaser;
+ /* SGI_base page registers */
+ uint32_t gicr_igroupr0;
+ uint32_t gicr_ienabler0;
+ uint32_t gicr_ipendr0;
+ uint32_t gicr_iactiver0;
+ uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */
+ uint32_t gicr_igrpmodr0;
+ uint32_t gicr_nsacr;
+ uint8_t gicr_ipriorityr[GIC_INTERNAL];
+
+ /* CPU interface */
+ uint64_t icc_ctlr_el1[2];
+ uint64_t icc_pmr_el1;
+ uint64_t icc_bpr[3];
+ uint64_t icc_apr[3][4];
+ uint64_t icc_igrpen[3];
+ uint64_t icc_ctlr_el3;
+};
+
+struct GICv3State {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
@@ -41,9 +178,58 @@ typedef struct GICv3State {
uint32_t num_irq;
uint32_t revision;
bool security_extn;
+ bool irq_reset_nonsecure;
int dev_fd; /* kvm device fd if backed by kvm vgic support */
-} GICv3State;
+ Error *migration_blocker;
+
+ /* Distributor */
+
+ /* for a GIC with the security extensions the NS banked version of this
+ * register is just an alias of bit 1 of the S banked version.
+ */
+ uint32_t gicd_ctlr;
+ uint32_t gicd_statusr[2];
+ GIC_DECLARE_BITMAP(group); /* GICD_IGROUPR */
+ GIC_DECLARE_BITMAP(grpmod); /* GICD_IGRPMODR */
+ GIC_DECLARE_BITMAP(enabled); /* GICD_ISENABLER */
+ GIC_DECLARE_BITMAP(pending); /* GICD_ISPENDR */
+ GIC_DECLARE_BITMAP(active); /* GICD_ISACTIVER */
+ GIC_DECLARE_BITMAP(level); /* Current level */
+ GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
+ uint8_t gicd_ipriority[GICV3_MAXIRQ];
+ uint64_t gicd_irouter[GICV3_MAXIRQ];
+ uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
+
+ GICv3CPUState *cpu;
+};
+
+#define GICV3_BITMAP_ACCESSORS(BMP) \
+ static inline void gicv3_gicd_##BMP##_set(GICv3State *s, int irq) \
+ { \
+ gic_bmp_set_bit(irq, s->BMP); \
+ } \
+ static inline int gicv3_gicd_##BMP##_test(GICv3State *s, int irq) \
+ { \
+ return gic_bmp_test_bit(irq, s->BMP); \
+ } \
+ static inline void gicv3_gicd_##BMP##_clear(GICv3State *s, int irq) \
+ { \
+ gic_bmp_clear_bit(irq, s->BMP); \
+ } \
+ static inline void gicv3_gicd_##BMP##_replace(GICv3State *s, \
+ int irq, int value) \
+ { \
+ gic_bmp_replace_bit(irq, s->BMP, value); \
+ }
+
+GICV3_BITMAP_ACCESSORS(group)
+GICV3_BITMAP_ACCESSORS(grpmod)
+GICV3_BITMAP_ACCESSORS(enabled)
+GICV3_BITMAP_ACCESSORS(pending)
+GICV3_BITMAP_ACCESSORS(active)
+GICV3_BITMAP_ACCESSORS(level)
+GICV3_BITMAP_ACCESSORS(edge_trigger)
#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
#define ARM_GICV3_COMMON(obj) \
--
cgit v1.2.3-55-g7522
From 3faf2b0cd5451c452fdaab32f9d2fb870b084f80 Mon Sep 17 00:00:00 2001
From: Peter Maydell
Date: Fri, 17 Jun 2016 15:23:46 +0100
Subject: hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
Move the GICv3 parent_irq and parent_fiq pointers into the
GICv3CPUState structure rather than giving them their own array.
This will make it easy to assert the IRQ and FIQ lines for a
particular CPU interface without having to know or calculate
the CPU index for the GICv3CPUState we are working on.
Signed-off-by: Peter Maydell
Reviewed-by: Shannon Zhao
Tested-by: Shannon Zhao
Message-id: 1465915112-29272-8-git-send-email-peter.maydell@linaro.org
---
hw/intc/arm_gicv3_common.c | 7 ++-----
include/hw/intc/arm_gicv3_common.h | 5 ++---
2 files changed, 4 insertions(+), 8 deletions(-)
(limited to 'include/hw')
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index bf6949f8cd..1557833173 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -72,14 +72,11 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu;
qdev_init_gpio_in(DEVICE(s), handler, i);
- s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq));
- s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq));
-
for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_irq[i]);
+ sysbus_init_irq(sbd, &s->cpu[i].parent_irq);
}
for (i = 0; i < s->num_cpu; i++) {
- sysbus_init_irq(sbd, &s->parent_fiq[i]);
+ sysbus_init_irq(sbd, &s->cpu[i].parent_fiq);
}
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index bd364a7e02..cc6ac74e63 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -134,6 +134,8 @@ typedef struct GICv3CPUState GICv3CPUState;
struct GICv3CPUState {
GICv3State *gic;
CPUState *cpu;
+ qemu_irq parent_irq;
+ qemu_irq parent_fiq;
/* Redistributor */
uint32_t level; /* Current IRQ level */
@@ -168,9 +170,6 @@ struct GICv3State {
SysBusDevice parent_obj;
/*< public >*/
- qemu_irq *parent_irq;
- qemu_irq *parent_fiq;
-
MemoryRegion iomem_dist; /* Distributor */
MemoryRegion iomem_redist; /* Redistributors */
--
cgit v1.2.3-55-g7522
From 56992670a45aa14637dafc145e9f9b68172efb13 Mon Sep 17 00:00:00 2001
From: Shlomo Pongratz
Date: Fri, 17 Jun 2016 15:23:46 +0100
Subject: hw/intc/arm_gicv3: ARM GICv3 device framework
This patch includes the device class itself, some ID register
value functions which will be needed by both distributor
and redistributor, and some skeleton functions for handling
interrupts coming in and going out, which will be filled in
in a subsequent patch.
Signed-off-by: Shlomo Pongratz
Reviewed-by: Shannon Zhao
Tested-by: Shannon Zhao
Signed-off-by: Peter Maydell
Message-id: 1465915112-29272-10-git-send-email-peter.maydell@linaro.org
[PMM: pulled this patch earlier in the sequence, and left
some code out of it for a later patch]
Signed-off-by: Peter Maydell
Reviewed-by: Shannon Zhao
---
hw/intc/Makefile.objs | 1 +
hw/intc/arm_gicv3.c | 74 +++++++++++++++++++++++++++++++++++++++++++++
hw/intc/gicv3_internal.h | 24 +++++++++++++++
include/hw/intc/arm_gicv3.h | 32 ++++++++++++++++++++
4 files changed, 131 insertions(+)
create mode 100644 hw/intc/arm_gicv3.c
create mode 100644 include/hw/intc/arm_gicv3.h
(limited to 'include/hw')
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 0e47f0f9ec..4e94fdd932 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -13,6 +13,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
new file mode 100644
index 0000000000..96e0d2ffcc
--- /dev/null
+++ b/hw/intc/arm_gicv3.c
@@ -0,0 +1,74 @@
+/*
+ * ARM Generic Interrupt Controller v3
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+/* This file contains implementation code for an interrupt controller
+ * which implements the GICv3 architecture. Specifically this is where
+ * the device class itself and the functions for handling interrupts
+ * coming in and going out live.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/intc/arm_gicv3.h"
+#include "gicv3_internal.h"
+
+/* Process a change in an external IRQ input. */
+static void gicv3_set_irq(void *opaque, int irq, int level)
+{
+ /* Meaning of the 'irq' parameter:
+ * [0..N-1] : external interrupts
+ * [N..N+31] : PPI (internal) interrupts for CPU 0
+ * [N+32..N+63] : PPI (internal interrupts for CPU 1
+ * ...
+ */
+ /* Do nothing for now */
+}
+
+static void arm_gic_realize(DeviceState *dev, Error **errp)
+{
+ /* Device instance realize function for the GIC sysbus device */
+ GICv3State *s = ARM_GICV3(dev);
+ ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s);
+ Error *local_err = NULL;
+
+ agc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ gicv3_init_irqs_and_mmio(s, gicv3_set_irq, NULL);
+}
+
+static void arm_gicv3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
+
+ agc->parent_realize = dc->realize;
+ dc->realize = arm_gic_realize;
+}
+
+static const TypeInfo arm_gicv3_info = {
+ .name = TYPE_ARM_GICV3,
+ .parent = TYPE_ARM_GICV3_COMMON,
+ .instance_size = sizeof(GICv3State),
+ .class_init = arm_gicv3_class_init,
+ .class_size = sizeof(ARMGICv3Class),
+};
+
+static void arm_gicv3_register_types(void)
+{
+ type_register_static(&arm_gicv3_info);
+}
+
+type_init(arm_gicv3_register_types)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index d23524b8d2..97c9d758a3 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,30 @@
#define ICC_CTLR_EL3_A3V (1U << 15)
#define ICC_CTLR_EL3_NDS (1U << 17)
+static inline uint32_t gicv3_iidr(void)
+{
+ /* Return the Implementer Identification Register value
+ * for the emulated GICv3, as reported in GICD_IIDR and GICR_IIDR.
+ *
+ * We claim to be an ARM r0p0 with a zero ProductID.
+ * This is the same as an r0p0 GIC-500.
+ */
+ return 0x43b;
+}
+
+static inline uint32_t gicv3_idreg(int regoffset)
+{
+ /* Return the value of the CoreSight ID register at the specified
+ * offset from the first ID register (as found in the distributor
+ * and redistributor register banks).
+ * These values indicate an ARM implementation of a GICv3.
+ */
+ static const uint8_t gicd_ids[] = {
+ 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
+ };
+ return gicd_ids[regoffset / 4];
+}
+
/**
* gicv3_redist_affid:
*
diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h
new file mode 100644
index 0000000000..4a6fd85e22
--- /dev/null
+++ b/include/hw/intc/arm_gicv3.h
@@ -0,0 +1,32 @@
+/*
+ * ARM Generic Interrupt Controller v3
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+#ifndef HW_ARM_GICV3_H
+#define HW_ARM_GICV3_H
+
+#include "arm_gicv3_common.h"
+
+#define TYPE_ARM_GICV3 "arm-gicv3"
+#define ARM_GICV3(obj) OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3)
+#define ARM_GICV3_CLASS(klass) \
+ OBJECT_CLASS_CHECK(ARMGICv3Class, (klass), TYPE_ARM_GICV3)
+#define ARM_GICV3_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ARMGICv3Class, (obj), TYPE_ARM_GICV3)
+
+typedef struct ARMGICv3Class {
+ /*< private >*/
+ ARMGICv3CommonClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+} ARMGICv3Class;
+
+#endif
--
cgit v1.2.3-55-g7522
From ce187c3c15f4bda579c9833cd78092fb73e651aa Mon Sep 17 00:00:00 2001
From: Peter Maydell
Date: Fri, 17 Jun 2016 15:23:46 +0100
Subject: hw/intc/arm_gicv3: Implement functions to identify next pending irq
Implement the GICv3 logic to recalculate the highest priority pending
interrupt for each CPU after some part of the GIC state has changed.
We avoid unnecessary full recalculation where possible.
Signed-off-by: Peter Maydell
Reviewed-by: Shannon Zhao
Tested-by: Shannon Zhao
Message-id: 1465915112-29272-11-git-send-email-peter.maydell@linaro.org
---
hw/intc/arm_gicv3.c | 293 +++++++++++++++++++++++++++++++++++++
hw/intc/arm_gicv3_common.c | 9 ++
hw/intc/gicv3_internal.h | 121 +++++++++++++++
include/hw/intc/arm_gicv3_common.h | 18 +++
4 files changed, 441 insertions(+)
(limited to 'include/hw')
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 96e0d2ffcc..171d58728c 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -21,6 +21,287 @@
#include "hw/intc/arm_gicv3.h"
#include "gicv3_internal.h"
+static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
+{
+ /* Return true if this IRQ at this priority should take
+ * precedence over the current recorded highest priority
+ * pending interrupt for this CPU. We also return true if
+ * the current recorded highest priority pending interrupt
+ * is the same as this one (a property which the calling code
+ * relies on).
+ */
+ if (prio < cs->hppi.prio) {
+ return true;
+ }
+ /* If multiple pending interrupts have the same priority then it is an
+ * IMPDEF choice which of them to signal to the CPU. We choose to
+ * signal the one with the lowest interrupt number.
+ */
+ if (prio == cs->hppi.prio && irq <= cs->hppi.irq) {
+ return true;
+ }
+ return false;
+}
+
+static uint32_t gicd_int_pending(GICv3State *s, int irq)
+{
+ /* Recalculate which distributor interrupts are actually pending
+ * in the group of 32 interrupts starting at irq (which should be a multiple
+ * of 32), and return a 32-bit integer which has a bit set for each
+ * interrupt that is eligible to be signaled to the CPU interface.
+ *
+ * An interrupt is pending if:
+ * + the PENDING latch is set OR it is level triggered and the input is 1
+ * + its ENABLE bit is set
+ * + the GICD enable bit for its group is set
+ * Conveniently we can bulk-calculate this with bitwise operations.
+ */
+ uint32_t pend, grpmask;
+ uint32_t pending = *gic_bmp_ptr32(s->pending, irq);
+ uint32_t edge_trigger = *gic_bmp_ptr32(s->edge_trigger, irq);
+ uint32_t level = *gic_bmp_ptr32(s->level, irq);
+ uint32_t group = *gic_bmp_ptr32(s->group, irq);
+ uint32_t grpmod = *gic_bmp_ptr32(s->grpmod, irq);
+ uint32_t enable = *gic_bmp_ptr32(s->enabled, irq);
+
+ pend = pending | (~edge_trigger & level);
+ pend &= enable;
+
+ if (s->gicd_ctlr & GICD_CTLR_DS) {
+ grpmod = 0;
+ }
+
+ grpmask = 0;
+ if (s->gicd_ctlr & GICD_CTLR_EN_GRP1NS) {
+ grpmask |= group;
+ }
+ if (s->gicd_ctlr & GICD_CTLR_EN_GRP1S) {
+ grpmask |= (~group & grpmod);
+ }
+ if (s->gicd_ctlr & GICD_CTLR_EN_GRP0) {
+ grpmask |= (~group & ~grpmod);
+ }
+ pend &= grpmask;
+
+ return pend;
+}
+
+static uint32_t gicr_int_pending(GICv3CPUState *cs)
+{
+ /* Recalculate which redistributor interrupts are actually pending,
+ * and return a 32-bit integer which has a bit set for each interrupt
+ * that is eligible to be signaled to the CPU interface.
+ *
+ * An interrupt is pending if:
+ * + the PENDING latch is set OR it is level triggered and the input is 1
+ * + its ENABLE bit is set
+ * + the GICD enable bit for its group is set
+ * Conveniently we can bulk-calculate this with bitwise operations.
+ */
+ uint32_t pend, grpmask, grpmod;
+
+ pend = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level);
+ pend &= cs->gicr_ienabler0;
+
+ if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
+ grpmod = 0;
+ } else {
+ grpmod = cs->gicr_igrpmodr0;
+ }
+
+ grpmask = 0;
+ if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) {
+ grpmask |= cs->gicr_igroupr0;
+ }
+ if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1S) {
+ grpmask |= (~cs->gicr_igroupr0 & grpmod);
+ }
+ if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP0) {
+ grpmask |= (~cs->gicr_igroupr0 & ~grpmod);
+ }
+ pend &= grpmask;
+
+ return pend;
+}
+
+/* Update the interrupt status after state in a redistributor
+ * or CPU interface has changed, but don't tell the CPU i/f.
+ */
+static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
+{
+ /* Find the highest priority pending interrupt among the
+ * redistributor interrupts (SGIs and PPIs).
+ */
+ bool seenbetter = false;
+ uint8_t prio;
+ int i;
+ uint32_t pend;
+
+ /* Find out which redistributor interrupts are eligible to be
+ * signaled to the CPU interface.
+ */
+ pend = gicr_int_pending(cs);
+
+ if (pend) {
+ for (i = 0; i < GIC_INTERNAL; i++) {
+ if (!(pend & (1 << i))) {
+ continue;
+ }
+ prio = cs->gicr_ipriorityr[i];
+ if (irqbetter(cs, i, prio)) {
+ cs->hppi.irq = i;
+ cs->hppi.prio = prio;
+ seenbetter = true;
+ }
+ }
+ }
+
+ if (seenbetter) {
+ cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
+ }
+
+ /* If the best interrupt we just found would preempt whatever
+ * was the previous best interrupt before this update, then
+ * we know it's definitely the best one now.
+ * If we didn't find an interrupt that would preempt the previous
+ * best, and the previous best is outside our range (or there was no
+ * previous pending interrupt at all), then that is still valid, and
+ * we leave it as the best.
+ * Otherwise, we need to do a full update (because the previous best
+ * interrupt has reduced in priority and any other interrupt could
+ * now be the new best one).
+ */
+ if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) {
+ gicv3_full_update_noirqset(cs->gic);
+ }
+}
+
+/* Update the GIC status after state in a redistributor or
+ * CPU interface has changed, and inform the CPU i/f of
+ * its new highest priority pending interrupt.
+ */
+void gicv3_redist_update(GICv3CPUState *cs)
+{
+ gicv3_redist_update_noirqset(cs);
+ gicv3_cpuif_update(cs);
+}
+
+/* Update the GIC status after state in the distributor has
+ * changed affecting @len interrupts starting at @start,
+ * but don't tell the CPU i/f.
+ */
+static void gicv3_update_noirqset(GICv3State *s, int start, int len)
+{
+ int i;
+ uint8_t prio;
+ uint32_t pend = 0;
+
+ assert(start >= GIC_INTERNAL);
+ assert(len > 0);
+
+ for (i = 0; i < s->num_cpu; i++) {
+ s->cpu[i].seenbetter = false;
+ }
+
+ /* Find the highest priority pending interrupt in this range. */
+ for (i = start; i < start + len; i++) {
+ GICv3CPUState *cs;
+
+ if (i == start || (i & 0x1f) == 0) {
+ /* Calculate the next 32 bits worth of pending status */
+ pend = gicd_int_pending(s, i & ~0x1f);
+ }
+
+ if (!(pend & (1 << (i & 0x1f)))) {
+ continue;
+ }
+ cs = s->gicd_irouter_target[i];
+ if (!cs) {
+ /* Interrupts targeting no implemented CPU should remain pending
+ * and not be forwarded to any CPU.
+ */
+ continue;
+ }
+ prio = s->gicd_ipriority[i];
+ if (irqbetter(cs, i, prio)) {
+ cs->hppi.irq = i;
+ cs->hppi.prio = prio;
+ cs->seenbetter = true;
+ }
+ }
+
+ /* If the best interrupt we just found would preempt whatever
+ * was the previous best interrupt before this update, then
+ * we know it's definitely the best one now.
+ * If we didn't find an interrupt that would preempt the previous
+ * best, and the previous best is outside our range (or there was
+ * no previous pending interrupt at all), then that
+ * is still valid, and we leave it as the best.
+ * Otherwise, we need to do a full update (because the previous best
+ * interrupt has reduced in priority and any other interrupt could
+ * now be the new best one).
+ */
+ for (i = 0; i < s->num_cpu; i++) {
+ GICv3CPUState *cs = &s->cpu[i];
+
+ if (cs->seenbetter) {
+ cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
+ }
+
+ if (!cs->seenbetter && cs->hppi.prio != 0xff &&
+ cs->hppi.irq >= start && cs->hppi.irq < start + len) {
+ gicv3_full_update_noirqset(s);
+ break;
+ }
+ }
+}
+
+void gicv3_update(GICv3State *s, int start, int len)
+{
+ int i;
+
+ gicv3_update_noirqset(s, start, len);
+ for (i = 0; i < s->num_cpu; i++) {
+ gicv3_cpuif_update(&s->cpu[i]);
+ }
+}
+
+void gicv3_full_update_noirqset(GICv3State *s)
+{
+ /* Completely recalculate the GIC status from scratch, but
+ * don't update any outbound IRQ lines.
+ */
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ s->cpu[i].hppi.prio = 0xff;
+ }
+
+ /* Note that we can guarantee that these functions will not
+ * recursively call back into gicv3_full_update(), because
+ * at each point the "previous best" is always outside the
+ * range we ask them to update.
+ */
+ gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL);
+
+ for (i = 0; i < s->num_cpu; i++) {
+ gicv3_redist_update_noirqset(&s->cpu[i]);
+ }
+}
+
+void gicv3_full_update(GICv3State *s)
+{
+ /* Completely recalculate the GIC status from scratch, including
+ * updating outbound IRQ lines.
+ */
+ int i;
+
+ gicv3_full_update_noirqset(s);
+ for (i = 0; i < s->num_cpu; i++) {
+ gicv3_cpuif_update(&s->cpu[i]);
+ }
+}
+
/* Process a change in an external IRQ input. */
static void gicv3_set_irq(void *opaque, int irq, int level)
{
@@ -33,6 +314,16 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
/* Do nothing for now */
}
+static void arm_gicv3_post_load(GICv3State *s)
+{
+ /* Recalculate our cached idea of the current highest priority
+ * pending interrupt, but don't set IRQ or FIQ lines.
+ */
+ gicv3_full_update_noirqset(s);
+ /* Repopulate the cache of GICv3CPUState pointers for target CPUs */
+ gicv3_cache_all_target_cpustates(s);
+}
+
static void arm_gic_realize(DeviceState *dev, Error **errp)
{
/* Device instance realize function for the GIC sysbus device */
@@ -52,8 +343,10 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
static void arm_gicv3_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
+ agcc->post_load = arm_gicv3_post_load;
agc->parent_realize = dc->realize;
dc->realize = arm_gic_realize;
}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index d1714e42ab..0f8c4b86e0 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -246,6 +246,8 @@ static void arm_gicv3_common_reset(DeviceState *dev)
cs->gicr_nsacr = 0;
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
+ cs->hppi.prio = 0xff;
+
/* State in the CPU interface must *not* be reset here, because it
* is part of the CPU's reset domain, not the GIC device's.
*/
@@ -271,6 +273,13 @@ static void arm_gicv3_common_reset(DeviceState *dev)
memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
+ /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must
+ * write these to get sane behaviour and we need not populate the
+ * pointer cache here; however having the cache be different for
+ * "happened to be 0 from reset" and "guest wrote 0" would be
+ * too confusing.
+ */
+ gicv3_cache_all_target_cpustates(s);
if (s->irq_reset_nonsecure) {
/* If we're resetting a TZ-aware GIC as if secure firmware
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 97c9d758a3..2ee9eebec8 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,63 @@
#define ICC_CTLR_EL3_A3V (1U << 15)
#define ICC_CTLR_EL3_NDS (1U << 17)
+/* Functions internal to the emulated GICv3 */
+
+/**
+ * gicv3_redist_update:
+ * @cs: GICv3CPUState for this redistributor
+ *
+ * Recalculate the highest priority pending interrupt after a
+ * change to redistributor state, and inform the CPU accordingly.
+ */
+void gicv3_redist_update(GICv3CPUState *cs);
+
+/**
+ * gicv3_update:
+ * @s: GICv3State
+ * @start: first interrupt whose state changed
+ * @len: length of the range of interrupts whose state changed
+ *
+ * Recalculate the highest priority pending interrupts after a
+ * change to the distributor state affecting @len interrupts
+ * starting at @start, and inform the CPUs accordingly.
+ */
+void gicv3_update(GICv3State *s, int start, int len);
+
+/**
+ * gicv3_full_update_noirqset:
+ * @s: GICv3State
+ *
+ * Recalculate the cached information about highest priority
+ * pending interrupts, but don't inform the CPUs. This should be
+ * called after an incoming migration has loaded new state.
+ */
+void gicv3_full_update_noirqset(GICv3State *s);
+
+/**
+ * gicv3_full_update:
+ * @s: GICv3State
+ *
+ * Recalculate the highest priority pending interrupts after
+ * a change that could affect the status of all interrupts,
+ * and inform the CPUs accordingly.
+ */
+void gicv3_full_update(GICv3State *s);
+
+/**
+ * gicv3_cpuif_update:
+ * @cs: GICv3CPUState for the CPU to update
+ *
+ * Recalculate whether to assert the IRQ or FIQ lines after a change
+ * to the current highest priority pending interrupt, the CPU's
+ * current running priority or the CPU's current exception level or
+ * security state.
+ */
+static inline void gicv3_cpuif_update(GICv3CPUState *cs)
+{
+ /* This will be implemented in a later commit. */
+}
+
static inline uint32_t gicv3_iidr(void)
{
/* Return the Implementer Identification Register value
@@ -183,6 +240,32 @@ static inline uint32_t gicv3_idreg(int regoffset)
return gicd_ids[regoffset / 4];
}
+/**
+ * gicv3_irq_group:
+ *
+ * Return the group which this interrupt is configured as (GICV3_G0,
+ * GICV3_G1 or GICV3_G1NS).
+ */
+static inline int gicv3_irq_group(GICv3State *s, GICv3CPUState *cs, int irq)
+{
+ bool grpbit, grpmodbit;
+
+ if (irq < GIC_INTERNAL) {
+ grpbit = extract32(cs->gicr_igroupr0, irq, 1);
+ grpmodbit = extract32(cs->gicr_igrpmodr0, irq, 1);
+ } else {
+ grpbit = gicv3_gicd_group_test(s, irq);
+ grpmodbit = gicv3_gicd_grpmod_test(s, irq);
+ }
+ if (grpbit) {
+ return GICV3_G1NS;
+ }
+ if (s->gicd_ctlr & GICD_CTLR_DS) {
+ return GICV3_G0;
+ }
+ return grpmodbit ? GICV3_G1 : GICV3_G0;
+}
+
/**
* gicv3_redist_affid:
*
@@ -193,4 +276,42 @@ static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs)
return cs->gicr_typer >> 32;
}
+/**
+ * gicv3_cache_target_cpustate:
+ *
+ * Update the cached CPU state corresponding to the target for this interrupt
+ * (which is kept in s->gicd_irouter_target[]).
+ */
+static inline void gicv3_cache_target_cpustate(GICv3State *s, int irq)
+{
+ GICv3CPUState *cs = NULL;
+ int i;
+ uint32_t tgtaff = extract64(s->gicd_irouter[irq], 0, 24) |
+ extract64(s->gicd_irouter[irq], 32, 8) << 24;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ if (s->cpu[i].gicr_typer >> 32 == tgtaff) {
+ cs = &s->cpu[i];
+ break;
+ }
+ }
+
+ s->gicd_irouter_target[irq] = cs;
+}
+
+/**
+ * gicv3_cache_all_target_cpustates:
+ *
+ * Populate the entire cache of CPU state pointers for interrupt targets
+ * (eg after inbound migration or CPU reset)
+ */
+static inline void gicv3_cache_all_target_cpustates(GICv3State *s)
+{
+ int irq;
+
+ for (irq = GIC_INTERNAL; irq < GICV3_MAXIRQ; irq++) {
+ gicv3_cache_target_cpustate(s, irq);
+ }
+}
+
#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index cc6ac74e63..f72e49922f 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -131,6 +131,12 @@ typedef struct GICv3CPUState GICv3CPUState;
#define GICV3_S 0
#define GICV3_NS 1
+typedef struct {
+ int irq;
+ uint8_t prio;
+ int grp;
+} PendingIrq;
+
struct GICv3CPUState {
GICv3State *gic;
CPUState *cpu;
@@ -163,6 +169,14 @@ struct GICv3CPUState {
uint64_t icc_apr[3][4];
uint64_t icc_igrpen[3];
uint64_t icc_ctlr_el3;
+
+ /* Current highest priority pending interrupt for this CPU.
+ * This is cached information that can be recalculated from the
+ * real state above; it doesn't need to be migrated.
+ */
+ PendingIrq hppi;
+ /* This is temporary working state, to avoid a malloc in gicv3_update() */
+ bool seenbetter;
};
struct GICv3State {
@@ -198,6 +212,10 @@ struct GICv3State {
GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
uint8_t gicd_ipriority[GICV3_MAXIRQ];
uint64_t gicd_irouter[GICV3_MAXIRQ];
+ /* Cached information: pointer to the cpu i/f for the CPUs specified
+ * in the IROUTER registers
+ */
+ GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ];
uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
GICv3CPUState *cpu;
--
cgit v1.2.3-55-g7522
From 1d3e65aa7ac5afb6798c222abd923eff49ac55f0 Mon Sep 17 00:00:00 2001
From: Andrew Jeffery
Date: Fri, 17 Jun 2016 15:23:48 +0100
Subject: hw/timer: Add value matching support to aspeed_timer
Value matching allows Linux to boot with CONFIG_NO_HZ_IDLE=y on the
palmetto-bmc machine. Two match registers are provided for each timer.
Signed-off-by: Andrew Jeffery
Message-id: 1465974248-20434-1-git-send-email-andrew@aj.id.au
Reviewed-by: Peter Maydell
Signed-off-by: Peter Maydell
---
hw/timer/aspeed_timer.c | 138 +++++++++++++++++++++++++++++-----------
include/hw/timer/aspeed_timer.h | 5 +-
2 files changed, 104 insertions(+), 39 deletions(-)
(limited to 'include/hw')
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 4b94808821..9b70ee09b0 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -10,12 +10,10 @@
*/
#include "qemu/osdep.h"
-#include "hw/ptimer.h"
#include "hw/sysbus.h"
#include "hw/timer/aspeed_timer.h"
#include "qemu-common.h"
#include "qemu/bitops.h"
-#include "qemu/main-loop.h"
#include "qemu/timer.h"
#include "qemu/log.h"
#include "trace.h"
@@ -77,21 +75,96 @@ static inline bool timer_can_pulse(AspeedTimer *t)
return t->id >= TIMER_FIRST_CAP_PULSE;
}
+static inline bool timer_external_clock(AspeedTimer *t)
+{
+ return timer_ctrl_status(t, op_external_clock);
+}
+
+static uint32_t clock_rates[] = { TIMER_CLOCK_APB_HZ, TIMER_CLOCK_EXT_HZ };
+
+static inline uint32_t calculate_rate(struct AspeedTimer *t)
+{
+ return clock_rates[timer_external_clock(t)];
+}
+
+static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
+{
+ uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
+ uint32_t rate = calculate_rate(t);
+ uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
+
+ return t->reload - MIN(t->reload, ticks);
+}
+
+static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
+{
+ uint64_t delta_ns;
+ uint64_t delta_ticks;
+
+ delta_ticks = t->reload - MIN(t->reload, ticks);
+ delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
+
+ return t->start + delta_ns;
+}
+
+static uint64_t calculate_next(struct AspeedTimer *t)
+{
+ uint64_t next = 0;
+ uint32_t rate = calculate_rate(t);
+
+ while (!next) {
+ /* We don't know the relationship between the values in the match
+ * registers, so sort using MAX/MIN/zero. We sort in that order as the
+ * timer counts down to zero. */
+ uint64_t seq[] = {
+ calculate_time(t, MAX(t->match[0], t->match[1])),
+ calculate_time(t, MIN(t->match[0], t->match[1])),
+ calculate_time(t, 0),
+ };
+ uint64_t reload_ns;
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if (now < seq[0]) {
+ next = seq[0];
+ } else if (now < seq[1]) {
+ next = seq[1];
+ } else if (now < seq[2]) {
+ next = seq[2];
+ } else {
+ reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
+ t->start = now - ((now - t->start) % reload_ns);
+ }
+ }
+
+ return next;
+}
+
static void aspeed_timer_expire(void *opaque)
{
AspeedTimer *t = opaque;
+ bool interrupt = false;
+ uint32_t ticks;
- /* Only support interrupts on match values of zero for the moment - this is
- * sufficient to boot an aspeed_defconfig Linux kernel.
- *
- * TODO: matching on arbitrary values (see e.g. hw/timer/a9gtimer.c)
- */
- bool match = !(t->match[0] && t->match[1]);
- bool interrupt = timer_overflow_interrupt(t) || match;
- if (timer_enabled(t) && interrupt) {
+ if (!timer_enabled(t)) {
+ return;
+ }
+
+ ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+
+ if (!ticks) {
+ interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
+ } else if (ticks <= MIN(t->match[0], t->match[1])) {
+ interrupt = true;
+ } else if (ticks <= MAX(t->match[0], t->match[1])) {
+ interrupt = true;
+ }
+
+ if (interrupt) {
t->level = !t->level;
qemu_set_irq(t->irq, t->level);
}
+
+ timer_mod(&t->timer, calculate_next(t));
}
static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
@@ -100,7 +173,7 @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
switch (reg) {
case TIMER_REG_STATUS:
- value = ptimer_get_count(t->timer);
+ value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
break;
case TIMER_REG_RELOAD:
value = t->reload;
@@ -160,24 +233,22 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
switch (reg) {
case TIMER_REG_STATUS:
if (timer_enabled(t)) {
- ptimer_set_count(t->timer, value);
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
+ uint32_t rate = calculate_rate(t);
+
+ t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+ timer_mod(&t->timer, calculate_next(t));
}
break;
case TIMER_REG_RELOAD:
t->reload = value;
- ptimer_set_limit(t->timer, value, 1);
break;
case TIMER_REG_MATCH_FIRST:
case TIMER_REG_MATCH_SECOND:
- if (value) {
- /* Non-zero match values are unsupported. As such an interrupt will
- * always be triggered when the timer reaches zero even if the
- * overflow interrupt control bit is clear.
- */
- qemu_log_mask(LOG_UNIMP, "%s: Match value unsupported by device: "
- "0x%" PRIx32 "\n", __func__, value);
- } else {
- t->match[reg - 2] = value;
+ t->match[reg - 2] = value;
+ if (timer_enabled(t)) {
+ timer_mod(&t->timer, calculate_next(t));
}
break;
default:
@@ -196,21 +267,16 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
{
trace_aspeed_timer_ctrl_enable(t->id, enable);
if (enable) {
- ptimer_run(t->timer, 0);
+ t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ timer_mod(&t->timer, calculate_next(t));
} else {
- ptimer_stop(t->timer);
- ptimer_set_limit(t->timer, t->reload, 1);
+ timer_del(&t->timer);
}
}
static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
{
trace_aspeed_timer_ctrl_external_clock(t->id, enable);
- if (enable) {
- ptimer_set_freq(t->timer, TIMER_CLOCK_EXT_HZ);
- } else {
- ptimer_set_freq(t->timer, TIMER_CLOCK_APB_HZ);
- }
}
static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
@@ -351,12 +417,10 @@ static const MemoryRegionOps aspeed_timer_ops = {
static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
{
- QEMUBH *bh;
AspeedTimer *t = &s->timers[id];
t->id = id;
- bh = qemu_bh_new(aspeed_timer_expire, t);
- t->timer = ptimer_init(bh);
+ timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
}
static void aspeed_timer_realize(DeviceState *dev, Error **errp)
@@ -399,12 +463,12 @@ static void aspeed_timer_reset(DeviceState *dev)
static const VMStateDescription vmstate_aspeed_timer = {
.name = "aspeed.timer",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT8(id, AspeedTimer),
VMSTATE_INT32(level, AspeedTimer),
- VMSTATE_PTIMER(timer, AspeedTimer),
+ VMSTATE_TIMER(timer, AspeedTimer),
VMSTATE_UINT32(reload, AspeedTimer),
VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
VMSTATE_END_OF_LIST()
@@ -419,7 +483,7 @@ static const VMStateDescription vmstate_aspeed_timer_state = {
VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
- ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
+ ASPEED_TIMER_NR_TIMERS, 2, vmstate_aspeed_timer,
AspeedTimer),
VMSTATE_END_OF_LIST()
}
diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h
index 44dc2f89d5..bd6c1a7f96 100644
--- a/include/hw/timer/aspeed_timer.h
+++ b/include/hw/timer/aspeed_timer.h
@@ -22,7 +22,7 @@
#ifndef ASPEED_TIMER_H
#define ASPEED_TIMER_H
-#include "hw/ptimer.h"
+#include "qemu/timer.h"
#define ASPEED_TIMER(obj) \
OBJECT_CHECK(AspeedTimerCtrlState, (obj), TYPE_ASPEED_TIMER);
@@ -33,15 +33,16 @@ typedef struct AspeedTimer {
qemu_irq irq;
uint8_t id;
+ QEMUTimer timer;
/**
* Track the line level as the ASPEED timers implement edge triggered
* interrupts, signalling with both the rising and falling edge.
*/
int32_t level;
- ptimer_state *timer;
uint32_t reload;
uint32_t match[2];
+ uint64_t start;
} AspeedTimer;
typedef struct AspeedTimerCtrlState {
--
cgit v1.2.3-55-g7522
From f06765a94a31bdd8b65fc83fd91a6c3f8e8a1195 Mon Sep 17 00:00:00 2001
From: Shannon Zhao
Date: Fri, 17 Jun 2016 15:23:48 +0100
Subject: ACPI: ARM: Present GIC version in MADT table
In ACPI 5.1 Errata, it adds GIC version in GIC distributor structure.
This is useful for guest kernel to identify which version GIC hardware
is. Update GIC distributor structure and present GIC version in MADT
table.
Signed-off-by: Shannon Zhao
Reviewed-by: Andrew Jones
Message-id: 1465960955-17388-1-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell
---
hw/arm/virt-acpi-build.c | 1 +
include/hw/acpi/acpi-defs.h | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
(limited to 'include/hw')
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1fa0581e33..28fc59c665 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -523,6 +523,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
gicd->length = sizeof(*gicd);
gicd->base_address = memmap[VIRT_GIC_DIST].base;
+ gicd->version = guest_info->gic_version;
for (i = 0; i < guest_info->smp_cpus; i++) {
AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 850a9626b7..ea9be0bdb1 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -367,7 +367,9 @@ struct AcpiMadtGenericDistributor {
uint32_t gic_id;
uint64_t base_address;
uint32_t global_irq_base;
- uint32_t reserved2;
+ /* ACPI 5.1 Errata 1228 Present GIC version in MADT table */
+ uint8_t version;
+ uint8_t reserved2[3];
} QEMU_PACKED;
typedef struct AcpiMadtGenericDistributor AcpiMadtGenericDistributor;
--
cgit v1.2.3-55-g7522