From patchwork Fri Jun 9 17:41:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9779001 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3FE2760318 for ; Fri, 9 Jun 2017 17:44:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 29473286E0 for ; Fri, 9 Jun 2017 17:44:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1E2BF286F8; Fri, 9 Jun 2017 17:44:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0F571286E0 for ; Fri, 9 Jun 2017 17:44:00 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dJNvS-0004GG-Jz; Fri, 09 Jun 2017 17:42:22 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dJNvQ-0004BB-Fm for xen-devel@lists.xenproject.org; Fri, 09 Jun 2017 17:42:20 +0000 Received: from [85.158.137.68] by server-8.bemta-3.messagelabs.com id 11/B8-23755-BFDDA395; Fri, 09 Jun 2017 17:42:19 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrGLMWRWlGSWpSXmKPExsVysyfVTff3Xat Ig65ebovvWyYzOTB6HP5whSWAMYo1My8pvyKBNePW9wssBT/cK5YtLmlg/GDaxcjFISSwmVHi w4J37F2MnEDOckaJSysLQWw2AV2JHTdfM4PYIgKhEk8XfGcGaWAWuM4ocXrHfDaQhLCApURP7 0MWEJtFQFXiwIIzYA28AtYSCz8vAxsqISAn0XD+PlicEyi+bc9aNohlVhIthy6zT2DkXsDIsI pRozi1qCy1SNfQQC+pKDM9oyQ3MTMHyDPWy00tLk5MT81JTCrWS87P3cQI9G89AwPjDsZtXc6 HGCU5mJREeacVWEUK8SXlp1RmJBZnxBeV5qQWH2KU4eBQkuDtuQOUEyxKTU+tSMvMAQYaTFqC g0dJhPfFSaA0b3FBYm5xZjpE6hSjopQ4ryVInwBIIqM0D64NFtyXGGWlhHkZGRgYhHgKUotyM 0tQ5V8xinMwKgnzOoNM4cnMK4Gb/gpoMRPQ4iXvLEAWlyQipKQaGBed5dm2/ZoGr2jyzCJTcc +lM4yOOQTd3We5MaZxoWh4hcmV092ztAKu3f44zyTn7t7CwoQs5TSuQyXfv0q0LlnWpsV97rG vuY7ZjW2Xt1jqsl9gzUrnm797wY6FtQ8Dc55mLHt969R9U5kdTIwXU1VSNj+eeH263iyrKuln 0f7fPM8pL26S/6zEUpyRaKjFXFScCADlNLrxaQIAAA== X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-6.tower-31.messagelabs.com!1497030138!66379862!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.4.19; banners=-,-,- X-VirusChecked: Checked Received: (qmail 19960 invoked from network); 9 Jun 2017 17:42:18 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-6.tower-31.messagelabs.com with SMTP; 9 Jun 2017 17:42:18 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2B0F715BF; Fri, 9 Jun 2017 10:42:18 -0700 (PDT) Received: from e104803-lin.lan (unknown [10.1.207.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B4F3C3F578; Fri, 9 Jun 2017 10:42:16 -0700 (PDT) From: Andre Przywara To: Julien Grall , Stefano Stabellini Date: Fri, 9 Jun 2017 18:41:32 +0100 Message-Id: <20170609174141.5068-26-andre.przywara@arm.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20170609174141.5068-1-andre.przywara@arm.com> References: <20170609174141.5068-1-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org, Vijaya Kumar K , Vijay Kilari , Shanker Donthineni , Manish Jaggi Subject: [Xen-devel] [PATCH v11 25/34] ARM: vITS: handle MAPD command X-BeenThere: xen-devel@lists.xen.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.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The MAPD command maps a device by associating a memory region for storing ITEs with a certain device ID. Since it features a valid bit, MAPD also covers the "unmap" functionality, which we also cover here. We store the given guest physical address in the device table, and, if this command comes from Dom0, tell the host ITS driver about this new mapping, so it can issue the corresponding host MAPD command and create the required tables. We take care of rolling back actions should one step fail. Upon unmapping a device we make sure we clean up all associated resources and release the memory again. We use our existing guest memory access function to find the right ITT entry and store the mapping there (in guest memory). Signed-off-by: Andre Przywara Acked-by: Julien Grall --- xen/arch/arm/gic-v3-its.c | 17 +++++ xen/arch/arm/gic-v3-lpi.c | 17 +++++ xen/arch/arm/vgic-v3-its.c | 143 +++++++++++++++++++++++++++++++++++++++ xen/include/asm-arm/gic_v3_its.h | 5 ++ 4 files changed, 182 insertions(+) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 38f0840..8864e0b 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -859,6 +859,23 @@ struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d, return get_event_pending_irq(d, vdoorbell_address, vdevid, eventid, NULL); } +int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address, + uint32_t vdevid, uint32_t eventid) +{ + uint32_t host_lpi = INVALID_LPI; + + if ( !get_event_pending_irq(d, vdoorbell_address, vdevid, eventid, + &host_lpi) ) + return -EINVAL; + + if ( host_lpi == INVALID_LPI ) + return -EINVAL; + + gicv3_lpi_update_host_entry(host_lpi, d->domain_id, INVALID_LPI); + + return 0; +} + /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */ void gicv3_its_dt_init(const struct dt_device_node *node) { diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c index 03d23b6..027248d 100644 --- a/xen/arch/arm/gic-v3-lpi.c +++ b/xen/arch/arm/gic-v3-lpi.c @@ -215,6 +215,23 @@ out: irq_exit(); } +void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id, + uint32_t virt_lpi) +{ + union host_lpi *hlpip, hlpi; + + ASSERT(host_lpi >= LPI_OFFSET); + + host_lpi -= LPI_OFFSET; + + hlpip = &lpi_data.host_lpis[host_lpi / HOST_LPIS_PER_PAGE][host_lpi % HOST_LPIS_PER_PAGE]; + + hlpi.virt_lpi = virt_lpi; + hlpi.dom_id = domain_id; + + write_u64_atomic(&hlpip->data, hlpi.data); +} + static int gicv3_lpi_allocate_pendtable(uint64_t *reg) { uint64_t val; diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index f6262fc..7d4e55c 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -159,6 +159,21 @@ static struct vcpu *get_vcpu_from_collection(struct virt_its *its, return its->d->vcpu[vcpu_id]; } +/* Set the address of an ITT for a given device ID. */ +static int its_set_itt_address(struct virt_its *its, uint32_t devid, + paddr_t itt_address, uint32_t nr_bits) +{ + paddr_t addr = get_baser_phys_addr(its->baser_dev); + dev_table_entry_t itt_entry = DEV_TABLE_ENTRY(itt_address, nr_bits); + + if ( devid >= its->max_devices ) + return -ENOENT; + + return vgic_access_guest_memory(its->d, + addr + devid * sizeof(dev_table_entry_t), + &itt_entry, sizeof(itt_entry), true); +} + /* * Lookup the address of the Interrupt Translation Table associated with * that device ID. @@ -375,6 +390,131 @@ out_unlock: return ret; } +/* Must be called with the ITS lock held. */ +static int its_discard_event(struct virt_its *its, + uint32_t vdevid, uint32_t vevid) +{ + struct pending_irq *p; + unsigned long flags; + struct vcpu *vcpu; + uint32_t vlpi; + + ASSERT(spin_is_locked(&its->its_lock)); + + if ( !read_itte(its, vdevid, vevid, &vcpu, &vlpi) ) + return -ENOENT; + + if ( vlpi == INVALID_LPI ) + return -ENOENT; + + /* + * TODO: This relies on the VCPU being correct in the ITS tables. + * This can be fixed by either using a per-IRQ lock or by using + * the VCPU ID from the pending_irq instead. + */ + spin_lock_irqsave(&vcpu->arch.vgic.lock, flags); + + /* Remove the pending_irq from the tree. */ + write_lock(&its->d->arch.vgic.pend_lpi_tree_lock); + p = radix_tree_delete(&its->d->arch.vgic.pend_lpi_tree, vlpi); + write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock); + + if ( !p ) + { + spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags); + + return -ENOENT; + } + + /* Cleanup the pending_irq and disconnect it from the LPI. */ + list_del_init(&p->inflight); + list_del_init(&p->lr_queue); + vgic_init_pending_irq(p, INVALID_LPI); + + spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags); + + /* Remove the corresponding host LPI entry */ + return gicv3_remove_guest_event(its->d, its->doorbell_address, + vdevid, vevid); +} + +static void its_unmap_device(struct virt_its *its, uint32_t devid) +{ + dev_table_entry_t itt; + uint64_t evid; + + spin_lock(&its->its_lock); + + if ( its_get_itt(its, devid, &itt) ) + goto out; + + /* + * For DomUs we need to check that the number of events per device + * is really limited, otherwise looping over all events can take too + * long for a guest. This ASSERT can then be removed if that is + * covered. + */ + ASSERT(is_hardware_domain(its->d)); + + for ( evid = 0; evid < DEV_TABLE_ITT_SIZE(itt); evid++ ) + /* Don't care about errors here, clean up as much as possible. */ + its_discard_event(its, devid, evid); + +out: + spin_unlock(&its->its_lock); +} + +static int its_handle_mapd(struct virt_its *its, uint64_t *cmdptr) +{ + /* size and devid get validated by the functions called below. */ + uint32_t devid = its_cmd_get_deviceid(cmdptr); + unsigned int size = its_cmd_get_size(cmdptr) + 1; + bool valid = its_cmd_get_validbit(cmdptr); + paddr_t itt_addr = its_cmd_get_ittaddr(cmdptr); + int ret; + + /* Sanitize the number of events. */ + if ( valid && (size > its->evid_bits) ) + return -1; + + if ( !valid ) + /* Discard all events and remove pending LPIs. */ + its_unmap_device(its, devid); + + /* + * There is no easy and clean way for Xen to know the ITS device ID of a + * particular (PCI) device, so we have to rely on the guest telling + * us about it. For *now* we are just using the device ID *Dom0* uses, + * because the driver there has the actual knowledge. + * Eventually this will be replaced with a dedicated hypercall to + * announce pass-through of devices. + */ + if ( is_hardware_domain(its->d) ) + { + + /* + * Dom0's ITSes are mapped 1:1, so both addresses are the same. + * Also the device IDs are equal. + */ + ret = gicv3_its_map_guest_device(its->d, its->doorbell_address, devid, + its->doorbell_address, devid, + BIT(size), valid); + if ( ret && valid ) + return ret; + } + + spin_lock(&its->its_lock); + + if ( valid ) + ret = its_set_itt_address(its, devid, itt_addr, size); + else + ret = its_set_itt_address(its, devid, INVALID_PADDR, 1); + + spin_unlock(&its->its_lock); + + return ret; +} + #define ITS_CMD_BUFFER_SIZE(baser) ((((baser) & 0xff) + 1) << 12) #define ITS_CMD_OFFSET(reg) ((reg) & GENMASK(19, 5)) @@ -420,6 +560,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its) case GITS_CMD_MAPC: ret = its_handle_mapc(its, command); break; + case GITS_CMD_MAPD: + ret = its_handle_mapd(its, command); + break; case GITS_CMD_SYNC: /* We handle ITS commands synchronously, so we ignore SYNC. */ break; diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h index be67726..0089ac2 100644 --- a/xen/include/asm-arm/gic_v3_its.h +++ b/xen/include/asm-arm/gic_v3_its.h @@ -175,6 +175,11 @@ struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d, paddr_t vdoorbell_address, uint32_t vdevid, uint32_t eventid); +int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address, + uint32_t vdevid, uint32_t eventid); +void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id, + uint32_t virt_lpi); + #else static inline void gicv3_its_dt_init(const struct dt_device_node *node)