From patchwork Mon Mar 5 16:03:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 130683 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp2854008lja; Mon, 5 Mar 2018 08:07:19 -0800 (PST) X-Google-Smtp-Source: AG47ELuMges7GgtF1kIV7gJVkXxXj8lKhUbSd5lp3ZSVq7RVo/DaRId4jEx3QTZmzO5QMznFCcLw X-Received: by 10.107.84.8 with SMTP id i8mr776303iob.260.1520266039488; Mon, 05 Mar 2018 08:07:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520266039; cv=none; d=google.com; s=arc-20160816; b=I99CdCc25zd++gPGBBTFD8ZkoWTNXTATOxUQNzKc/SH4JL26izpWiaITlVnkAQVnhJ qxl9oEmdH9FcH/27qIsQE1lps4wTJs9ruSmkufM+ot+EasJY87HeS5gqu7oNyJm3r2TK UH7voGA4G6kV0uzA5qXrkxneNZiY3vcxpQ6lRVeiERZC40NyTJMjy2hUxbwTW23ngwtr R9l7c1E0c68n1d93bX5zjfF5zO3zttlTzWi8KHjN3k8+cHSSAct7d9h2KAFNnfPx7Epl 6Y26xWkjAwrrCDwNiQPgPpanKFRwdO64voa77N6cPfZC16Ajtw6h1NIP0QBk1klZXVt6 29zA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-unsubscribe:list-id :precedence:subject:cc:references:in-reply-to:message-id:date:to :from:dkim-signature:arc-authentication-results; bh=qQBj5L3+Tav8R4vlViSyk6j2yQXAUnzSngSBqPd5R70=; b=XqBMEcjqxX1jfRZZscPNqPxkc41bloa2IK0c/4kFdC3SL5lQab2o+swEQ+xiwuZ5KD zj2UkCA++wcGSktb9wrbEqCpws8NuEOElj4FjNKiX4bFCigOSEOfiF0YJQd5CT1svWbI VIYlIChsHhA2SzSoH2zZM1FhMYQ0HzP7k/3RiGKIfVXmo4tX8hmOn8533aBkP3fJlOac w4GuByH9Uz3xfce7cqoDLtTc4om5Er96PF1M7B1C+16o1uAFRiGrDc3vxYjECWGT4aeM kyCUDjXbhPajbslr3TXZX7toMiq0JV6oRz5bnZwqDNnZetASu3nCtMSuKgMsyVAc+392 9Y2A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Tlsn6iEF; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id f14si4789857itc.2.2018.03.05.08.07.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 05 Mar 2018 08:07:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Tlsn6iEF; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1essbj-00088J-9t; Mon, 05 Mar 2018 16:04:59 +0000 Received: from us1-rack-dfw2.inumbo.com ([104.130.134.6]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1essbh-000836-II for xen-devel@lists.xenproject.org; Mon, 05 Mar 2018 16:04:57 +0000 X-Inumbo-ID: cb02da7d-208e-11e8-ba59-bc764e045a96 Received: from mail-wm0-x243.google.com (unknown [2a00:1450:400c:c09::243]) by us1-rack-dfw2.inumbo.com (Halon) with ESMTPS id cb02da7d-208e-11e8-ba59-bc764e045a96; Mon, 05 Mar 2018 17:03:50 +0100 (CET) Received: by mail-wm0-x243.google.com with SMTP id a20so13874994wmd.1 for ; Mon, 05 Mar 2018 08:04:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=iAqjxr+o2HOFapyaUfR5bUaRNb5AETzIXOZtE1sXMTc=; b=Tlsn6iEFfs5CAGVqlDlu1B6pLrg4oHPd+P41D5UfuVNR6yRtdiYLssdMn6OSFk5oQy uJCLmlrXfIi833D9SJpkHztPpLDumGndsoIv3nifOxEwVLRuDlL05E0eE4RXOKmQkNoJ eoR8bMJVt/UI49FjEGq5UI0Iwm3cWvEwJWuHY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=iAqjxr+o2HOFapyaUfR5bUaRNb5AETzIXOZtE1sXMTc=; b=XYRiP3lc3Hyva1QC7LzxRvBGvh8fhzu0TKy4PoJLcC6+md7M3yW74+KRikuJLNJS5y m8OBIJ7411axgfZX+Tq3cc758TqvgZq6KVTY6pD9fox19MED09JTWbUrBpZ6INr9sxg/ zrTWtFsd/tP/+qt2T27r+U8UjgiXdcUJfbDvabm3ye7cDRvroD1nVBgyN0rQNfonHE82 7D2Wah1fJ8kjv8FptEPHLxbOuSvLTFpdzzmB4vntEEJ3HepIasLHPMQFIkv3/An4M2IQ lT4MvGYlbdym1wcGFUJIfuQRdQZ1FWts02cDBJCeDjailkfmMta0+BQN1owO8XVmV4R6 8CAQ== X-Gm-Message-State: AElRT7Hi2oITJ+jLHzSOdqoESU8cqKiURPip5gsHGGqWGzQJP71iWnTy FUaNP/Rq1gyotiwO16D6NrZMyw== X-Received: by 10.28.63.23 with SMTP id m23mr9306748wma.69.1520265894784; Mon, 05 Mar 2018 08:04:54 -0800 (PST) Received: from e104803-lin.lan (mail.andrep.de. [217.160.17.100]) by smtp.gmail.com with ESMTPSA id y6sm6574381wmy.14.2018.03.05.08.04.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 Mar 2018 08:04:54 -0800 (PST) From: Andre Przywara To: Julien Grall , Stefano Stabellini Date: Mon, 5 Mar 2018 16:03:50 +0000 Message-Id: <20180305160415.16760-33-andre.przywara@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20180305160415.16760-1-andre.przywara@linaro.org> References: <20180305160415.16760-1-andre.przywara@linaro.org> Cc: xen-devel@lists.xenproject.org Subject: [Xen-devel] [PATCH 32/57] ARM: new VGIC: Add GICv2 world switch backend X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Processing maintenance interrupts and accessing the list registers are dependent on the host's GIC version. Introduce vgic-v2.c to contain GICv2 specific functions. Implement the GICv2 specific code for syncing the emulation state into the VGIC registers. This also adds the hook to let Xen setup the host GIC addresses. This is based on Linux commit 140b086dd197, written by Marc Zyngier. Signed-off-by: Andre Przywara --- Changelog RFC ... v1: - extend comments - adapt to former changes - use existing Xen LR accessor interface (->write_lr, ->read_lr) - merge save_state and restore_state into callers - add vgic_irq_is_mapped_level() helper xen/arch/arm/vgic/vgic-v2.c | 231 ++++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/vgic/vgic.c | 7 ++ xen/arch/arm/vgic/vgic.h | 9 ++ 3 files changed, 247 insertions(+) create mode 100644 xen/arch/arm/vgic/vgic-v2.c diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c new file mode 100644 index 0000000000..4e74ebf7f5 --- /dev/null +++ b/xen/arch/arm/vgic/vgic-v2.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2015, 2016 ARM Ltd. + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "vgic.h" + +static struct { + bool enabled; + paddr_t dbase; /* Distributor interface address */ + paddr_t cbase; /* CPU interface address & size */ + paddr_t csize; + paddr_t vbase; /* Virtual CPU interface address */ + + /* Offset to add to get an 8kB contiguous region if GIC is aliased */ + uint32_t aliased_offset; +} gic_v2_hw_data; + +void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, paddr_t csize, + paddr_t vbase, uint32_t aliased_offset) +{ + gic_v2_hw_data.enabled = true; + gic_v2_hw_data.dbase = dbase; + gic_v2_hw_data.cbase = cbase; + gic_v2_hw_data.csize = csize; + gic_v2_hw_data.vbase = vbase; + gic_v2_hw_data.aliased_offset = aliased_offset; +} + +void vgic_v2_set_underflow(struct vcpu *vcpu) +{ + gic_hw_ops->update_hcr_status(GICH_HCR_UIE, 1); +} + +/* + * transfer the content of the LRs back into the corresponding ap_list: + * - active bit is transferred as is + * - pending bit is + * - transferred as is in case of edge sensitive IRQs + * - set to the line-level (resample time) for level sensitive IRQs + */ +void vgic_v2_fold_lr_state(struct vcpu *vcpu) +{ + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic; + unsigned int used_lrs = vcpu->arch.vgic.used_lrs; + unsigned long flags; + unsigned int lr; + + if ( !used_lrs ) /* No LRs used, so nothing to sync back here. */ + return; + + gic_hw_ops->update_hcr_status(GICH_HCR_UIE, 0); + + for ( lr = 0; lr < used_lrs; lr++ ) + { + struct gic_lr lr_val; + uint32_t intid; + struct vgic_irq *irq; + + gic_hw_ops->read_lr(lr, &lr_val); + + /* + * TODO: Possible optimization to avoid reading LRs: + * Read the ELRSR to find out which of our LRs have been cleared + * by the guest. We just need to know the IRQ number for those, which + * we could save in an array when populating the LRs. + * This trades one MMIO access (ELRSR) for possibly more than one (LRs), + * but requires some more code to save the IRQ number and to handle + * those finished IRQs according to the algorithm below. + * We need some numbers to justify this: chances are that we don't + * have many LRs in use most of the time, so we might not save much. + */ + gic_hw_ops->clear_lr(lr); + + intid = lr_val.virq; + irq = vgic_get_irq(vcpu->domain, vcpu, intid); + + spin_lock_irqsave(&irq->irq_lock, flags); + + /* Always preserve the active bit */ + irq->active = !!(lr_val.state & GICH_LR_ACTIVE); + + /* Edge is the only case where we preserve the pending bit */ + if ( irq->config == VGIC_CONFIG_EDGE && (lr_val.state & GICH_LR_PENDING) ) + { + irq->pending_latch = true; + + if ( vgic_irq_is_sgi(intid) ) + irq->source |= (1U << lr_val.source); + } + + /* + * Level-triggered mapped IRQs are special because we only + * observe rising edges as input to the VGIC. + * + * If the guest never acked the interrupt we have to sample + * the physical line and set the line level, because the + * device state could have changed or we simply need to + * process the still pending interrupt later. + * + * If this causes us to lower the level, we have to also clear + * the physical active state, since we will otherwise never be + * told when the interrupt becomes asserted again. + */ + if ( vgic_irq_is_mapped_level(irq) && (lr_val.state & GICH_LR_PENDING) ) + { + struct irq_desc *irqd; + + ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS); + + irqd = irq_to_desc(irq->hwintid); + irq->line_level = gic_read_pending_state(irqd); + + if ( !irq->line_level ) + gic_set_active_state(irqd, false); + } + + spin_unlock_irqrestore(&irq->irq_lock, flags); + vgic_put_irq(vcpu->domain, irq); + } + + gic_hw_ops->update_hcr_status(GICH_HCR_EN, 0); + vgic_cpu->used_lrs = 0; +} + +/** + * vgic_v2_populate_lr() - Populates an LR with the state of a given IRQ. + * @vcpu: The VCPU which the given @irq belongs to. + * @irq: The IRQ to convert into an LR. The irq_lock must be held already. + * @lr: The LR number to transfer the state into. + * + * This moves a virtual IRQ, represented by its vgic_irq, into a list register. + * Apart from translating the logical state into the LR bitfields, it also + * changes some state in the vgic_irq. + * For an edge sensitive IRQ the pending state is cleared in struct vgic_irq, + * for a level sensitive IRQ the pending state value is unchanged, as it is + * dictated directly by the input line level. + * + * If @irq describes an SGI with multiple sources, we choose the + * lowest-numbered source VCPU and clear that bit in the source bitmap. + * + * The irq_lock must be held by the caller. + */ +void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr) +{ + struct gic_lr lr_val = {0}; + + lr_val.virq = irq->intid; + + if ( irq_is_pending(irq) ) + { + lr_val.state |= GICH_LR_PENDING; + + if ( irq->config == VGIC_CONFIG_EDGE ) + irq->pending_latch = false; + + if ( vgic_irq_is_sgi(irq->intid) ) + { + u32 src = ffs(irq->source); + + BUG_ON(!src); + lr_val.source = (src - 1); + irq->source &= ~(1 << (src - 1)); + if ( irq->source ) + irq->pending_latch = true; + } + } + + if ( irq->active ) + lr_val.state |= GICH_LR_ACTIVE; + + if ( irq->hw ) + { + lr_val.hw_status = 1; + lr_val.pirq = irq->hwintid; + /* + * Never set pending+active on a HW interrupt, as the + * pending state is kept at the physical distributor + * level. + */ + if ( irq->active && irq_is_pending(irq) ) + lr_val.state &= ~GICH_LR_PENDING; + } + else + { + if ( irq->config == VGIC_CONFIG_LEVEL ) + lr_val.eoi = 1; + } + + /* + * Level-triggered mapped IRQs are special because we only observe + * rising edges as input to the VGIC. We therefore lower the line + * level here, so that we can take new virtual IRQs. See + * vgic_v2_fold_lr_state for more info. + */ + if ( vgic_irq_is_mapped_level(irq) && (lr_val.state & GICH_LR_PENDING) ) + irq->line_level = false; + + /* The GICv2 LR only holds five bits of priority. */ + lr_val.priority = irq->priority >> 3; + + gic_hw_ops->write_lr(lr, &lr_val); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c index 8e5215a00d..85e39f6f42 100644 --- a/xen/arch/arm/vgic/vgic.c +++ b/xen/arch/arm/vgic/vgic.c @@ -511,6 +511,7 @@ retry: static inline void vgic_fold_lr_state(struct vcpu *vcpu) { + vgic_v2_fold_lr_state(vcpu); } /* Requires the irq_lock to be held. */ @@ -518,10 +519,13 @@ static inline void vgic_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr) { ASSERT(spin_is_locked(&irq->irq_lock)); + + vgic_v2_populate_lr(vcpu, irq, lr); } static inline void vgic_set_underflow(struct vcpu *vcpu) { + vgic_v2_set_underflow(vcpu); } /* Requires the ap_list_lock to be held. */ @@ -638,7 +642,10 @@ void vgic_sync_to_lrs(void) spin_lock(¤t->arch.vgic.ap_list_lock); vgic_flush_lr_state(current); spin_unlock(¤t->arch.vgic.ap_list_lock); + + gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1); } + /* * Local variables: * mode: C diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h index a495116cb7..116b26544e 100644 --- a/xen/arch/arm/vgic/vgic.h +++ b/xen/arch/arm/vgic/vgic.h @@ -27,6 +27,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq) return irq->pending_latch || irq->line_level; } +static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq) +{ + return irq->config == VGIC_CONFIG_LEVEL && irq->hw; +} + struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu, u32 intid); void vgic_put_irq(struct domain *d, struct vgic_irq *irq); @@ -41,6 +46,10 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq) atomic_inc(&irq->refcount); } +void vgic_v2_fold_lr_state(struct vcpu *vcpu); +void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr); +void vgic_v2_set_underflow(struct vcpu *vcpu); + #endif /*