From nobody Mon Feb 9 15:26:43 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (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 1891C329E6D for ; Wed, 7 Jan 2026 20:18:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767817087; cv=none; b=HJwPMqCQr8psFpEA9hRsH0hhfhGtzVHHZ7fk1Q/K2j1QEjOnLYel0VASA3+RdiGgK10cCzOODQtkwQe+0RKikp/P2nwY7E6RjMoMnroT207rlFV3YH3m2rSihWjY6CmohVQwoGTnWPQJGZfveY3m/XwjRbBbzveVOFXk4LtFzqQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767817087; c=relaxed/simple; bh=98LSmDyrncFN4yAfUmC/lF2S2QLQXjk1Mnqe7MNMAYA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=BFs5ofiK6gynkAGxxCJmHSeU65Q+50r7GBWUWvH5cHNUpUDDLIZfmzMZdDLjkYxIJA5YaD0IFIP6SkFtebbl+iUjP7w7wtG0KklR0FqO5WXL4G0ue+JihxVPwLQjAqCqSwiiOTsOzeovUJO8xcwVajkjubT3nEe8S8Zdimi8VPg= 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=olMo5wlg; arc=none smtp.client-ip=209.85.216.73 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="olMo5wlg" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-34e5a9de94bso4664052a91.0 for ; Wed, 07 Jan 2026 12:18:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767817084; x=1768421884; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=igY4dYldp2fGVYjzSgtn3dTLLodbnD38eUgrWzBU1Xo=; b=olMo5wlgg3uUQeWFscH3hdCYprnUJbboyvc1+zaIQHbu9jw3samGNMdfuzWOtXiCBi J/6BxMLoNFVTqNv+bXrKTOvTIjfja23InlyF0lnbtlZvhY9YmwAADMx3sy28epU6vH61 pwranRAMrh6kFjuN6RjL995lvVBOy5MFypQDAHT/DPKG6uDGRzLl1EaSK6qwQkNoY2Lr 9I3veejyM68IzSuDDHuHSkSNMB/RX/yDptSfwzH42M1vhlKagCLjxFophuLq2bwc2+oF bAKmNvEBxdguZYxUQHLta3TV0jZYPT3AedhH0aV2qX+M5rxytyaG2Ri8BAzZxVXG6MLb PPtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767817084; x=1768421884; h=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; bh=igY4dYldp2fGVYjzSgtn3dTLLodbnD38eUgrWzBU1Xo=; b=GCSd+oz5IgDlk5PEKlQOd6hmg/pSO/y+ggic4EUPDUnl6T8OqHBCh05BxjYEagPmyn rEXfB79BQOgzEO+j+M/I4ucXw42kvazoEeGKh7Ho/g+1FQqk7g/aR/xkxAkzLsPMpXZG 1R2RkxZf4+XmovD50v/8z3xDBEwW3+EF6SBzP2i4W18u7PIWAHoM0MuZT5j7WHkeLLR8 u70edLCnLFZUXhuLKX3Y2gi7xokzGDuRSqtQq5feXpSZAkq8AUx/8FOkhF/+JiC7NEgk AzGtmiMXPDE3OhsRdCC82o/EmPTnd0gNjGh2A/KmHk02sIXVaJNHO/0yb7wfGVFRJK2W u/Aw== X-Forwarded-Encrypted: i=1; AJvYcCVUUk6+9IYBJ0hO5S+REvHS6GtD9tC3qkYcvKqk1R5sqF3L6CxQwkgEpk6E8EdaHUcGR9nwFJSryAXGU0A=@vger.kernel.org X-Gm-Message-State: AOJu0YyWLFEKPTdN8Z8LnhTLwNbslXOEsRwLiwe+rU7R/3PiF1BFf365 afYQkkmIPnTm4ot5/k3DggF/OT0naC69d/NCgoHTP7WM2MatNa18j+Ahh7JuTfm2S3mYTaDO/Q0 NISNqcO4bSyJLsg== X-Google-Smtp-Source: AGHT+IHfXVop97/Vz192HqH+eaT1EXDIWQ0CMkd2UMbL7Q1pQUtgV9kwq04SG9DCOLRooq67paZ2vlfZ5GXHcw== X-Received: from pjcc11.prod.google.com ([2002:a17:90b:574b:b0:34c:c510:f186]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:544f:b0:343:7714:4ca8 with SMTP id 98e67ed59e1d1-34f68c94494mr3403970a91.15.1767817084253; Wed, 07 Jan 2026 12:18:04 -0800 (PST) Date: Wed, 7 Jan 2026 20:17:58 +0000 In-Reply-To: <20260107201800.2486137-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: <20260107201800.2486137-1-skhawaja@google.com> X-Mailer: git-send-email 2.52.0.351.gbe84eed79e-goog Message-ID: <20260107201800.2486137-2-skhawaja@google.com> Subject: [PATCH 1/3] iommu/vt-d: Allow replacing no_pasid iommu_domain From: Samiullah Khawaja To: David Woodhouse , Lu Baolu , Joerg Roedel , Will Deacon , Pasha Tatashin , Jason Gunthorpe , David Matlack Cc: Samiullah Khawaja , Robin Murphy , Pratyush Yadav , Kevin Tian , Alex Williamson , Shuah Khan , iommu@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Saeed Mahameed , Adithya Jayachandran , Parav Pandit , Leon Romanovsky , William Tu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Intel IOMMU driver already supports replacing IOMMU domains attachments with PASIDs. Add support for replacing a domain attached with no_pasid. This includes replacing domains in legacy mode. Signed-off-by: Samiullah Khawaja --- drivers/iommu/intel/iommu.c | 107 ++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 134302fbcd92..c0e359fd3ee1 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1140,6 +1140,7 @@ static void context_present_cache_flush(struct intel_= iommu *iommu, u16 did, } =20 static int domain_context_mapping_one(struct dmar_domain *domain, + struct dmar_domain *old_domain, struct intel_iommu *iommu, u8 bus, u8 devfn) { @@ -1148,7 +1149,8 @@ static int domain_context_mapping_one(struct dmar_dom= ain *domain, u16 did =3D domain_id_iommu(domain, iommu); int translation =3D CONTEXT_TT_MULTI_LEVEL; struct pt_iommu_vtdss_hw_info pt_info; - struct context_entry *context; + struct context_entry *context, new_context; + u16 did_old; int ret; =20 if (WARN_ON(!intel_domain_is_ss_paging(domain))) @@ -1166,26 +1168,44 @@ static int domain_context_mapping_one(struct dmar_d= omain *domain, goto out_unlock; =20 ret =3D 0; - if (context_present(context) && !context_copied(iommu, bus, devfn)) + if (!old_domain && (context_present(context) && !context_copied(iommu, bu= s, devfn))) goto out_unlock; =20 + if (old_domain) { + did_old =3D context_domain_id(context); + WARN_ON(did_old !=3D domain_id_iommu(old_domain, iommu)); + } + copied_context_tear_down(iommu, context, bus, devfn); - context_clear_entry(context); - context_set_domain_id(context, did); + context_set_domain_id(&new_context, did); =20 if (info && info->ats_supported) translation =3D CONTEXT_TT_DEV_IOTLB; else translation =3D CONTEXT_TT_MULTI_LEVEL; =20 - context_set_address_root(context, pt_info.ssptptr); - context_set_address_width(context, pt_info.aw); - context_set_translation_type(context, translation); - context_set_fault_enable(context); - context_set_present(context); + context_set_address_root(&new_context, pt_info.ssptptr); + context_set_address_width(&new_context, pt_info.aw); + context_set_translation_type(&new_context, translation); + context_set_fault_enable(&new_context); + context_set_present(&new_context); + + *context =3D new_context; if (!ecap_coherent(iommu->ecap)) clflush_cache_range(context, sizeof(*context)); - context_present_cache_flush(iommu, did, bus, devfn); + + /* + * Spec 6.5.3.3, changing a present context entry requires, + * - IOTLB invalidation for each effected Domain. + * - Issue Device IOTLB invalidation for function. + */ + if (old_domain) { + intel_context_flush_no_pasid(info, context, did); + intel_context_flush_no_pasid(info, context, did_old); + } else { + context_present_cache_flush(iommu, did, bus, devfn); + } + ret =3D 0; =20 out_unlock: @@ -1194,30 +1214,39 @@ static int domain_context_mapping_one(struct dmar_d= omain *domain, return ret; } =20 +struct domain_context_mapping_data { + struct dmar_domain *domain; + struct dmar_domain *old_domain; +}; + static int domain_context_mapping_cb(struct pci_dev *pdev, u16 alias, void *opaque) { struct device_domain_info *info =3D dev_iommu_priv_get(&pdev->dev); struct intel_iommu *iommu =3D info->iommu; - struct dmar_domain *domain =3D opaque; + struct domain_context_mapping_data *data =3D opaque; =20 - return domain_context_mapping_one(domain, iommu, + return domain_context_mapping_one(data->domain, data->old_domain, iommu, PCI_BUS_NUM(alias), alias & 0xff); } =20 static int -domain_context_mapping(struct dmar_domain *domain, struct device *dev) +domain_context_mapping(struct dmar_domain *domain, + struct dmar_domain *old_domain, struct device *dev) { struct device_domain_info *info =3D dev_iommu_priv_get(dev); struct intel_iommu *iommu =3D info->iommu; u8 bus =3D info->bus, devfn =3D info->devfn; + struct domain_context_mapping_data data; int ret; =20 if (!dev_is_pci(dev)) - return domain_context_mapping_one(domain, iommu, bus, devfn); + return domain_context_mapping_one(domain, old_domain, iommu, bus, devfn); =20 + data.domain =3D domain; + data.old_domain =3D old_domain; ret =3D pci_for_each_dma_alias(to_pci_dev(dev), - domain_context_mapping_cb, domain); + domain_context_mapping_cb, &data); if (ret) return ret; =20 @@ -1309,18 +1338,28 @@ static int domain_setup_first_level(struct intel_io= mmu *iommu, pt_info.gcr3_pt, flags, old); } =20 -static int dmar_domain_attach_device(struct dmar_domain *domain, - struct device *dev) +static int device_replace_dmar_domain(struct dmar_domain *domain, + struct dmar_domain *old_domain, + struct device *dev) { struct device_domain_info *info =3D dev_iommu_priv_get(dev); struct intel_iommu *iommu =3D info->iommu; unsigned long flags; int ret; =20 + if (old_domain && dev_is_real_dma_subdevice(dev)) + return -EOPNOTSUPP; + ret =3D domain_attach_iommu(domain, iommu); if (ret) return ret; =20 + if (old_domain) { + spin_lock_irqsave(&info->domain->lock, flags); + list_del(&info->link); + spin_unlock_irqrestore(&info->domain->lock, flags); + } + info->domain =3D domain; info->domain_attached =3D true; spin_lock_irqsave(&domain->lock, flags); @@ -1331,27 +1370,27 @@ static int dmar_domain_attach_device(struct dmar_do= main *domain, return 0; =20 if (!sm_supported(iommu)) - ret =3D domain_context_mapping(domain, dev); + ret =3D domain_context_mapping(domain, old_domain, dev); else if (intel_domain_is_fs_paging(domain)) ret =3D domain_setup_first_level(iommu, domain, dev, - IOMMU_NO_PASID, NULL); + IOMMU_NO_PASID, &old_domain->domain); else if (intel_domain_is_ss_paging(domain)) ret =3D domain_setup_second_level(iommu, domain, dev, - IOMMU_NO_PASID, NULL); + IOMMU_NO_PASID, &old_domain->domain); else if (WARN_ON(true)) ret =3D -EINVAL; =20 - if (ret) - goto out_block_translation; + if (!ret) + ret =3D cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID); =20 - ret =3D cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID); if (ret) - goto out_block_translation; + device_block_translation(dev); =20 - return 0; + if (old_domain) { + cache_tag_unassign_domain(old_domain, dev, IOMMU_NO_PASID); + domain_detach_iommu(old_domain, iommu); + } =20 -out_block_translation: - device_block_translation(dev); return ret; } =20 @@ -3127,19 +3166,27 @@ static int intel_iommu_attach_device(struct iommu_d= omain *domain, struct device *dev, struct iommu_domain *old) { + struct device_domain_info *info =3D dev_iommu_priv_get(dev); int ret; =20 - device_block_translation(dev); + if (dev_is_real_dma_subdevice(dev) || + domain->type !=3D __IOMMU_DOMAIN_PAGING || + !info->domain || &info->domain->domain !=3D old) + old =3D NULL; + + if (!old) + device_block_translation(dev); =20 ret =3D paging_domain_compatible(domain, dev); if (ret) return ret; =20 - ret =3D iopf_for_domain_set(domain, dev); + ret =3D iopf_for_domain_replace(domain, old, dev); if (ret) return ret; =20 - ret =3D dmar_domain_attach_device(to_dmar_domain(domain), dev); + ret =3D device_replace_dmar_domain(to_dmar_domain(domain), + old ? to_dmar_domain(old) : NULL, dev); if (ret) iopf_for_domain_remove(domain, dev); =20 --=20 2.52.0.351.gbe84eed79e-goog