Commit ab3400eb authored by Alex Sierra's avatar Alex Sierra Committed by Alex Deucher

drm/amdkfd: avoid unmap dma address when svm_ranges are split

DMA address reference within svm_ranges should be unmapped only after
the memory has been released from the system. In case of range
splitting, the DMA address information should be copied to the
corresponding range after this has split. But leaving dma mapping
intact.
Signed-off-by: default avatarAlex Sierra <alex.sierra@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 15f5b0a7
...@@ -461,7 +461,6 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, ...@@ -461,7 +461,6 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
0, node->id, trigger); 0, node->id, trigger);
svm_range_dma_unmap(adev->dev, scratch, 0, npages); svm_range_dma_unmap(adev->dev, scratch, 0, npages);
svm_range_free_dma_mappings(prange);
out_free: out_free:
kvfree(buf); kvfree(buf);
...@@ -543,10 +542,12 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, ...@@ -543,10 +542,12 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
addr = next; addr = next;
} }
if (cpages) if (cpages) {
prange->actual_loc = best_loc; prange->actual_loc = best_loc;
else svm_range_free_dma_mappings(prange, true);
} else {
svm_range_vram_node_free(prange); svm_range_vram_node_free(prange);
}
return r < 0 ? r : 0; return r < 0 ? r : 0;
} }
......
...@@ -243,7 +243,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, ...@@ -243,7 +243,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr,
} }
} }
void svm_range_free_dma_mappings(struct svm_range *prange) void svm_range_free_dma_mappings(struct svm_range *prange, bool unmap_dma)
{ {
struct kfd_process_device *pdd; struct kfd_process_device *pdd;
dma_addr_t *dma_addr; dma_addr_t *dma_addr;
...@@ -264,13 +264,14 @@ void svm_range_free_dma_mappings(struct svm_range *prange) ...@@ -264,13 +264,14 @@ void svm_range_free_dma_mappings(struct svm_range *prange)
continue; continue;
} }
dev = &pdd->dev->adev->pdev->dev; dev = &pdd->dev->adev->pdev->dev;
if (unmap_dma)
svm_range_dma_unmap(dev, dma_addr, 0, prange->npages); svm_range_dma_unmap(dev, dma_addr, 0, prange->npages);
kvfree(dma_addr); kvfree(dma_addr);
prange->dma_addr[gpuidx] = NULL; prange->dma_addr[gpuidx] = NULL;
} }
} }
static void svm_range_free(struct svm_range *prange, bool update_mem_usage) static void svm_range_free(struct svm_range *prange, bool do_unmap)
{ {
uint64_t size = (prange->last - prange->start + 1) << PAGE_SHIFT; uint64_t size = (prange->last - prange->start + 1) << PAGE_SHIFT;
struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms); struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
...@@ -279,9 +280,9 @@ static void svm_range_free(struct svm_range *prange, bool update_mem_usage) ...@@ -279,9 +280,9 @@ static void svm_range_free(struct svm_range *prange, bool update_mem_usage)
prange->start, prange->last); prange->start, prange->last);
svm_range_vram_node_free(prange); svm_range_vram_node_free(prange);
svm_range_free_dma_mappings(prange); svm_range_free_dma_mappings(prange, do_unmap);
if (update_mem_usage && !p->xnack_enabled) { if (do_unmap && !p->xnack_enabled) {
pr_debug("unreserve prange 0x%p size: 0x%llx\n", prange, size); pr_debug("unreserve prange 0x%p size: 0x%llx\n", prange, size);
amdgpu_amdkfd_unreserve_mem_limit(NULL, size, amdgpu_amdkfd_unreserve_mem_limit(NULL, size,
KFD_IOC_ALLOC_MEM_FLAGS_USERPTR, 0); KFD_IOC_ALLOC_MEM_FLAGS_USERPTR, 0);
...@@ -853,6 +854,37 @@ static void svm_range_debug_dump(struct svm_range_list *svms) ...@@ -853,6 +854,37 @@ static void svm_range_debug_dump(struct svm_range_list *svms)
} }
} }
static void *
svm_range_copy_array(void *psrc, size_t size, uint64_t num_elements,
uint64_t offset)
{
unsigned char *dst;
dst = kvmalloc_array(num_elements, size, GFP_KERNEL);
if (!dst)
return NULL;
memcpy(dst, (unsigned char *)psrc + offset, num_elements * size);
return (void *)dst;
}
static int
svm_range_copy_dma_addrs(struct svm_range *dst, struct svm_range *src)
{
int i;
for (i = 0; i < MAX_GPU_INSTANCE; i++) {
if (!src->dma_addr[i])
continue;
dst->dma_addr[i] = svm_range_copy_array(src->dma_addr[i],
sizeof(*src->dma_addr[i]), src->npages, 0);
if (!dst->dma_addr[i])
return -ENOMEM;
}
return 0;
}
static int static int
svm_range_split_array(void *ppnew, void *ppold, size_t size, svm_range_split_array(void *ppnew, void *ppold, size_t size,
uint64_t old_start, uint64_t old_n, uint64_t old_start, uint64_t old_n,
...@@ -867,22 +899,16 @@ svm_range_split_array(void *ppnew, void *ppold, size_t size, ...@@ -867,22 +899,16 @@ svm_range_split_array(void *ppnew, void *ppold, size_t size,
if (!pold) if (!pold)
return 0; return 0;
new = kvmalloc_array(new_n, size, GFP_KERNEL); d = (new_start - old_start) * size;
new = svm_range_copy_array(pold, size, new_n, d);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
d = (new_start == old_start) ? new_n * size : 0;
d = (new_start - old_start) * size; old = svm_range_copy_array(pold, size, old_n, d);
memcpy(new, pold + d, new_n * size);
old = kvmalloc_array(old_n, size, GFP_KERNEL);
if (!old) { if (!old) {
kvfree(new); kvfree(new);
return -ENOMEM; return -ENOMEM;
} }
d = (new_start == old_start) ? new_n * size : 0;
memcpy(old, pold + d, old_n * size);
kvfree(pold); kvfree(pold);
*(void **)ppold = old; *(void **)ppold = old;
*(void **)ppnew = new; *(void **)ppnew = new;
...@@ -1928,7 +1954,10 @@ static struct svm_range *svm_range_clone(struct svm_range *old) ...@@ -1928,7 +1954,10 @@ static struct svm_range *svm_range_clone(struct svm_range *old)
new = svm_range_new(old->svms, old->start, old->last, false); new = svm_range_new(old->svms, old->start, old->last, false);
if (!new) if (!new)
return NULL; return NULL;
if (svm_range_copy_dma_addrs(new, old)) {
svm_range_free(new, false);
return NULL;
}
if (old->svm_bo) { if (old->svm_bo) {
new->ttm_res = old->ttm_res; new->ttm_res = old->ttm_res;
new->offset = old->offset; new->offset = old->offset;
......
...@@ -183,7 +183,7 @@ void svm_range_add_list_work(struct svm_range_list *svms, ...@@ -183,7 +183,7 @@ void svm_range_add_list_work(struct svm_range_list *svms,
void schedule_deferred_list_work(struct svm_range_list *svms); void schedule_deferred_list_work(struct svm_range_list *svms);
void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr,
unsigned long offset, unsigned long npages); unsigned long offset, unsigned long npages);
void svm_range_free_dma_mappings(struct svm_range *prange); void svm_range_free_dma_mappings(struct svm_range *prange, bool unmap_dma);
int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
uint64_t *svm_priv_data_size); uint64_t *svm_priv_data_size);
int kfd_criu_checkpoint_svm(struct kfd_process *p, int kfd_criu_checkpoint_svm(struct kfd_process *p,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment