<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<p style="font-family:Calibri;font-size:10pt;color:#0000FF;margin:5pt;font-style:normal;font-weight:normal;text-decoration:none;" align="Left">
[AMD Official Use Only - AMD Internal Distribution Only]<br>
</p>
<br>
<div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +     amdgpu_vm_it_for_each_entry(avm, mapping, 0, U64_MAX) {</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +             if (mapping->bo_va == bo_va) {</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                     if (vm_index < args->num_mappings) {</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                             vm_buckets[vm_index].start = mapping->start;</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                             vm_buckets[vm_index].last = mapping->last;</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                             vm_buckets[vm_index].offset = mapping->offset;</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                             vm_buckets[vm_index].flags = hardware_flags_to_uapi_flags(drm_to_adev(dev), mapping->flags);</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                     }</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +                     vm_index += 1;</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +             }</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> > +     }</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
></div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
> This chunk should go into amdgpu_vm.c And I strongly suggest to not go over the mapping rb tree but rather the list in the bo_va.</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
></div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Do you mean the invalids and valids lists? I remember you having objections to using those in a previous patch.</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
David</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Koenig, Christian <Christian.Koenig@amd.com><br>
<b>Sent:</b> Monday, June 16, 2025 5:01 AM<br>
<b>To:</b> Francis, David <David.Francis@amd.com>; dri-devel@lists.freedesktop.org <dri-devel@lists.freedesktop.org><br>
<b>Cc:</b> tvrtko.ursulin@igalia.com <tvrtko.ursulin@igalia.com>; Kuehling, Felix <Felix.Kuehling@amd.com>; Yat Sin, David <David.YatSin@amd.com>; Freehill, Chris <Chris.Freehill@amd.com>; dcostantino@meta.com <dcostantino@meta.com>; sruffell@meta.com <sruffell@meta.com>;
 simona@ffwll.ch <simona@ffwll.ch>; mripard@kernel.org <mripard@kernel.org>; tzimmermann@suse.de <tzimmermann@suse.de><br>
