From patchwork Fri Mar 17 11:27:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "lan,Tianyu" X-Patchwork-Id: 9630449 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 EB4F560249 for ; Fri, 17 Mar 2017 11:37:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D3D88284E9 for ; Fri, 17 Mar 2017 11:37:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C88422864B; Fri, 17 Mar 2017 11:37:46 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID 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 1F1D6284E9 for ; Fri, 17 Mar 2017 11:37:46 +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 1coqAn-0004de-1G; Fri, 17 Mar 2017 11:35:57 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1coqAm-0004b3-0g for xen-devel@lists.xen.org; Fri, 17 Mar 2017 11:35:56 +0000 Received: from [85.158.139.211] by server-4.bemta-5.messagelabs.com id 35/41-13971-B1ACBC85; Fri, 17 Mar 2017 11:35:55 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrFLMWRWlGSWpSXmKPExsVywNwkVlfy1Ok Ig8Pt8hZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8asqS1MBfdDK87NOMjUwNhr38XIycEicItJ 4vobqS5GLg4hgemMEu8+fWYFSUgI8EocWTYDyvaXuPFsFTtEUT+jxMJLXWAJNgF1iROLJzKC2 CIC0hLXPl9mBCliFmhklGjY28gGkhAW8JTY/W0ZE8Q6VYmDJy+zgNi8Aq4Spy62Aw3iANqgID Fnkg1ImBMofLftATuILSTgInGv6wrLBEa+BYwMqxjVi1OLylKLdE30kooy0zNKchMzc3QNDUz 1clOLixPTU3MSk4r1kvNzNzECw4QBCHYw3upzPsQoycGkJMqrIngiQogvKT+lMiOxOCO+qDQn tfgQowwHh5IE7/FkoJxgUWp6akVaZg4wYGHSEhw8SiK8J0HSvMUFibnFmekQqVOMilLivL0gC QGQREZpHlwbLEouMcpKCfMyAh0ixFOQWpSbWYIq/4pRnINRSZj3NMgUnsy8Erjpr4AWMwEtTv x5BGRxSSJCSqqBMfrS5AueSuY2GybMudHc1rd2Tsi5jRE9nkv/KP45qjuN+84Wl4WSyxTYXL3 O5ATdvrS1enbfn+rPPXtbNL9Ie9wJEUmfqsMt/eP0ySg3tSkeBrsvsbuX1mdLbWywbRdomOjL 8NyQaUs8u/JxLt/wiKT5kY/yxSZ7Vr3c1Gl1NHXlY0llKeN6JZbijERDLeai4kQAq74iLY0CA AA= X-Env-Sender: tianyu.lan@intel.com X-Msg-Ref: server-16.tower-206.messagelabs.com!1489750548!74114611!3 X-Originating-IP: [192.55.52.93] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTkyLjU1LjUyLjkzID0+IDMyNDY2NQ==\n X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 60657 invoked from network); 17 Mar 2017 11:35:53 -0000 Received: from mga11.intel.com (HELO mga11.intel.com) (192.55.52.93) by server-16.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 17 Mar 2017 11:35:53 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=intel; t=1489750553; x=1521286553; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=PqE0rELEBmMQoaDCMvxQbzNeOjA02fIQXDt1sACf7Jk=; b=sYJxJ6dQ+jbvnJENLJa+wiOgN7ZSgMPA4slawSaEjpISIKTVplg/QSCE i6xis5myUU0IOsa+AUk9kJrQvXGBag==; Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 Mar 2017 04:35:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,176,1486454400"; d="scan'208";a="237460526" Received: from lantianyu-ws.sh.intel.com (HELO localhost) ([10.239.159.159]) by fmsmga004.fm.intel.com with ESMTP; 17 Mar 2017 04:35:51 -0700 From: Lan Tianyu To: xen-devel@lists.xen.org Date: Fri, 17 Mar 2017 19:27:23 +0800 Message-Id: <1489750043-17260-24-git-send-email-tianyu.lan@intel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1489750043-17260-1-git-send-email-tianyu.lan@intel.com> References: <1489750043-17260-1-git-send-email-tianyu.lan@intel.com> Cc: Lan Tianyu , andrew.cooper3@citrix.com, kevin.tian@intel.com, jbeulich@suse.com, chao.gao@intel.com Subject: [Xen-devel] [RFC PATCH 23/23] X86/vvtd: Add queued invalidation (QI) support 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 From: Chao Gao Queued Invalidation Interface is an expanded invalidation interface with extended capabilities. Hardware implementations report support for queued invalidation interface through the Extended Capability Register. The queued invalidation interface uses an Invalidation Queue (IQ), which is a circular buffer in system memory. Software submits commands by writing Invalidation Descriptors to the IQ. In this patch, a new function viommu_process_iq() is used for emulating how hardware handles invalidation requests through QI. Signed-off-by: Chao Gao Signed-off-by: Lan Tianyu --- xen/arch/x86/hvm/vvtd.c | 248 ++++++++++++++++++++++++++++++++++++ xen/drivers/passthrough/vtd/iommu.h | 29 ++++- 2 files changed, 276 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/vvtd.c b/xen/arch/x86/hvm/vvtd.c index 28d8f36..6d11075 100644 --- a/xen/arch/x86/hvm/vvtd.c +++ b/xen/arch/x86/hvm/vvtd.c @@ -423,6 +423,185 @@ static int vvtd_log_fault(struct vvtd *vvtd, return X86EMUL_OKAY; } +/* + * Process a invalidation descriptor. Currently, only Two types descriptors, + * Interrupt Entry Cache invalidation descritor and Invalidation Wait + * Descriptor are handled. + * @vvtd: the virtual vtd instance + * @i: the index of the invalidation descriptor to be processed + * + * If success return 0, or return -1 when failure. + */ +static int process_iqe(struct vvtd *vvtd, int i) +{ + uint64_t iqa, addr; + struct qinval_entry *qinval_page; + void *pg; + int ret; + + vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa); + ret = map_guest_page(vvtd->domain, DMA_IQA_ADDR(iqa)>>PAGE_SHIFT, + (void**)&qinval_page); + if ( ret ) + { + gdprintk(XENLOG_ERR, "Can't map guest IRT (rc %d)", ret); + return -1; + } + + switch ( qinval_page[i].q.inv_wait_dsc.lo.type ) + { + case TYPE_INVAL_WAIT: + if ( qinval_page[i].q.inv_wait_dsc.lo.sw ) + { + addr = (qinval_page[i].q.inv_wait_dsc.hi.saddr << 2); + ret = map_guest_page(vvtd->domain, addr >> PAGE_SHIFT, &pg); + if ( ret ) + { + gdprintk(XENLOG_ERR, "Can't map guest memory to inform guest " + "IWC completion (rc %d)", ret); + goto error; + } + *(uint32_t *)((uint64_t)pg + (addr & ~PAGE_MASK)) = + qinval_page[i].q.inv_wait_dsc.lo.sdata; + unmap_guest_page(pg); + } + + /* + * The following code generates an invalidation completion event + * indicating the invalidation wait descriptor completion. Note that + * the following code fragment is not tested properly. + */ + if ( qinval_page[i].q.inv_wait_dsc.lo.iflag ) + { + uint32_t ie_data, ie_addr; + if ( !vvtd_test_and_set_bit(vvtd, DMAR_ICS_REG, DMA_ICS_IWC_BIT) ) + { + __vvtd_set_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT); + if ( !vvtd_test_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT) ) + { + ie_data = vvtd_get_reg(vvtd, DMAR_IEDATA_REG); + ie_addr = vvtd_get_reg(vvtd, DMAR_IEADDR_REG); + vvtd_generate_interrupt(vvtd, ie_addr, ie_data); + __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT); + } + } + } + break; + + case TYPE_INVAL_IEC: + /* + * Currently, no cache is preserved in hypervisor. Only need to update + * pIRTEs which are modified in binding process. + */ + break; + + default: + goto error; + } + + unmap_guest_page((void*)qinval_page); + return 0; + +error: + unmap_guest_page((void*)qinval_page); + gdprintk(XENLOG_ERR, "Internal error in Queue Invalidation.\n"); + domain_crash(vvtd->domain); + return -1; +} + +/* + * Invalidate all the descriptors in Invalidation Queue. + */ +static void vvtd_process_iq(struct vvtd *vvtd) +{ + uint64_t iqh, iqt, iqa, max_entry, i; + int ret = 0; + + /* + * No new descriptor is fetched from the Invalidation Queue until + * software clears the IQE field in the Fault Status Register + */ + if ( vvtd_test_bit(vvtd, DMAR_FSTS_REG, DMA_FSTS_IQE_BIT) ) + return; + + vvtd_get_reg_quad(vvtd, DMAR_IQH_REG, iqh); + vvtd_get_reg_quad(vvtd, DMAR_IQT_REG, iqt); + vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa); + + max_entry = DMA_IQA_ENTRY_PER_PAGE << DMA_IQA_QS(iqa); + iqh = DMA_IQH_QH(iqh); + iqt = DMA_IQT_QT(iqt); + + ASSERT(iqt < max_entry); + if ( iqh == iqt ) + return; + + i = iqh; + while ( i != iqt ) + { + ret = process_iqe(vvtd, i); + if ( ret ) + break; + else + i = (i + 1) % max_entry; + vvtd_set_reg_quad(vvtd, DMAR_IQH_REG, i << DMA_IQH_QH_SHIFT); + } + + /* + * When IQE set, IQH references the desriptor associated with the error. + */ + if ( ret ) + vvtd_report_non_recoverable_fault(vvtd, DMA_FSTS_IQE_BIT); +} + +static int vvtd_write_iqt(struct vvtd *vvtd, unsigned long val) +{ + uint64_t iqa; + + if ( val & DMA_IQT_RSVD ) + { + VVTD_DEBUG(VVTD_DBG_RW, "Attempt to set reserved bits in " + "Invalidation Queue Tail."); + return X86EMUL_OKAY; + } + + vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa); + if ( DMA_IQT_QT(val) >= DMA_IQA_ENTRY_PER_PAGE << DMA_IQA_QS(iqa) ) + { + VVTD_DEBUG(VVTD_DBG_RW, "IQT: Value %lx exceeded supported max " + "index.", val); + return X86EMUL_OKAY; + } + + vvtd_set_reg_quad(vvtd, DMAR_IQT_REG, val); + vvtd_process_iq(vvtd); + return X86EMUL_OKAY; +} + +static int vvtd_write_iqa(struct vvtd *vvtd, unsigned long val) +{ + if ( val & DMA_IQA_RSVD ) + { + VVTD_DEBUG(VVTD_DBG_RW, "Attempt to set reserved bits in " + "Invalidation Queue Address."); + return X86EMUL_OKAY; + } + + vvtd_set_reg_quad(vvtd, DMAR_IQA_REG, val); + return X86EMUL_OKAY; +} + +static int vvtd_write_ics(struct vvtd *vvtd, unsigned long val) +{ + if ( val & DMA_ICS_IWC ) + { + __vvtd_clear_bit(vvtd, DMAR_ICS_REG, DMA_ICS_IWC_BIT); + /*When IWC field is cleared, the IP field needs to be cleared */ + __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT); + } + return X86EMUL_OKAY; +} + static int vvtd_write_frcd3(struct vvtd *vvtd, unsigned long val) { /* Writing a 1 means clear fault */ @@ -434,6 +613,29 @@ static int vvtd_write_frcd3(struct vvtd *vvtd, unsigned long val) return X86EMUL_OKAY; } +static int vvtd_write_iectl(struct vvtd *vvtd, unsigned long val) +{ + /* + * Only DMA_IECTL_IM bit is writable. Generate pending event when unmask. + */ + if ( !(val & DMA_IECTL_IM) ) + { + /* Clear IM and clear IP */ + __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT); + if ( vvtd_test_and_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT) ) + { + uint32_t ie_data, ie_addr; + ie_data = vvtd_get_reg(vvtd, DMAR_IEDATA_REG); + ie_addr = vvtd_get_reg(vvtd, DMAR_IEADDR_REG); + vvtd_generate_interrupt(vvtd, ie_addr, ie_data); + } + } + else + __vvtd_set_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT); + + return X86EMUL_OKAY; +} + static int vvtd_write_fectl(struct vvtd *vvtd, unsigned long val) { /* @@ -476,6 +678,10 @@ static int vvtd_write_fsts(struct vvtd *vvtd, unsigned long val) if ( !((vvtd_get_reg(vvtd, DMAR_FSTS_REG) & DMA_FSTS_FAULTS)) ) __vvtd_clear_bit(vvtd, DMAR_FECTL_REG, DMA_FECTL_IP_BIT); + /* Continue to deal invalidation when IQE is clear */ + if ( !vvtd_test_bit(vvtd, DMAR_FSTS_REG, DMA_FSTS_IQE_BIT) ) + vvtd_process_iq(vvtd); + return X86EMUL_OKAY; } @@ -636,6 +842,48 @@ static int vvtd_write(struct vcpu *v, unsigned long addr, ret = vvtd_write_gcmd(vvtd, val_lo); break; + case DMAR_IQT_REG: + if ( len == 8 ) + ret = vvtd_write_iqt(vvtd, val); + else + ret = vvtd_write_iqt(vvtd, val_lo); + break; + + case DMAR_IQA_REG: + if ( len == 8 ) + ret = vvtd_write_iqa(vvtd, val); + else + { + unsigned long iqa_hi; + + iqa_hi = vvtd_get_reg(vvtd, DMAR_IQA_REG_HI); + ret = vvtd_write_iqa(vvtd, val_lo | (iqa_hi << 32)); + } + break; + + case DMAR_IQA_REG_HI: + { + unsigned long iqa_lo; + + if ( len == 8 ) + goto error; + iqa_lo = vvtd_get_reg(vvtd, DMAR_IQA_REG); + ret = vvtd_write_iqa(vvtd, (val_lo << 32) | iqa_lo); + break; + } + + case DMAR_ICS_REG: + if ( len == 8 ) + goto error; + ret = vvtd_write_ics(vvtd, val_lo); + break; + + case DMAR_IECTL_REG: + if ( len == 8 ) + goto error; + ret = vvtd_write_iectl(vvtd, val_lo); + break; + case DMAR_IRTA_REG: if ( len == 8 ) vvtd_set_reg_quad(vvtd, DMAR_IRTA_REG, val); diff --git a/xen/drivers/passthrough/vtd/iommu.h b/xen/drivers/passthrough/vtd/iommu.h index 20e6172..2ee7c5c 100644 --- a/xen/drivers/passthrough/vtd/iommu.h +++ b/xen/drivers/passthrough/vtd/iommu.h @@ -207,6 +207,32 @@ #define DMA_IRTA_S(val) (val & 0xf) #define DMA_IRTA_SIZE(val) (1UL << (DMA_IRTA_S(val) + 1)) +/* IQH_REG */ +#define DMA_IQH_QH_SHIFT 4 +#define DMA_IQH_QH(val) ((val >> 4) & 0x7fffULL) + +/* IQT_REG */ +#define DMA_IQT_QT_SHIFT 4 +#define DMA_IQT_QT(val) ((val >> 4) & 0x7fffULL) +#define DMA_IQT_RSVD 0xfffffffffff80007ULL + +/* IQA_REG */ +#define DMA_MGAW 39 /* Maximum Guest Address Width */ +#define DMA_IQA_ADDR(val) (val & ~0xfffULL) +#define DMA_IQA_QS(val) (val & 0x7) +#define DMA_IQA_ENTRY_PER_PAGE (1 << 8) +#define DMA_IQA_RSVD (~((1ULL << DMA_MGAW) -1 ) | 0xff8ULL) + +/* IECTL_REG */ +#define DMA_IECTL_IM_BIT 31 +#define DMA_IECTL_IM (1 << DMA_IECTL_IM_BIT) +#define DMA_IECTL_IP_BIT 30 +#define DMA_IECTL_IP (((u64)1) << DMA_IECTL_IP_BIT) + +/* ICS_REG */ +#define DMA_ICS_IWC_BIT 0 +#define DMA_ICS_IWC (1 << DMA_ICS_IWC_BIT) + /* PMEN_REG */ #define DMA_PMEN_EPM (((u32)1) << 31) #define DMA_PMEN_PRS (((u32)1) << 0) @@ -241,7 +267,8 @@ #define DMA_FSTS_PPF ((u64)1 << DMA_FSTS_PPF_BIT) #define DMA_FSTS_AFO ((u64)1 << 2) #define DMA_FSTS_APF ((u64)1 << 3) -#define DMA_FSTS_IQE ((u64)1 << 4) +#define DMA_FSTS_IQE_BIT 4 +#define DMA_FSTS_IQE ((u64)1 << DMA_FSTS_IQE_BIT) #define DMA_FSTS_ICE ((u64)1 << 5) #define DMA_FSTS_ITE ((u64)1 << 6) #define DMA_FSTS_PRO_BIT 7