From patchwork Mon Jan 15 10:37:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Duan, Zhenzhong" X-Patchwork-Id: 13519522 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 07F65C4707C for ; Mon, 15 Jan 2024 10:43:43 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rPKOb-0002ls-ET; Mon, 15 Jan 2024 05:40:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rPKOZ-0002VE-D9 for qemu-devel@nongnu.org; Mon, 15 Jan 2024 05:40:43 -0500 Received: from mgamail.intel.com ([192.198.163.8]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rPKOX-0003GV-Fn for qemu-devel@nongnu.org; Mon, 15 Jan 2024 05:40:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1705315241; x=1736851241; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4mJOnaIw6qtr7WL6aK18qEAf6e2n7DTWjVvJ4h8laqw=; b=KnGqQnZT7N3yxFID1qCJP/71tnA4HGKhX06f16Jp6doB5l00KkgSjV1F 2KJh5L2yLV9tjgo3ghKcYVPMrc701DvfU56VW6b1UZdY3v6ge5qlW+kfw Px7zmgQFXBK2/S31eBjVEWHSJOaM6y5SlDc5BP/aOCSw8SjcX1mIJJ7ct YLmh9yrCCnrLksU5Pq2w8vyf++nGCxk5BBOcv8hO8xh7HrLX8XJH1RncH zg+rF8owW2FACPtUim1E3j478wcJ7XOFFSclBSnSIdAHViVpfd7Wl2ZF2 LE3eInFQD5Ro274Zjy+WfOsSA7LQMWfsV55bqfE90l7y3tCvi7MpldMin g==; X-IronPort-AV: E=McAfee;i="6600,9927,10953"; a="13067776" X-IronPort-AV: E=Sophos;i="6.04,196,1695711600"; d="scan'208";a="13067776" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Jan 2024 02:40:41 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10953"; a="874065404" X-IronPort-AV: E=Sophos;i="6.04,196,1695711600"; d="scan'208";a="874065404" Received: from spr-s2600bt.bj.intel.com ([10.240.192.124]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Jan 2024 02:40:35 -0800 From: Zhenzhong Duan To: qemu-devel@nongnu.org Cc: alex.williamson@redhat.com, clg@redhat.com, eric.auger@redhat.com, peterx@redhat.com, jasowang@redhat.com, mst@redhat.com, jgg@nvidia.com, nicolinc@nvidia.com, joao.m.martins@oracle.com, kevin.tian@intel.com, yi.l.liu@intel.com, yi.y.sun@intel.com, chao.p.peng@intel.com, Yi Sun , Zhenzhong Duan , Marcel Apfelbaum , Paolo Bonzini , Richard Henderson , Eduardo Habkost Subject: [PATCH rfcv1 14/23] intel_iommu: propagate PASID-based iotlb invalidation to host Date: Mon, 15 Jan 2024 18:37:26 +0800 Message-Id: <20240115103735.132209-15-zhenzhong.duan@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240115103735.132209-1-zhenzhong.duan@intel.com> References: <20240115103735.132209-1-zhenzhong.duan@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.198.163.8; envelope-from=zhenzhong.duan@intel.com; helo=mgamail.intel.com X-Spam_score_int: -48 X-Spam_score: -4.9 X-Spam_bar: ---- X-Spam_report: (-4.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-2.758, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Yi Liu This traps the guest PASID-based iotlb invalidation request and propagate it to host. Intel VT-d 3.0 supports nested translation in PASID granular. Guest SVA support could be implemented by configuring nested translation on specific PASID. This is also known as dual stage DMA translation. Under such configuration, guest owns the GVA->GPA translation which is configured as stage-1 page table in host side for a specific pasid, and host owns GPA->HPA translation. As guest owns stage-1 translation table, piotlb invalidation should be propagated to host since host IOMMU will cache first level page table related mappings during DMA address translation. Signed-off-by: Yi Liu Signed-off-by: Yi Sun Signed-off-by: Zhenzhong Duan --- hw/i386/intel_iommu_internal.h | 7 +++ hw/i386/intel_iommu.c | 103 +++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 40361de207..ed0d5cd99b 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -560,6 +560,13 @@ struct VTDPASIDCacheInfo { }; typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; +struct VTDPIOTLBInvInfo { + uint16_t domain_id; + uint32_t pasid; + struct iommu_hwpt_vtd_s1_invalidate *inv_data; +}; +typedef struct VTDPIOTLBInvInfo VTDPIOTLBInvInfo; + /* PASID Table Related Definitions */ #define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL) #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 6aa44b80d6..2912fc6b88 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3786,15 +3786,118 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return !pc_info.error_happened ? true : false; } +/** + * Caller of this function should hold iommu_lock. + */ +static void vtd_invalidate_piotlb(VTDPASIDAddressSpace *vtd_pasid_as, + struct iommu_hwpt_vtd_s1_invalidate *cache) +{ + VTDIOMMUFDDevice *vtd_idev; + VTDHwpt *hwpt = &vtd_pasid_as->hwpt; + int devfn = vtd_pasid_as->devfn; + struct vtd_as_key key = { + .bus = vtd_pasid_as->bus, + .devfn = devfn, + }; + IntelIOMMUState *s = vtd_pasid_as->iommu_state; + uint32_t entry_num = 1; /* Only implement one request for simplicity */ + + if (!hwpt) { + return; + } + + vtd_idev = g_hash_table_lookup(s->vtd_iommufd_dev, &key); + if (!vtd_idev || !vtd_idev->idev) { + return; + } + if (iommufd_backend_invalidate_cache(vtd_idev->idev->iommufd, hwpt->hwpt_id, + IOMMU_HWPT_INVALIDATE_DATA_VTD_S1, + sizeof(*cache), &entry_num, cache)) { + error_report("Cache flush failed, entry_num %d", entry_num); + } +} + +/** + * This function is a loop function for the s->vtd_pasid_as + * list with VTDPIOTLBInvInfo as execution filter. It propagates + * the piotlb invalidation to host. Caller of this function + * should hold iommu_lock. + */ +static void vtd_flush_pasid_iotlb(gpointer key, gpointer value, + gpointer user_data) +{ + VTDPIOTLBInvInfo *piotlb_info = user_data; + VTDPASIDAddressSpace *vtd_pasid_as = value; + VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; + uint16_t did; + + if (!vtd_pe_pgtt_is_flt(&pc_entry->pasid_entry)) { + return; + } + + did = vtd_pe_get_domain_id(&pc_entry->pasid_entry); + + if ((piotlb_info->domain_id == did) && + (piotlb_info->pasid == vtd_pasid_as->pasid)) { + vtd_invalidate_piotlb(vtd_pasid_as, + piotlb_info->inv_data); + } + + /* + * TODO: needs to add QEMU piotlb flush when QEMU piotlb + * infrastructure is ready. For now, it is enough for passthru + * devices. + */ +} + static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s, uint16_t domain_id, uint32_t pasid) { + struct iommu_hwpt_vtd_s1_invalidate cache_info = { 0 }; + VTDPIOTLBInvInfo piotlb_info; + + cache_info.addr = 0; + cache_info.npages = (uint64_t)-1; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.inv_data = &cache_info; + + vtd_iommu_lock(s); + /* + * Here loops all the vtd_pasid_as instances in s->vtd_pasid_as + * to find out the affected devices since piotlb invalidation + * should check pasid cache per architecture point of view. + */ + g_hash_table_foreach(s->vtd_pasid_as, + vtd_flush_pasid_iotlb, &piotlb_info); + vtd_iommu_unlock(s); } static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, uint32_t pasid, hwaddr addr, uint8_t am, bool ih) { + struct iommu_hwpt_vtd_s1_invalidate cache_info = { 0 }; + VTDPIOTLBInvInfo piotlb_info; + + cache_info.addr = addr; + cache_info.npages = 1 << am; + cache_info.flags = ih ? IOMMU_VTD_INV_FLAGS_LEAF : 0; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.inv_data = &cache_info; + + vtd_iommu_lock(s); + /* + * Here loops all the vtd_pasid_as instances in s->vtd_pasid_as + * to find out the affected devices since piotlb invalidation + * should check pasid cache per architecture point of view. + */ + g_hash_table_foreach(s->vtd_pasid_as, + vtd_flush_pasid_iotlb, &piotlb_info); + vtd_iommu_unlock(s); } static bool vtd_process_piotlb_desc(IntelIOMMUState *s,