<b>Subject:</b> Re: [PATCH 2/3] drm/amdgpu: Adding amdgpu CRIU ioctl</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">On 6/13/25 20:23, David Francis wrote:<br>
> amdgpu CRIU requires an amdgpu CRIU ioctl. This ioctl<br>
> has a similar interface to the amdkfd CRIU ioctl.<br>
> <br>
> The objects that can be checkpointed and restored are bos and vm<br>
> mappings. Because a single amdgpu bo can have multiple mappings.<br>
> the mappings are recorded separately.<br>
> <br>
> The ioctl has two modes: PROCESS_INFO, which sends to the user<br>
> how many bos and vms to expect, and CHECKPOINT, which copies<br>
> data about bos and vms into user-provided buffers.<br>
> <br>
> Restore is handled using existing amdgpu and drm ioctls.<br>
> <br>
> The new ioctl lives in a new file amdgpu_criu.c with its own<br>
> header amdgpu_criu.h<br>
> <br>
> Signed-off-by: David Francis <David.Francis@amd.com><br>
> ---<br>
>  drivers/gpu/drm/amd/amdgpu/Makefile      |   2 +-<br>
>  drivers/gpu/drm/amd/amdgpu/amdgpu_criu.c | 234 +++++++++++++++++++++++<br>
>  drivers/gpu/drm/amd/amdgpu/amdgpu_criu.h |  34 ++++<br>
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c  |   3 +<br>
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c   |  11 ++<br>
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h   |  10 +<br>
>  drivers/gpu/drm/amd/amdkfd/kfd_chardev.c |   2 +<br>
>  include/uapi/drm/amdgpu_drm.h            |  62 ++++++<br>
>  8 files changed, 357 insertions(+), 1 deletion(-)<br>
>  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_criu.c<br>
>  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_criu.h<br>
> <br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile<br>
> index 87080c06e5fc..0863edcdd03f 100644<br>
> --- a/drivers/gpu/drm/amd/amdgpu/Makefile<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/Makefile<br>
> @@ -63,7 +63,7 @@ amdgpu-y += amdgpu_device.o amdgpu_doorbell_mgr.o amdgpu_kms.o \<br>
>        amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \<br>
>        amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \<br>
>        amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \<br>
> -     amdgpu_fw_attestation.o amdgpu_securedisplay.o \<br>
> +     amdgpu_fw_attestation.o amdgpu_securedisplay.o amdgpu_criu.o \<br>
>        amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \<br>
>        amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_aca.o amdgpu_dev_coredump.o \<br>
>        amdgpu_cper.o amdgpu_userq_fence.o amdgpu_eviction_fence.o<br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.c<br>
> new file mode 100644<br>
> index 000000000000..8141ab09698c<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.c<br>
> @@ -0,0 +1,234 @@<br>
> +/* SPDX-License-Identifier: MIT */<br>
> +/*<br>
> +* Copyright 2025 Advanced Micro Devices, Inc.<br>
> +*<br>
> +* Permission is hereby granted, free of charge, to any person obtaining a<br>
> +* copy of this software and associated documentation files (the "Software"),<br>
> +* to deal in the Software without restriction, including without limitation<br>
> +* the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> +* and/or sell copies of the Software, and to permit persons to whom the<br>
> +* Software is furnished to do so, subject to the following conditions:<br>
> +*<br>
> +* The above copyright notice and this permission notice shall be included in<br>
> +* all copies or substantial portions of the Software.<br>
> +*<br>
> +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
> +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> +* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR<br>
> +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
> +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
> +* OTHER DEALINGS IN THE SOFTWARE.<br>
> +*/<br>
> +<br>
> +#include <linux/dma-buf.h><br>
> +#include <linux/hashtable.h><br>
> +#include <linux/mutex.h><br>
> +#include <linux/random.h><br>
> +<br>
> +#include <drm/amdgpu_drm.h><br>
> +#include <drm/drm_device.h><br>
> +#include <drm/drm_file.h><br>
> +<br>
> +#include "amdgpu_criu.h"<br>
> +<br>
> +#include <drm/amdgpu_drm.h><br>
> +#include <drm/drm_drv.h><br>
> +#include <drm/drm_exec.h><br>
> +#include <drm/drm_gem_ttm_helper.h><br>
> +#include <drm/ttm/ttm_tt.h><br>
> +#include <linux/interval_tree_generic.h><br>
> +<br>
> +#include "amdgpu.h"<br>
> +#include "amdgpu_display.h"<br>
> +#include "amdgpu_dma_buf.h"<br>
> +#include "amdgpu_hmm.h"<br>
> +#include "amdgpu_xgmi.h"<br>
> +<br>
> +static uint32_t hardware_flags_to_uapi_flags(struct amdgpu_device *adev, uint64_t pte_flags)<br>
> +{<br>
> +     uint32_t gem_flags = 0;<br>
> +<br>
> +     //This function will be replaced by the mapping flags rework<br>
> +<br>
> +     if (pte_flags & AMDGPU_PTE_EXECUTABLE)<br>
> +             gem_flags |= AMDGPU_VM_PAGE_EXECUTABLE;<br>
> +     if (pte_flags & AMDGPU_PTE_READABLE)<br>
> +             gem_flags |= AMDGPU_VM_PAGE_READABLE;<br>
> +     if (pte_flags & AMDGPU_PTE_WRITEABLE)<br>
> +             gem_flags |= AMDGPU_VM_PAGE_WRITEABLE;<br>
> +     if (pte_flags & AMDGPU_PTE_PRT_FLAG(adev))<br>
> +             gem_flags |= AMDGPU_VM_PAGE_PRT;<br>
> +     if (pte_flags & AMDGPU_PTE_NOALLOC)<br>
> +             gem_flags |= AMDGPU_VM_PAGE_NOALLOC;<br>
> +<br>
> +     return gem_flags;<br>
> +}<br>
> +<br>
> +<br>
> +/**<br>
> + * amdgpu_criu_bo_info_ioctl - get information about a process' buffer objects<br>
> + *<br>
> + * @dev: drm device pointer<br>
> + * @data: drm_amdgpu_criu_bo_info_args<br>
> + * @filp: drm file pointer<br>
> + *<br>
> + * num_bos is set as an input to the size of the bo_buckets array.<br>
> + * num_bos is sent back as output as the number of bos in the process.<br>
> + * If that number is larger than the size of the array, the ioctl must<br>
> + * be retried.<br>
> + *<br>
> + * Returns:<br>
> + * 0 for success, -errno for errors.<br>
> + */<br>
> +int amdgpu_criu_bo_info_ioctl(struct drm_device *dev, void *data,<br>
> +                         struct drm_file *filp)<br>
> +{<br>
> +     struct drm_amdgpu_criu_bo_info_args *args = data;<br>
> +     struct drm_amdgpu_criu_bo_bucket *bo_buckets;<br>
> +     struct drm_gem_object *gobj;<br>
> +     int id, ret = 0;<br>
> +     int bo_index = 0;<br>
> +     int num_bos = 0;<br>
> +<br>
> +     spin_lock(&filp->table_lock);<br>
> +     idr_for_each_entry(&filp->object_idr, gobj, id)<br>
> +             num_bos += 1;<br>
> +     spin_unlock(&filp->table_lock);<br>
> +<br>
> +     if (args->num_bos < num_bos) {<br>
> +             args->num_bos = num_bos;<br>
> +             goto exit;<br>
> +     }<br>
> +     args->num_bos = num_bos;<br>
> +     if (num_bos == 0) {<br>
> +             goto exit;<br>
> +     }<br>
> +<br>
> +     bo_buckets = kvzalloc(num_bos * sizeof(*bo_buckets), GFP_KERNEL);<br>
> +     if (!bo_buckets) {<br>
> +             ret = -ENOMEM;<br>
> +             goto free_buckets;<br>
> +     }<br>
> +<br>
> +     spin_lock(&filp->table_lock);<br>
> +     idr_for_each_entry(&filp->object_idr, gobj, id) {<br>
> +             struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);<br>
> +             struct drm_amdgpu_criu_bo_bucket *bo_bucket;<br>
> +<br>
> +             bo_bucket = &bo_buckets[bo_index];<br>
> +<br>
> +             bo_bucket->size = amdgpu_bo_size(bo);<br>
> +             bo_bucket->offset = amdgpu_bo_mmap_offset(bo);<br>
<br>
Not all BOs have a MMAP offset. Additional to that we already have an IOCTL to query the mmap offset which does the appropriate checks and doesn't potentially crash when there is none.<br>
<br>
> +             bo_bucket->alloc_flags = bo->flags & (~AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE);<br>
> +             bo_bucket->preferred_domains = bo->preferred_domains;<br>
> +             bo_bucket->gem_handle = id;<br>
> +<br>
> +             if (bo->tbo.base.import_attach)<br>
> +                     bo_bucket->flags |= AMDGPU_CRIU_BO_FLAG_IS_IMPORT;<br>
> +<br>
> +             bo_index += 1;<br>
> +     }<br>
> +     spin_unlock(&filp->table_lock);<br>
> +<br>
> +     ret = copy_to_user((void __user *)args->bo_buckets, bo_buckets, num_bos * sizeof(*bo_buckets));<br>
> +     if (ret) {<br>
> +             pr_debug("Failed to copy BO information to user\n");<br>
> +             ret = -EFAULT;<br>
> +     }<br>
> +<br>
> +free_buckets:<br>
> +     kvfree(bo_buckets);<br>
> +exit:<br>
> +<br>
> +     return ret;<br>
> +}<br>
> +<br>
> +/**<br>
> + * amdgpu_criu_bo_info_ioctl - get information about a process' buffer objects<br>
> + *<br>
> + * @dev: drm device pointer<br>
> + * @data: drm_amdgpu_criu_mapping_info_args<br>
> + * @filp: drm file pointer<br>
> + *<br>
> + * num_mappings is set as an input to the size of the vm_buckets array.<br>
> + * num_mappings is sent back as output as the number of mappings the bo has.<br>
> + * If that number is larger than the size of the array, the ioctl must<br>
> + * be retried.<br>
> + *<br>
> + * Returns:<br>
> + * 0 for success, -errno for errors.<br>
> + */<br>
> +int amdgpu_criu_mapping_info_ioctl(struct drm_device *dev, void *data,<br>
> +                         struct drm_file *filp)<br>
<br>
Please split adding that into a separate patch.<br>
<br>
<br>
<br>
> +{<br>
> +     struct drm_amdgpu_criu_mapping_info_args *args = data;<br>
> +     struct drm_gem_object *gobj = idr_find(&filp->object_idr, args->gem_handle);<br>
> +     struct amdgpu_vm *avm = &((struct amdgpu_fpriv *)filp->driver_priv)->vm;<br>
> +     struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);<br>
> +     struct amdgpu_bo_va *bo_va = amdgpu_vm_bo_find(avm, bo);<br>
> +     struct amdgpu_fpriv *fpriv = filp->driver_priv;<br>
> +     struct drm_amdgpu_criu_vm_bucket *vm_buckets;<br>
> +     struct amdgpu_bo_va_mapping *mapping;<br>
> +     struct drm_exec exec;<br>
<br>
> +     int vm_index = 0;<br>
<br>
That needs a better name.<br>
<br>
> +     int ret = 0;<br>
<br>
Don't initialize return variables if you don't need it. That is very bad practice.<br>
<br>
> +<br>
> +     vm_buckets = kvzalloc(args->num_mappings * sizeof(*vm_buckets), GFP_KERNEL);<br>
> +     if (!vm_buckets) {<br>
> +             ret = -ENOMEM;<br>
> +             goto free_vms;<br>
> +     }<br>
> +<br>
> +     drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT |<br>
> +                   DRM_EXEC_IGNORE_DUPLICATES, 0);<br>
> +     drm_exec_until_all_locked(&exec) {<br>
> +             if (gobj) {<br>
> +                     ret = drm_exec_lock_obj(&exec, gobj);<br>
> +                     drm_exec_retry_on_contention(&exec);<br>
> +                     if (ret)<br>
> +                             goto unlock_exec;<br>
> +             }<br>
> +<br>
> +             ret = amdgpu_vm_lock_pd(&fpriv->vm, &exec, 2);<br>
> +             drm_exec_retry_on_contention(&exec);<br>
> +             if (ret)<br>
> +                     goto unlock_exec;<br>
> +     }<br>
> +<br>
<br>
<br>
> +     amdgpu_vm_it_for_each_entry(avm, mapping, 0, U64_MAX) {<br>
> +             if (mapping->bo_va == bo_va) {<br>
> +                     if (vm_index < args->num_mappings) {<br>
> +                             vm_buckets[vm_index].start = mapping->start;<br>
> +                             vm_buckets[vm_index].last = mapping->last;<br>
> +                             vm_buckets[vm_index].offset = mapping->offset;<br>
> +                             vm_buckets[vm_index].flags = hardware_flags_to_uapi_flags(drm_to_adev(dev), mapping->flags);<br>
> +                     }<br>
> +                     vm_index += 1;<br>
> +             }<br>
> +     }<br>
<br>
This chunk should go into amdgpu_vm.c And I strongly suggest to not go over the mapping rb tree but rather the list in the bo_va.<br>
<br>
Regards,<br>
Christian.<br>
<br>
> +<br>
> +     drm_exec_fini(&exec);<br>
> +<br>
> +     if (vm_index > 0) {<br>
> +             if (vm_index <= args->num_mappings) {<br>
> +                     ret = copy_to_user((void __user *)args->vm_buckets, vm_buckets, vm_index * sizeof(*vm_buckets));<br>
> +                     if (ret) {<br>
> +                             pr_debug("Failed to copy BO information to user\n");<br>
> +                             ret = -EFAULT;<br>
> +                     }<br>
> +             }<br>
> +     }<br>
> +     args->num_mappings = vm_index;<br>
> +<br>
> +<br>
> +     kvfree(vm_buckets);<br>
> +<br>
> +     return ret;<br>
> +unlock_exec:<br>
> +     drm_exec_fini(&exec);<br>
> +free_vms:<br>
> +     kvfree(vm_buckets);<br>
> +<br>
> +     return ret;<br>
> +}<br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.h<br>
> new file mode 100644<br>
> index 000000000000..9c196973ed0f<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_criu.h<br>
> @@ -0,0 +1,34 @@<br>
> +/* SPDX-License-Identifier: MIT */<br>
> +/*<br>
> +* Copyright 2025 Advanced Micro Devices, Inc.<br>
> +*<br>
> +* Permission is hereby granted, free of charge, to any person obtaining a<br>
> +* copy of this software and associated documentation files (the "Software"),<br>
> +* to deal in the Software without restriction, including without limitation<br>
> +* the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> +* and/or sell copies of the Software, and to permit persons to whom the<br>
> +* Software is furnished to do so, subject to the following conditions:<br>
> +*<br>
> +* The above copyright notice and this permission notice shall be included in<br>
> +* all copies or substantial portions of the Software.<br>
> +*<br>
> +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
> +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> +* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR<br>
> +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
> +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
> +* OTHER DEALINGS IN THE SOFTWARE.<br>
> +*/<br>
> +<br>
> +#ifndef __AMDGPU_CRIU_H__<br>
> +#define __AMDGPU_CRIU_H__<br>
> +<br>
> +#include <drm/amdgpu_drm.h><br>
> +<br>
> +int amdgpu_criu_bo_info_ioctl(struct drm_device *dev, void *data,<br>
> +                         struct drm_file *filp);<br>
> +int amdgpu_criu_mapping_info_ioctl(struct drm_device *dev, void *data,<br>
> +                         struct drm_file *filp);<br>
> +<br>
> +#endif<br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c<br>
> index 4db92e0a60da..5f3de93a665d 100644<br>
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c<br>
> @@ -53,6 +53,7 @@<br>
>  #include "amdgpu_xgmi.h"<br>
>  #include "amdgpu_userq.h"<br>
>  #include "amdgpu_userq_fence.h"<br>
> +#include "amdgpu_criu.h"<br>
>  #include "../amdxcp/amdgpu_xcp_drv.h"<br>
>  <br>
>  /*<br>
> @@ -3021,6 +3022,8 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {<br>
>        DRM_IOCTL_DEF_DRV(AMDGPU_USERQ, amdgpu_userq_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
>        DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_SIGNAL, amdgpu_userq_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
>        DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_WAIT, amdgpu_userq_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
> +     DRM_IOCTL_DEF_DRV(AMDGPU_CRIU_BO_INFO, amdgpu_criu_bo_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
> +     DRM_IOCTL_DEF_DRV(AMDGPU_CRIU_MAPPING_INFO, amdgpu_criu_mapping_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
>  };<br>
>  <br>
>  static const struct drm_driver amdgpu_kms_driver = {<br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c<br>
> index 3911c78f8282..f803908cf46d 100644<br>
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c<br>
> @@ -3156,3 +3156,14 @@ bool amdgpu_vm_is_bo_always_valid(struct amdgpu_vm *vm, struct amdgpu_bo *bo)<br>
>  {<br>
>        return bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv;<br>
>  }<br>
> +<br>
> +<br>
> +struct amdgpu_bo_va_mapping *amdgpu_vm_it_first_mapping_in_range(struct amdgpu_vm *avm, uint64_t start, uint64_t end)<br>
> +{<br>
> +     return amdgpu_vm_it_iter_first(&avm->va, start, end);<br>
> +}<br>
> +<br>
> +struct amdgpu_bo_va_mapping *amdgpu_vm_it_next_mapping_in_range(struct amdgpu_bo_va_mapping *mapping, uint64_t start, uint64_t end)<br>
> +{<br>
> +     return amdgpu_vm_it_iter_next(mapping, start, end);<br>
> +}<br>
> \ No newline at end of file<br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h<br>
> index f3ad687125ad..cd7d3940cc7a 100644<br>
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h<br>
> @@ -668,4 +668,14 @@ void amdgpu_vm_tlb_fence_create(struct amdgpu_device *adev,<br>
>                                 struct amdgpu_vm *vm,<br>
>                                 struct dma_fence **fence);<br>
>  <br>
> +struct amdgpu_bo_va_mapping *amdgpu_vm_it_first_mapping_in_range(<br>
> +     struct amdgpu_vm *avm, uint64_t start, uint64_t end);<br>
> +struct amdgpu_bo_va_mapping *amdgpu_vm_it_next_mapping_in_range(<br>
> +     struct amdgpu_bo_va_mapping *mapping, uint64_t start, uint64_t end);<br>
> +<br>
> +#define amdgpu_vm_it_for_each_entry(avm, mapping, start, end) \<br>
> +     for (mapping = amdgpu_vm_it_first_mapping_in_range(avm, start, end); \<br>
> +             mapping; \<br>
> +             mapping = amdgpu_vm_it_next_mapping_in_range(mapping, start, end))<br>
> +<br>
>  #endif<br>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c<br>
> index a2149afa5803..a8cf2d4580cc 100644<br>
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c<br>
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c<br>
> @@ -45,6 +45,8 @@<br>
>  #include "amdgpu_dma_buf.h"<br>
>  #include "kfd_debug.h"<br>
>  <br>
> +#include "amdgpu_criu.h"<br>
> +<br>
>  static long kfd_ioctl(struct file *, unsigned int, unsigned long);<br>
>  static int kfd_open(struct inode *, struct file *);<br>
>  static int kfd_release(struct inode *, struct file *);<br>
> diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h<br>
> index 45c4fa13499c..16aee825e116 100644<br>
> --- a/include/uapi/drm/amdgpu_drm.h<br>
> +++ b/include/uapi/drm/amdgpu_drm.h<br>
> @@ -57,6 +57,10 @@ extern "C" {<br>
>  #define DRM_AMDGPU_USERQ             0x16<br>
>  #define DRM_AMDGPU_USERQ_SIGNAL              0x17<br>
>  #define DRM_AMDGPU_USERQ_WAIT                0x18<br>
> +#define DRM_AMDGPU_CRIU_OP           0x19<br>
> +<br>
> +#define DRM_AMDGPU_CRIU_BO_INFO      0x20<br>
> +#define DRM_AMDGPU_CRIU_MAPPING_INFO 0x21<br>
>  <br>
>  #define DRM_IOCTL_AMDGPU_GEM_CREATE  DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)<br>
>  #define DRM_IOCTL_AMDGPU_GEM_MMAP    DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)<br>
> @@ -77,6 +81,10 @@ extern "C" {<br>
>  #define DRM_IOCTL_AMDGPU_USERQ               DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ, union drm_amdgpu_userq)<br>
>  #define DRM_IOCTL_AMDGPU_USERQ_SIGNAL        DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_SIGNAL, struct drm_amdgpu_userq_signal)<br>
>  #define DRM_IOCTL_AMDGPU_USERQ_WAIT  DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_WAIT, struct drm_amdgpu_userq_wait)<br>
> +#define DRM_IOCTL_AMDGPU_CRIU_OP     DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CRIU_OP, struct drm_amdgpu_criu_args)<br>
> +<br>
> +#define DRM_IOCTL_AMDGPU_CRIU_BO_INFO        DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CRIU_BO_INFO, struct drm_amdgpu_criu_bo_info_args)<br>
> +#define DRM_IOCTL_AMDGPU_CRIU_MAPPING_INFO   DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CRIU_MAPPING_INFO, struct drm_amdgpu_criu_mapping_info_args)<br>
>  <br>
>  /**<br>
>   * DOC: memory domains<br>
> @@ -1626,6 +1634,60 @@ struct drm_color_ctm_3x4 {<br>
>        __u64 matrix[12];<br>
>  };<br>
>  <br>
> +#define AMDGPU_CRIU_BO_FLAG_IS_IMPORT        (1 << 0)<br>
> +<br>
> +struct drm_amdgpu_criu_bo_info_args {<br>
> +    /* IN: Size of bo_buckets buffer. OUT: Number of bos in process (if larger than size of buffer, must retry) */<br>
> +    __u32   num_bos;<br>
> +<br>
> +    /* User pointer to array of drm_amdgpu_criu_bo_bucket */<br>
> +    __u64   bo_buckets;<br>
> +};<br>
> +<br>
> +struct drm_amdgpu_criu_bo_bucket {<br>
> +    /* Size of bo */<br>
> +    __u64 size;<br>
> +<br>
> +    /* Offset of bo in device file */<br>
> +    __u64 offset;<br>
> +<br>
> +    /* GEM_CREATE flags for re-creation of buffer */<br>
> +    __u64 alloc_flags;<br>
> +<br>
> +    /* Pending how to handle this; provides information needed to remake the buffer on restore */<br>
> +    __u32 preferred_domains;<br>
> +<br>
> +    /* Currently just one flag: IS_IMPORT */<br>
> +    __u32 flags;<br>
> +<br>
> +    __u32 gem_handle;<br>
> +};<br>
> +<br>
> +struct drm_amdgpu_criu_mapping_info_args {<br>
> +    /* Handle of bo to get mappings of */<br>
> +    __u32   gem_handle;<br>
> +<br>
> +    /* IN: Size of vm_buckets buffer. OUT: Number of bos in process (if larger than size of buffer, must retry) */<br>
> +    __u32   num_mappings;<br>
> +<br>
> +    /* User pointer to array of drm_amdgpu_criu_vm_bucket */<br>
> +    __u64   vm_buckets;<br>
> +};<br>
> +<br>
> +struct drm_amdgpu_criu_vm_bucket {<br>
> +    /* Start of mapping (in number of pages) */<br>
> +    __u64 start;<br>
> +<br>
> +    /* End of mapping (in number of pages) */<br>
> +    __u64 last;<br>
> +<br>
> +    /* Mapping offset */<br>
> +    __u64 offset;<br>
> +<br>
> +    /* flags needed to recreate mapping; still pending how to get these */<br>
> +    __u64 flags;<br>
> +};<br>
> +<br>
>  #if defined(__cplusplus)<br>
>  }<br>
>  #endif<br>
<br>
</div>
</span></font></div>
</div>
</body>
</html>