From patchwork Sat Feb 8 15:57:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 24352 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f199.google.com (mail-vc0-f199.google.com [209.85.220.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 7C3BE20967 for ; Sat, 8 Feb 2014 16:01:15 +0000 (UTC) Received: by mail-vc0-f199.google.com with SMTP id hu8sf10488141vcb.10 for ; Sat, 08 Feb 2014 08:01:14 -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=3nf3clsvAm4m0/FIpMymO6bKX5Yn0FDn6Gie1iUCXlo=; b=KIdr1701C2ldmRSs5pACjYg2J8qPbodR5caVV+idUaGAWIx8xDGueU8YzF048I9OIZ T73aLErXRfygLBKIv1XcY2zlpsT6zZUhY8kvE965931EGFw/pj3Q5uYbLu9ryRWSq3eM Y7+ImMf2nJgcqPe6NQfJLlIbe8SlOXktJT3Z12XU0p6zmVP1QcxC92w7o1IC/McFSZhg VoJbf1yVk6LHLnwGaqJX7GDjMtyIKroKGyM5PiAzJjRl9mQcSrM1cegx92/gNinXjglV nPeIe0TN/DJfxc9lm/JWQTHuzAFHIpQloPVOs4cLVjPtH/WIrVA/nT/G5BK1TNU/B8Rq 30gw== X-Gm-Message-State: ALoCoQmGiINfgGYP9yEjOAZ2L89FqRiZYoaHY6+gTWE4H0S/u1HqKKdj9ueFo2fXu8eThJvBdZqU X-Received: by 10.58.170.6 with SMTP id ai6mr6717706vec.7.1391875274552; Sat, 08 Feb 2014 08:01:14 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.33.200 with SMTP id j66ls1411605qgj.80.gmail; Sat, 08 Feb 2014 08:01:14 -0800 (PST) X-Received: by 10.58.85.133 with SMTP id h5mr15296096vez.4.1391875274462; Sat, 08 Feb 2014 08:01:14 -0800 (PST) Received: from mail-ve0-f177.google.com (mail-ve0-f177.google.com [209.85.128.177]) by mx.google.com with ESMTPS id t20si2623326vek.79.2014.02.08.08.01.14 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 08 Feb 2014 08:01:14 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.177 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.177; Received: by mail-ve0-f177.google.com with SMTP id jz11so3649908veb.8 for ; Sat, 08 Feb 2014 08:01:14 -0800 (PST) X-Received: by 10.220.103.141 with SMTP id k13mr1374378vco.25.1391875274113; Sat, 08 Feb 2014 08:01:14 -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 u4csp40372vcz; Sat, 8 Feb 2014 08:01:13 -0800 (PST) X-Received: by 10.224.30.69 with SMTP id t5mr32616120qac.30.1391875273170; Sat, 08 Feb 2014 08:01:13 -0800 (PST) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id j4si6145632qao.72.2014.02.08.08.01.12 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Sat, 08 Feb 2014 08:01:13 -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]:47008 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCALA-0002tq-Jx for patch@linaro.org; Sat, 08 Feb 2014 11:01:12 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47088) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCAIS-0007Tr-Fb for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WCAIQ-0002uH-U9 for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:24 -0500 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:45684) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WCAIQ-0002tl-LM for qemu-devel@nongnu.org; Sat, 08 Feb 2014 10:58:22 -0500 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1WCAI9-0003LU-F3; Sat, 08 Feb 2014 15:58:05 +0000 From: Peter Maydell To: Anthony Liguori Date: Sat, 8 Feb 2014 15:57:51 +0000 Message-Id: <1391875084-12772-17-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 16/29] arm_gic: Keep track of SGI sources 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.128.177 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 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 Signed-off-by: Peter Maydell --- 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 8a2aa00..d2e0c2f 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];