nvdla: Fix build for CONFIG_FRAME_WARN=1024

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 <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2694097
Tested-by: Amit Sharma (SW-TEGRA) <amisharma@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Amit Sharma (SW-TEGRA) <amisharma@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Arvind M <am@nvidia.com>
Reviewed-by: Praveen K <kpraveen@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Jon Hunter
2022-04-07 17:09:39 +01:00
committed by Laxman Dewangan
parent 0b7fd59dca
commit b67df49181

View File

@@ -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 *args =
(struct nvdla_submit_args *)arg; (struct nvdla_submit_args *)arg;
struct nvdla_ioctl_emu_submit_task __user *user_tasks; 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 platform_device *pdev;
struct nvdla_queue *queue; struct nvdla_queue *queue;
struct nvdla_emu_task task; struct nvdla_emu_task *task;
int err = 0, i = 0; int err = 0, i = 0;
u32 num_tasks; 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"); nvdla_dbg_fn(pdev, "inside emulator task submit");
task.queue = queue;
user_tasks = (struct nvdla_ioctl_emu_submit_task __user *) user_tasks = (struct nvdla_ioctl_emu_submit_task __user *)
(uintptr_t)args->tasks; (uintptr_t)args->tasks;
if (!user_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); nvdla_dbg_info(pdev, "num of emulator tasks [%d]", num_tasks);
/* IOCTL copy descriptors*/ task = kmalloc(sizeof(*task), GFP_KERNEL);
if (copy_from_user(local_tasks, (void __user *)user_tasks, if (!task)
(num_tasks * sizeof(*user_tasks)))) { 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; err = -EFAULT;
goto exit; goto exit;
} }
nvdla_dbg_info(pdev, "copy of user tasks done");
for (i = 0; i < num_tasks; i++) {
nvdla_dbg_info(pdev, "submit [%d]th task", i + 1); nvdla_dbg_info(pdev, "submit [%d]th task", i + 1);
task.num_prefences = local_tasks[i].num_prefences; task->num_prefences = local_task.num_prefences;
task.num_postfences = local_tasks[i].num_postfences; task->num_postfences = local_task.num_postfences;
/* get pre fences */ /* get pre fences */
if (copy_from_user(task.prefences, if (copy_from_user(task->prefences,
(void __user *)local_tasks[i].prefences, (void __user *)local_task.prefences,
(task.num_prefences * sizeof(struct nvdev_fence)))) { (task->num_prefences * sizeof(struct nvdev_fence)))) {
err = -EFAULT; err = -EFAULT;
nvdla_dbg_err(pdev, "failed to copy prefences"); nvdla_dbg_err(pdev, "failed to copy prefences");
goto exit; goto exit;
} }
/* get post fences */ /* get post fences */
if (copy_from_user(task.postfences, if (copy_from_user(task->postfences,
(void __user *)local_tasks[i].postfences, (void __user *)local_task.postfences,
(task.num_postfences * sizeof(struct nvdev_fence)))) { (task->num_postfences * sizeof(struct nvdev_fence)))) {
err = -EFAULT; err = -EFAULT;
nvdla_dbg_err(pdev, "failed to copy postfences"); nvdla_dbg_err(pdev, "failed to copy postfences");
goto exit; goto exit;
} }
err = nvdla_emulator_submit(queue, &task); err = nvdla_emulator_submit(queue, task);
if (err) { if (err) {
nvdla_dbg_err(pdev, "fail to submit task: %d", i + 1); nvdla_dbg_err(pdev, "fail to submit task: %d", i + 1);
goto exit; 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); nvdla_dbg_info(pdev, "task[%d] submitted", i + 1);
/* send signal fences to user */ /* 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) { if (err) {
nvdla_dbg_err(pdev, "fail to send sig fence%d", i + 1); nvdla_dbg_err(pdev, "fail to send sig fence%d", i + 1);
goto exit; 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!"); nvdla_dbg_fn(pdev, "Emulator task submitted, done!");
exit: exit:
kfree(task);
return 0; 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 *args =
(struct nvdla_submit_args *)arg; (struct nvdla_submit_args *)arg;
struct nvdla_ioctl_submit_task __user *user_tasks; 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 platform_device *pdev;
struct nvdla_queue *queue; struct nvdla_queue *queue;
struct nvdla_buffers *buffers; 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); bypass_exec = ((args->flags & NVDLA_SUBMIT_FLAGS_BYPASS_EXEC) != 0U);
nvdla_dbg_info(pdev, "submit flags [%u]", args->flags); nvdla_dbg_info(pdev, "submit flags [%u]", args->flags);
/* IOCTL copy descriptors*/ for (i = 0; i < num_tasks; i++) {
if (copy_from_user(local_tasks, (void __user *)user_tasks, /* IOCTL copy descriptor */
(num_tasks * sizeof(*user_tasks)))) { if (copy_from_user(&local_task, (void __user *)&user_tasks[i],
sizeof(*user_tasks))) {
err = -EFAULT; err = -EFAULT;
goto fail_to_copy_task; goto fail_to_copy_task;
} }
nvdla_dbg_info(pdev, "copy of user tasks done");
for (i = 0; i < num_tasks; i++) {
nvdla_dbg_info(pdev, "submit [%d]th task", i + 1); nvdla_dbg_info(pdev, "submit [%d]th task", i + 1);
err = nvdla_get_task_mem(queue, &task); 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); kref_init(&task->ref);
/* fill local task param from user args */ /* 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) { if (err) {
nvdla_dbg_err(pdev, "failed to fill task[%d]", i + 1); nvdla_dbg_err(pdev, "failed to fill task[%d]", i + 1);
goto fail_to_fill_task; 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); nvdla_dbg_info(pdev, "task[%d] got fences", i + 1);
/* update fences to user */ /* update fences to user */
err = nvdla_update_signal_fences(task, local_tasks + i); err = nvdla_update_signal_fences(task, &local_task);
if (err) { if (err) {
nvdla_dbg_err(pdev, "fail update postfence%d", i + 1); nvdla_dbg_err(pdev, "fail update postfence%d", i + 1);
goto fail_to_update_postfences; goto fail_to_update_postfences;