From patchwork Sat Dec 21 06:09:34 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 22701 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pb0-f72.google.com (mail-pb0-f72.google.com [209.85.160.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 75B5120822 for ; Sat, 21 Dec 2013 06:10:04 +0000 (UTC) Received: by mail-pb0-f72.google.com with SMTP id jt11sf8916798pbb.11 for ; Fri, 20 Dec 2013 22:10:03 -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: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=w0K9Hh83QVbJvwLotV/0vNkWOT1Trun5cMgKRX/6iOY=; b=c3w1r1PZ6shkBAGC5nGgygnoQSRM9S98qerxMLcWs55yQ4+LX8BT8mbk41a15dHblv vZfqOHWekfGdyNzqqq8J4EikcBuet9sWdzwyLvAps8scHZwMKBZrqiZMIPYKhBuo48/i 4IMQwHLLOefych0/gIwfaDNLAuDfJdb3XLLiUdo0+4nVSTwrUa6VLSx4Dt9idSxYXuHA 4LV2bIx3iqkEuSVuc3ZlliwAUoUVP0IKzv97PFNsDhGKeIxtr2iagpOFXTqDWhfQtUHG 7B+V0gzR2xCy+mepaAbHEdANDxyQDJCC/TXestWetQJtED67kZP1a5m5SfJRPv4ZaQYF 3Eag== X-Gm-Message-State: ALoCoQkR7V7dnE29PK9U2P+Jl0j5Em4lcFHsPR45PUJC8Do84GTLc43kC1KwAvZn35q2XsvgB5Oq X-Received: by 10.66.138.79 with SMTP id qo15mr5208818pab.34.1387606203789; Fri, 20 Dec 2013 22:10:03 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.60.37 with SMTP id e5ls1015646qer.84.gmail; Fri, 20 Dec 2013 22:10:03 -0800 (PST) X-Received: by 10.52.52.137 with SMTP id t9mr3177959vdo.22.1387606203568; Fri, 20 Dec 2013 22:10:03 -0800 (PST) Received: from mail-ve0-f171.google.com (mail-ve0-f171.google.com [209.85.128.171]) by mx.google.com with ESMTPS id rl1si2309082vcb.74.2013.12.20.22.10.03 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 22:10:03 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.171; Received: by mail-ve0-f171.google.com with SMTP id pa12so1940622veb.2 for ; Fri, 20 Dec 2013 22:10:03 -0800 (PST) X-Received: by 10.58.181.230 with SMTP id dz6mr699447vec.35.1387606203457; Fri, 20 Dec 2013 22:10:03 -0800 (PST) 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.59.13.131 with SMTP id ey3csp109303ved; Fri, 20 Dec 2013 22:10:02 -0800 (PST) X-Received: by 10.66.166.47 with SMTP id zd15mr13271953pab.72.1387606202433; Fri, 20 Dec 2013 22:10:02 -0800 (PST) Received: from mail-pa0-f50.google.com (mail-pa0-f50.google.com [209.85.220.50]) by mx.google.com with ESMTPS id sz7si5544023pab.29.2013.12.20.22.10.02 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 22:10:02 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.50 is neither permitted nor denied by best guess record for domain of christoffer.dall@linaro.org) client-ip=209.85.220.50; Received: by mail-pa0-f50.google.com with SMTP id kp14so1613495pab.23 for ; Fri, 20 Dec 2013 22:10:02 -0800 (PST) X-Received: by 10.68.29.72 with SMTP id i8mr13457479pbh.116.1387606201400; Fri, 20 Dec 2013 22:10:01 -0800 (PST) Received: from localhost.localdomain (c-67-169-181-221.hsd1.ca.comcast.net. [67.169.181.221]) by mx.google.com with ESMTPSA id ae5sm24345852pac.18.2013.12.20.22.09.58 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 22:10:00 -0800 (PST) From: Christoffer Dall To: qemu-devel@nongnu.org Cc: kvmarm@lists.cs.columbia.edu, patches@linaro.org, Christoffer Dall Subject: [RFC PATCH v4 3/8] arm_gic: Fix GIC pending behavior Date: Fri, 20 Dec 2013 22:09:34 -0800 Message-Id: <1387606179-22709-4-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.8.5 In-Reply-To: <1387606179-22709-1-git-send-email-christoffer.dall@linaro.org> References: <1387606179-22709-1-git-send-email-christoffer.dall@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: christoffer.dall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.171 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 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 existing implementation of the pending behavior in gic_set_irq, gic_acknowledge_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 change the behavior to be in accordance with the GICv2.0 specs for "generic implementations" (s->revision == 1 || s->revision == 2). Generic implementations also mandate that level-triggered interrupts that are pending due to a write to GICD_ISPENDR stay pending until the interrupt is acknowledged or until there's a write to the GICD_ICPENDR. Similarly, only clear the pending state on writes to GICD_ICPENDR if the interrupt signal is not asserted. This requires an extra state variable to keep track of writes to the set/clear registers, corresponding to the D-flip flop in the GICv2.0 specs Figure 4-10. The following changes are added: gic_set_irq: Split out the 11MPCore from the generic behavior. For the generic behavior, simply set pending state on positive level and edge triggered interrupts and clear the pending state only for level triggered interrupts. gic_acknowledge_irq: Keep existing functionality for 11MPCore, but only clear the pending state if the interrupt is edge-triggered or if the interrupt is non-asserted and level-triggered. gic_complete_irq: Only resample the line for line-triggered interrupts on an 11MPCore. Generic implementations will latch the pending state when the level changes, on reads of GICC_IAR, and on wrtites to GICD_I{SC}PENDRn. gic_dist_writeb: 1. Fix bugs to ensure that writes to GICD_ICPENDR and GICD_ISPENDR are ignored for SGIs (common behavior for 11MPCore and generic implementations). 2. Do not clear the pending state for level-triggered interrupts on writes to GICD_ICPENDR if the interrupt signal remains asserted. Signed-off-by: Christoffer Dall --- Changes [v3 -> v4]: - Maintain 11MPCore semantics - Combine all pending interrupts fixing patches into this patch. See the detailed description above. Changes [v1 -> v2]: - Fix bisection issue, by not using gic_clear_pending yet. hw/intc/arm_gic.c | 106 ++++++++++++++++++++++++++++++--------- hw/intc/arm_gic_common.c | 5 +- hw/intc/gic_internal.h | 3 ++ include/hw/intc/arm_gic_common.h | 2 + 4 files changed, 91 insertions(+), 25 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 6c59650..dd76e1d 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -97,6 +97,38 @@ void gic_set_pending_private(GICState *s, int cpu, int irq) 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); + GIC_SET_PENDING(irq, target); + } else { + /* Clear level-triggered interrupts that have not been set to pending + * through GICD_SPENDR. + */ + if (!GIC_TEST_EDGE_TRIGGER(irq) && !GIC_TEST_SW_PENDING(irq, cm)) { + GIC_CLEAR_PENDING(irq, target); + } + 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 +158,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) { + 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); } @@ -160,9 +189,23 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu) return 1023; } s->last_active[new_irq][cpu] = s->running_irq[cpu]; - /* Clear pending flags for both level and edge triggered interrupts. - Level triggered IRQs will be reasserted once they become inactive. */ - GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm); + + cm = GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm; + GIC_CLEAR_SW_PENDING(new_irq, cm); + if (s->revision == REV_11MPCORE) { + /* Clear pending flags for both level and edge triggered interrupts. + * Level triggered IRQs will be reasserted once they become inactive. + */ + GIC_CLEAR_PENDING(new_irq, cm); + } else { + /* Clear pending flags for edge-triggered and non-asserted + * level-triggered interrupts + */ + if (GIC_TEST_EDGE_TRIGGER(new_irq) || !GIC_TEST_LEVEL(new_irq, cpu)) { + GIC_CLEAR_PENDING(new_irq, cm); + } + } + gic_set_running_irq(s, cpu, new_irq); DPRINTF("ACK %d\n", new_irq); return new_irq; @@ -195,14 +238,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) { + /* 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]; @@ -423,25 +470,38 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; - if (irq < 16) - irq = 0; + if (irq < GIC_NR_SGIS) + value = 0; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++, irq++) { if (value & (1 << i)) { - GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); + GIC_SET_PENDING(irq, GIC_TARGET(irq)); + GIC_SET_SW_PENDING(irq, GIC_TARGET(irq)); } } } else if (offset < 0x300) { + int cm = (1 << cpu); /* Interrupt Clear Pending. */ irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; - for (i = 0; i < 8; i++) { + if (irq < GIC_NR_SGIS) + value = 0; + + for (i = 0; i < 8; i++, irq++) { /* ??? This currently clears the pending bit for all CPUs, even for per-CPU interrupts. It's unclear whether this is the corect behavior. */ if (value & (1 << i)) { - GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); + GIC_CLEAR_SW_PENDING(irq, cm); + if (s->revision == REV_11MPCORE) { + GIC_CLEAR_PENDING(irq, ALL_CPU_MASK); + } else { + if (GIC_TEST_EDGE_TRIGGER(irq) || + !GIC_TEST_LEVEL(irq, cm)) { + GIC_CLEAR_PENDING(irq, ALL_CPU_MASK); + } + } } } } else if (offset < 0x400) { diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 710607b..8c7621a 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -43,11 +43,12 @@ static int gic_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_gic_irq_state = { .name = "arm_gic_irq_state", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT8(enabled, gic_irq_state), VMSTATE_UINT8(pending, gic_irq_state), + VMSTATE_UINT8(sw_pending, gic_irq_state), VMSTATE_UINT8(active, gic_irq_state), VMSTATE_UINT8(level, gic_irq_state), VMSTATE_BOOL(model, gic_irq_state), diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 8c02d58..3ebe4dc 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -35,6 +35,9 @@ #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_SW_PENDING(irq, cm) (s->irq_state[irq].sw_pending |= (cm)) +#define GIC_CLEAR_SW_PENDING(irq, cm) (s->irq_state[irq].sw_pending &= ~(cm)) +#define GIC_TEST_SW_PENDING(irq, cm) ((s->irq_state[irq].sw_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) diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 40cd3d6..126e122 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -27,6 +27,7 @@ #define GIC_MAXIRQ 1020 /* First 32 are private to each CPU (SGIs and PPIs). */ #define GIC_INTERNAL 32 +#define GIC_NR_SGIS 16 /* Maximum number of possible CPU interfaces, determined by GIC architecture */ #define GIC_NCPU 8 @@ -34,6 +35,7 @@ typedef struct gic_irq_state { /* The enable bits are only banked for per-cpu interrupts. */ uint8_t enabled; uint8_t pending; + uint8_t sw_pending; /* keep track of GICD_ISPENDR and GICD_ICPENDR writes */ uint8_t active; uint8_t level; bool model; /* 0 = N:N, 1 = 1:N */