Loading drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +129 −142 Original line number Diff line number Diff line Loading @@ -2094,154 +2094,94 @@ static int criu_restore_devices(struct kfd_process *p, return ret; } static int criu_restore_bos(struct kfd_process *p, struct kfd_ioctl_criu_args *args, uint64_t *priv_offset, uint64_t max_priv_data_size) static int criu_restore_memory_of_gpu(struct kfd_process_device *pdd, struct kfd_criu_bo_bucket *bo_bucket, struct kfd_criu_bo_priv_data *bo_priv, struct kgd_mem **kgd_mem) { struct kfd_criu_bo_bucket *bo_buckets = NULL; struct kfd_criu_bo_priv_data *bo_privs = NULL; int idr_handle; int ret; const bool criu_resume = true; int ret = 0, j = 0; uint32_t i = 0; if (*priv_offset + (args->num_bos * sizeof(*bo_privs)) > max_priv_data_size) return -EINVAL; /* Prevent MMU notifications until stage-4 IOCTL (CRIU_RESUME) is received */ amdgpu_amdkfd_block_mmu_notifications(p->kgd_process_info); bo_buckets = kvmalloc_array(args->num_bos, sizeof(*bo_buckets), GFP_KERNEL); if (!bo_buckets) return -ENOMEM; ret = copy_from_user(bo_buckets, (void __user *)args->bos, args->num_bos * sizeof(*bo_buckets)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } bo_privs = kvmalloc_array(args->num_bos, sizeof(*bo_privs), GFP_KERNEL); if (!bo_privs) { ret = -ENOMEM; goto exit; } ret = copy_from_user(bo_privs, (void __user *)args->priv_data + *priv_offset, args->num_bos * sizeof(*bo_privs)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } *priv_offset += args->num_bos * sizeof(*bo_privs); /* Create and map new BOs */ for (; i < args->num_bos; 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; struct kgd_mem *kgd_mem; void *mem; u64 offset; int idr_handle; bo_bucket = &bo_buckets[i]; bo_priv = &bo_privs[i]; 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); pdd = kfd_process_device_data_by_id(p, bo_bucket->gpu_id); if (!pdd) { pr_err("Failed to get pdd\n"); ret = -ENODEV; goto exit; } dev = pdd->dev; 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; } if (bo_bucket->size != kfd_doorbell_process_slice(pdd->dev)) return -EINVAL; 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; return -EINVAL; } offset = dev->adev->rmmio_remap.bus_addr; offset = pdd->dev->adev->rmmio_remap.bus_addr; if (!offset) { pr_err("amdgpu_amdkfd_get_mmio_remap_phys_addr failed\n"); ret = -ENOMEM; goto exit; return -ENOMEM; } } 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->adev, bo_bucket->addr, bo_bucket->size, pdd->drm_priv, (struct kgd_mem **) &mem, &offset, bo_bucket->alloc_flags, criu_resume); ret = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(pdd->dev->adev, bo_bucket->addr, bo_bucket->size, pdd->drm_priv, kgd_mem, &offset, bo_bucket->alloc_flags, criu_resume); if (ret) { pr_err("Could not create the BO\n"); ret = -ENOMEM; goto exit; return ret; } pr_debug("New BO created: size = 0x%llx, bo_addr = 0x%llx bo_offset = 0x%llx\n", pr_debug("New BO created: size:0x%llx addr:0x%llx offset:0x%llx\n", bo_bucket->size, bo_bucket->addr, offset); /* Restore previuos IDR handle */ /* Restore previous IDR handle */ pr_debug("Restoring old IDR handle for the BO"); idr_handle = idr_alloc(&pdd->alloc_idr, mem, bo_priv->idr_handle, idr_handle = idr_alloc(&pdd->alloc_idr, *kgd_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->adev, (struct kgd_mem *)mem, pdd->drm_priv, NULL); ret = -ENOMEM; goto exit; amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->adev, *kgd_mem, pdd->drm_priv, NULL); return -ENOMEM; } 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); 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); 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"); } return 0; } static int criu_restore_bo(struct kfd_process *p, struct kfd_criu_bo_bucket *bo_bucket, struct kfd_criu_bo_priv_data *bo_priv) { struct kfd_process_device *pdd; struct kgd_mem *kgd_mem; int ret; int j; pr_debug("Restoring BO size:0x%llx addr:0x%llx gpu_id:0x%x flags:0x%x idr_handle:0x%x\n", bo_bucket->size, bo_bucket->addr, bo_bucket->gpu_id, bo_bucket->alloc_flags, bo_priv->idr_handle); pdd = kfd_process_device_data_by_id(p, bo_bucket->gpu_id); if (!pdd) { pr_err("Failed to get pdd\n"); return -ENODEV; } ret = criu_restore_memory_of_gpu(pdd, bo_bucket, bo_priv, &kgd_mem); if (ret) return ret; /* now map these BOs to GPU/s */ for (j = 0; j < p->n_pdds; j++) { Loading @@ -2252,35 +2192,82 @@ static int criu_restore_bos(struct kfd_process *p, break; peer_pdd = kfd_process_device_data_by_id(p, bo_priv->mapped_gpuids[j]); if (!peer_pdd) { ret = -EINVAL; goto exit; } if (!peer_pdd) return -EINVAL; peer = peer_pdd->dev; 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->adev, (struct kgd_mem *)mem, peer_pdd->drm_priv, NULL); if (IS_ERR(peer_pdd)) return PTR_ERR(peer_pdd); ret = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(peer->adev, kgd_mem, peer_pdd->drm_priv, NULL); if (ret) { pr_err("Failed to map to gpu %d/%d\n", j, p->n_pdds); goto exit; return ret; } } pr_debug("map memory was successful for the BO\n"); /* create the dmabuf object and export the bo */ kgd_mem = (struct kgd_mem *)mem; if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { ret = criu_get_prime_handle(&kgd_mem->bo->tbo.base, DRM_RDWR, ret = criu_get_prime_handle(&kgd_mem->bo->tbo.base, DRM_RDWR, &bo_bucket->dmabuf_fd); if (ret) return ret; } return 0; } static int criu_restore_bos(struct kfd_process *p, struct kfd_ioctl_criu_args *args, uint64_t *priv_offset, uint64_t max_priv_data_size) { struct kfd_criu_bo_bucket *bo_buckets = NULL; struct kfd_criu_bo_priv_data *bo_privs = NULL; int ret = 0; uint32_t i = 0; if (*priv_offset + (args->num_bos * sizeof(*bo_privs)) > max_priv_data_size) return -EINVAL; /* Prevent MMU notifications until stage-4 IOCTL (CRIU_RESUME) is received */ amdgpu_amdkfd_block_mmu_notifications(p->kgd_process_info); bo_buckets = kvmalloc_array(args->num_bos, sizeof(*bo_buckets), GFP_KERNEL); if (!bo_buckets) return -ENOMEM; ret = copy_from_user(bo_buckets, (void __user *)args->bos, args->num_bos * sizeof(*bo_buckets)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } bo_privs = kvmalloc_array(args->num_bos, sizeof(*bo_privs), GFP_KERNEL); if (!bo_privs) { ret = -ENOMEM; goto exit; } ret = copy_from_user(bo_privs, (void __user *)args->priv_data + *priv_offset, args->num_bos * sizeof(*bo_privs)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } *priv_offset += args->num_bos * sizeof(*bo_privs); /* Create and map new BOs */ for (; i < args->num_bos; i++) { ret = criu_restore_bo(p, &bo_buckets[i], &bo_privs[i]); if (ret) { pr_debug("Failed to restore BO[%d] ret%d\n", i, ret); goto exit; } } /* done */ Loading Loading
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +129 −142 Original line number Diff line number Diff line Loading @@ -2094,154 +2094,94 @@ static int criu_restore_devices(struct kfd_process *p, return ret; } static int criu_restore_bos(struct kfd_process *p, struct kfd_ioctl_criu_args *args, uint64_t *priv_offset, uint64_t max_priv_data_size) static int criu_restore_memory_of_gpu(struct kfd_process_device *pdd, struct kfd_criu_bo_bucket *bo_bucket, struct kfd_criu_bo_priv_data *bo_priv, struct kgd_mem **kgd_mem) { struct kfd_criu_bo_bucket *bo_buckets = NULL; struct kfd_criu_bo_priv_data *bo_privs = NULL; int idr_handle; int ret; const bool criu_resume = true; int ret = 0, j = 0; uint32_t i = 0; if (*priv_offset + (args->num_bos * sizeof(*bo_privs)) > max_priv_data_size) return -EINVAL; /* Prevent MMU notifications until stage-4 IOCTL (CRIU_RESUME) is received */ amdgpu_amdkfd_block_mmu_notifications(p->kgd_process_info); bo_buckets = kvmalloc_array(args->num_bos, sizeof(*bo_buckets), GFP_KERNEL); if (!bo_buckets) return -ENOMEM; ret = copy_from_user(bo_buckets, (void __user *)args->bos, args->num_bos * sizeof(*bo_buckets)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } bo_privs = kvmalloc_array(args->num_bos, sizeof(*bo_privs), GFP_KERNEL); if (!bo_privs) { ret = -ENOMEM; goto exit; } ret = copy_from_user(bo_privs, (void __user *)args->priv_data + *priv_offset, args->num_bos * sizeof(*bo_privs)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } *priv_offset += args->num_bos * sizeof(*bo_privs); /* Create and map new BOs */ for (; i < args->num_bos; 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; struct kgd_mem *kgd_mem; void *mem; u64 offset; int idr_handle; bo_bucket = &bo_buckets[i]; bo_priv = &bo_privs[i]; 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); pdd = kfd_process_device_data_by_id(p, bo_bucket->gpu_id); if (!pdd) { pr_err("Failed to get pdd\n"); ret = -ENODEV; goto exit; } dev = pdd->dev; 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; } if (bo_bucket->size != kfd_doorbell_process_slice(pdd->dev)) return -EINVAL; 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; return -EINVAL; } offset = dev->adev->rmmio_remap.bus_addr; offset = pdd->dev->adev->rmmio_remap.bus_addr; if (!offset) { pr_err("amdgpu_amdkfd_get_mmio_remap_phys_addr failed\n"); ret = -ENOMEM; goto exit; return -ENOMEM; } } 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->adev, bo_bucket->addr, bo_bucket->size, pdd->drm_priv, (struct kgd_mem **) &mem, &offset, bo_bucket->alloc_flags, criu_resume); ret = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(pdd->dev->adev, bo_bucket->addr, bo_bucket->size, pdd->drm_priv, kgd_mem, &offset, bo_bucket->alloc_flags, criu_resume); if (ret) { pr_err("Could not create the BO\n"); ret = -ENOMEM; goto exit; return ret; } pr_debug("New BO created: size = 0x%llx, bo_addr = 0x%llx bo_offset = 0x%llx\n", pr_debug("New BO created: size:0x%llx addr:0x%llx offset:0x%llx\n", bo_bucket->size, bo_bucket->addr, offset); /* Restore previuos IDR handle */ /* Restore previous IDR handle */ pr_debug("Restoring old IDR handle for the BO"); idr_handle = idr_alloc(&pdd->alloc_idr, mem, bo_priv->idr_handle, idr_handle = idr_alloc(&pdd->alloc_idr, *kgd_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->adev, (struct kgd_mem *)mem, pdd->drm_priv, NULL); ret = -ENOMEM; goto exit; amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->adev, *kgd_mem, pdd->drm_priv, NULL); return -ENOMEM; } 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); 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); 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"); } return 0; } static int criu_restore_bo(struct kfd_process *p, struct kfd_criu_bo_bucket *bo_bucket, struct kfd_criu_bo_priv_data *bo_priv) { struct kfd_process_device *pdd; struct kgd_mem *kgd_mem; int ret; int j; pr_debug("Restoring BO size:0x%llx addr:0x%llx gpu_id:0x%x flags:0x%x idr_handle:0x%x\n", bo_bucket->size, bo_bucket->addr, bo_bucket->gpu_id, bo_bucket->alloc_flags, bo_priv->idr_handle); pdd = kfd_process_device_data_by_id(p, bo_bucket->gpu_id); if (!pdd) { pr_err("Failed to get pdd\n"); return -ENODEV; } ret = criu_restore_memory_of_gpu(pdd, bo_bucket, bo_priv, &kgd_mem); if (ret) return ret; /* now map these BOs to GPU/s */ for (j = 0; j < p->n_pdds; j++) { Loading @@ -2252,35 +2192,82 @@ static int criu_restore_bos(struct kfd_process *p, break; peer_pdd = kfd_process_device_data_by_id(p, bo_priv->mapped_gpuids[j]); if (!peer_pdd) { ret = -EINVAL; goto exit; } if (!peer_pdd) return -EINVAL; peer = peer_pdd->dev; 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->adev, (struct kgd_mem *)mem, peer_pdd->drm_priv, NULL); if (IS_ERR(peer_pdd)) return PTR_ERR(peer_pdd); ret = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(peer->adev, kgd_mem, peer_pdd->drm_priv, NULL); if (ret) { pr_err("Failed to map to gpu %d/%d\n", j, p->n_pdds); goto exit; return ret; } } pr_debug("map memory was successful for the BO\n"); /* create the dmabuf object and export the bo */ kgd_mem = (struct kgd_mem *)mem; if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { ret = criu_get_prime_handle(&kgd_mem->bo->tbo.base, DRM_RDWR, ret = criu_get_prime_handle(&kgd_mem->bo->tbo.base, DRM_RDWR, &bo_bucket->dmabuf_fd); if (ret) return ret; } return 0; } static int criu_restore_bos(struct kfd_process *p, struct kfd_ioctl_criu_args *args, uint64_t *priv_offset, uint64_t max_priv_data_size) { struct kfd_criu_bo_bucket *bo_buckets = NULL; struct kfd_criu_bo_priv_data *bo_privs = NULL; int ret = 0; uint32_t i = 0; if (*priv_offset + (args->num_bos * sizeof(*bo_privs)) > max_priv_data_size) return -EINVAL; /* Prevent MMU notifications until stage-4 IOCTL (CRIU_RESUME) is received */ amdgpu_amdkfd_block_mmu_notifications(p->kgd_process_info); bo_buckets = kvmalloc_array(args->num_bos, sizeof(*bo_buckets), GFP_KERNEL); if (!bo_buckets) return -ENOMEM; ret = copy_from_user(bo_buckets, (void __user *)args->bos, args->num_bos * sizeof(*bo_buckets)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } bo_privs = kvmalloc_array(args->num_bos, sizeof(*bo_privs), GFP_KERNEL); if (!bo_privs) { ret = -ENOMEM; goto exit; } ret = copy_from_user(bo_privs, (void __user *)args->priv_data + *priv_offset, args->num_bos * sizeof(*bo_privs)); if (ret) { pr_err("Failed to copy BOs information from user\n"); ret = -EFAULT; goto exit; } *priv_offset += args->num_bos * sizeof(*bo_privs); /* Create and map new BOs */ for (; i < args->num_bos; i++) { ret = criu_restore_bo(p, &bo_buckets[i], &bo_privs[i]); if (ret) { pr_debug("Failed to restore BO[%d] ret%d\n", i, ret); goto exit; } } /* done */ Loading