From patchwork Tue Nov 19 06:18:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 21598 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-gg0-f197.google.com (mail-gg0-f197.google.com [209.85.161.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0C5D220972 for ; Tue, 19 Nov 2013 06:17:11 +0000 (UTC) Received: by mail-gg0-f197.google.com with SMTP id e5sf11898054ggk.4 for ; Mon, 18 Nov 2013 22:17:10 -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=4Rg8PTP3CIYE7222BiAxbEtBin4h6J8XmQVEUQtNty0=; b=P63zQjl2uJa0YqmfPXKaU+PLLM1/5GZLvAhf0x1X8BJirRKJu8uuLVNiFYaI4O6Fhg Pe9eTt/V6tw7fNem3K6a/CYWzk8IFTEekfDa2ygjdxpFgKOocffU5n7KBIpiWLn/k0h5 yvO3h5QFCnlvgNRLqz9+TqM1qFCy2erTZ97UQJ6pkD1xsJ0qF7UCV72heu+iEmNzLElf wmnF6foWc61bSQbUu+xAJFAcI3CXpCI0Xrioq7Zzc32NlKS6ddLDnZG31ZU2exMdd9uS 3KkX1cFRnfj6vPQhHoXrZ+cZYxdBaY7BFkTcEaOlBfpKQu4PJGGbnMgd9btV2yvLWgSb sZmQ== X-Gm-Message-State: ALoCoQmtlvBaZJ9rVnntZ3+GLPjsSeWXfS2DeOo03iRCmW5TOZG5JbKew1dvA05aWTo8VIl2lS5H X-Received: by 10.236.180.2 with SMTP id i2mr11618793yhm.4.1384841830783; Mon, 18 Nov 2013 22:17:10 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.96.101 with SMTP id dr5ls2827001qeb.80.gmail; Mon, 18 Nov 2013 22:17:10 -0800 (PST) X-Received: by 10.220.86.69 with SMTP id r5mr19442019vcl.9.1384841830683; Mon, 18 Nov 2013 22:17:10 -0800 (PST) Received: from mail-vc0-f176.google.com (mail-vc0-f176.google.com [209.85.220.176]) by mx.google.com with ESMTPS id im16si5779914vec.92.2013.11.18.22.17.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 18 Nov 2013 22:17:10 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.176 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.176; Received: by mail-vc0-f176.google.com with SMTP id ia6so3762467vcb.35 for ; Mon, 18 Nov 2013 22:17:10 -0800 (PST) X-Received: by 10.220.159.4 with SMTP id h4mr19079267vcx.1.1384841830552; Mon, 18 Nov 2013 22:17:10 -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 u4csp255364vcz; Mon, 18 Nov 2013 22:17:09 -0800 (PST) X-Received: by 10.68.28.231 with SMTP id e7mr21886pbh.180.1384841829392; Mon, 18 Nov 2013 22:17:09 -0800 (PST) Received: from mail-pa0-f42.google.com (mail-pa0-f42.google.com [209.85.220.42]) by mx.google.com with ESMTPS id gn4si11235254pbc.81.2013.11.18.22.17.09 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 18 Nov 2013 22:17:09 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.42 is neither permitted nor denied by best guess record for domain of christoffer.dall@linaro.org) client-ip=209.85.220.42; Received: by mail-pa0-f42.google.com with SMTP id lj1so2087298pab.29 for ; Mon, 18 Nov 2013 22:17:09 -0800 (PST) X-Received: by 10.68.198.97 with SMTP id jb1mr17140649pbc.104.1384841828862; Mon, 18 Nov 2013 22:17:08 -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 rz6sm19165159pab.22.2013.11.18.22.17.07 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 18 Nov 2013 22:17:08 -0800 (PST) From: Christoffer Dall To: qemu-devel@nongnu.org Cc: kvmarm@lists.cs.columbia.edu, patches@linaro.org, Christoffer Dall Subject: [RFC PATCH v3 03/10] hw: arm_gic: Keep track of SGI sources Date: Mon, 18 Nov 2013 22:18:09 -0800 Message-Id: <1384841896-19566-4-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1384841896-19566-1-git-send-email-christoffer.dall@linaro.org> References: <1384841896-19566-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.176 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. 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. Also fixes a subtle ancient bug in handling of writes to the GICD_SPENDr where the irq variable was set to 0 if the IRQ was an SGI (irq < 16), but the intention was to set the written value, the "value" variable, to 0. Make the check explicit instead and ignore any such writes. Signed-off-by: Christoffer Dall Changelog [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 Changelog [v2]: - Fixed endless loop bug - Bump version_id and minimum_version_id on vmstate struct --- hw/intc/arm_gic.c | 62 ++++++++++++++++++++++++++++++---------- hw/intc/arm_gic_common.c | 5 ++-- hw/intc/gic_internal.h | 3 ++ include/hw/intc/arm_gic_common.h | 2 ++ 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 7eaa55f..2ed9a1a 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -97,6 +97,32 @@ void gic_set_pending_private(GICState *s, int cpu, int irq) gic_update(s); } +static void gic_clear_pending(GICState *s, int irq, int cm, uint8_t src) +{ + int cpu; + + DPRINTF("%s: irq %d, cm 0x%x, src %d\n", __func__, irq, cm, src); + if (irq < GIC_NR_SGIS) { + bool pend = false; + + for (cpu = 0; cpu < s->num_cpu; cpu++) { + if (cm & (1 << cpu)) { + s->sgi_source[irq][cpu] &= ~(1 << src); + } else { + if (s->sgi_source[irq][cpu]) { + pend = true; + } + } + } + + if (!pend) { + GIC_CLEAR_PENDING(irq, cm); + } + } else { + GIC_CLEAR_PENDING(irq, cm); + } +} + /* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) { @@ -132,7 +158,7 @@ static void gic_set_irq(void *opaque, int irq, int level) GIC_SET_PENDING(irq, target); } else { if (!GIC_TEST_TRIGGER(irq)) { - GIC_CLEAR_PENDING(irq, target); + gic_clear_pending(s, irq, target, 0); } GIC_CLEAR_LEVEL(irq, cm); } @@ -163,7 +189,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu) 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_clear_pending(s, new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm, + GIC_SGI_SRC(new_irq, cpu)); gic_set_running_irq(s, cpu, new_irq); DPRINTF("ACK %d\n", new_irq); return new_irq; @@ -424,12 +451,9 @@ 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; - - for (i = 0; i < 8; i++) { - if (value & (1 << i)) { - GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); + for (i = 0; i < 8; i++, irq++) { + if (irq >= GIC_NR_SGIS && value & (1 << i)) { + GIC_SET_PENDING(irq, GIC_TARGET(irq)); } } } else if (offset < 0x300) { @@ -437,12 +461,9 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; - for (i = 0; i < 8; i++) { - /* ??? 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); + for (i = 0; i < 8; i++, irq++) { + if (irq >= GIC_NR_SGIS && value & (1 << i)) { + gic_clear_pending(s, irq, 1 << cpu, 0); } } } else if (offset < 0x400) { @@ -515,6 +536,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset, int cpu; int irq; int mask; + unsigned target_cpu; cpu = gic_get_current_cpu(s); irq = value & 0x3ff; @@ -534,6 +556,12 @@ static void gic_dist_writel(void *opaque, hwaddr offset, break; } GIC_SET_PENDING(irq, mask); + target_cpu = (unsigned)ffs(mask) - 1; + while (target_cpu < GIC_NCPU) { + s->sgi_source[irq][target_cpu] |= (1 << cpu); + mask &= ~(1 << target_cpu); + target_cpu = (unsigned)ffs(mask) - 1; + } gic_update(s); return; } @@ -551,6 +579,8 @@ static const MemoryRegionOps gic_dist_ops = { static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) { + int value; + switch (offset) { case 0x00: /* Control */ return s->cpu_enabled[cpu]; @@ -560,7 +590,9 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) /* ??? Not implemented. */ return 0; case 0x0c: /* Acknowledge */ - return gic_acknowledge_irq(s, cpu); + value = gic_acknowledge_irq(s, cpu); + value |= (GIC_SGI_SRC(value, cpu) & 0x7) << 10; + return value; case 0x14: /* Running Priority */ return s->running_priority[cpu]; case 0x18: /* Highest Pending Interrupt */ diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index c765850..d1a1b0f 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_source, 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/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index f916725..3d36653 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -51,6 +51,9 @@ s->priority1[irq][cpu] : \ s->priority2[(irq) - GIC_INTERNAL]) #define GIC_TARGET(irq) s->irq_target[irq] +#define GIC_SGI_SRC(irq, cpu) (((irq) < GIC_NR_SGIS) ? \ + ffs(s->sgi_source[irq][cpu]) - 1 : \ + 0) /* The special cases for the revision property: */ #define REV_11MPCORE 0 diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index ed18bb8..e19481b 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 @@ -54,6 +55,7 @@ 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]; + uint8_t sgi_source[GIC_NR_SGIS][GIC_NCPU]; uint16_t priority_mask[GIC_NCPU]; uint16_t running_irq[GIC_NCPU];