From patchwork Thu Sep 26 21:03:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 278279 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E072C2C00C8 for ; Fri, 27 Sep 2013 07:29:36 +1000 (EST) Received: from localhost ([::1]:59930 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VPIjD-0008KG-VV for incoming@patchwork.ozlabs.org; Thu, 26 Sep 2013 17:04:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56807) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VPIiW-00086u-Bi for qemu-devel@nongnu.org; Thu, 26 Sep 2013 17:03:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VPIiP-0000rA-N5 for qemu-devel@nongnu.org; Thu, 26 Sep 2013 17:03:20 -0400 Received: from mail-pa0-f43.google.com ([209.85.220.43]:59398) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VPIiP-0000qv-Dp for qemu-devel@nongnu.org; Thu, 26 Sep 2013 17:03:13 -0400 Received: by mail-pa0-f43.google.com with SMTP id hz1so1843483pad.2 for ; Thu, 26 Sep 2013 14:03:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=QmOsTOJIeZwt4uaSv30tSCB5kTqOAuz7AOLnvtE5oPA=; b=LPODGYx3lIdnxLb4NIWoo1wVzdaEIoRhlKMt9wHFmehhK6qtB/O2hpLvbar8P2C12v 6zsKv1czqF7Yaju0mj/jL/h7l2XikvYojZLycaNqNpKZnHYov1rxSscFEo45EDUr4zWr 9k0M8jo6q/dNvM9yPkHaabyLF7E9lAZa/Mb/kTEmyZMJLjjjLLbLRysukzTo1SCpk2fo 6qMaWong0YuGpl2T+jKKJP5EFLP9k1usAfgX1qAM0l2gFZs947Z2+L2EhjgEgMPUq7SU Z78v1tel6txmH0e5zlNeYxai94ZK9w3xV9MNek1fOPqVbbgVejcr7TbWq96pxAcmU9N3 qeyQ== X-Gm-Message-State: ALoCoQm8NqeUVez1c93nO8CArtxlIYuehavSOUZ+AI4+eBL6H4bk1LqtQsp5gcOHqaQ+cWF2QvBJ X-Received: by 10.66.218.198 with SMTP id pi6mr7545050pac.107.1380229392653; Thu, 26 Sep 2013 14:03:12 -0700 (PDT) Received: from localhost.localdomain (c-67-169-181-221.hsd1.ca.comcast.net. [67.169.181.221]) by mx.google.com with ESMTPSA id 7sm7385572paf.22.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 26 Sep 2013 14:03:11 -0700 (PDT) From: Christoffer Dall To: qemu-devel@nongnu.org Date: Thu, 26 Sep 2013 14:03:03 -0700 Message-Id: <1380229386-24166-4-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1380229386-24166-1-git-send-email-christoffer.dall@linaro.org> References: <1380229386-24166-1-git-send-email-christoffer.dall@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.220.43 Cc: kvmarm@lists.cs.columbia.edu, Christoffer Dall , patches@linaro.org Subject: [Qemu-devel] [RFC PATCH v2 3/6] hw: 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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. Signed-off-by: Christoffer Dall --- Changelog [v2]: - Fixed endless loop bug - Bump version_id and minimum_version_id on vmstate struct --- hw/intc/arm_gic.c | 41 ++++++++++++++++++++++++++++++++--------- hw/intc/arm_gic_common.c | 5 +++-- hw/intc/gic_internal.h | 3 +++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 7eaa55f..6470d37 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -97,6 +97,20 @@ 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) +{ + unsigned cpu; + + GIC_CLEAR_PENDING(irq, cm); + if (irq < GIC_NR_SGIS) { + cpu = (unsigned)ffs(cm) - 1; + while (cpu < NCPU) { + s->sgi_source[irq][cpu] &= ~(1 << src); + cpu = (unsigned)ffs(cm) - 1; + } + } +} + /* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) { @@ -132,7 +146,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 +177,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; @@ -437,12 +452,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 +527,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 +547,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 < 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 +570,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 +581,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 709b5c2..0657e8b 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, NCPU), VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL), VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU), + VMSTATE_UINT8_2DARRAY(sgi_source, GICState, GIC_NR_SGIS, NCPU), VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU), VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU), VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU), diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 09e7722..5b53242 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.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 NCPU 8 @@ -58,6 +59,7 @@ 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) typedef struct gic_irq_state { /* The enable bits are only banked for per-cpu interrupts. */ @@ -83,6 +85,7 @@ typedef struct GICState { uint8_t priority1[GIC_INTERNAL][NCPU]; uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL]; uint16_t last_active[GIC_MAXIRQ][NCPU]; + uint8_t sgi_source[GIC_NR_SGIS][NCPU]; uint16_t priority_mask[NCPU]; uint16_t running_irq[NCPU];