From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B355A31714A for ; Sat, 8 Aug 2026 02:27:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786156055; cv=none; b=JlTPNdp/BhrmC5+UXcsgfjtC6gZEPGNb9JJEjNR9r7pReGQ/E4jDBsUjeaVrm9dpYlqir22qXuC3M10mjRlt5xxZ3sBCRbj6TmEDRlsh5o2gYJbgg2mb3q4+iK6afrrVQBx/KV3PTFCiRvCMu+KAjdW21yW8GWgGCdVe2SM/Z+c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786156055; c=relaxed/simple; bh=8LD06dIhRCF5PxnDhCscBmnYC0JP1pM0yFq4tq9N8Ds=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=uD+mEkjz83hha2iI2anE0ZBDjOA/mhWQKEl4LVormd9o+tXPQSBuxfGxCVj1I+keyC47WZuDPQgdGrMKnbkoMfpRgILe8ni2ehYvPNEDUixILvItLgyc8SZgtZ0Eynij4Ebka0REIyxZgqDYHfgWPJpeFIcRE6E4Wa1pswdnFt0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=agi3jzIN; arc=none smtp.client-ip=209.85.216.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="agi3jzIN" Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-385d2703b64so2649932a91.1 for ; Fri, 07 Aug 2026 19:27:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786156051; x=1786760851; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=JWyLeKilFL2QB6oEmh5/AodCqSOtAK0blBAl1E1VSrM=; b=agi3jzINaxyBPQgs7hcUrncir4bEbDBWD0CgZ6XUjY20+mML/YvfpDiM8Ng0VUWHpz w7aNh/witjj1+c9INfQt+Qw8971JrCtYVYGJkKhfeNFSEvaSvJaZ7KJ+jUnYTZfsxkhZ UXFALY9H5syniyA7VE1VETHetX+Dz4lKeLG2C7JiyZ9A2H8nelg7zOl6ux3am/H60gxe rUW42MvV2wfVxbu2FKQtuzcLKR5bLf61IUGq3a7yQu5jKI39v6SvkJPypCiwyZcoifB5 V09pzDPWjmtgaow7H1SrLCny75d+/rk/wZZCXjGtXK5/hpZJ48ev9rA0FmAXZHDXFxLU IgvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786156051; x=1786760851; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=JWyLeKilFL2QB6oEmh5/AodCqSOtAK0blBAl1E1VSrM=; b=PCQKF7x0SDQCDg85+fwlq4WiINxzjS6p/rIu+syfkZ2QCkH29puI9+1v03wRwiHPgM 8jkzsWOzbgOjgfcJ1ltPOOIOYKGows2bij0/U8yMI00exYNCWO6WbnhrOwQghNqC4ib8 /55Nzsfp+ZeEaNSOIZEcNFXx14AJyPJsvoTH43P9G5iFE44bc36/1jyNBYKf30AZ/ADm QxNZq5FcyWY6qaLpabbtC+vhts493FseeL/poZa//e6uFAsVlSewkSM6/q2D+M4tB6nr v3Ux3Zy/u7oGYxnheTRoDcbPPp8YveDz9cZ0RVntuJimwyauERWin9wVpJlAV+DJQ1+T HCdg== X-Forwarded-Encrypted: i=1; AHgh+RrAQIK1Gy2ks/Wv7vCwUpfhXZ6PVK+uZqqo6hc05+Ig5+jazd+Lq8GfFzzvoptonZ2aiGFGWnnj/nUlcF8=@vger.kernel.org X-Gm-Message-State: AOJu0YwbFArU/JRU9uBxP7D6oVCYdh5aHfRn345zUQGx9ry0pUBiwk/8 eu4uUOPUqetrpav2fCJ49Q251rdghOv3MiXS0TSBD4bwKGPhdllw+Z1Dq/b2xcVgmosm54etNhy /6121khIIsEoFjw== X-Received: from pjbne5.prod.google.com ([2002:a17:90b:3745:b0:390:99da:dad6]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:3907:b0:38e:b3fd:d584 with SMTP id 98e67ed59e1d1-392846f10f3mr1369252a91.15.1786156050750; Fri, 07 Aug 2026 19:27:30 -0700 (PDT) Date: Sat, 8 Aug 2026 02:27:13 +0000 In-Reply-To: <20260808022723.3893618-1-skhawaja@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260808022723.3893618-1-skhawaja@google.com> X-Mailer: git-send-email 2.55.0.679.g6767b8d81c-goog Message-ID: <20260808022723.3893618-9-skhawaja@google.com> Subject: [PATCH v4 08/18] iommu/vt-d: Clear unpreserved context entries during shutdown From: Samiullah Khawaja To: David Woodhouse , Lu Baolu , Joerg Roedel , Will Deacon , Jason Gunthorpe Cc: Samiullah Khawaja , Robin Murphy , Kevin Tian , Alex Williamson , Shuah Khan , iommu@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Pratyush Yadav , Pasha Tatashin , David Matlack , Andrew Morton , Pranjal Shrivastava , Vipin Sharma Content-Type: text/plain; charset="UTF-8" During normal shutdown the iommu translation is disabled. Since the root table is preserved during live update, it needs to be cleaned up and the context entries of the unpreserved devices and root entries for the unpreserved context tables need to be cleared. Signed-off-by: Samiullah Khawaja --- drivers/iommu/intel/iommu.c | 15 +++- drivers/iommu/intel/iommu.h | 5 ++ drivers/iommu/intel/liveupdate.c | 140 +++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index aeae0563dfd0..eca3944d9cf5 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1832,6 +1832,14 @@ static int iommu_suspend(void *data) iommu_flush_all(); + /* + * Note that IOMMU suspend doesn't affect live update. The state + * preserved during live update is not released and remains valid during + * suspend and reused during IOMMU resume. + * + * Also note deployment of suspend/resume and live updated use case + * should be mostly mutually exclusive. + */ for_each_active_iommu(iommu, drhd) { iommu_disable_translation(iommu); @@ -2377,8 +2385,11 @@ void intel_iommu_shutdown(void) /* Disable PMRs explicitly here. */ iommu_disable_protect_mem_regions(iommu); - /* Make sure the IOMMUs are switched off */ - iommu_disable_translation(iommu); + /* Make sure the IOMMUs are switched off if not preserved. */ + if (iommu_preserved_state(&iommu->iommu)) + clear_unpreserved_context_entries(iommu); + else + iommu_disable_translation(iommu); } } diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 4906cce1e66e..6c971f04ead3 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -1306,6 +1306,7 @@ int intel_iommu_preserve(struct iommu_device *iommu, struct iommu_hw_ser *iommu_ser); void intel_iommu_unpreserve(struct iommu_device *iommu, struct iommu_hw_ser *iommu_ser); +void clear_unpreserved_context_entries(struct intel_iommu *iommu); #else static inline int intel_iommu_preserve_device(struct device *dev, struct iommu_device_ser *device_ser) @@ -1328,6 +1329,10 @@ static inline void intel_iommu_unpreserve(struct iommu_device *iommu, struct iommu_hw_ser *iommu_ser) { } + +static inline void clear_unpreserved_context_entries(struct intel_iommu *iommu) +{ +} #endif #ifdef CONFIG_INTEL_IOMMU_SVM diff --git a/drivers/iommu/intel/liveupdate.c b/drivers/iommu/intel/liveupdate.c index ffdcebf2b773..b5aaebeeb5c1 100644 --- a/drivers/iommu/intel/liveupdate.c +++ b/drivers/iommu/intel/liveupdate.c @@ -77,6 +77,146 @@ static int preserve_context_table(struct intel_iommu *iommu, return 0; } +static void clear_unpreserved_context_root_entries(struct intel_iommu *iommu, + struct iommu_hw_ser *ser) +{ + struct root_entry *root; + int i; + + for (i = 0; i < ROOT_ENTRY_NR; i++) { + root = &iommu->root_entry[i]; + + if (!is_context_table_preserved(iommu, ser, i, 0) && (root->lo & 1)) { + root->lo = 0; + __iommu_flush_cache(iommu, + &root->lo, + sizeof(root->lo)); + } + + if (!sm_supported(iommu)) + continue; + + if (!is_context_table_preserved(iommu, ser, i, 0x80) && (root->hi & 1)) { + root->hi = 0; + __iommu_flush_cache(iommu, + &root->hi, + sizeof(root->hi)); + } + } +} + +static void clear_unpreserved_context(struct device_domain_info *info, u8 bus, u8 devfn) +{ + struct context_entry *context; + + /* + * This cleanup is done during shutdown, so it should be fine to only + * clear the entries here and issue one global invalidation later to + * invalidate all cleared entries. + * + * Note that the device IOTLB invalidation for unpreserved devices is + * skipped this way, but that should not be needed as the devices are + * quiesced at this point. This should improve the performance of the + * cleanup process and avoids any invalidation timeouts because drivers + * might have moved devices to D3 state. + */ + context = iommu_context_addr(info->iommu, bus, devfn, 0); + if (context) { + context_clear_entry(context); + __iommu_flush_cache(info->iommu, context, sizeof(*context)); + } +} + +static int clear_unpreserved_alias_cb(struct pci_dev *pdev, u16 alias, void *data) +{ + struct device_domain_info *info = data; + + clear_unpreserved_context(info, PCI_BUS_NUM(alias), alias & 0xff); + return 0; +} + +static int clear_unpreserve_context_entry_fn(struct device *dev, + struct iommu_device *iommu_dev, + void *arg) +{ + struct device_domain_info *info; + struct context_entry *context; + + info = dev_iommu_priv_get(dev); + if (!info) + return 0; + + if (!dev_is_pci(dev) || !dev_iommu_preserved_state(dev)) + goto out_unpreserved; + + /* + * PRE use cases are not supported with Live Update and a preservation + * attempt on such domains returns an error. But Intel IOMMU driver + * enables PRE by default on all devices that support it. For preserved + * entries, the PRE needs to be disabled so preserved PCI devices do not + * generate PRQs, during kexec, as translations are kept enabled during + * live update. There is no need to disable these for DMA aliases. + */ + if (sm_supported(info->iommu)) { + context = iommu_context_addr(info->iommu, info->bus, info->devfn, 0); + if (context) { + context_clear_sm_pre(context); + __iommu_flush_cache(info->iommu, context, sizeof(*context)); + } + } + + return 0; + +out_unpreserved: + if (dev_is_pci(dev)) + pci_for_each_dma_alias(to_pci_dev(dev), + clear_unpreserved_alias_cb, info); + else + clear_unpreserved_context(info, info->bus, info->devfn); + + return 0; +} + +/** + * clear_unpreserved_context_entries() - Clear context entries for unpreserved devices + * @iommu: Target IOMMU + * + * Clear the context entries of unpreserved devices during shutdown before kexec. + */ +void clear_unpreserved_context_entries(struct intel_iommu *iommu) +{ + struct iommu_dev_iter iter = { + .fn = clear_unpreserve_context_entry_fn, + .iommu = &iommu->iommu, + .arg = NULL, + + }; + + /* + * Clear context entries for unpreserved devices. + * + * Note that the error can be ignored as the iterator function does not + * fail. + */ + iommu_for_each_dev(&iter); + + /* Clear reference to unpreserved context tables */ + clear_unpreserved_context_root_entries(iommu, + iommu_preserved_state(&iommu->iommu)); + + /* + * Some devices might not have teardown/detached properly depending on + * whether a proper device remove is done before kexec is triggered. + * Also unpreserved context tables and entries are removed during + * shutdown. So issue global invalidations to remove references to + * unpreserved tables and entries. + */ + iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL); + if (sm_supported(iommu)) + qi_flush_pasid_cache(iommu, 0, QI_PC_GLOBAL, 0); + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); +} + static void unpreserve_iommu_context_tables(struct intel_iommu *iommu, struct iommu_hw_ser *ser) { -- 2.55.0.679.g6767b8d81c-goog