[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v9 08/13] iommu/ipmmu-vmsa: Implement suspend/resume callbacks


  • To: Mykola Kvach <xakep.amatop@xxxxxxxxx>
  • From: Luca Fancellu <Luca.Fancellu@xxxxxxx>
  • Date: Thu, 14 May 2026 15:57:22 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 4.158.2.129) smtp.rcpttodomain=gmail.com smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=arm.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com])
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ciRlN6asEmFIavj5GiXh91TQSSOXozk9gGrur0OGMmk=; b=UgC/lMxdPyaN19sm1ScgtnJY2YbX/e3GJQ1ZH3fpiGwFxT4Bdc0pl/tJgSi5IEL4iBHo91Nb+92cCafixsK/7k96qeBEniUl9UPkwOBIYaCb/CIa0WQVbXa7g1mFeVk5M3W00yr/a1EVV4uGRPjNhsvL0y1i+h8vjim0dnDuqQjFQe9TZWiorNnqPuiVEyRpTlOym9dtnZe80tmSX8KZS98YlwEY3kt7rw2tCrdKcIysrXsLMSBdyuSC1TsPMSzjwTCE6MWUmJywrd27vo6NZ8SjEkiokBeAdm6FnvzUX55J2ah16bw/Hd3Uo9aH9zIpdgWPGdBWzeYgSm8kEPci8w==
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ciRlN6asEmFIavj5GiXh91TQSSOXozk9gGrur0OGMmk=; b=OJDnMUhsiRMqJ3VvaccldcblGuHsuMApu5PtOBE1C5doDKQOR6j3a/Lozgik4MssYz0dyUjXJgSWWSHE+S0GTUlIv3O7AxQQQjMChzpLbKYycX0wgK7OavYF/XVbVReaXDTOIpr39FKAQwSBRanWrHJ4QJZM8OnFmR8wv3cIP+aM6JBVd5RK8tiCR2l/kVaO+lDflQR7lh5Sgx9N+JfNCi6pQmcrJcwTgwSUtnP93rzkPH3Rs/EyyfDhOepD4diyFQGOMgrr+kODS6lR7VtnvrQai5dOdku1VXam3D8RUuGtJIchxWyxpPqxiLFUBbD7a29NHWAh/GiyIAPqOXMn+A==
  • Arc-seal: i=2; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=pass; b=hCAN/GcUV2jkX3bBHKN+J/o7IEGF/vMtxO6xPWzt4qsSKhxkQOo5zG+SgaYSgG4HLZdHGO+PuSLZs3CvMBcZ7tXtxg4jFTv6s8pTHbJpC5l+iOBuKfGS3VozDa0fg025xa3LuHYFx3+4HxDgI3lj/R+ZW22mWjgebc9jXOfXTXmAdRNeGATqAevpaYJxDwI1YGCNtUVP7i4hjvfeA+YROQkSkfLfIF+iGBbCPtmnDX/PYtOyJ37OkCKod3u+iXaWW9rSoagmwHcy3DlbQEavraLf9owilkyZvxaq6DyjnbBWaYmDUK50PaZ7FJ9Hlf9EWU6h7csdiWsEnyy0zsJv8Q==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=gI3KZzEybp2TkTUz9AmqwGDTA4Ml8Xo4EI2aZH/HT3Xh6ncVelO0vpLI6OrxjV5v7DDg4OUvz1w4HwJUwmkDCRAIk7uRmttW4iSB1/WSyuW4/Rhk8JJJXZfav92qUwIcN4bJ9/LGTV+MZNaSLRcvasNpagGUGj0NRCmMlcIMamSb4Aqr3Kc5q+bMMIt7ihjThsi8WoQ+HFA2ph1NVJ3rRgCKo7Gatv0B8ezt3UdJUvrDNaXUADwcDSQ0Naj3CDxEnLivhAO1rU+o+nEFg11xpajRvusBU8SXmcMO2nN90HlTE5cA6IwezpyuJ88OVkcGHtS1/LYz4z1p3FFPMgk8NQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Mykola Kvach <mykola_kvach@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <Bertrand.Marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Thu, 14 May 2026 15:58:38 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Thread-index: AQHc4jI0ue/pVmX78UiKnsCn9gvTibYNsCmA
  • Thread-topic: [PATCH v9 08/13] iommu/ipmmu-vmsa: Implement suspend/resume callbacks

Hi Mykola,

> 
> diff --git a/xen/drivers/passthrough/arm/ipmmu-vmsa.c 
> b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
> index fa9ab9cb13..e1b47a5824 100644
> --- a/xen/drivers/passthrough/arm/ipmmu-vmsa.c
> +++ b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
> @@ -71,6 +71,8 @@
> })
> #endif
> 
> +#define dev_dbg(dev, fmt, ...)    \
> +    dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
> #define dev_info(dev, fmt, ...)    \
>     dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
> #define dev_warn(dev, fmt, ...)    \
> @@ -130,6 +132,24 @@ struct ipmmu_features {
>     unsigned int imuctr_ttsel_mask;
> };
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +
> +struct ipmmu_reg_ctx {
> +    unsigned int imttlbr0;
> +    unsigned int imttubr0;
> +    unsigned int imttbcr;
> +    unsigned int imctr;
> +};
> +
> +struct ipmmu_vmsa_backup {
> +    struct device *dev;
> +    unsigned int *utlbs_val;
> +    unsigned int *asids_val;
> +    struct list_head list;
> +};
> +
> +#endif
> +
> /* Root/Cache IPMMU device's information */
> struct ipmmu_vmsa_device {
>     struct device *dev;
> @@ -142,6 +162,9 @@ struct ipmmu_vmsa_device {
>     struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];
>     unsigned int utlb_refcount[IPMMU_UTLB_MAX];
>     const struct ipmmu_features *features;
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +    struct ipmmu_reg_ctx *reg_backup[IPMMU_CTX_MAX];
> +#endif
> };
> 
> /*
> @@ -547,6 +570,245 @@ static void ipmmu_domain_free_context(struct 
> ipmmu_vmsa_device *mmu,
>     spin_unlock_irqrestore(&mmu->lock, flags);
> }
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +
> +static DEFINE_SPINLOCK(ipmmu_devices_backup_lock);
> +static LIST_HEAD(ipmmu_devices_backup);
> +
> +static struct ipmmu_reg_ctx root_pgtable[IPMMU_CTX_MAX];
> +
> +static uint32_t ipmmu_imuasid_read(struct ipmmu_vmsa_device *mmu,
> +                                   unsigned int utlb)
> +{
> +    return ipmmu_read(mmu, ipmmu_utlb_reg(mmu, IMUASID(utlb)));
> +}
> +
> +static void ipmmu_utlbs_backup(struct ipmmu_vmsa_device *mmu)
> +{
> +    struct ipmmu_vmsa_backup *backup_data;
> +
> +    dev_dbg(mmu->dev, "Handle micro-TLBs backup\n");
> +
> +    spin_lock(&ipmmu_devices_backup_lock);
> +
> +    list_for_each_entry( backup_data, &ipmmu_devices_backup, list )
> +    {
> +        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(backup_data->dev);
> +        unsigned int i;
> +
> +        if ( to_ipmmu(backup_data->dev) != mmu )
> +            continue;
> +
> +        for ( i = 0; i < fwspec->num_ids; i++ )
> +        {
> +            unsigned int utlb = fwspec->ids[i];
> +
> +            backup_data->asids_val[i] = ipmmu_imuasid_read(mmu, utlb);
> +            backup_data->utlbs_val[i] = ipmmu_imuctr_read(mmu, utlb);
> +        }
> +    }
> +
> +    spin_unlock(&ipmmu_devices_backup_lock);
> +}
> +
> +static void ipmmu_utlbs_restore(struct ipmmu_vmsa_device *mmu)
> +{
> +    struct ipmmu_vmsa_backup *backup_data;
> +
> +    dev_dbg(mmu->dev, "Handle micro-TLBs restore\n");
> +
> +    spin_lock(&ipmmu_devices_backup_lock);
> +
> +    list_for_each_entry( backup_data, &ipmmu_devices_backup, list )
> +    {
> +        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(backup_data->dev);
> +        unsigned int i;
> +
> +        if ( to_ipmmu(backup_data->dev) != mmu )
> +            continue;
> +
> +        for ( i = 0; i < fwspec->num_ids; i++ )
> +        {
> +            unsigned int utlb = fwspec->ids[i];
> +
> +            ipmmu_imuasid_write(mmu, utlb, backup_data->asids_val[i]);
> +            ipmmu_imuctr_write(mmu, utlb, backup_data->utlbs_val[i]);
> +        }
> +    }
> +
> +    spin_unlock(&ipmmu_devices_backup_lock);
> +}
> +
> +static void ipmmu_domain_backup_context(struct ipmmu_vmsa_domain *domain)
> +{
> +    struct ipmmu_vmsa_device *mmu = domain->mmu->root;
> +    struct ipmmu_reg_ctx *regs = mmu->reg_backup[domain->context_id];
> +
> +    dev_dbg(mmu->dev, "Handle domain context %u backup\n", 
> domain->context_id);
> +
> +    regs->imttlbr0 = ipmmu_ctx_read_root(domain, IMTTLBR0);
> +    regs->imttubr0 = ipmmu_ctx_read_root(domain, IMTTUBR0);
> +    regs->imttbcr  = ipmmu_ctx_read_root(domain, IMTTBCR);
> +    regs->imctr    = ipmmu_ctx_read_root(domain, IMCTR);
> +}
> +
> +static void ipmmu_domain_restore_context(struct ipmmu_vmsa_domain *domain)
> +{
> +    struct ipmmu_vmsa_device *mmu = domain->mmu->root;
> +    struct ipmmu_reg_ctx *regs  = mmu->reg_backup[domain->context_id];

NIT: There is a double space before the `=`

> +
> +    dev_dbg(mmu->dev, "Handle domain context %u restore\n", 
> domain->context_id);
> +
> +    ipmmu_ctx_write_root(domain, IMTTLBR0, regs->imttlbr0);
> +    ipmmu_ctx_write_root(domain, IMTTUBR0, regs->imttubr0);
> +    ipmmu_ctx_write_root(domain, IMTTBCR,  regs->imttbcr);
> +    ipmmu_ctx_write_all(domain,  IMCTR,    regs->imctr | IMCTR_FLUSH);

I see in ipmmu_tlb_invalidate() we do:
dsb(sy);
ipmmu_tlb_sync(domain);

Is it safe to omit them here?

> +}
> +
> +/*
> + * Xen: Unlike Linux implementation, Xen uses a single driver instance
> + * for handling all IPMMUs. There is no framework for ipmmu_suspend/resume
> + * callbacks to be invoked for each IPMMU device. So, we need to iterate
> + * through all registered IPMMUs performing required actions.
> + *
> + * Also take care of restoring special settings, such as translation
> + * table format, etc.
> + */
> +static int __must_check ipmmu_suspend(void)
> +{
> +    struct ipmmu_vmsa_device *mmu;
> +
> +    if ( !iommu_enabled )
> +        return 0;
> +
> +    printk(XENLOG_DEBUG "ipmmu: Suspending...\n");
> +
> +    spin_lock(&ipmmu_devices_lock);
> +
> +    list_for_each_entry( mmu, &ipmmu_devices, list )
> +    {
> +        if ( ipmmu_is_root(mmu) )
> +        {
> +            unsigned int i;
> +
> +            for ( i = 0; i < mmu->num_ctx; i++ )
> +            {
> +                if ( !mmu->domains[i] )
> +                    continue;
> +                ipmmu_domain_backup_context(mmu->domains[i]);
> +            }
> +        }
> +        else
> +            ipmmu_utlbs_backup(mmu);
> +    }
> +
> +    spin_unlock(&ipmmu_devices_lock);
> +
> +    return 0;
> +}
> +
> +static void ipmmu_resume(void)
> +{
> +    struct ipmmu_vmsa_device *mmu;
> +
> +    if ( !iommu_enabled )
> +        return;
> +
> +    printk(XENLOG_DEBUG "ipmmu: Resuming...\n");
> +
> +    spin_lock(&ipmmu_devices_lock);
> +
> +    list_for_each_entry( mmu, &ipmmu_devices, list )

This loop has an ordering problem because we can run ipmmu_utlbs_restore() 
before
the root ipmmu is restored (ipmmu_probe() uses `list_add()`).
Maybe going twice on the list, restoring first the root and in the second round 
the rest
should work.

Cheers,
Luca




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.