diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c index d0648cdc7..079e48dba 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c @@ -1344,11 +1344,43 @@ long gk20a_channel_ioctl(struct file *filp, break; } + /* + * This restriction is because the last entry is kept empty and used to + * determine buffer empty or full condition. Additionally, kmd submit + * uses pre/post sync which need another entry. + */ + if ((setup_bind_args.flags & + NVGPU_CHANNEL_SETUP_BIND_FLAGS_USERMODE_SUPPORT) != 0U) { + if (setup_bind_args.num_gpfifo_entries < 2U) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + } else { + if (setup_bind_args.num_gpfifo_entries < 4U) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + } + if (!is_power_of_2(setup_bind_args.num_gpfifo_entries)) { err = -EINVAL; gk20a_idle(ch->g); break; } + + /* + * setup_bind_args.num_gpfifo_entries * nvgpu_get_gpfifo_entry_size() has + * to fit in u32. + */ + if (setup_bind_args.num_gpfifo_entries > + (U32_MAX / nvgpu_get_gpfifo_entry_size())) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + err = nvgpu_channel_setup_bind(ch, &setup_bind_args); channel_setup_bind_args->work_submit_token = setup_bind_args.work_submit_token; @@ -1371,11 +1403,44 @@ long gk20a_channel_ioctl(struct file *filp, break; } + /* + * This restriction is because the last entry is kept empty and used to + * determine buffer empty or full condition. Additionally, kmd submit + * uses pre/post sync which need another entry. + */ + if ((alloc_gpfifo_ex_args->flags & + NVGPU_CHANNEL_SETUP_BIND_FLAGS_USERMODE_SUPPORT) != 0U) { + if (alloc_gpfifo_ex_args->num_entries < 2U) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + } else { + if (alloc_gpfifo_ex_args->num_entries < 4U) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + } + + if (!is_power_of_2(alloc_gpfifo_ex_args->num_entries)) { err = -EINVAL; gk20a_idle(ch->g); break; } + + /* + * alloc_gpfifo_ex_args->num_entries * nvgpu_get_gpfifo_entry_size() has + * to fit in u32. + */ + if (alloc_gpfifo_ex_args->num_entries > + (U32_MAX / nvgpu_get_gpfifo_entry_size())) { + err = -EINVAL; + gk20a_idle(ch->g); + break; + } + err = nvgpu_channel_setup_bind(ch, &setup_bind_args); gk20a_idle(ch->g); break; diff --git a/include/uapi/linux/nvgpu.h b/include/uapi/linux/nvgpu.h index 59228b94e..5ea58a13a 100644 --- a/include/uapi/linux/nvgpu.h +++ b/include/uapi/linux/nvgpu.h @@ -694,6 +694,16 @@ struct nvgpu_alloc_gpfifo_ex_args { * Setup the channel and bind it (enable). */ struct nvgpu_channel_setup_bind_args { +/* + * Must be power of 2. Max value U32_MAX/8 (size of gpfifo entry) rounded of to + * nearest lower power of 2 i.e. 2^28. The lower limit is due to the fact that + * the last entry of gpfifo is kept empty and used to determine buffer empty or + * full condition. Additionally, kmd submit uses pre/post sync which needs + * another extra entry. + * Range: 2, 4, 8, ..., 2^28 when + * NVGPU_CHANNEL_SETUP_BIND_FLAGS_USERMODE_SUPPORT is set. + * Range: 4, 8, 16, ..., 2^28 otherwise. + */ __u32 num_gpfifo_entries; __u32 num_inflight_jobs; /* Set owner channel of this gpfifo as a vpr channel. */