From: David Yat Sin <david.yatsin@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: <felix.kuehling@amd.com>, <rajneesh.bhardwaj@amd.com>,
David Yat Sin <david.yatsin@amd.com>
Subject: [PATCH 06/18] drm/amdkfd: CRIU Implement KFD restore ioctl
Date: Thu, 19 Aug 2021 09:37:01 -0400 [thread overview]
Message-ID: <20210819133713.4168-7-david.yatsin@amd.com> (raw)
In-Reply-To: <20210819133713.4168-1-david.yatsin@amd.com>
From: Rajneesh Bhardwaj <rajneesh.bhardwaj@amd.com>
This implements the KFD CRIU Restore ioctl that lays the basic
foundation for the CRIU restore operation. It provides support to
create the buffer objects corresponding to Non-Paged system memory
mapped for GPU and/or CPU access and lays basic foundation for the
userptrs buffer objects which will be added in a separate patch.
This ioctl creates various types of buffer objects such as VRAM,
MMIO, Doorbell, GTT based on the date sent from the userspace plugin.
The data mostly contains the previously checkpointed KFD images from
some KFD processs.
While restoring a criu process, attach old IDR values to newly
created BOs. This also adds the minimal gpu mapping support for a single
gpu checkpoint restore use case.
Signed-off-by: David Yat Sin <david.yatsin@amd.com>
Signed-off-by: Rajneesh Bhardwaj <rajneesh.bhardwaj@amd.com>
(cherry picked from commit 47bb685701c336d1fde7e91be93d9cabe89a4c1b)
(cherry picked from commit b71ba8158a7ddf9e4fd8d872be4e40ddd9a29b4f)
---
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 284 ++++++++++++++++++++++-
1 file changed, 282 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index d548e6691d69..2dab1845f9d3 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -2010,12 +2010,292 @@ static int kfd_ioctl_criu_dumper(struct file *filep,
return ret;
}
+static int criu_restore_process(struct kfd_process *p, struct kfd_ioctl_criu_restorer_args *args)
+{
+ int ret = 0;
+ uint8_t *objects;
+ struct kfd_criu_process_bucket *process_bucket;
+ struct kfd_criu_process_priv_data *process_priv;
+
+ if (args->num_objects != 1) {
+ pr_err("Only 1 process supported\n");
+ return -EINVAL;
+ }
+
+ if (args->objects_size != sizeof(*process_bucket) + sizeof(*process_priv)) {
+ pr_err("Invalid objects size for process\n");
+ return -EINVAL;
+ }
+
+ objects = kmalloc(args->objects_size, GFP_KERNEL);
+ if (!objects)
+ return -ENOMEM;
+
+ ret = copy_from_user(objects, (void __user *)args->objects, args->objects_size);
+ if (ret) {
+ pr_err("Failed to copy process information from user\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ process_bucket = (struct kfd_criu_process_bucket *)objects;
+ /* Private data starts after process bucket */
+ process_priv = (struct kfd_criu_process_priv_data *)
+ (objects + sizeof(*process_bucket) + process_bucket->priv_data_offset);
+
+ if (process_priv->version != KFD_CRIU_PRIV_VERSION) {
+ pr_err("Invalid CRIU API version (checkpointed:%d current:%d)\n",
+ process_priv->version, KFD_CRIU_PRIV_VERSION);
+ return -EINVAL;
+ }
+
+exit:
+ kfree(objects);
+ return ret;
+}
+
+static int criu_restore_bos(struct kfd_process *p, struct kfd_ioctl_criu_restorer_args *args)
+{
+ uint8_t *objects, *private_data;
+ struct kfd_criu_bo_bucket *bo_buckets;
+ int ret = 0, i, j = 0;
+
+ if (args->objects_size != args->num_objects *
+ (sizeof(*bo_buckets) + sizeof(struct kfd_criu_bo_priv_data))) {
+ pr_err("Invalid objects size for BOs\n");
+ return -EINVAL;
+ }
+
+ objects = kmalloc(args->objects_size, GFP_KERNEL);
+ if (!objects)
+ return -ENOMEM;
+
+ ret = copy_from_user(objects, (void __user *)args->objects, args->objects_size);
+ if (ret) {
+ pr_err("Failed to copy BOs information from user\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ bo_buckets = (struct kfd_criu_bo_bucket *) objects;
+ /* Private data for first BO starts after all bo_buckets */
+ private_data = (void *)(bo_buckets + args->num_objects);
+
+ /* Create and map new BOs */
+ for (i = 0; i < args->num_objects; i++) {
+ struct kfd_criu_bo_bucket *bo_bucket;
+ struct kfd_criu_bo_priv_data *bo_priv;
+ struct kfd_dev *dev;
+ struct kfd_process_device *pdd;
+ void *mem;
+ u64 offset;
+ int idr_handle;
+
+ bo_bucket = &bo_buckets[i];
+ bo_priv = (struct kfd_criu_bo_priv_data *)
+ (private_data + bo_bucket->priv_data_offset);
+
+ dev = kfd_device_by_id(bo_bucket->gpu_id);
+ if (!dev) {
+ ret = -EINVAL;
+ pr_err("Failed to get pdd\n");
+ goto exit;
+ }
+ pdd = kfd_get_process_device_data(dev, p);
+ if (!pdd) {
+ ret = -EINVAL;
+ pr_err("Failed to get pdd\n");
+ goto exit;
+ }
+
+ pr_debug("kfd restore ioctl - bo_bucket[%d]:\n", i);
+ pr_debug("size = 0x%llx, bo_addr = 0x%llx bo_offset = 0x%llx\n"
+ "gpu_id = 0x%x alloc_flags = 0x%x\n"
+ "idr_handle = 0x%x\n",
+ bo_bucket->size,
+ bo_bucket->addr,
+ bo_bucket->offset,
+ bo_bucket->gpu_id,
+ bo_bucket->alloc_flags,
+ bo_priv->idr_handle);
+
+ if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL) {
+ pr_debug("restore ioctl: KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL\n");
+ if (bo_bucket->size != kfd_doorbell_process_slice(dev)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ offset = kfd_get_process_doorbells(pdd);
+ } else if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP) {
+ /* MMIO BOs need remapped bus address */
+ pr_debug("restore ioctl :KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP\n");
+ if (bo_bucket->size != PAGE_SIZE) {
+ pr_err("Invalid page size\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ offset = amdgpu_amdkfd_get_mmio_remap_phys_addr(dev->kgd);
+ if (!offset) {
+ pr_err("amdgpu_amdkfd_get_mmio_remap_phys_addr failed\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ } else if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
+ offset = bo_priv->user_addr;
+ }
+
+ /* Create the BO */
+ ret = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(dev->kgd,
+ bo_bucket->addr,
+ bo_bucket->size,
+ pdd->drm_priv,
+ (struct kgd_mem **) &mem,
+ &offset,
+ bo_bucket->alloc_flags);
+ if (ret) {
+ pr_err("Could not create the BO\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ pr_debug("New BO created: size = 0x%llx, bo_addr = 0x%llx bo_offset = 0x%llx\n",
+ bo_bucket->size, bo_bucket->addr, offset);
+
+ /* Restore previuos IDR handle */
+ pr_debug("Restoring old IDR handle for the BO");
+ idr_handle = idr_alloc(&pdd->alloc_idr, mem,
+ bo_priv->idr_handle,
+ bo_priv->idr_handle + 1, GFP_KERNEL);
+ if (idr_handle < 0) {
+ pr_err("Could not allocate idr\n");
+ amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd,
+ (struct kgd_mem *)mem,
+ pdd->drm_priv, NULL);
+
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL)
+ bo_bucket->restored_offset = KFD_MMAP_TYPE_DOORBELL |
+ KFD_MMAP_GPU_ID(pdd->dev->id);
+ if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP) {
+ bo_bucket->restored_offset = KFD_MMAP_TYPE_MMIO |
+ KFD_MMAP_GPU_ID(pdd->dev->id);
+ } else if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_GTT) {
+ bo_bucket->restored_offset = offset;
+ pr_debug("updating offset for GTT\n");
+ } else if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) {
+ bo_bucket->restored_offset = offset;
+ /* Update the VRAM usage count */
+ WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + bo_bucket->size);
+ pr_debug("updating offset for VRAM\n");
+ }
+
+ /* now map these BOs to GPU/s */
+ for (j = 0; j < p->n_pdds; j++) {
+ struct kfd_process_device *pdd = p->pdds[j];
+ struct kfd_dev *peer;
+ struct kfd_process_device *peer_pdd;
+
+ peer = kfd_device_by_id(pdd->dev->id);
+
+ pr_debug("Inside mapping loop with desired gpu_id = 0x%x\n",
+ pdd->dev->id);
+ if (!peer) {
+ pr_debug("Getting device by id failed for 0x%x\n",
+ pdd->dev->id);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ peer_pdd = kfd_bind_process_to_device(peer, p);
+ if (IS_ERR(peer_pdd)) {
+ ret = PTR_ERR(peer_pdd);
+ goto exit;
+ }
+ pr_debug("map mem in restore ioctl -> 0x%llx\n",
+ ((struct kgd_mem *)mem)->va);
+ ret = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(peer->kgd,
+ (struct kgd_mem *)mem, peer_pdd->drm_priv);
+ if (ret) {
+ pr_err("Failed to map to gpu %d/%d\n",
+ j, p->n_pdds);
+ goto exit;
+ }
+ }
+
+ ret = amdgpu_amdkfd_gpuvm_sync_memory(dev->kgd,
+ (struct kgd_mem *) mem, true);
+ if (ret) {
+ pr_debug("Sync memory failed, wait interrupted by user signal\n");
+ goto exit;
+ }
+
+ pr_debug("map memory was successful for the BO\n");
+ } /* done */
+
+ /* Flush TLBs after waiting for the page table updates to complete */
+ for (j = 0; j < p->n_pdds; j++) {
+ struct kfd_dev *peer;
+ struct kfd_process_device *pdd = p->pdds[j];
+ struct kfd_process_device *peer_pdd;
+
+ peer = kfd_device_by_id(pdd->dev->id);
+ if (WARN_ON_ONCE(!peer))
+ continue;
+ peer_pdd = kfd_get_process_device_data(peer, p);
+ if (WARN_ON_ONCE(!peer_pdd))
+ continue;
+ kfd_flush_tlb(peer_pdd);
+ }
+ /* Copy only the buckets back so user can read bo_buckets[N].restored_offset */
+ ret = copy_to_user((void __user *)args->objects,
+ bo_buckets,
+ (args->num_objects * sizeof(*bo_buckets)));
+ if (ret)
+ ret = -EFAULT;
+
+exit:
+ kvfree(objects);
+ return ret;
+}
+
static int kfd_ioctl_criu_restorer(struct file *filep,
struct kfd_process *p, void *data)
{
- pr_debug("Inside %s\n", __func__);
+ struct kfd_ioctl_criu_restorer_args *args = data;
+ int ret;
- return 0;
+ if (!args->objects || !args->objects_size)
+ return -EINVAL;
+
+ mutex_lock(&p->mutex);
+
+ switch (args->type) {
+ case KFD_CRIU_OBJECT_TYPE_PROCESS:
+ ret = criu_restore_process(p, args);
+ break;
+ case KFD_CRIU_OBJECT_TYPE_BO:
+ ret = criu_restore_bos(p, args);
+ break;
+ case KFD_CRIU_OBJECT_TYPE_QUEUE:
+ case KFD_CRIU_OBJECT_TYPE_EVENT:
+ case KFD_CRIU_OBJECT_TYPE_DEVICE:
+ case KFD_CRIU_OBJECT_TYPE_SVM_RANGE:
+ default:
+ pr_err("Unsupported object type:%d\n", args->type);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ mutex_unlock(&p->mutex);
+ if (ret)
+ pr_err("Failed to restore CRIU type:%d ret:%d\n", args->type, ret);
+ else
+ pr_debug("CRIU restore type:%d ret:%d\n", args->type, ret);
+
+ return ret;
}
static int kfd_ioctl_criu_pause(struct file *filep, struct kfd_process *p, void *data)
--
2.17.1
next prev parent reply other threads:[~2021-08-19 13:37 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-19 13:36 [PATCH 00/18] CHECKPOINT RESTORE WITH ROCm David Yat Sin
2021-08-19 13:36 ` [PATCH 01/18] x86/configs: CRIU update release defconfig David Yat Sin
2021-08-19 13:36 ` [PATCH 02/18] x86/configs: CRIU update debug rock defconfig David Yat Sin
2021-08-19 13:36 ` [PATCH 03/18] drm/amdkfd: CRIU Introduce Checkpoint-Restore APIs David Yat Sin
2021-08-23 18:57 ` Felix Kuehling
2021-08-19 13:36 ` [PATCH 04/18] drm/amdkfd: CRIU Implement KFD process_info ioctl David Yat Sin
2021-08-19 13:37 ` [PATCH 05/18] drm/amdkfd: CRIU Implement KFD dumper ioctl David Yat Sin
2021-08-23 18:53 ` Felix Kuehling
2021-08-19 13:37 ` David Yat Sin [this message]
2021-08-19 13:37 ` [PATCH 07/18] drm/amdkfd: CRIU Implement KFD resume ioctl David Yat Sin
2021-08-19 13:37 ` [PATCH 08/18] drm/amdkfd: CRIU Implement KFD pause ioctl David Yat Sin
2021-08-19 13:37 ` [PATCH 09/18] drm/amdkfd: CRIU add queues support David Yat Sin
2021-08-23 18:29 ` Felix Kuehling
2021-08-19 13:37 ` [PATCH 10/18] drm/amdkfd: CRIU restore queue ids David Yat Sin
2021-08-23 18:29 ` Felix Kuehling
2021-08-19 13:37 ` [PATCH 11/18] drm/amdkfd: CRIU restore sdma id for queues David Yat Sin
2021-08-19 13:37 ` [PATCH 12/18] drm/amdkfd: CRIU restore queue doorbell id David Yat Sin
2021-08-19 13:37 ` [PATCH 13/18] drm/amdkfd: CRIU dump and restore queue mqds David Yat Sin
2021-08-19 13:37 ` [PATCH 14/18] drm/amdkfd: CRIU dump/restore queue control stack David Yat Sin
2021-08-19 13:37 ` [PATCH 15/18] drm/amdkfd: CRIU dump and restore events David Yat Sin
2021-08-23 18:39 ` Felix Kuehling
2021-08-19 13:37 ` [PATCH 16/18] drm/amdkfd: CRIU implement gpu_id remapping David Yat Sin
2021-08-23 18:48 ` Felix Kuehling
2021-08-19 13:37 ` [PATCH 17/18] Revert "drm/amdgpu: Remove verify_access shortcut for KFD BOs" David Yat Sin
2021-08-19 13:37 ` [PATCH 18/18] drm/amdkfd: CRIU export kfd bos as prime dmabuf objects David Yat Sin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210819133713.4168-7-david.yatsin@amd.com \
--to=david.yatsin@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=felix.kuehling@amd.com \
--cc=rajneesh.bhardwaj@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox