From patchwork Sat Feb 8 15:57:50 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 24364 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-oa0-f71.google.com (mail-oa0-f71.google.com [209.85.219.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 62D6020967 for ; Sat, 8 Feb 2014 16:08:16 +0000 (UTC) Received: by mail-oa0-f71.google.com with SMTP id g12sf20777389oah.10 for ; Sat, 08 Feb 2014 08:08:15 -0800 (PST) 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:date :message-id:in-reply-to:references:cc:subject:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list; bh=ChXEkjgtpSDmGVtWDyYqzTHNBWJ2jSTYrwD9tJvHPSE=; b=mN2Oe1uyDrg+TPUxDMzSNPw0NdQ9NQWcZSG8ebw7XebLYrcM4ls0rm9h4A6NhKTeWb UQn32ja4iOF+5N+2LQu0Z5s94BgcYwLkH/nWKkIGPqG4lPiORcp6LuEYjgOIaENjiNpq F0/WuPRecsUhGhJ/D7woDxRLyRBz4sXqMk5EuUTw7F4od7Dq9MrKve7PryQwkixWA2JK mbzRF2b7sCkxAFUn7St+ydCKGerMtw1F+8D0LyFZ3RkaF1Yn/MR0hknqac+e1DGI2+Ox CB1L1+ZlFYfmqFSinoEgugWVTP+0rAUMnT9GXF/qUS1c/isdEzNe3dAzEG6TP+dX3r/d sI9w== X-Gm-Message-State: ALoCoQlpeon4LwMXylNasqdxDWrERKjc3qfvSpbW/92MRIonsgNgnJ8m49eA+41xHH7o09hqgHoa X-Received: by 10.42.112.195 with SMTP id z3mr6453689icp.7.1391875695471; Sat, 08 Feb 2014 08:08:15 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.24.215 with SMTP id 81ls1367498qgr.14.gmail; Sat, 08 Feb 2014 08:08:15 -0800 (PST) X-Received: by 10.58.169.7 with SMTP id aa7mr1438481vec.24.1391875695332; Sat, 08 Feb 2014 08:08:15 -0800 (PST) Received: from mail-vb0-f43.google.com (mail-vb0-f43.google.com [209.85.212.43]) by mx.google.com with ESMTPS id kl10si2622079vdb.103.2014.02.08.08.08.15 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 08 Feb 2014 08:08:15 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.43 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.43; Received: by mail-vb0-f43.google.com with SMTP id p5so3525066vbn.2 for ; Sat, 08 Feb 2014 08:08:15 -0800 (PST) X-Received: by 10.52.27.9 with SMTP id p9mr1177005vdg.28.1391875695248; Sat, 08 Feb 2014 08:08:15 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.174.196 with SMTP id u4csp40773vcz; Sat, 8 Feb 2014 08:08:01 -0800 (PST) X-Received: by 10.140.51.170 with SMTP id u39mr30504841qga.69.1391875680375; Sat, 08 Feb 2014 08:08:00 -0800 (PST) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id j4si6169192qao.40.2014.02.08.08.08.00 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Sat, 08 Feb 2014 08:08:00 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Received: from localhost ([::1]:47080 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCARj-00062w-OJ for patch@linaro.org; Sat, 08 Feb 2014 11:07:59 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47284) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCAIY-0007fV-67 for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WCAIT-0002vx-BD for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:30 -0500 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:45684) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCAIT-0002tl-3o for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:25 -0500 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1WCAI9-0003LQ-Dm; Sat, 08 Feb 2014 15:58:05 +0000 From: Peter Maydell To: Anthony Liguori Date: Sat, 8 Feb 2014 15:57:50 +0000 Message-Id: <1391875084-12772-16-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1391875084-12772-1-git-send-email-peter.maydell@linaro.org> References: <1391875084-12772-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Cc: Blue Swirl , qemu-devel@nongnu.org, Aurelien Jarno Subject: [Qemu-devel] [PULL 15/29] arm_gic: Fix GIC pending behavior 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+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.43 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 From: Christoffer Dall The existing implementation of the pending behavior in gic_set_irq, gic_complete_irq, and the distributor pending set/clear registers does not follow the semantics of the GICv2.0 specs, but may implement the 11MPCore support. Therefore, maintain the existing semantics for 11MPCore and v7M NVIC and change the behavior to be in accordance with the GICv2.0 specs for "generic implementations" (s->revision == 1 || s->revision == 2). Generic implementations distinguish between setting a level-triggered interrupt pending through writes to the GICD_ISPENDR and when hardware raises the interrupt line. Writing to the GICD_ICPENDR will not cause the interrupt to become non-pending if the line is still active, and conversely, if the line is deactivated but the interrupt is marked as pending through a write to GICD_ISPENDR, the interrupt remains pending. Handle this situation in the GIC_TEST_PENDING (which now becomes a static inline named gic_test_pending) and let the 'pending' field correspond only to the latched state of the D-flip flop in the GICv2.0 specs Figure 4-10. The following changes are added: gic_test_pending: Make this a static inline and split out the 11MPCore from the generic behavior. For the generic behavior, consider interrupts pending if: ((s->irq_state[irq].pending & (cm) != 0) || (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm)) gic_set_irq: Split out the 11MPCore from the generic behavior. For the generic behavior, always GIC_SET_LEVEL() on positive level, but only GIC_SET_PENDING for edge-triggered interrupts and always simply GIC_CLEAR_LEVEL() on negative level. gic_complete_irq: Only resample the line for line-triggered interrupts on an 11MPCore. Generic implementations will sample the line directly in gic_test_pending(). Signed-off-by: Christoffer Dall Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 64 ++++++++++++++++++++++++++++++++++++-------------- hw/intc/gic_internal.h | 16 ++++++++++++- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 1c4a114..77519c0 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -66,7 +66,7 @@ void gic_update(GICState *s) best_prio = 0x100; best_irq = 1023; for (irq = 0; irq < s->num_irq; irq++) { - if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) { + if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm)) { if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { best_prio = GIC_GET_PRIORITY(irq, cpu); best_irq = irq; @@ -89,14 +89,43 @@ void gic_set_pending_private(GICState *s, int cpu, int irq) { int cm = 1 << cpu; - if (GIC_TEST_PENDING(irq, cm)) + if (gic_test_pending(s, irq, cm)) { return; + } DPRINTF("Set %d pending cpu %d\n", irq, cpu); GIC_SET_PENDING(irq, cm); gic_update(s); } +static void gic_set_irq_11mpcore(GICState *s, int irq, int level, + int cm, int target) +{ + if (level) { + GIC_SET_LEVEL(irq, cm); + if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { + DPRINTF("Set %d pending mask %x\n", irq, target); + GIC_SET_PENDING(irq, target); + } + } else { + GIC_CLEAR_LEVEL(irq, cm); + } +} + +static void gic_set_irq_generic(GICState *s, int irq, int level, + int cm, int target) +{ + if (level) { + GIC_SET_LEVEL(irq, cm); + DPRINTF("Set %d pending mask %x\n", irq, target); + if (GIC_TEST_EDGE_TRIGGER(irq)) { + GIC_SET_PENDING(irq, target); + } + } else { + GIC_CLEAR_LEVEL(irq, cm); + } +} + /* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) { @@ -126,15 +155,12 @@ static void gic_set_irq(void *opaque, int irq, int level) return; } - if (level) { - GIC_SET_LEVEL(irq, cm); - if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { - DPRINTF("Set %d pending mask %x\n", irq, target); - GIC_SET_PENDING(irq, target); - } + if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { + gic_set_irq_11mpcore(s, irq, level, cm, target); } else { - GIC_CLEAR_LEVEL(irq, cm); + gic_set_irq_generic(s, irq, level, cm, target); } + gic_update(s); } @@ -195,14 +221,18 @@ void gic_complete_irq(GICState *s, int cpu, int irq) } if (s->running_irq[cpu] == 1023) return; /* No active IRQ. */ - /* Mark level triggered interrupts as pending if they are still - raised. */ - if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) - && 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->revision == REV_11MPCORE || s->revision == REV_NVIC) { + /* Mark level triggered interrupts as pending if they are still + raised. */ + if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) + && 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 (irq != s->running_irq[cpu]) { /* Complete an IRQ that is not currently running. */ int tmp = s->running_irq[cpu]; @@ -273,7 +303,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset) res = 0; mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { - if (GIC_TEST_PENDING(irq + i, mask)) { + if (gic_test_pending(s, irq + i, mask)) { res |= (1 << i); } } diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 8c02d58..92a6f7a 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -34,7 +34,6 @@ #define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0) #define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm) #define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm) -#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0) #define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm) #define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm) #define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0) @@ -63,4 +62,19 @@ void gic_update(GICState *s); void gic_init_irqs_and_distributor(GICState *s, int num_irq); void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val); +static inline bool gic_test_pending(GICState *s, int irq, int cm) +{ + if (s->revision == REV_NVIC || s->revision == REV_11MPCORE) { + return s->irq_state[irq].pending & cm; + } else { + /* Edge-triggered interrupts are marked pending on a rising edge, but + * level-triggered interrupts are either considered pending when the + * level is active or if software has explicitly written to + * GICD_ISPENDR to set the state pending. + */ + return (s->irq_state[irq].pending & cm) || + (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm)); + } +} + #endif /* !QEMU_ARM_GIC_INTERNAL_H */