From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.214.198 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792894784; b=Es/JUspCBtkzwKWTr2B0mHJAC5QVKOqC/gQouYKJ/5HkkltNYD4kNh+NRQ6/7KT1uTRc a9tlRvflbu3S+nDCV+ClyIp1r8LXYIQhIsxm76abY9sOogWecusqxtT6l9rdy4WECK5up A3aLHnZvUFwgJ/nM5lLcqfBzuofPhwJyysGRtSHXmxSpRzZLpzV3pr3C7K/uH566P+fcR A31tPBMEfD+8kUop6h1YEG4ZCQrGqWmV6u1a8BaA0BGOX9dzKjSR49xz3sVwDHw43HGky m9w4CJWiJi4pj8dM85MoyhTYdJoA7QJ1pLR5cwmUMWQy6F9oZVAEXHJ9yNQ4qgx/p2w== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792894784; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Received:Date:In-Reply-To: Mime-Version:References:X-Mailer:Message-ID:Subject:From:To:Cc: Content-Type; bh=zmn2qFrznCocuz8YObSy+9ENkeuL7HIkttyD64ro7B0=; b=ncteXZjLA+dlhcnwPvXVRD0gk+mcpSLhnp9qkHwu7Ke3qqQ5Vx8XfKeXPJhK9EDkNepw zNoWqWZNJodnpTiTOZZzmv2AfIGQDQ+SkykmL4Fau/b3i/rkXnZVdiNSK6LgflJFbvpNa Fho4MoGkFHAEWfzUxy3kz28yGqheNxQP8QQfUYksLyHgSChir4x7ACnGUAhlEH45h/W9y EFucHfS3SZnY/u/5PosSXWU5ITKRkJyGEJRcJNrareP8yFso9sTgJJ6rw7XrrNL1s8WzL a9WmglJInjE8qR+wB47Va/zXMta7auZkb/xLhb7+EHLf218zyJ9Y3Aftn/7YOn/P+5g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=google.com; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com; dkim=pass header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20251104 header.b=B3sddiTq; arc=none smtp.remote-ip=209.85.214.198 Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3CDF560A6F5B for ; Sun, 25 Oct 2026 02:19:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 3CDF560A6F5B 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, unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20251104 header.b=B3sddiTq Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2ea0fe07201so12915475ad.1 for ; Sat, 24 Oct 2026 19:19:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1792894784; x=1793499584; 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=zmn2qFrznCocuz8YObSy+9ENkeuL7HIkttyD64ro7B0=; b=B3sddiTqzQd64LVsABh8kHkMOvuneItV9GFNootyJO4H5NFpJYsvSRiC60xxcW1nNq 7CSAV1BA7917nahx14uMY+lE2VWKAELsU9MIaKzK0ikYZw4fC6tB94p4GUWUDyhq3sxU dD9Ar8VG2iOfuHwvBttNGWzvrxCLgZuy5gxAGDlIAZC0vodftRHZi9jagMf88b0qg0iE 80voV1U9UNSu0QGd4Bc5VmJRfw7dXf29uGaL0tREWIrP8/4g5+wf8rA9KtkOs8lEHKHY ryUYiyTTTKgNUhu6L/T0V4beGrPotVJawLsN3ygrJ9yJV3E1cLkBMcCFU0j7TPVqpIEB 0kvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792894784; x=1793499584; 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=zmn2qFrznCocuz8YObSy+9ENkeuL7HIkttyD64ro7B0=; b=FROQ8f8r/CDQw3SHtX4JQgn8t5j1pEtvBauCVx/v4gRQ7eZR06FBo/67uy60dcwDal CXrQGSqNvvn/qhvql4ClXMvVl/OA7C2+U+Zc0buErQbRzP6v7FJyZ1rmexmLR9h+urxX cG9rZ4bZXdRc0lQVVhKWl2q6lMivGvDL0kIzwaLVV/PHzrDRt4L/duEuLLlA4IojdXMc SHWDPMkmdNGRmrPXEMYA6VK2+lmu5SPaaeJhRsteqBJyKIdqbLKsjVhnJvix4l7FkJiq GwFHZAFVR/Gkem8PWSBw+meCifklfxGZklqdTDyVWaPCqdfS1VjDPkSwxrhnNwY0abdq jmnw== X-Forwarded-Encrypted: i=1; AKwUvBxFbD835WsnKZlpU840TtBrKef7Cj5PAODPCLLXmpTG1YnvTLObasC1tOWZ/7Qk680yuauj8y7nyNHBevE=@vger.kernel.org X-Gm-Message-State: AFq9FYJ1EZ0v0TQB0I58DxLyeYbd6RHwaIs9eki9GpPX644e/9a05u8D Ubenqj0xdrJs2aP6m4jiHzgzPIrwgTDzGUeL8IIKQcSS0qQ9Xzh2MGwQsKpJCwBkMlR1AK3RTLt P661yUQfQLLyKgA== X-Received: from pgbj3-n2.prod.google.com ([2002:a05:6a02:61c3:20b0:cd6:db2:b293]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:3dd0:b0:3ac:9c37:942e with SMTP id 98e67ed59e1d1-3adead50095mr3154325a91.49.1792894783505; Sat, 24 Oct 2026 19:19:43 -0700 (PDT) Date: Sun, 25 Oct 2026 02:19:18 +0000 In-Reply-To: <20261025021930.674647-1-skhawaja@google.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list Mime-Version: 1.0 References: <20261025021930.674647-1-skhawaja@google.com> X-Mailer: git-send-email 2.56.0.257.gf7497c7d27-goog Message-ID: <20261025021930.674647-8-skhawaja@google.com> Subject: [PATCH v6 07/18] iommu/vt-d: Clear unpreserved context entries during shutdown From: Samiullah Khawaja To: Joerg Roedel , Will Deacon , Lu Baolu , Jason Gunthorpe , David Woodhouse 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 , Ankit Soni , Nicolin Chen , John Starks 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. This is required because during kexec reboot and shutdown the devices do not go through the release flow, so there might be stale entries in the root table and context tables. Also note that new unpreserved context tables for unpreserved devices might have been added after preservation, so the root table entries for unpreserved context tables also need to removed. Signed-off-by: Samiullah Khawaja --- drivers/iommu/intel/iommu.c | 15 +++- drivers/iommu/intel/iommu.h | 5 ++ drivers/iommu/intel/liveupdate.c | 134 +++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 14bd1ca4fbd5..23a1da351ddf 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1967,6 +1967,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); @@ -2512,8 +2520,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 a6c0ed55db30..16ab103d308a 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -1316,6 +1316,11 @@ 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 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 0047f9d92cbc..f92cb774cc99 100644 --- a/drivers/iommu/intel/liveupdate.c +++ b/drivers/iommu/intel/liveupdate.c @@ -82,6 +82,140 @@ 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; + + /* + * Individual invalidations for each context table removal are not + * needed as we issue global invalidations later. + */ + 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. This matches the normal kexec reboot, where the + * IOMMU translation is disabled without invalidating the device IOTLBs, + * and the unpreserved devices go through the same flow in the next + * kernel as they do after a normal kexec reboot. Issuing device IOTLB + * invalidations this late during shutdown could also cause invalidation + * timeouts, as drivers might have moved devices to a low power state, + * and would add to the shutdown time. + * + * The iommu lock is not needed as the context tables are never removed + * and the new ones are not added during shutdown. + */ + context = iommu_context_addr(info->iommu, bus, devfn, 0); + if (context) { + /* + * Individual invalidations are not needed as we issue global + * invalidations later once all the cleanups are done. + */ + context_clear_present(context); + __iommu_flush_cache(info->iommu, context, sizeof(*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) +{ + struct device_domain_info *info; + + info = dev_iommu_priv_get(dev); + if (!info) + return 0; + + if (dev_iommu_preserved_state(dev)) + return 0; + + 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) +{ + /* + * Clear context entries for unpreserved devices because during kexec + * reboot and shutdown the devices do not go through the release flow, + * so there might be stale entries in the root table and context tables. + * + * Note that the error can be ignored as the iterator function does not + * fail. + */ + iommu_for_each_dev(&iommu->iommu, clear_unpreserve_context_entry_fn); + + /* + * New unpreserved context tables for unpreserved devices might have + * been added after preservation, so the root table entries for + * unpreserved context tables need to be removed. + */ + 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.56.0.257.gf7497c7d27-goog