From patchwork Fri Jun 17 03:37:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quan Xu X-Patchwork-Id: 9182403 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 B44716075D for ; Fri, 17 Jun 2016 03:44:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A693128399 for ; Fri, 17 Jun 2016 03:44:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9B459283A3; Fri, 17 Jun 2016 03:44:06 +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 E077328399 for ; Fri, 17 Jun 2016 03:44:05 +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 1bDkfR-0007um-Iu; Fri, 17 Jun 2016 03:42:01 +0000 Received: from mail6.bemta6.messagelabs.com ([85.158.143.247]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bDkfQ-0007uE-QE for xen-devel@lists.xen.org; Fri, 17 Jun 2016 03:42:00 +0000 Received: from [85.158.143.35] by server-3.bemta-6.messagelabs.com id C0/83-22092-88173675; Fri, 17 Jun 2016 03:42:00 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLLMWRWlGSWpSXmKPExsVywNykQre9MDn c4OYDMYslHxezODB6HN39mymAMYo1My8pvyKBNWPfg/lMBTtCKyY9W8bcwHjGqouRk0NIoFKi 908XO4gtIcArcWTZDFYI21/i9OZTTBA1NRL7zu1gBLHZBFQkZjS/A6sXEZCWuPb5MlCci4NZ4 AWjRFtLD1iRsIC5xJFdv5lBbBYBVYm9P3aygNi8Ao4S2y4/ZINYoCCx7MtasBpOASeJuxMOsE Isc5T4t+09ywRG3gWMDKsY1YtTi8pSi3QN9ZKKMtMzSnITM3N0DQ3M9HJTi4sT01NzEpOK9ZL zczcxAoOBAQh2MO587nSIUZKDSUmUVzszOVyILyk/pTIjsTgjvqg0J7X4EKMMB4eSBK9kAVBO sCg1PbUiLTMHGJYwaQkOHiURXm6QNG9xQWJucWY6ROoUo6KUOO+3fKCEAEgiozQPrg0WC5cYZ aWEeRmBDhHiKUgtys0sQZV/xSjOwagkzOsGMp4nM68EbvoroMVMQIttpseDLC5JREhJNTD6zn odPllXJfBpHE/n8QtuRcsLm/JmthzbcOn4wQ+prp78xom35l0Uf372+vE5j8yfB5xgan3N5RV c4BEofEPjjO2Dkv/qtfFz6oqe9YUs7nnD/TrudbXk+/wlYu+ZJ2v9vHrDcNKdneuVj7/qXdFz Xi9FP8rxyk4hr905EzbvOy7Lb9Als/SpEktxRqKhFnNRcSIAZ6z1loACAAA= X-Env-Sender: quan.xu@intel.com X-Msg-Ref: server-12.tower-21.messagelabs.com!1466134917!19488233!2 X-Originating-IP: [192.55.52.120] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.46; banners=-,-,- X-VirusChecked: Checked Received: (qmail 63466 invoked from network); 17 Jun 2016 03:41:58 -0000 Received: from mga04.intel.com (HELO mga04.intel.com) (192.55.52.120) by server-12.tower-21.messagelabs.com with SMTP; 17 Jun 2016 03:41:58 -0000 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga104.fm.intel.com with ESMTP; 16 Jun 2016 20:41:58 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,481,1459839600"; d="scan'208";a="720451541" Received: from xen-commits.sh.intel.com ([10.239.82.178]) by FMSMGA003.fm.intel.com with ESMTP; 16 Jun 2016 20:41:56 -0700 From: "Xu, Quan" To: xen-devel@lists.xen.org Date: Fri, 17 Jun 2016 11:37:23 +0800 Message-Id: <1466134645-50852-2-git-send-email-quan.xu@intel.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1466134645-50852-1-git-send-email-quan.xu@intel.com> References: <1466134645-50852-1-git-send-email-quan.xu@intel.com> Cc: Kevin Tian , Keir Fraser , Quan Xu , Andrew Cooper , dario.faggioli@citrix.com, Jan Beulich , Feng Wu Subject: [Xen-devel] [PATCH v9 1/3] vt-d: fix the IOMMU flush issue 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: Quan Xu The propagation value from IOMMU flush interfaces may be positive, which indicates callers need to flush cache, not one of faliures. when the propagation value is positive, this patch fixes this flush issue as follows: - call iommu_flush_write_buffer() to flush cache. - return zero. Signed-off-by: Quan Xu Acked-by: Kevin Tian CC: Kevin Tian CC: Feng Wu CC: Keir Fraser CC: Jan Beulich CC: Andrew Cooper --- v9: fix naming issue, changing 'iommu_rc / iommu_ret' to 'context_rc / iotlb_rc' --- xen/drivers/passthrough/vtd/iommu.c | 150 +++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 47 deletions(-) diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 48edb67..2679ef6 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -388,17 +388,18 @@ static int flush_context_reg( return 0; } -static int iommu_flush_context_global( - struct iommu *iommu, int flush_non_present_entry) +static int __must_check iommu_flush_context_global(struct iommu *iommu, + int flush_non_present_entry) { struct iommu_flush *flush = iommu_get_flush(iommu); return flush->context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL, flush_non_present_entry); } -static int iommu_flush_context_device( - struct iommu *iommu, u16 did, u16 source_id, - u8 function_mask, int flush_non_present_entry) +static int __must_check iommu_flush_context_device(struct iommu *iommu, + u16 did, u16 source_id, + u8 function_mask, + int flush_non_present_entry) { struct iommu_flush *flush = iommu_get_flush(iommu); return flush->context(iommu, did, source_id, function_mask, @@ -473,8 +474,9 @@ static int flush_iotlb_reg(void *_iommu, u16 did, return 0; } -static int iommu_flush_iotlb_global(struct iommu *iommu, - int flush_non_present_entry, int flush_dev_iotlb) +static int __must_check iommu_flush_iotlb_global(struct iommu *iommu, + int flush_non_present_entry, + int flush_dev_iotlb) { struct iommu_flush *flush = iommu_get_flush(iommu); int status; @@ -491,8 +493,9 @@ static int iommu_flush_iotlb_global(struct iommu *iommu, return status; } -static int iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did, - int flush_non_present_entry, int flush_dev_iotlb) +static int __must_check iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did, + int flush_non_present_entry, + int flush_dev_iotlb) { struct iommu_flush *flush = iommu_get_flush(iommu); int status; @@ -509,9 +512,10 @@ static int iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did, return status; } -static int iommu_flush_iotlb_psi( - struct iommu *iommu, u16 did, u64 addr, unsigned int order, - int flush_non_present_entry, int flush_dev_iotlb) +static int __must_check iommu_flush_iotlb_psi(struct iommu *iommu, u16 did, + u64 addr, unsigned int order, + int flush_non_present_entry, + int flush_dev_iotlb) { struct iommu_flush *flush = iommu_get_flush(iommu); int status; @@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void) struct acpi_drhd_unit *drhd; struct iommu *iommu; int flush_dev_iotlb; + int rc = 0; flush_all_cache(); for_each_drhd_unit ( drhd ) { + int context_rc, iotlb_rc; + iommu = drhd->iommu; - iommu_flush_context_global(iommu, 0); + context_rc = iommu_flush_context_global(iommu, 0); flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0; - iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb); + iotlb_rc = iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb); + + /* + * The current logic for returns: + * - positive invoke iommu_flush_write_buffer to flush cache. + * - zero on success. + * - negative on failure. Continue to flush IOMMU IOTLB on a + * best effort basis. + */ + if ( context_rc > 0 || iotlb_rc > 0 ) + iommu_flush_write_buffer(iommu); + if ( context_rc >= 0 ) + rc = context_rc; + if ( rc >= 0 ) + rc = iotlb_rc; } - return 0; + if ( rc > 0 ) + rc = 0; + + return rc; } static int __must_check iommu_flush_iotlb(struct domain *d, @@ -569,6 +593,7 @@ static int __must_check iommu_flush_iotlb(struct domain *d, struct iommu *iommu; int flush_dev_iotlb; int iommu_domid; + int rc = 0; /* * No need pcideves_lock here because we have flush @@ -587,21 +612,23 @@ static int __must_check iommu_flush_iotlb(struct domain *d, continue; if ( page_count != 1 || gfn == INVALID_GFN ) - { - if ( iommu_flush_iotlb_dsi(iommu, iommu_domid, - 0, flush_dev_iotlb) ) - iommu_flush_write_buffer(iommu); - } + rc = iommu_flush_iotlb_dsi(iommu, iommu_domid, + 0, flush_dev_iotlb); else + rc = iommu_flush_iotlb_psi(iommu, iommu_domid, + (paddr_t)gfn << PAGE_SHIFT_4K, + PAGE_ORDER_4K, + !dma_old_pte_present, + flush_dev_iotlb); + + if ( rc > 0 ) { - if ( iommu_flush_iotlb_psi(iommu, iommu_domid, - (paddr_t)gfn << PAGE_SHIFT_4K, PAGE_ORDER_4K, - !dma_old_pte_present, flush_dev_iotlb) ) - iommu_flush_write_buffer(iommu); + iommu_flush_write_buffer(iommu); + rc = 0; } } - return 0; + return rc; } static int __must_check iommu_flush_iotlb_pages(struct domain *d, @@ -1290,7 +1317,8 @@ int domain_context_mapping_one( struct context_entry *context, *context_entries; u64 maddr, pgd_maddr; u16 seg = iommu->intel->drhd->segment; - int agaw; + int agaw, rc, ret; + int flush_dev_iotlb; ASSERT(pcidevs_locked()); spin_lock(&iommu->lock); @@ -1404,14 +1432,24 @@ int domain_context_mapping_one( spin_unlock(&iommu->lock); /* Context entry was previously non-present (with domid 0). */ - if ( iommu_flush_context_device(iommu, 0, (((u16)bus) << 8) | devfn, - DMA_CCMD_MASK_NOBIT, 1) ) + rc = iommu_flush_context_device(iommu, 0, PCI_BDF2(bus, devfn), + DMA_CCMD_MASK_NOBIT, 1); + flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0; + ret = iommu_flush_iotlb_dsi(iommu, 0, 1, flush_dev_iotlb); + + /* + * The current logic for returns: + * - positive invoke iommu_flush_write_buffer to flush cache. + * - zero on success. + * - negative on failure. Continue to flush IOMMU IOTLB on a + * best effort basis. + */ + if ( rc > 0 || ret > 0 ) iommu_flush_write_buffer(iommu); - else - { - int flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0; - iommu_flush_iotlb_dsi(iommu, 0, 1, flush_dev_iotlb); - } + if ( rc >= 0 ) + rc = ret; + if ( rc > 0 ) + rc = 0; set_bit(iommu->index, &hd->arch.iommu_bitmap); @@ -1420,7 +1458,7 @@ int domain_context_mapping_one( if ( !seg ) me_wifi_quirk(domain, bus, devfn, MAP_ME_PHANTOM_FUNC); - return 0; + return rc; } static int domain_context_mapping( @@ -1514,7 +1552,8 @@ int domain_context_unmap_one( { struct context_entry *context, *context_entries; u64 maddr; - int iommu_domid; + int iommu_domid, rc, ret; + int flush_dev_iotlb; ASSERT(pcidevs_locked()); spin_lock(&iommu->lock); @@ -1542,15 +1581,26 @@ int domain_context_unmap_one( return -EINVAL; } - if ( iommu_flush_context_device(iommu, iommu_domid, - (((u16)bus) << 8) | devfn, - DMA_CCMD_MASK_NOBIT, 0) ) + rc = iommu_flush_context_device(iommu, iommu_domid, + PCI_BDF2(bus, devfn), + DMA_CCMD_MASK_NOBIT, 0); + + flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0; + ret = iommu_flush_iotlb_dsi(iommu, iommu_domid, 0, flush_dev_iotlb); + + /* + * The current logic for returns: + * - positive invoke iommu_flush_write_buffer to flush cache. + * - zero on success. + * - negative on failure. Continue to flush IOMMU IOTLB on a + * best effort basis. + */ + if ( rc > 0 || ret > 0 ) iommu_flush_write_buffer(iommu); - else - { - int flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0; - iommu_flush_iotlb_dsi(iommu, iommu_domid, 0, flush_dev_iotlb); - } + if ( rc >= 0 ) + rc = ret; + if ( rc > 0 ) + rc = 0; spin_unlock(&iommu->lock); unmap_vtd_domain_page(context_entries); @@ -1558,7 +1608,7 @@ int domain_context_unmap_one( if ( !iommu->intel->drhd->segment ) me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC); - return 0; + return rc; } static int domain_context_unmap( @@ -1772,6 +1822,7 @@ int iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, struct domain_iommu *hd = dom_iommu(d); int flush_dev_iotlb; int iommu_domid; + int rc = 0; iommu_flush_cache_entry(pte, sizeof(struct dma_pte)); @@ -1785,13 +1836,18 @@ int iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, iommu_domid= domain_iommu_domid(d, iommu); if ( iommu_domid == -1 ) continue; - if ( iommu_flush_iotlb_psi(iommu, iommu_domid, + + rc = iommu_flush_iotlb_psi(iommu, iommu_domid, (paddr_t)gfn << PAGE_SHIFT_4K, - order, !present, flush_dev_iotlb) ) + order, !present, flush_dev_iotlb); + if ( rc > 0 ) + { iommu_flush_write_buffer(iommu); + rc = 0; + } } - return 0; + return rc; } static int __init vtd_ept_page_compatible(struct iommu *iommu)