From patchwork Thu Nov 19 14:53:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Auger X-Patchwork-Id: 7658111 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 4CA44BF90C for ; Thu, 19 Nov 2015 15:00:35 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F2AB82063C for ; Thu, 19 Nov 2015 15:00:33 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C58AA204D9 for ; Thu, 19 Nov 2015 15:00:32 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZzQfZ-0006Nk-E2; Thu, 19 Nov 2015 14:58:41 +0000 Received: from mail-wm0-x230.google.com ([2a00:1450:400c:c09::230]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZzQbl-0001Cw-DZ for linux-arm-kernel@lists.infradead.org; Thu, 19 Nov 2015 14:54:53 +0000 Received: by wmww144 with SMTP id w144so119954573wmw.0 for ; Thu, 19 Nov 2015 06:54:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=guUe4MT/Hkyd9AmbJWqfFsAqK2hToIRUgZDoZVVY0ec=; b=Ck6hOvLF0eZRtTbSGpkyMcpOuw7l8TAyLWHlA2K5cy/b8qokJ8yFHUx3T67xs6PN/Y k7IpShOJrtEqXLQLvecHf7GASEq1Z2AnYQpqJKsHtkrw0/GoNQPk7+e3FgXzEUM6BOhv Zgvt0DoEZqxnG4xml3mfIWBw/ehBIKn99phmbu5dDRFffXEhceOwlcIp5Xjkq0Tpxza2 Fh0qhhF4+VwUETs5srtYFhkzLPs9P4FASsXvgGJJT0AtcQ+U3ozAX2fkILNXrGPGaP1u PIkbRlTzOHAhPBN0KP3oe3FE2f4L6dW+Z/ENe9Mpw2u96iVJAsOdl+0+hI/G7o3ISbZC BVMQ== 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=guUe4MT/Hkyd9AmbJWqfFsAqK2hToIRUgZDoZVVY0ec=; b=LQJm58hWyCw5N3gtgyeekAXgy7n5tlxHP4XpBudnza65TjOSjHzFSzEswbCzsNJRNJ hZ0s1Ugx24Rtf+J45awv6ItrS+t+8F6qfmkAvgzONUtC1oDmGFTkU6JJqAtKzfPMFXOr SxTdSIWUHTGwMX8L9wduPfBj6j1TUtMsjOZ99eJC9URyljW0UHdKEZgjHX8yK3pJjxH8 SKQiEgHpXpXhvTJTKoSrhBquGlXKonfQ3R9lTt9P5I85FSovUubvc8oTqdaVaNCQ27oK +zvy3czPiHoJIBgsP0deK0/n9UJqVuBWwJ4a9b91uIsPTZsWY31cKRhtPcqb0mKygC1T 2fbw== X-Gm-Message-State: ALoCoQnP8RSnnGNbS1bxI4Xf/Wb2gyWPaqhO4cT74RJ8mTON2++9qix6qmh4OYlIyc3fjljok8+X X-Received: by 10.194.192.42 with SMTP id hd10mr8617105wjc.179.1447944864007; Thu, 19 Nov 2015 06:54:24 -0800 (PST) Received: from new-host-3.home (LMontsouris-657-1-37-90.w80-11.abo.wanadoo.fr. [80.11.198.90]) by smtp.gmail.com with ESMTPSA id h67sm34493865wmf.17.2015.11.19.06.54.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 19 Nov 2015 06:54:23 -0800 (PST) From: Eric Auger To: eric.auger@st.com, eric.auger@linaro.org, alex.williamson@redhat.com, b.reynal@virtualopensystems.com, christoffer.dall@linaro.org, marc.zyngier@arm.com, linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Subject: [PATCH v4 08/13] KVM: arm/arm64: vgic: adapt state machine for non shared mapped interrupts Date: Thu, 19 Nov 2015 14:53:58 +0000 Message-Id: <1447944843-17731-9-git-send-email-eric.auger@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1447944843-17731-1-git-send-email-eric.auger@linaro.org> References: <1447944843-17731-1-git-send-email-eric.auger@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151119_065446_023673_492D7D34 X-CRM114-Status: GOOD ( 23.11 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: andre.przywara@arm.com, linux-kernel@vger.kernel.org, patches@linaro.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marc Zyngier So far, the only user of the mapped interrupt facility was the timer: the physical distributor active state needed to be context-switched for each vcpu, as the device is shared across all vcpus. This patch allows to indicate whether a mapped IRQ originates from a device shared between several VMs (typically the architected timer) or from a device assigned to a single VM. A new "shared" flag is added to irq_phys_map and passed to the mapping function. the VGIC state machine is adapted to support the non shared mapped IRQs: - only can be sampled when it is pending - when queueing the IRQ (programming the LR), the pending state is removed as for edge sensitive IRQs - queued state is not modelled. Level state is not modelled - its injection with high level always is valid since steming from the HW. Signed-off-by: Eric Auger Signed-off-by: Marc Zyngier --- v3 -> v4: - reword the patch title - rebase on [PATCH v2 0/8] Rework architected timer and forwarded IRQs handling - renamed shared_hw into non_shared_mapped_irq; - handle edge-sensitive unshared mapped IRQs - vgic_validate_injection rejects mapped unshared edge with level == 0 --- include/kvm/arm_vgic.h | 3 ++- virt/kvm/arm/arch_timer.c | 2 +- virt/kvm/arm/vgic.c | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 9c747cb..9bf6a30 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -158,6 +158,7 @@ struct irq_phys_map { u32 virt_irq; u32 phys_irq; u32 irq; + bool shared; }; struct irq_phys_map_entry { @@ -344,7 +345,7 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu); struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, - int virt_irq, int irq); + int virt_irq, int irq, bool shared); int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map); #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 21a0ab2..9eea751 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -289,7 +289,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, * Tell the VGIC that the virtual interrupt is tied to a * physical interrupt. We do that once per VCPU. */ - map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq); + map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq, true); if (WARN_ON(IS_ERR(map))) return PTR_ERR(map); diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index bc30d93..dba8eb6 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -410,7 +410,11 @@ void vgic_cpu_irq_clear(struct kvm_vcpu *vcpu, int irq) static bool vgic_can_sample_irq(struct kvm_vcpu *vcpu, int irq) { - return !vgic_irq_is_queued(vcpu, irq); + struct irq_phys_map *map = vgic_irq_map_search(vcpu, irq); + bool non_shared_mapped_irq = map && !map->shared; + + return !vgic_irq_is_queued(vcpu, irq) || + (non_shared_mapped_irq && vgic_dist_irq_is_pending(vcpu, irq)); } /** @@ -1205,11 +1209,14 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq) { + struct irq_phys_map *map = vgic_irq_map_search(vcpu, irq); + bool non_shared_mapped_irq = map && !map->shared; + if (!vgic_can_sample_irq(vcpu, irq)) return true; /* level interrupt, already queued */ if (vgic_queue_irq(vcpu, 0, irq)) { - if (vgic_irq_is_edge(vcpu, irq)) { + if (vgic_irq_is_edge(vcpu, irq) || non_shared_mapped_irq) { vgic_dist_irq_clear_pending(vcpu, irq); vgic_cpu_irq_clear(vcpu, irq); } else { @@ -1292,6 +1299,8 @@ static int process_queued_irq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr) { int pending = 0; + struct irq_phys_map *map = vgic_irq_map_search(vcpu, vlr.irq); + bool non_shared_mapped_irq = map && !map->shared; /* * If the IRQ was EOIed (called from vgic_process_maintenance) or it @@ -1312,8 +1321,7 @@ static int process_queued_irq(struct kvm_vcpu *vcpu, vgic_irq_clear_queued(vcpu, vlr.irq); /* Any additional pending interrupt? */ - if (vgic_irq_is_edge(vcpu, vlr.irq)) { - BUG_ON(!(vlr.state & LR_HW)); + if (vgic_irq_is_edge(vcpu, vlr.irq) || non_shared_mapped_irq) { pending = vgic_dist_irq_is_pending(vcpu, vlr.irq); } else { if (vgic_dist_irq_get_level(vcpu, vlr.irq)) { @@ -1506,18 +1514,23 @@ void vgic_kick_vcpus(struct kvm *kvm) } } -static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level) +static int vgic_validate_injection(struct kvm_vcpu *vcpu, + struct irq_phys_map *map, + int irq, int level) { int edge_triggered = vgic_irq_is_edge(vcpu, irq); /* * Only inject an interrupt if: * - edge triggered and we have a rising edge - * - level triggered and we change level + * - level triggered and we change level (except for + * mapped unshared IRQs where level is not modelled) */ if (edge_triggered) { int state = vgic_dist_irq_is_pending(vcpu, irq); return level > state; + } else if (map && !map->shared) { + return true; } else { int state = vgic_dist_irq_get_level(vcpu, irq); return level != state; @@ -1545,7 +1558,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, edge_triggered = vgic_irq_is_edge(vcpu, irq_num); level_triggered = !edge_triggered; - if (!vgic_validate_injection(vcpu, irq_num, level)) { + if (!vgic_validate_injection(vcpu, map, irq_num, level)) { ret = false; goto out; } @@ -1718,16 +1731,20 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu, * @vcpu: The VCPU pointer * @virt_irq: The virtual irq number * @irq: The Linux IRQ number + * @shared: Indicates if the interrupt has to be context-switched or + * if it is private to a VM * * Establish a mapping between a guest visible irq (@virt_irq) and a * Linux irq (@irq). On injection, @virt_irq will be associated with * the physical interrupt represented by @irq. This mapping can be * established multiple times as long as the parameters are the same. + * If @shared is true, the active state of the interrupt will be + * context-switched. * * Returns a valid pointer on success, and an error pointer otherwise */ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, - int virt_irq, int irq) + int virt_irq, int irq, bool shared) { struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq); @@ -1761,7 +1778,8 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, if (map) { /* Make sure this mapping matches */ if (map->phys_irq != phys_irq || - map->irq != irq) + map->irq != irq || + map->shared != shared) map = ERR_PTR(-EINVAL); /* Found an existing, valid mapping */ @@ -1772,6 +1790,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, map->virt_irq = virt_irq; map->phys_irq = phys_irq; map->irq = irq; + map->shared = shared; list_add_tail_rcu(&entry->entry, root);