From patchwork Sun Feb 2 23:17:20 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 24017 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f71.google.com (mail-pa0-f71.google.com [209.85.220.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id CE10920341 for ; Sun, 2 Feb 2014 23:17:29 +0000 (UTC) Received: by mail-pa0-f71.google.com with SMTP id kp14sf17661037pab.6 for ; Sun, 02 Feb 2014 15:17:29 -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=B0pK3jCPKo9B5/dg5kv8Jlihbi8BhBZ7lbK4uXFalpw=; b=UcQ04khsMgU3ajibWLloZ/w0KsZoi4spog/gRHawLsSWoutmI7KFitG4ftDAIWRkoR fZ9FoOMgG11uDesNiuvyETfifabz4YxNLtgUz3OB2hNSXcP4phchZKdI28u8/2hiPa7M i8xiztAkt4rQTcc8WVBXnmaf1s5DX936XjqWYgvSQDPycB3GcAyhEVRemkEYYwp1EjoP lQu7RuoJLrIv3+6wS07JausUDncCX/mE9G5gwiTdQINPHNpIenCmZLOdPg4hvXUAxyyx A3N+lvVI5fDm3IHaW/VnUUJG9LmL/HCKqNtTI4QJhdV4vU8uTZp2CzYRirRfMar/LDCt gYgw== X-Gm-Message-State: ALoCoQn+NaYjV4HKkbTiV+lm0r5h2394v67/DpbfxWOuld3Pk15T1qZKACOEmzFngosbFmiXVv8B X-Received: by 10.66.66.109 with SMTP id e13mr12364996pat.1.1391383049092; Sun, 02 Feb 2014 15:17:29 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.102.244 with SMTP id w107ls1702088qge.26.gmail; Sun, 02 Feb 2014 15:17:29 -0800 (PST) X-Received: by 10.58.100.100 with SMTP id ex4mr26248390veb.2.1391383048987; Sun, 02 Feb 2014 15:17:28 -0800 (PST) Received: from mail-vc0-f180.google.com (mail-vc0-f180.google.com [209.85.220.180]) by mx.google.com with ESMTPS id rv9si2250374vcb.14.2014.02.02.15.17.28 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 02 Feb 2014 15:17:28 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.180 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.180; Received: by mail-vc0-f180.google.com with SMTP id ks9so4363261vcb.11 for ; Sun, 02 Feb 2014 15:17:28 -0800 (PST) X-Received: by 10.58.54.15 with SMTP id f15mr3193394vep.5.1391383048858; Sun, 02 Feb 2014 15:17:28 -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.220.174.196 with SMTP id u4csp117656vcz; Sun, 2 Feb 2014 15:17:28 -0800 (PST) X-Received: by 10.68.106.130 with SMTP id gu2mr33634655pbb.59.1391383047928; Sun, 02 Feb 2014 15:17:27 -0800 (PST) Received: from mail-pb0-f50.google.com (mail-pb0-f50.google.com [209.85.160.50]) by mx.google.com with ESMTPS id m8si18365794pbq.89.2014.02.02.15.17.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 02 Feb 2014 15:17:27 -0800 (PST) Received-SPF: neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of christoffer.dall@linaro.org) client-ip=209.85.160.50; Received: by mail-pb0-f50.google.com with SMTP id rq2so6406992pbb.9 for ; Sun, 02 Feb 2014 15:17:27 -0800 (PST) X-Received: by 10.69.31.97 with SMTP id kl1mr9199086pbd.62.1391383047535; Sun, 02 Feb 2014 15:17:27 -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 qq5sm49777615pbb.24.2014.02.02.15.17.26 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 02 Feb 2014 15:17:26 -0800 (PST) From: Christoffer Dall To: qemu-devel@nongnu.org Cc: kvmarm@lists.cs.columbia.edu, patches@linaro.org, Christoffer Dall Subject: [PATCH v6 2/6] hw: arm_gic: Keep track of SGI sources Date: Sun, 2 Feb 2014 15:17:20 -0800 Message-Id: <1391383044-596-3-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.8.5.2 In-Reply-To: <1391383044-596-1-git-send-email-christoffer.dall@linaro.org> References: <1391383044-596-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.220.180 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: , Right now the arm gic emulation doesn't keep track of the source of an SGI (which apparently Linux guests don't use, or they're fine with assuming CPU 0 always). Add the necessary matrix on the GICState structure and maintain the data when setting and clearing the pending state of an IRQ and make the state visible to the guest. Note that we always choose to present the source as the lowest-numbered CPU in case multiple cores have signalled the same SGI number to a core on the system. Reviewed-by: Peter Maydell Signed-off-by: Christoffer Dall --- Changes [v5 -> v6]: - Only clear IRQ pending in writes to GICD_CPENDSGIR if the IRQ is no longer pending from any source CPUs. Changes [v4 -> v5]: - Add braces to if-statement - Make GICD_CPENDSGIR and GICD_SPENDSGIR guest visible for v1/v2 GIC Changes [v3 -> v4]: - Assert that we are not messing with SGI state in gic_set_irq - Move bugfix of GICD_SPENDR to pending fixes patch - Get rid of the idea of git_clear_pending and handle clearing of source bits directly in gic_acknowledge_irq - Don't loop through CPUs to clear SGI sources - Return source CPU directly from gic_acknowledge_irq - Rename sgi_source to sgi_pending - Add comment (courtesey of Peter) to sgi_pending struct member. Changes [v2 -> v3]: - Changed ffs(x) - 1 to ctz32 - Changed cpu type to int in gic_clear_pending to avoid cast - Really try to fix the endless loop bug - Change gic_clear_pending to only clear the pending bit of SGIs if all CPUs do not have that IRQ pending from any CPUs. - Wrap long line in gic_internal.h - Fix bug allowing setting SGIs through the GICD_SPENDR Changes [v1 -> v2]: - Fixed endless loop bug - Bump version_id and minimum_version_id on vmstate struct hw/intc/arm_gic.c | 98 +++++++++++++++++++++++++++++++++++----- hw/intc/arm_gic_common.c | 5 +- include/hw/intc/arm_gic_common.h | 7 +++ 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 77519c0..6550292 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -151,6 +151,8 @@ static void gic_set_irq(void *opaque, int irq, int level) target = cm; } + assert(irq >= GIC_NR_SGIS); + if (level == GIC_TEST_LEVEL(irq, cm)) { return; } @@ -177,21 +179,48 @@ static void gic_set_running_irq(GICState *s, int cpu, int irq) uint32_t gic_acknowledge_irq(GICState *s, int cpu) { - int new_irq; + int ret, irq, src; int cm = 1 << cpu; - new_irq = s->current_pending[cpu]; - if (new_irq == 1023 - || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) { + irq = s->current_pending[cpu]; + if (irq == 1023 + || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { DPRINTF("ACK no pending IRQ\n"); 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); - gic_set_running_irq(s, cpu, new_irq); - DPRINTF("ACK %d\n", new_irq); - return new_irq; + s->last_active[irq][cpu] = s->running_irq[cpu]; + + 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(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); + ret = irq; + } else { + if (irq < GIC_NR_SGIS) { + /* Lookup the source CPU for the SGI and clear this in the + * sgi_pending map. Return the src and clear the overall pending + * state on this CPU if the SGI is not pending from any CPUs. + */ + assert(s->sgi_pending[irq][cpu] != 0); + src = ctz32(s->sgi_pending[irq][cpu]); + s->sgi_pending[irq][cpu] &= ~(1 << src); + if (s->sgi_pending[irq][cpu] == 0) { + GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); + } + ret = irq | ((src & 0x7) << 10); + } else { + /* Clear pending state for both level and edge triggered + * interrupts. (level triggered interrupts with an active line + * remain pending, see gic_test_pending) + */ + GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); + ret = irq; + } + } + + gic_set_running_irq(s, cpu, irq); + DPRINTF("ACK %d\n", irq); + return ret; } void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) @@ -353,6 +382,22 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset) if (GIC_TEST_EDGE_TRIGGER(irq + i)) res |= (2 << (i * 2)); } + } else if (offset < 0xf10) { + goto bad_reg; + } else if (offset < 0xf30) { + if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { + goto bad_reg; + } + + if (offset < 0xf20) { + /* GICD_CPENDSGIRn */ + irq = (offset - 0xf10); + } else { + irq = (offset - 0xf20); + /* GICD_SPENDSGIRn */ + } + + res = s->sgi_pending[irq][cpu]; } else if (offset < 0xfe0) { goto bad_reg; } else /* offset >= 0xfe0 */ { @@ -527,9 +572,31 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, GIC_CLEAR_EDGE_TRIGGER(irq + i); } } - } else { + } else if (offset < 0xf10) { /* 0xf00 is only handled for 32-bit writes. */ goto bad_reg; + } else if (offset < 0xf20) { + /* GICD_CPENDSGIRn */ + if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { + goto bad_reg; + } + irq = (offset - 0xf10); + + s->sgi_pending[irq][cpu] &= ~value; + if (s->sgi_pending[irq][cpu] == 0) { + GIC_CLEAR_PENDING(irq, 1 << cpu); + } + } else if (offset < 0xf30) { + /* GICD_SPENDSGIRn */ + if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { + goto bad_reg; + } + irq = (offset - 0xf20); + + GIC_SET_PENDING(irq, 1 << cpu); + s->sgi_pending[irq][cpu] |= value; + } else { + goto bad_reg; } gic_update(s); return; @@ -553,6 +620,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset, int cpu; int irq; int mask; + int target_cpu; cpu = gic_get_current_cpu(s); irq = value & 0x3ff; @@ -572,6 +640,12 @@ static void gic_dist_writel(void *opaque, hwaddr offset, break; } GIC_SET_PENDING(irq, mask); + target_cpu = ctz32(mask); + while (target_cpu < GIC_NCPU) { + s->sgi_pending[irq][target_cpu] |= (1 << cpu); + mask &= ~(1 << target_cpu); + target_cpu = ctz32(mask); + } gic_update(s); return; } diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index e4fc650..92de7f8 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -58,8 +58,8 @@ static const VMStateDescription vmstate_gic_irq_state = { static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 4, - .minimum_version_id = 4, + .version_id = 5, + .minimum_version_id = 5, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { @@ -71,6 +71,7 @@ static const VMStateDescription vmstate_gic = { 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), diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index dbf8787..5dd826d 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -55,6 +55,13 @@ typedef struct GICState { 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 + * the bytes in the GIC_SPENDSGIR* registers as + * read by the target CPU. + */ + uint8_t sgi_pending[GIC_NR_SGIS][GIC_NCPU]; uint16_t priority_mask[GIC_NCPU]; uint16_t running_irq[GIC_NCPU];