[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 08/16] hw/intc/arm_gic: Make ICCICR/GICC_CTLR
From: |
Peter Maydell |
Subject: |
Re: [Qemu-devel] [PATCH v2 08/16] hw/intc/arm_gic: Make ICCICR/GICC_CTLR banked |
Date: |
Tue, 14 Apr 2015 20:22:48 +0100 |
On 30 October 2014 at 22:12, Greg Bellows <address@hidden> wrote:
> From: Fabian Aggeler <address@hidden>
>
> ICCICR/GICC_CTLR is banked in GICv1 implementations with Security
> Extensions or in GICv2 in independent from Security Extensions.
> This makes it possible to enable forwarding of interrupts from
> the CPU interfaces to the connected processors for Group0 and Group1.
>
> We also allow to set additional bits like AckCtl and FIQEn by changing
> the type from bool to uint32. Since the field does not only store the
> enable bit anymore and since we are touching the vmstate, we use the
> opportunity to rename the field to cpu_control.
>
> Signed-off-by: Fabian Aggeler <address@hidden>
>
> ---
>
> v1 -> v2
> - Rework gic_set_cpu_control() and gic_get_cpu_control() to close gap on
> handling GICv1 wihtout security extensions.
> - Fix use of incorrect control index in update.
> ---
> hw/intc/arm_gic.c | 82
> +++++++++++++++++++++++++++++++++++++---
> hw/intc/arm_gic_common.c | 5 ++-
> hw/intc/arm_gic_kvm.c | 8 ++--
> hw/intc/armv7m_nvic.c | 2 +-
> hw/intc/gic_internal.h | 14 +++++++
> include/hw/intc/arm_gic_common.h | 2 +-
> 6 files changed, 100 insertions(+), 13 deletions(-)
>
> diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
> index 1db15aa..3c0414f 100644
> --- a/hw/intc/arm_gic.c
> +++ b/hw/intc/arm_gic.c
> @@ -66,7 +66,7 @@ void gic_update(GICState *s)
> for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
> cm = 1 << cpu;
> s->current_pending[cpu] = 1023;
> - if (!s->enabled || !s->cpu_enabled[cpu]) {
> + if (!s->enabled || !(s->cpu_control[cpu][1] & 1)) {
> qemu_irq_lower(s->parent_irq[cpu]);
> return;
> }
> @@ -240,6 +240,80 @@ void gic_set_priority(GICState *s, int cpu, int irq,
> uint8_t val)
> }
> }
>
> +uint32_t gic_get_cpu_control(GICState *s, int cpu)
> +{
> + uint32_t ret;
> +
> + if (!s->security_extn) {
> + if (s->revision == 1) {
> + ret = s->cpu_control[cpu][1];
> + ret &= 0x1; /* Mask of reserved bits */
> + } else {
> + ret = s->cpu_control[cpu][0];
> + ret &= GICC_CTLR_S_MASK; /* Mask of reserved bits */
> + }
> + } else {
> + if (ns_access()) {
> + ret = s->cpu_control[cpu][1];
> + ret &= GICC_CTLR_NS_MASK; /* Mask of reserved bits */
> + if (s->revision == 1) {
> + ret &= 0x1; /* Mask of reserved bits */
> + }
> + } else {
> + ret = s->cpu_control[cpu][0];
> + ret &= GICC_CTLR_S_MASK; /* Mask of reserved bits */
> + }
> + }
> +
> + return ret;
> +}
> +
> +void gic_set_cpu_control(GICState *s, int cpu, uint32_t value)
> +{
> + if (!s->security_extn) {
> + if (s->revision == 1) {
> + s->cpu_control[cpu][1] = value & 0x1;
> + DPRINTF("CPU Interface %d %sabled\n", cpu,
> + s->cpu_control[cpu][1] ? "En" : "Dis");
> + } else {
> + /* Write to Secure instance of the register */
> + s->cpu_control[cpu][0] = value & GICC_CTLR_S_MASK;
> + /* Synchronize EnableGrp1 alias of Non-secure copy */
> + s->cpu_control[cpu][1] &= ~GICC_CTLR_NS_EN_GRP1;
> + s->cpu_control[cpu][1] |=
> + (value & GICC_CTLR_S_EN_GRP1) ? GICC_CTLR_NS_EN_GRP1 : 0;
> + DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, "
> + "Group1 Interrupts %sabled\n", cpu,
> + (s->cpu_control[cpu][0] & GICC_CTLR_S_EN_GRP0) ? "En" :
> "Dis",
> + (s->cpu_control[cpu][0] & GICC_CTLR_S_EN_GRP1) ? "En" :
> "Dis");
> + }
> + } else {
> + if (ns_access()) {
> + if (s->revision == 1) {
> + s->cpu_control[cpu][1] = value & 0x1;
> + DPRINTF("CPU Interface %d %sabled\n", cpu,
> + s->cpu_control[cpu][1] ? "En" : "Dis");
> + } else {
> + /* Write to Non-secure instance of the register */
> + s->cpu_control[cpu][1] = value & GICC_CTLR_NS_MASK;
> + /* Synchronize EnableGrp1 alias of Secure copy */
> + s->cpu_control[cpu][0] &= ~GICC_CTLR_S_EN_GRP1;
> + s->cpu_control[cpu][0] |=
> + (value & GICC_CTLR_NS_EN_GRP1) ? GICC_CTLR_S_EN_GRP1 : 0;
> + }
> + DPRINTF("CPU Interface %d: Group1 Interrupts %sabled\n", cpu,
> + (s->cpu_control[cpu][1] & GICC_CTLR_NS_EN_GRP1) ? "En" :
> "Dis");
> + } else {
> + /* Write to Secure instance of the register */
> + s->cpu_control[cpu][0] = value & GICC_CTLR_S_MASK;
> + /* Synchronize EnableGrp1 alias of Non-secure copy */
> + s->cpu_control[cpu][1] &= ~GICC_CTLR_NS_EN_GRP1;
> + s->cpu_control[cpu][1] |=
> + (value & GICC_CTLR_S_EN_GRP1) ? GICC_CTLR_NS_EN_GRP1 : 0;
> + }
> + }
> +}
These feel a bit verbose -- I shall look to see if there's any
simplification possible here.
> +
> void gic_complete_irq(GICState *s, int cpu, int irq)
> {
> int update = 0;
> @@ -762,7 +836,7 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int
> offset)
> {
> switch (offset) {
> case 0x00: /* Control */
> - return s->cpu_enabled[cpu];
> + return gic_get_cpu_control(s, cpu);
> case 0x04: /* Priority mask */
> return s->priority_mask[cpu];
> case 0x08: /* Binary Point */
> @@ -788,9 +862,7 @@ static void gic_cpu_write(GICState *s, int cpu, int
> offset, uint32_t value)
> {
> switch (offset) {
> case 0x00: /* Control */
> - s->cpu_enabled[cpu] = (value & 1);
> - DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
> - break;
> + return gic_set_cpu_control(s, cpu, value);
gic_set_cpu_control() has a 'void' return type, so you
can't use it like this.
> case 0x04: /* Priority mask */
> s->priority_mask[cpu] = (value & 0xff);
> break;
> diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
> index c44050d..e225f2b 100644
> --- a/hw/intc/arm_gic_common.c
> +++ b/hw/intc/arm_gic_common.c
> @@ -65,7 +65,7 @@ static const VMStateDescription vmstate_gic = {
> .post_load = gic_post_load,
> .fields = (VMStateField[]) {
> VMSTATE_UINT8_ARRAY(enabled_grp, GICState, GIC_NR_GROUP),
> - VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, GIC_NCPU),
> + VMSTATE_UINT32_2DARRAY(cpu_control, GICState, GIC_NCPU,
> GIC_NR_GROUP),
> VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
> vmstate_gic_irq_state, gic_irq_state),
> VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
> @@ -127,7 +127,8 @@ static void arm_gic_common_reset(DeviceState *dev)
> s->current_pending[i] = 1023;
> s->running_irq[i] = 1023;
> s->running_priority[i] = 0x100;
> - s->cpu_enabled[i] = false;
> + s->cpu_control[i][0] = false;
> + s->cpu_control[i][1] = false;
The type has changed from bool to uint32_t, so we should
be initializing these to 0, not false.
> }
> for (i = 0; i < GIC_NR_SGIS; i++) {
> GIC_SET_ENABLED(i, ALL_CPU_MASK);
> diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
> index 5038885..9a6a2bb 100644
> --- a/hw/intc/arm_gic_kvm.c
> +++ b/hw/intc/arm_gic_kvm.c
> @@ -379,8 +379,8 @@ static void kvm_arm_gic_put(GICState *s)
> */
>
> for (cpu = 0; cpu < s->num_cpu; cpu++) {
> - /* s->cpu_enabled[cpu] -> GICC_CTLR */
> - reg = s->cpu_enabled[cpu];
> + /* s->cpu_enabled[cpu][0] -> GICC_CTLR */
> + reg = s->cpu_control[cpu];
This is missing the second array index. (Comment should have
the same var name as the code, too.)
> kvm_gicc_access(s, 0x00, cpu, ®, true);
>
> /* s->priority_mask[cpu] -> GICC_PMR */
> @@ -478,9 +478,9 @@ static void kvm_arm_gic_get(GICState *s)
> */
>
> for (cpu = 0; cpu < s->num_cpu; cpu++) {
> - /* GICC_CTLR -> s->cpu_enabled[cpu] */
> + /* GICC_CTLR -> s->cpu_control[cpu][0] */
> kvm_gicc_access(s, 0x00, cpu, ®, false);
> - s->cpu_enabled[cpu] = (reg & 1);
> + s->cpu_control[cpu][0] = reg;
>
> /* GICC_PMR -> s->priority_mask[cpu] */
> kvm_gicc_access(s, 0x04, cpu, ®, false);
> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
> index d0543d4..7f4a55c 100644
> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -465,7 +465,7 @@ static void armv7m_nvic_reset(DeviceState *dev)
> * as enabled by default, and with a priority mask which allows
> * all interrupts through.
> */
> - s->gic.cpu_enabled[0] = true;
> + s->gic.cpu_control[0][0] = true;
> s->gic.priority_mask[0] = 0x100;
> /* The NVIC as a whole is always enabled. */
> s->gic.enabled = true;
> diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
> index f01955a..e360de6 100644
> --- a/hw/intc/gic_internal.h
> +++ b/hw/intc/gic_internal.h
> @@ -54,6 +54,17 @@
> #define GIC_SET_GROUP1(irq, cm) (s->irq_state[irq].group |= (cm))
> #define GIC_TEST_GROUP0(irq, cm) ((s->irq_state[irq].group & (cm)) == 0)
>
> +#define GICC_CTLR_S_EN_GRP0 (1U << 0)
> +#define GICC_CTLR_S_EN_GRP1 (1U << 1)
> +#define GICC_CTLR_S_ACK_CTL (1U << 2)
> +#define GICC_CTLR_S_FIQ_EN (1U << 3)
> +#define GICC_CTLR_S_CBPR (1U << 4) /* GICv1: SBPR */
Odd indent here.
> +
> +#define GICC_CTLR_S_MASK 0x7ff
> +
> +#define GICC_CTLR_NS_EN_GRP1 (1U << 0)
> +#define GICC_CTLR_NS_MASK (1 | 3 << 5 | 1 << 9)
More brackets in this expression would help clarity.
> +
>
> /* The special cases for the revision property: */
> #define REV_11MPCORE 0
> @@ -65,6 +76,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq);
> void gic_update(GICState *s);
> void gic_init_irqs_and_distributor(GICState *s);
> void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val);
> +uint32_t gic_get_cpu_control(GICState *s, int cpu);
> +void gic_set_cpu_control(GICState *s, int cpu, uint32_t value);
> +
>
> static inline bool gic_test_pending(GICState *s, int irq, int cm)
> {
> diff --git a/include/hw/intc/arm_gic_common.h
> b/include/hw/intc/arm_gic_common.h
> index 16e193d..1daa672 100644
> --- a/include/hw/intc/arm_gic_common.h
> +++ b/include/hw/intc/arm_gic_common.h
> @@ -58,7 +58,7 @@ typedef struct GICState {
> uint8_t enabled;
> uint8_t enabled_grp[GIC_NR_GROUP]; /* EnableGrp0 and EnableGrp1 */
> };
> - bool cpu_enabled[GIC_NCPU];
> + uint32_t cpu_control[GIC_NCPU][GIC_NR_GROUP];
>
> gic_irq_state irq_state[GIC_MAXIRQ];
> uint8_t irq_target[GIC_MAXIRQ];
> --
> 1.8.3.2
-- PMM
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-devel] [PATCH v2 08/16] hw/intc/arm_gic: Make ICCICR/GICC_CTLR banked,
Peter Maydell <=