From b67df491818b6f3ae5e54d11e9c34401c8c6ebc8 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 7 Apr 2022 17:09:39 +0100 Subject: [PATCH] nvdla: Fix build for CONFIG_FRAME_WARN=1024 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some 3rd party Linux distributions, set the kernel configuration option "CONFIG_FRAME_WARN=1024" which will causes the compiler to generate compilation errors when a functions stack frame size exceeds 1024 bytes. When compiling the DLA driver on Fedora the compilation fails with the following errors. drivers/video/tegra/host/nvdla/nvdla.o] Error 1 drivers/video/tegra/host/nvdla/nvdla_ioctl.c: In function ‘nvdla_emu_task_submit’: build/drivers/video/tegra/host/nvdla/nvdla_ioctl.c:918:1: error: the frame size of 1456 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] drivers/video/tegra/host/nvdla/nvdla_ioctl.c: In function ‘nvdla_submit’: drivers/video/tegra/host/nvdla/nvdla_ioctl.c:1118:1: error: the frame size of 1440 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Fix this by copying the user tasks from userspace one at a time and allocating the structure nvdla_emu_task dynamically so that is it not allocated on the stack. Bug 3524939 Change-Id: If752423a170c46efd9b6cffc458a7c1db1984afe Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2694097 Tested-by: Amit Sharma (SW-TEGRA) Reviewed-by: svc-mobile-coverity Reviewed-by: svc-mobile-cert Reviewed-by: Amit Sharma (SW-TEGRA) Reviewed-by: svc_kernel_abi Reviewed-by: Arvind M Reviewed-by: Praveen K GVS: Gerrit_Virtual_Submit --- drivers/video/tegra/host/nvdla/nvdla_ioctl.c | 67 ++++++++++---------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c index 021a2f08..cc0cea98 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c +++ b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c @@ -832,10 +832,10 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) struct nvdla_submit_args *args = (struct nvdla_submit_args *)arg; struct nvdla_ioctl_emu_submit_task __user *user_tasks; - struct nvdla_ioctl_emu_submit_task local_tasks[MAX_NVDLA_TASKS_PER_SUBMIT]; + struct nvdla_ioctl_emu_submit_task local_task; struct platform_device *pdev; struct nvdla_queue *queue; - struct nvdla_emu_task task; + struct nvdla_emu_task *task; int err = 0, i = 0; u32 num_tasks; @@ -849,8 +849,6 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_fn(pdev, "inside emulator task submit"); - task.queue = queue; - user_tasks = (struct nvdla_ioctl_emu_submit_task __user *) (uintptr_t)args->tasks; if (!user_tasks) @@ -862,40 +860,44 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_info(pdev, "num of emulator tasks [%d]", num_tasks); - /* IOCTL copy descriptors*/ - if (copy_from_user(local_tasks, (void __user *)user_tasks, - (num_tasks * sizeof(*user_tasks)))) { - err = -EFAULT; - goto exit; - } - nvdla_dbg_info(pdev, "copy of user tasks done"); + task = kmalloc(sizeof(*task), GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->queue = queue; for (i = 0; i < num_tasks; i++) { + /* IOCTL copy descriptor */ + if (copy_from_user(&local_task, (void __user *)&user_tasks[i], + sizeof(*user_tasks))) { + err = -EFAULT; + goto exit; + } nvdla_dbg_info(pdev, "submit [%d]th task", i + 1); - task.num_prefences = local_tasks[i].num_prefences; - task.num_postfences = local_tasks[i].num_postfences; + task->num_prefences = local_task.num_prefences; + task->num_postfences = local_task.num_postfences; /* get pre fences */ - if (copy_from_user(task.prefences, - (void __user *)local_tasks[i].prefences, - (task.num_prefences * sizeof(struct nvdev_fence)))) { + if (copy_from_user(task->prefences, + (void __user *)local_task.prefences, + (task->num_prefences * sizeof(struct nvdev_fence)))) { err = -EFAULT; nvdla_dbg_err(pdev, "failed to copy prefences"); goto exit; } /* get post fences */ - if (copy_from_user(task.postfences, - (void __user *)local_tasks[i].postfences, - (task.num_postfences * sizeof(struct nvdev_fence)))) { + if (copy_from_user(task->postfences, + (void __user *)local_task.postfences, + (task->num_postfences * sizeof(struct nvdev_fence)))) { err = -EFAULT; nvdla_dbg_err(pdev, "failed to copy postfences"); goto exit; } - err = nvdla_emulator_submit(queue, &task); + err = nvdla_emulator_submit(queue, task); if (err) { nvdla_dbg_err(pdev, "fail to submit task: %d", i + 1); goto exit; @@ -903,7 +905,7 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_info(pdev, "task[%d] submitted", i + 1); /* send signal fences to user */ - err = nvdla_send_emu_signal_fences(&task, local_tasks + i); + err = nvdla_send_emu_signal_fences(task, &local_task); if (err) { nvdla_dbg_err(pdev, "fail to send sig fence%d", i + 1); goto exit; @@ -914,6 +916,8 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_fn(pdev, "Emulator task submitted, done!"); exit: + kfree(task); + return 0; } @@ -986,7 +990,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) struct nvdla_submit_args *args = (struct nvdla_submit_args *)arg; struct nvdla_ioctl_submit_task __user *user_tasks; - struct nvdla_ioctl_submit_task local_tasks[MAX_NVDLA_TASKS_PER_SUBMIT]; + struct nvdla_ioctl_submit_task local_task; struct platform_device *pdev; struct nvdla_queue *queue; struct nvdla_buffers *buffers; @@ -1020,15 +1024,14 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) bypass_exec = ((args->flags & NVDLA_SUBMIT_FLAGS_BYPASS_EXEC) != 0U); nvdla_dbg_info(pdev, "submit flags [%u]", args->flags); - /* IOCTL copy descriptors*/ - if (copy_from_user(local_tasks, (void __user *)user_tasks, - (num_tasks * sizeof(*user_tasks)))) { - err = -EFAULT; - goto fail_to_copy_task; - } - nvdla_dbg_info(pdev, "copy of user tasks done"); - for (i = 0; i < num_tasks; i++) { + /* IOCTL copy descriptor */ + if (copy_from_user(&local_task, (void __user *)&user_tasks[i], + sizeof(*user_tasks))) { + err = -EFAULT; + goto fail_to_copy_task; + } + nvdla_dbg_info(pdev, "submit [%d]th task", i + 1); err = nvdla_get_task_mem(queue, &task); @@ -1042,7 +1045,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) kref_init(&task->ref); /* fill local task param from user args */ - err = nvdla_fill_task(queue, buffers, local_tasks + i, task); + err = nvdla_fill_task(queue, buffers, &local_task, task); if (err) { nvdla_dbg_err(pdev, "failed to fill task[%d]", i + 1); goto fail_to_fill_task; @@ -1075,7 +1078,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_info(pdev, "task[%d] got fences", i + 1); /* update fences to user */ - err = nvdla_update_signal_fences(task, local_tasks + i); + err = nvdla_update_signal_fences(task, &local_task); if (err) { nvdla_dbg_err(pdev, "fail update postfence%d", i + 1); goto fail_to_update_postfences;