From nobody Sun Feb 8 02:41:21 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 From nobody Sun Feb 8 02:41:21 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 6D082338936 for ; Wed, 7 Jan 2026 20:18:07 +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=1767817089; cv=none; b=ZuxMyYfLOEKjNy4QAH2o2oODl2uvFzEVgQzTqiU1QcE4yW9WsueioE+4wFjx3IfWtxzn/cO2Ffv1jWOUCA5qBexeBGk8dn2OT9/YiY3zvcCvP9MHFvukTovPoheB8S/suppGmqcvH8mme/WDsHyUg0QH4W7USKYLh7jfC5UaanA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767817089; c=relaxed/simple; bh=hUn7TlBmNUdymtQg3Kq9wRTksnPrB1glAZZeGAPR86s=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nEssF1CfpccnfNZ9izgcP7BXcKgPs5vNNqgVF+9ZYMF8knlQLgkgijlY1Dveo0w57n3OlUhoZ2T0ZQ8g+gXxTq9yW5lJ+dXV4oq1Vm5iToUqVhDHVPT87s24iY4kO+Yt2Y+6Un+6bAvpLvn8nj3F9OJ+2XYSFT7+SdRJ/gXPhLI= 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=fEI3bV+h; 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="fEI3bV+h" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-34c3501d784so2822973a91.1 for ; Wed, 07 Jan 2026 12:18:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767817087; x=1768421887; 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=6zK+/AslzkBPlSJC8UvJQiRH9fqye6KU8Yh2AdIhmFE=; b=fEI3bV+hXrU7ePKTI4LcQQozaMA6JOZr6r/H7QyUz7TuPHk0M+wHIDNkq1+xqBE8pM q8XcF3LVV4rLtaH8FurPuaKcO5rK6qMGXkWdPFiTX74a/UudA3GxG25FA0ViCUC8MEuw tAzI2zWY0LIL6UjW+YL0tBIrkP7GoArngvEdHpJ/CoQXwZjD2nSgohd8bdQ8lxH2dkGg EGRiBw60udedDyOGzjeB7FfKPxIKtnK8XPhIi22fhCaktuozv6hsyxN73TjQGltncZle V3SPrRslTGhoIPlPNRowUR8tnvkCCEu1PAOvb85iqPDM39Bwng7N7S1Ww+uX9DC73kNg 4wDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767817087; x=1768421887; 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=6zK+/AslzkBPlSJC8UvJQiRH9fqye6KU8Yh2AdIhmFE=; b=H14tfwpQIUilwRHdhwHKKhxlR/+oN3EWVA0Ze2hSkOKuSBSQdLSN6cmUOVZdNjzUdO aYR1utXuZCdvvRsCk3zSaXFujxYBk8BMu45GjkcdSGDutuLV8rA0a6alh2LSI48e7hq4 y/Hx9h2ioQ/sUMLyZClswyhU4hOsqnMsOyyJ0+0KBpan7vO1gYq34jDFL3Z38jgjXWVj fKe7dRj5TfXhxu4T4FfBf5RVGxLGLvzMmmxBDJyAnycY9YMXJovSl58i9oq3+Ybu4icO Bc43sjLTUWiDKcWFF1MuHpJ5QERh60tlY2/DacObtyiLwEW4CvPAcywvliO/Q1N8cEiV Ia+g== X-Forwarded-Encrypted: i=1; AJvYcCWHgh27cuZ/iT9Yt1175dWKQsjZ7/8rxzpmN5Yl1HHLjIgD/6VHKMNmdGL9JfENb5Z72fOCrHHzGBNMJjc=@vger.kernel.org X-Gm-Message-State: AOJu0YxIzxdYcgWV9GCmlrcMMlFfj3tPPoB0pKcNU7ec84j2j+Lalnsz 2H8FgIBZatbPcC6kdGDhJ9LwlsMsjEvWL0ybJoVjiLoSA02zFG1C/ATXykqEzGrXSGrWCAVYccJ 2Z1hWj3glCNkQwQ== X-Google-Smtp-Source: AGHT+IHThLlbeg0Bz0L6XHahvlrl4KT7b217LsvR54vbtTKdYnIle66+HnkOhYRBZx9jZcBHpKpDIq/Pi3rfmQ== X-Received: from pjbhl15.prod.google.com ([2002:a17:90b:134f:b0:34c:2778:11c5]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2642:b0:32b:9774:d340 with SMTP id 98e67ed59e1d1-34f68c47f38mr2755853a91.33.1767817086729; Wed, 07 Jan 2026 12:18:06 -0800 (PST) Date: Wed, 7 Jan 2026 20:17:59 +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-3-skhawaja@google.com> Subject: [PATCH 2/3] vfio: selftests: Add support of creating iommus from iommufd 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" Add API to init a struct iommu using an already opened iommufd instance and attach devices to it. Signed-off-by: Samiullah Khawaja --- .../vfio/lib/include/libvfio/iommu.h | 2 + .../lib/include/libvfio/vfio_pci_device.h | 2 + tools/testing/selftests/vfio/lib/iommu.c | 60 +++++++++++++++++-- .../selftests/vfio/lib/vfio_pci_device.c | 16 ++++- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/too= ls/testing/selftests/vfio/lib/include/libvfio/iommu.h index 5c9b9dc6d993..9e96da1e6fd3 100644 --- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h +++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h @@ -29,10 +29,12 @@ struct iommu { int container_fd; int iommufd; u32 ioas_id; + u32 hwpt_id; struct list_head dma_regions; }; =20 struct iommu *iommu_init(const char *iommu_mode); +struct iommu *iommufd_iommu_init(int iommufd, u32 dev_id); void iommu_cleanup(struct iommu *iommu); =20 int __iommu_map(struct iommu *iommu, struct dma_region *region); diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_devi= ce.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h index 2858885a89bb..1143ceb6a9b8 100644 --- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h +++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h @@ -19,6 +19,7 @@ struct vfio_pci_device { const char *bdf; int fd; int group_fd; + u32 dev_id; =20 struct iommu *iommu; =20 @@ -65,6 +66,7 @@ void vfio_pci_config_access(struct vfio_pci_device *devic= e, bool write, #define vfio_pci_config_writew(_d, _o, _v) vfio_pci_config_write(_d, _o, _= v, u16) #define vfio_pci_config_writel(_d, _o, _v) vfio_pci_config_write(_d, _o, _= v, u32) =20 +void vfio_pci_device_attach_iommu(struct vfio_pci_device *device, struct i= ommu *iommu); void vfio_pci_irq_enable(struct vfio_pci_device *device, u32 index, u32 vector, int count); void vfio_pci_irq_disable(struct vfio_pci_device *device, u32 index); diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selft= ests/vfio/lib/iommu.c index 58b7fb7430d4..2c67d7e24d0c 100644 --- a/tools/testing/selftests/vfio/lib/iommu.c +++ b/tools/testing/selftests/vfio/lib/iommu.c @@ -408,6 +408,18 @@ struct iommu_iova_range *iommu_iova_ranges(struct iomm= u *iommu, u32 *nranges) return ranges; } =20 +static u32 iommufd_hwpt_alloc(struct iommu *iommu, u32 dev_id) +{ + struct iommu_hwpt_alloc args =3D { + .size =3D sizeof(args), + .pt_id =3D iommu->ioas_id, + .dev_id =3D dev_id, + }; + + ioctl_assert(iommu->iommufd, IOMMU_HWPT_ALLOC, &args); + return args.out_hwpt_id; +} + static u32 iommufd_ioas_alloc(int iommufd) { struct iommu_ioas_alloc args =3D { @@ -418,11 +430,9 @@ static u32 iommufd_ioas_alloc(int iommufd) return args.out_ioas_id; } =20 -struct iommu *iommu_init(const char *iommu_mode) +static struct iommu *iommu_alloc(const char *iommu_mode) { - const char *container_path; struct iommu *iommu; - int version; =20 iommu =3D calloc(1, sizeof(*iommu)); VFIO_ASSERT_NOT_NULL(iommu); @@ -430,6 +440,16 @@ struct iommu *iommu_init(const char *iommu_mode) INIT_LIST_HEAD(&iommu->dma_regions); =20 iommu->mode =3D lookup_iommu_mode(iommu_mode); + return iommu; +} + +struct iommu *iommu_init(const char *iommu_mode) +{ + const char *container_path; + struct iommu *iommu; + int version; + + iommu =3D iommu_alloc(iommu_mode); =20 container_path =3D iommu->mode->container_path; if (container_path) { @@ -453,10 +473,42 @@ struct iommu *iommu_init(const char *iommu_mode) return iommu; } =20 +struct iommu *iommufd_iommu_init(int iommufd, u32 dev_id) +{ + struct iommu *iommu; + + iommu =3D iommu_alloc("iommufd"); + + iommu->iommufd =3D dup(iommufd); + VFIO_ASSERT_GT(iommu->iommufd, 0); + + iommu->ioas_id =3D iommufd_ioas_alloc(iommu->iommufd); + iommu->hwpt_id =3D iommufd_hwpt_alloc(iommu, dev_id); + + return iommu; +} + +static void iommufd_iommu_cleanup(struct iommu *iommu) +{ + struct iommu_destroy args =3D { + .size =3D sizeof(args), + }; + + if (iommu->hwpt_id) { + args.id =3D iommu->hwpt_id; + ioctl_assert(iommu->iommufd, IOMMU_DESTROY, &args); + } + + args.id =3D iommu->ioas_id; + ioctl_assert(iommu->iommufd, IOMMU_DESTROY, &args); + + VFIO_ASSERT_EQ(close(iommu->iommufd), 0); +} + void iommu_cleanup(struct iommu *iommu) { if (iommu->iommufd) - VFIO_ASSERT_EQ(close(iommu->iommufd), 0); + iommufd_iommu_cleanup(iommu); else VFIO_ASSERT_EQ(close(iommu->container_fd), 0); =20 diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/tes= ting/selftests/vfio/lib/vfio_pci_device.c index fac4c0ecadef..9bc1f5ade5c4 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -298,7 +298,7 @@ const char *vfio_pci_get_cdev_path(const char *bdf) return cdev_path; } =20 -static void vfio_device_bind_iommufd(int device_fd, int iommufd) +static int vfio_device_bind_iommufd(int device_fd, int iommufd) { struct vfio_device_bind_iommufd args =3D { .argsz =3D sizeof(args), @@ -306,6 +306,7 @@ static void vfio_device_bind_iommufd(int device_fd, int= iommufd) }; =20 ioctl_assert(device_fd, VFIO_DEVICE_BIND_IOMMUFD, &args); + return args.out_devid; } =20 static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id) @@ -326,10 +327,21 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_de= vice *device, const char *b VFIO_ASSERT_GE(device->fd, 0); free((void *)cdev_path); =20 - vfio_device_bind_iommufd(device->fd, device->iommu->iommufd); + device->dev_id =3D vfio_device_bind_iommufd(device->fd, device->iommu->io= mmufd); vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id); } =20 +void vfio_pci_device_attach_iommu(struct vfio_pci_device *device, struct i= ommu *iommu) +{ + u32 pt_id =3D iommu->ioas_id; + + if (iommu->hwpt_id) + pt_id =3D iommu->hwpt_id; + + VFIO_ASSERT_NE(pt_id, 0); + vfio_device_attach_iommufd_pt(device->fd, pt_id); +} + struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu= *iommu) { struct vfio_pci_device *device; --=20 2.52.0.351.gbe84eed79e-goog From nobody Sun Feb 8 02:41:21 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (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 0EE713396E6 for ; Wed, 7 Jan 2026 20:18:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767817091; cv=none; b=j0AwFDqEy1UrSlOAwnObaVqRaTv7a5Nj6p3klDScl77NN/QGnQF2XkBMjMoUUJbOx6YRdO96ayrjUvuyRTL9O9S91p03hyZBjVAnIRmYa0DMcqrPYQLvNIhHAzH4B0yOd1/1tsl4ds2yt7o1N0fCW0KIX2GInjU0ngP2w4zq1LU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767817091; c=relaxed/simple; bh=4Pd02XCOO1b0RU5MmE2Uwo/GFJB5CoMMUmyDrSB5Hn0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=rCoss+d8Fy5QeaIRKdZltehdR0YNnXTBghO0FEfI8U9yqCCNslNIeYOy7ibHob+MoTwnKQGpVCiXtTFatK0NabRrPXkBpyH14Ys+sTreUu4805hnVqd8nhfVD6lA1m/xVUNAE3ni8C/3bj/dhko3Axy/wEfOt1xKoEejxo90ugM= 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=aIoRH2Wj; arc=none smtp.client-ip=209.85.214.201 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="aIoRH2Wj" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2a0dabc192eso33841735ad.0 for ; Wed, 07 Jan 2026 12:18:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767817088; x=1768421888; 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=YbIgDevabE4WtwYsX6fHSQEhrlUTqPdnsQVPiMzIU6I=; b=aIoRH2WjHIDGeXHNv5++w9KWHjf3ppnHYlnOJ9kv0WcX2PPirM8tAcwjmoxeNX/X7y NxwSWoM23sNLaisokd/iriHBrGQMxV2QXf6BDsliSafO55MmGoIPIXsrqStwVIUj4QNX lK+mwiYhzyEGKJmT6dANzzc8TT/yrtf0Kegi48hG2OZbLIgmgv2mgcfh9EhZtz4zeXXW LfCmHHAHtGeyhFNewT53TNAlaEozzOSZd78QvaeITS0dgSvQCcGh/R6YIKYmct39pFGO W7SENbrFD9iGt0eI5Q46biADU6vf1sH32LTxBXDuvLHzcuY/fIhcJI19xayR1fahJn1n TKRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767817088; x=1768421888; 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=YbIgDevabE4WtwYsX6fHSQEhrlUTqPdnsQVPiMzIU6I=; b=uBZlZhtgfxvL4xvgt7j6xMDhUr75/cs0G0VNO3fq6m+MM52qj+X/9U4ggt8tfkz8Fj 12FsjBh+ROQN7zuqpiULTdHCovXlzQXaub7h+S79C+LJ1c+HctGA137f0MoZqurs8Q+h GV36qptSYSZyOZ0QABc67ySD7Zv3GFWHyfR3yZHo2AWFuwwhMpMDXHMFk2gjSk5cCeOg 94Jj02UhmP1J2FbW9PUUi94Wb5Lr37xfYFwGV16dT0R6pr83Yww3bvG6RMVTHFWHYue3 KECPxCEDeqwGWNew0LInbRR7nQnaqKjOffwxsyhlGb0JQ9dlCThrcWzWMZqE3PtG2OEU 79Xw== X-Forwarded-Encrypted: i=1; AJvYcCVdBb9QDWTW6W9/CyQMYWxEDqXZdZZw6DFhm3NIhQIpFBYcwv9TBiNan8Dqb0jHPi5ZkH/Ydk/xnWFXCyo=@vger.kernel.org X-Gm-Message-State: AOJu0Yyz1PmHqqz+ZQzZWaYzwkNifs5u/XiR3qhhxrAiFpZa0fW1RWkD nmMjVA5pKiAPeDpdzUZS4h4qhbx9JHgYpZX+jlcKRKut9hwpFhIl5jpQ2TZBrK9VVYEq7q5n0Ye xqQLdvZ61kavbmA== X-Google-Smtp-Source: AGHT+IE1DFCnmny/nHtC+I3vQMTODQGJxSrSd6kNwp+xLBMyWXqHQwoP9SAPWVjXbrVNZ0Jk6FS+jUxa+UC6xw== X-Received: from plyw19.prod.google.com ([2002:a17:902:d713:b0:2a0:f83c:bb4b]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:e391:b0:2a0:9d0f:b1ed with SMTP id d9443c01a7336-2a3ee45b3b5mr21123465ad.24.1767817088271; Wed, 07 Jan 2026 12:18:08 -0800 (PST) Date: Wed, 7 Jan 2026 20:18:00 +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-4-skhawaja@google.com> Subject: [PATCH 3/3] vfio: selftests: Add iommufd hwpt replace test 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" Add a test that does iommufd hwpt replace while a DMA is ongoing. This verifies the hitless replace of IOMMU domain without disrupting the DMA. Note that the new domain is attached after mapping the required DMA memory at the same IOVA in the new domain. Signed-off-by: Samiullah Khawaja --- tools/testing/selftests/vfio/Makefile | 1 + .../vfio/vfio_iommufd_hwpt_replace_test.c | 151 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_= test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftest= s/vfio/Makefile index 3c796ca99a50..09a1e57cc77d 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -1,5 +1,6 @@ CFLAGS =3D $(KHDR_INCLUDES) TEST_GEN_PROGS +=3D vfio_dma_mapping_test +TEST_GEN_PROGS +=3D vfio_iommufd_hwpt_replace_test TEST_GEN_PROGS +=3D vfio_iommufd_setup_test TEST_GEN_PROGS +=3D vfio_pci_device_test TEST_GEN_PROGS +=3D vfio_pci_device_init_perf_test diff --git a/tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c = b/tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c new file mode 100644 index 000000000000..efef3233494f --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include +#include + +#include + +#include "kselftest_harness.h" + +static const char *device_bdf; + +static void region_setup(struct iommu *iommu, + struct iova_allocator *iova_allocator, + struct dma_region *region, u64 size) +{ + const int flags =3D MAP_SHARED | MAP_ANONYMOUS; + const int prot =3D PROT_READ | PROT_WRITE; + void *vaddr; + + vaddr =3D mmap(NULL, size, prot, flags, -1, 0); + VFIO_ASSERT_NE(vaddr, MAP_FAILED); + + region->vaddr =3D vaddr; + region->iova =3D iova_allocator_alloc(iova_allocator, size); + region->size =3D size; + + iommu_map(iommu, region); +} + +static void region_teardown(struct iommu *iommu, struct dma_region *region) +{ + iommu_unmap(iommu, region); + VFIO_ASSERT_EQ(munmap(region->vaddr, region->size), 0); +} + +FIXTURE(vfio_iommufd_replace_hwpt_test) { + struct iommu *iommu; + struct vfio_pci_device *device; + struct iova_allocator *iova_allocator; + struct dma_region memcpy_region; + void *vaddr; + + u64 size; + void *src; + void *dst; + iova_t src_iova; + iova_t dst_iova; +}; + +FIXTURE_SETUP(vfio_iommufd_replace_hwpt_test) +{ + struct vfio_pci_driver *driver; + + self->iommu =3D iommu_init("iommufd"); + self->device =3D vfio_pci_device_init(device_bdf, self->iommu); + self->iova_allocator =3D iova_allocator_init(self->iommu); + + driver =3D &self->device->driver; + + region_setup(self->iommu, self->iova_allocator, &self->memcpy_region, SZ_= 1G); + region_setup(self->iommu, self->iova_allocator, &driver->region, SZ_2M); + + if (driver->ops) + vfio_pci_driver_init(self->device); + + self->size =3D self->memcpy_region.size / 2; + self->src =3D self->memcpy_region.vaddr; + self->dst =3D self->src + self->size; + + self->src_iova =3D to_iova(self->device, self->src); + self->dst_iova =3D to_iova(self->device, self->dst); +} + +FIXTURE_TEARDOWN(vfio_iommufd_replace_hwpt_test) +{ + struct vfio_pci_driver *driver =3D &self->device->driver; + + if (driver->ops) + vfio_pci_driver_remove(self->device); + + region_teardown(self->iommu, &self->memcpy_region); + region_teardown(self->iommu, &driver->region); + + iova_allocator_cleanup(self->iova_allocator); + vfio_pci_device_cleanup(self->device); + iommu_cleanup(self->iommu); +} + +FIXTURE_VARIANT(vfio_iommufd_replace_hwpt_test) { + bool replace_hwpt; +}; + +FIXTURE_VARIANT_ADD(vfio_iommufd_replace_hwpt_test, domain_replace) { + .replace_hwpt =3D true, +}; + +FIXTURE_VARIANT_ADD(vfio_iommufd_replace_hwpt_test, noreplace) { + .replace_hwpt =3D false, +}; + +TEST_F(vfio_iommufd_replace_hwpt_test, memcpy) +{ + struct dma_region memcpy_region, driver_region; + struct iommu *iommu2; + + if (self->device->driver.ops) { + memset(self->src, 'x', self->size); + memset(self->dst, 'y', self->size); + + vfio_pci_driver_memcpy_start(self->device, + self->src_iova, + self->dst_iova, + self->size, + 100); + } + + if (variant->replace_hwpt) { + iommu2 =3D iommufd_iommu_init(self->iommu->iommufd, + self->device->dev_id); + + memcpy_region =3D self->memcpy_region; + driver_region =3D self->device->driver.region; + + iommu_map(iommu2, &memcpy_region); + iommu_map(iommu2, &driver_region); + + vfio_pci_device_attach_iommu(self->device, iommu2); + } + + if (self->device->driver.ops) { + ASSERT_EQ(0, vfio_pci_driver_memcpy_wait(self->device)); + ASSERT_EQ(0, memcmp(self->src, self->dst, self->size)); + } + + if (variant->replace_hwpt) { + vfio_pci_device_attach_iommu(self->device, self->iommu); + + iommu_unmap(iommu2, &memcpy_region); + iommu_unmap(iommu2, &driver_region); + iommu_cleanup(iommu2); + } +} + +int main(int argc, char *argv[]) +{ + device_bdf =3D vfio_selftests_get_bdf(&argc, argv); + + return test_harness_run(argc, argv); +} --=20 2.52.0.351.gbe84eed79e-goog