From patchwork Tue Jul 28 13:22:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 51599 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f200.google.com (mail-lb0-f200.google.com [209.85.217.200]) by patches.linaro.org (Postfix) with ESMTPS id 1CEFA20323 for ; Tue, 28 Jul 2015 13:22:47 +0000 (UTC) Received: by lbcjf8 with SMTP id jf8sf38005061lbc.0 for ; Tue, 28 Jul 2015 06:22:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=+eKy9CGs0Q1x0agZ/WpzngDz5nxbk9NAHsZ96IeVcLk=; b=SlJG0PgB7qlGbIHKVoz4WdzPgLUgYTeirzg0rVt6QoLaD3u2lM2Dzz0sh9cDSCXj8U m5GgUeuDpuYhLMgY8lGA0Rsz8Heh/8YpcBPh+gxsTKMvH8krWVAuqYA9OiV/Ir1S+uj3 mdF3o/qGe8p3zBqrLxWLE0uJrZXLoy0wHmFew8GpV9Ws+k6qS88FQG+w6Y/qf4wTLNmq vcjVKgRak/LRT0Mo6baG/75As0N7Xn82Gi7FYYhRVuQzagzzBUzB1lZAX6l6PPsyo12/ PUS3h05vZ06y+/hoPuwG5VKHeBOYrcfJVGTSigrVwkl1wZ52jznLhR4SR+HSJrPvA2H/ T5ww== X-Gm-Message-State: ALoCoQltG54HZBwYoV3D3I8RSYWQsk/zOT4a45HODWwPzQ8WWiSZ4odC47yqW2wJ7an/y75dGrzV X-Received: by 10.194.188.104 with SMTP id fz8mr14084023wjc.1.1438089766165; Tue, 28 Jul 2015 06:22:46 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.27.234 with SMTP id w10ls706377lag.41.gmail; Tue, 28 Jul 2015 06:22:45 -0700 (PDT) X-Received: by 10.152.10.97 with SMTP id h1mr32923065lab.45.1438089765879; Tue, 28 Jul 2015 06:22:45 -0700 (PDT) Received: from mail-la0-f43.google.com (mail-la0-f43.google.com. [209.85.215.43]) by mx.google.com with ESMTPS id uo9si18348125lbb.12.2015.07.28.06.22.45 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 28 Jul 2015 06:22:45 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.43 as permitted sender) client-ip=209.85.215.43; Received: by lagw2 with SMTP id w2so68418928lag.3 for ; Tue, 28 Jul 2015 06:22:45 -0700 (PDT) X-Received: by 10.112.145.169 with SMTP id sv9mr19380356lbb.73.1438089765616; Tue, 28 Jul 2015 06:22:45 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.112.7.198 with SMTP id l6csp2138516lba; Tue, 28 Jul 2015 06:22:44 -0700 (PDT) X-Received: by 10.70.129.102 with SMTP id nv6mr81752255pdb.55.1438089755069; Tue, 28 Jul 2015 06:22:35 -0700 (PDT) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id n3si869838pap.184.2015.07.28.06.22.33 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 28 Jul 2015 06:22:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::1 as permitted sender) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1ZK4pw-0001Rs-H4; Tue, 28 Jul 2015 14:22:28 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, "Edgar E. Iglesias" Subject: [PATCH 4/5] hw/intc/arm_gic: Drop running_irq and last_active arrays Date: Tue, 28 Jul 2015 14:22:27 +0100 Message-Id: <1438089748-5528-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1438089748-5528-1-git-send-email-peter.maydell@linaro.org> References: <1438089748-5528-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.43 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The running_irq and last_active arrays represent state which doesn't exist in a real hardware GIC. The only thing we use them for is updating the running priority when an interrupt is completed, but in fact we can use the active-priority registers to do this. The running priority is always the priority corresponding to the lowest set bit in the active priority registers, because only one interrupt at any particular priority can be active at once. Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 103 ++++++++++++++++++++++++++++----------- hw/intc/arm_gic_common.c | 7 +-- include/hw/intc/arm_gic_common.h | 10 ---- 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index ed7faf5..427c221 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -245,15 +245,72 @@ static int gic_get_group_priority(GICState *s, int cpu, int irq) return GIC_GET_PRIORITY(irq, cpu) & mask; } -static void gic_set_running_irq(GICState *s, int cpu, int irq) +static void gic_activate_irq(GICState *s, int cpu, int irq) { - s->running_irq[cpu] = irq; - if (irq == 1023) { - s->running_priority[cpu] = 0x100; + /* Set the appropriate Active Priority Register bit for this IRQ, + * and update the running priority. + */ + int prio = gic_get_group_priority(s, cpu, irq); + int preemption_level = prio >> (GIC_MIN_BPR + 1); + int regno = preemption_level / 32; + int bitno = preemption_level % 32; + + if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) { + s->nsapr[regno][cpu] &= (1 << bitno); } else { - s->running_priority[cpu] = gic_get_group_priority(s, cpu, irq); + s->apr[regno][cpu] &= (1 << bitno); } - gic_update(s); + + s->running_priority[cpu] = prio; +} + +static int gic_get_prio_from_apr_bits(GICState *s, int cpu) +{ + /* Recalculate the current running priority for this CPU based + * on the set bits in the Active Priority Registers. + */ + int i; + for (i = 0; i < GIC_NR_APRS; i++) { + uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; + if (!apr) { + continue; + } + return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); + } + return 0x100; +} + +static void gic_drop_prio(GICState *s, int cpu, int group) +{ + /* Drop the priority of the currently active interrupt in the + * specified group. + * + * Note that we can guarantee (because of the requirement to nest + * GICC_IAR reads [which activate an interrupt and raise priority] + * with GICC_EOIR writes [which drop the priority for the interrupt]) + * that the interrupt we're being called for is the highest priority + * active interrupt, meaning that it has the lowest set bit in the + * APR registers. + * + * If the guest does not honour the ordering constraints then the + * behaviour of the GIC is UNPREDICTABLE, which for us means that + * the values of the APR registers might become incorrect and the + * running priority will be wrong, so interrupts that should preempt + * might not do so, and interrupts that should not preempt might do so. + */ + int i; + + for (i = 0; i < GIC_NR_APRS; i++) { + uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; + if (!*papr) { + continue; + } + /* Clear lowest set bit */ + *papr &= *papr - 1; + break; + } + + s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); } uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) @@ -276,7 +333,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); return 1023; } - s->last_active[irq][cpu] = s->running_irq[cpu]; if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { /* Clear pending flags for both level and edge triggered interrupts. @@ -307,7 +363,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) } } - gic_set_running_irq(s, cpu, irq); + gic_activate_irq(s, cpu, irq); + gic_update(s); DPRINTF("ACK %d\n", irq); return ret; } @@ -437,8 +494,9 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) { - int update = 0; int cm = 1 << cpu; + int group; + DPRINTF("EOI %d\n", irq); if (irq >= s->num_irq) { /* This handles two cases: @@ -451,8 +509,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) */ return; } - if (s->running_irq[cpu] == 1023) + if (s->running_priority[cpu] == 0x100) { return; /* No active IRQ. */ + } if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { /* Mark level triggered interrupts as pending if they are still @@ -461,11 +520,12 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { DPRINTF("Set %d pending mask %x\n", irq, cm); GIC_SET_PENDING(irq, cm); - update = 1; } } - if (s->security_extn && !attrs.secure && !GIC_TEST_GROUP(irq, cm)) { + group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); + + if (s->security_extn && !attrs.secure && !group) { DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); return; } @@ -475,23 +535,8 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) * i.e. go ahead and complete the irq anyway. */ - if (irq != s->running_irq[cpu]) { - /* Complete an IRQ that is not currently running. */ - int tmp = s->running_irq[cpu]; - while (s->last_active[tmp][cpu] != 1023) { - if (s->last_active[tmp][cpu] == irq) { - s->last_active[tmp][cpu] = s->last_active[irq][cpu]; - break; - } - tmp = s->last_active[tmp][cpu]; - } - if (update) { - gic_update(s); - } - } else { - /* Complete the current running IRQ. */ - gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); - } + gic_drop_prio(s, cpu, group); + gic_update(s); } static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index ea412ae..d19efac 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -59,8 +59,8 @@ static const VMStateDescription vmstate_gic_irq_state = { static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 11, - .minimum_version_id = 11, + .version_id = 12, + .minimum_version_id = 12, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { @@ -71,10 +71,8 @@ static const VMStateDescription vmstate_gic = { VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ), VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU), VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL), - VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU), VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU), VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU), - VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU), VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU), VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU), VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU), @@ -133,7 +131,6 @@ static void arm_gic_common_reset(DeviceState *dev) s->priority_mask[i] = 0; } s->current_pending[i] = 1023; - s->running_irq[i] = 1023; s->running_priority[i] = 0x100; s->cpu_ctlr[i] = 0; s->bpr[i] = GIC_MIN_BPR; diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index f7d33a5..bbc4c4d 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -68,7 +68,6 @@ typedef struct GICState { uint8_t irq_target[GIC_MAXIRQ]; uint8_t priority1[GIC_INTERNAL][GIC_NCPU]; uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL]; - uint16_t last_active[GIC_MAXIRQ][GIC_NCPU]; /* For each SGI on the target CPU, we store 8 bits * indicating which source CPUs have made this SGI * pending on the target CPU. These correspond to @@ -78,7 +77,6 @@ typedef struct GICState { uint8_t sgi_pending[GIC_NR_SGIS][GIC_NCPU]; uint16_t priority_mask[GIC_NCPU]; - uint16_t running_irq[GIC_NCPU]; uint16_t running_priority[GIC_NCPU]; uint16_t current_pending[GIC_NCPU]; @@ -96,14 +94,6 @@ typedef struct GICState { * If an interrupt for preemption level X is active, then * APRn[X mod 32] == 0b1, where n = X / 32 * otherwise the bit is clear. - * - * TODO: rewrite the interrupt acknowlege/complete routines to use - * the APR registers to track the necessary information to update - * s->running_priority[] on interrupt completion (ie completely remove - * last_active[][] and running_irq[]). This will be necessary if we ever - * want to support TCG<->KVM migration, or TCG guests which can - * do power management involving powering down and restarting - * the GIC. */ uint32_t apr[GIC_NR_APRS][GIC_NCPU]; uint32_t nsapr[GIC_NR_APRS][GIC_NCPU];