gpu: nvgpu: fix REMAP to support small/big pages

Initially, REMAP only worked with big pages but in some cases
only small pages are supported where REMAP functionality is
also needed.

This cleans up some page size assumptions. In particular, on a
remap request, the nvgpu_vm_area is found from the passed in VA,
but can only be done from virt_offset_in_pages if we're also
told the page size.

This now occurs from _PAGESIZE_ flags which are required by
both map and unmap operations.

Jira NVGPU-6804

Change-Id: I311980a1b5e0e5e1840bdc1123479350a5c9d469
Signed-off-by: Chris Johnson <cwj@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2566087
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Chris Johnson
2022-01-16 19:28:26 -08:00
committed by mobile promotions
parent 359e83b45a
commit 14ed75e857
5 changed files with 124 additions and 66 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -157,23 +157,50 @@ void nvgpu_vm_remap_os_buf_put(struct vm_gk20a *vm,
static int nvgpu_vm_remap_validate_map_op(struct nvgpu_as_remap_op *op)
{
int err = 0;
u32 valid_flags = (NVGPU_AS_REMAP_OP_FLAGS_CACHEABLE |
const u32 pagesize_flags = (NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_4K |
NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_64K |
NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_128K);
const u32 valid_flags = (pagesize_flags |
NVGPU_AS_REMAP_OP_FLAGS_CACHEABLE |
NVGPU_AS_REMAP_OP_FLAGS_ACCESS_NO_WRITE);
const u32 pagesize = op->flags & pagesize_flags;
if ((op->flags & ~valid_flags) != 0) {
err = -EINVAL;
}
/* must be set and to a single pagesize */
if ((pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_4K) &&
(pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_64K) &&
(pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_128K)) {
err = -EINVAL;
}
return err;
}
static int nvgpu_vm_remap_validate_unmap_op(struct nvgpu_as_remap_op *op)
{
int err = 0;
const u32 pagesize_flags = (NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_4K |
NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_64K |
NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_128K);
const u32 valid_flags = pagesize_flags;
const u32 pagesize = op->flags & pagesize_flags;
if ((op->flags & ~valid_flags) != 0) {
err = -EINVAL;
}
/* must be set and to a single pagesize */
if ((pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_4K) &&
(pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_64K) &&
(pagesize != NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_128K)) {
err = -EINVAL;
}
if ((op->compr_kind != NVGPU_KIND_INVALID) ||
(op->incompr_kind != NVGPU_KIND_INVALID) ||
(op->flags != 0) ||
(op->mem_offset_in_pages != 0)) {
err = -EINVAL;
}
@@ -191,7 +218,15 @@ static u32 nvgpu_vm_remap_translate_as_flags(u32 flags)
if ((flags & NVGPU_AS_REMAP_OP_FLAGS_ACCESS_NO_WRITE) != 0) {
core_flags |= NVGPU_VM_REMAP_OP_FLAGS_ACCESS_NO_WRITE;
}
if ((flags & NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_4K) != 0) {
core_flags |= NVGPU_VM_REMAP_OP_FLAGS_PAGESIZE_4K;
}
if ((flags & NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_64K) != 0) {
core_flags |= NVGPU_VM_REMAP_OP_FLAGS_PAGESIZE_64K;
}
if ((flags & NVGPU_AS_REMAP_OP_FLAGS_PAGESIZE_128K) != 0) {
core_flags |= NVGPU_VM_REMAP_OP_FLAGS_PAGESIZE_128K;
}
return core_flags;
}
@@ -201,7 +236,6 @@ int nvgpu_vm_remap_translate_as_op(struct vm_gk20a *vm,
{
int err = 0;
u64 page_size;
u64 max_num_pages;
if (as_op->mem_handle == 0) {
err = nvgpu_vm_remap_validate_unmap_op(as_op);
@@ -212,18 +246,17 @@ int nvgpu_vm_remap_translate_as_op(struct vm_gk20a *vm,
if (err != 0)
goto clean_up;
page_size = vm->gmmu_page_sizes[GMMU_PAGE_SIZE_BIG];
max_num_pages = (ULONG_MAX / page_size);
vm_op->flags = nvgpu_vm_remap_translate_as_flags(as_op->flags);
page_size = nvgpu_vm_remap_page_size(vm_op);
if ((as_op->num_pages == 0) ||
(as_op->num_pages > max_num_pages) ||
(as_op->mem_offset_in_pages > max_num_pages) ||
(as_op->virt_offset_in_pages > max_num_pages)) {
if ((as_op->num_pages == 0) || (page_size == 0) ||
(as_op->num_pages > (vm->va_limit / page_size)) ||
(as_op->mem_offset_in_pages > (vm->va_limit / page_size)) ||
(as_op->virt_offset_in_pages > (vm->va_limit / page_size))) {
err = -EINVAL;
goto clean_up;
}
vm_op->flags = nvgpu_vm_remap_translate_as_flags(as_op->flags);
vm_op->compr_kind = as_op->compr_kind;
vm_op->incompr_kind = as_op->incompr_kind;
vm_op->mem_handle = as_op->mem_handle;