From d0e4dfd6efd651abc431aba9cfae5907638f8172 Mon Sep 17 00:00:00 2001 From: Debarshi Dutta Date: Fri, 23 Mar 2018 15:32:27 +0530 Subject: gpu: nvgpu: sync_framework cleanups This patch deals with cleanups meant to make things simpler for the upcoming os abstraction patches for the sync framework. This patch causes some substantial changes which are listed out as follows. 1) sync_timeline is moved out of gk20a_fence into struct nvgpu_channel_linux. New function pointers are created to facilitate os independent methods for enabling/disabling timeline and are now named as os_fence_framework. These function pointers are located in the struct os_channel under struct gk20a. 2) construction of the channel_sync require nvgpu_finalize_poweron_linux() to be invoked before invocations to nvgpu_init_mm_ce_context(). Hence, these methods are now moved away from gk20a_finalize_poweron() and invoked after nvgpu_finalize_poweron_linux(). 3) sync_fence creation is now delinked from fence construction and move to the channel_sync_gk20a's channel_incr methods. These sync_fences are mainly associated with post_fences. 4) In case userspace requires the sync_fences to be constructed, we try to obtain an fd before the gk20a_channel_submit_gpfifo() instead of trying to do that later. This is used to avoid potential after effects of duplicate work submission due to failure to obtain an unused fd. JIRA NVGPU-66 Change-Id: I42a3e4e2e692a113b1b36d2b48ab107ae4444dfa Signed-off-by: Debarshi Dutta Reviewed-on: https://git-master.nvidia.com/r/1678400 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/linux/channel.c | 79 ++++++++++++++++++++++++++ drivers/gpu/nvgpu/common/linux/channel.h | 15 ++++- drivers/gpu/nvgpu/common/linux/ioctl_channel.c | 21 +++++-- drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 21 +++++-- drivers/gpu/nvgpu/common/linux/module.c | 16 +++++- 5 files changed, 140 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/nvgpu/common') diff --git a/drivers/gpu/nvgpu/common/linux/channel.c b/drivers/gpu/nvgpu/common/linux/channel.c index a360d0df..8f2adc3a 100644 --- a/drivers/gpu/nvgpu/common/linux/channel.c +++ b/drivers/gpu/nvgpu/common/linux/channel.c @@ -40,6 +40,8 @@ #include #include +#include "gk20a/sync_gk20a.h" + u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags) { u32 flags = 0; @@ -292,6 +294,10 @@ static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch) ch->os_priv = priv; priv->ch = ch; +#ifdef CONFIG_SYNC + ch->has_os_fence_framework_support = true; +#endif + err = nvgpu_mutex_init(&priv->error_notifier.mutex); if (err) { nvgpu_kfree(g, priv); @@ -309,6 +315,64 @@ static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch) nvgpu_mutex_destroy(&priv->error_notifier.mutex); nvgpu_kfree(g, priv); + + ch->os_priv = NULL; + +#ifdef CONFIG_SYNC + ch->has_os_fence_framework_support = false; +#endif +} + +static int nvgpu_channel_init_os_fence_framework(struct channel_gk20a *ch, + const char *fmt, ...) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + struct nvgpu_os_fence_framework *fence_framework; + char name[30]; + va_list args; + + fence_framework = &priv->fence_framework; + + va_start(args, fmt); + vsnprintf(name, sizeof(name), fmt, args); + va_end(args); + + fence_framework->timeline = gk20a_sync_timeline_create(name); + + if (!fence_framework->timeline) + return -EINVAL; + + return 0; +} +static void nvgpu_channel_signal_os_fence_framework(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + struct nvgpu_os_fence_framework *fence_framework; + + fence_framework = &priv->fence_framework; + + gk20a_sync_timeline_signal(fence_framework->timeline); +} + +static void nvgpu_channel_destroy_os_fence_framework(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + struct nvgpu_os_fence_framework *fence_framework; + + fence_framework = &priv->fence_framework; + + gk20a_sync_timeline_destroy(fence_framework->timeline); + fence_framework->timeline = NULL; +} + +static bool nvgpu_channel_fence_framework_exists(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + struct nvgpu_os_fence_framework *fence_framework; + + fence_framework = &priv->fence_framework; + + return (fence_framework->timeline != NULL); } int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) @@ -332,6 +396,16 @@ int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) nvgpu_channel_work_completion_signal; g->os_channel.work_completion_cancel_sync = nvgpu_channel_work_completion_cancel_sync; + + g->os_channel.os_fence_framework_inst_exists = + nvgpu_channel_fence_framework_exists; + g->os_channel.init_os_fence_framework = + nvgpu_channel_init_os_fence_framework; + g->os_channel.signal_os_fence_framework = + nvgpu_channel_signal_os_fence_framework; + g->os_channel.destroy_os_fence_framework = + nvgpu_channel_destroy_os_fence_framework; + return 0; err_clean: @@ -354,6 +428,11 @@ void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l) nvgpu_channel_free_linux(g, ch); } + + g->os_channel.os_fence_framework_inst_exists = NULL; + g->os_channel.init_os_fence_framework = NULL; + g->os_channel.signal_os_fence_framework = NULL; + g->os_channel.destroy_os_fence_framework = NULL; } u32 nvgpu_get_gpfifo_entry_size(void) diff --git a/drivers/gpu/nvgpu/common/linux/channel.h b/drivers/gpu/nvgpu/common/linux/channel.h index d4cb6d55..805de55a 100644 --- a/drivers/gpu/nvgpu/common/linux/channel.h +++ b/drivers/gpu/nvgpu/common/linux/channel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -29,6 +29,9 @@ struct gk20a_fence; struct fifo_profile_gk20a; struct nvgpu_os_linux; +struct sync_fence; +struct sync_timeline; + struct nvgpu_channel_completion_cb { /* * Signal channel owner via a callback, if set, in job cleanup with @@ -52,9 +55,19 @@ struct nvgpu_error_notifier { struct nvgpu_mutex mutex; }; +/* + * This struct contains fence_related data. + * e.g. sync_timeline for sync_fences. + */ +struct nvgpu_os_fence_framework { + struct sync_timeline *timeline; +}; + struct nvgpu_channel_linux { struct channel_gk20a *ch; + struct nvgpu_os_fence_framework fence_framework; + struct nvgpu_channel_completion_cb completion_cb; struct nvgpu_error_notifier error_notifier; diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c index b4d7d501..06dfb180 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_channel.c @@ -774,6 +774,7 @@ static int gk20a_ioctl_channel_submit_gpfifo( struct gk20a_fence *fence_out; struct fifo_profile_gk20a *profile = NULL; u32 submit_flags = 0; + int fd = -1; int ret = 0; gk20a_dbg_fn(""); @@ -794,19 +795,31 @@ static int gk20a_ioctl_channel_submit_gpfifo( nvgpu_get_fence_args(&args->fence, &fence); submit_flags = nvgpu_submit_gpfifo_user_flags_to_common_flags(args->flags); + + /* Try and allocate an fd here*/ + if ((args->flags & NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_GET) + && (args->flags & NVGPU_SUBMIT_GPFIFO_FLAGS_SYNC_FENCE)) { + fd = get_unused_fd_flags(O_RDWR); + if (fd < 0) + return fd; + } + ret = gk20a_submit_channel_gpfifo(ch, NULL, args, args->num_entries, submit_flags, &fence, &fence_out, false, profile); - if (ret) + if (ret) { + if (fd != -1) + put_unused_fd(fd); goto clean_up; + } /* Convert fence_out to something we can pass back to user space. */ if (args->flags & NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_GET) { if (args->flags & NVGPU_SUBMIT_GPFIFO_FLAGS_SYNC_FENCE) { - int fd = gk20a_fence_install_fd(fence_out); - if (fd < 0) - ret = fd; + ret = gk20a_fence_install_fd(fence_out, fd); + if (ret) + put_unused_fd(fd); else args->fence.id = fd; } else { diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index e4b66460..70707a5c 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c @@ -344,10 +344,19 @@ static int gk20a_ctrl_prepare_compressible_read( struct gk20a_fence *fence_out = NULL; int submit_flags = nvgpu_submit_gpfifo_user_flags_to_common_flags( args->submit_flags); + int fd = -1; fence.id = args->fence.syncpt_id; fence.value = args->fence.syncpt_value; + /* Try and allocate an fd here*/ + if ((submit_flags & NVGPU_SUBMIT_FLAGS_FENCE_GET) + && (submit_flags & NVGPU_SUBMIT_FLAGS_SYNC_FENCE)) { + fd = get_unused_fd_flags(O_RDWR); + if (fd < 0) + return fd; + } + ret = gk20a_prepare_compressible_read(l, args->handle, args->request_compbits, args->offset, args->compbits_hoffset, args->compbits_voffset, @@ -356,20 +365,24 @@ static int gk20a_ctrl_prepare_compressible_read( submit_flags, &fence, &args->valid_compbits, &args->zbc_color, &fence_out); - if (ret) + if (ret) { + if (fd != -1) + put_unused_fd(fd); return ret; + } /* Convert fence_out to something we can pass back to user space. */ if (submit_flags & NVGPU_SUBMIT_FLAGS_FENCE_GET) { if (submit_flags & NVGPU_SUBMIT_FLAGS_SYNC_FENCE) { if (fence_out) { - int fd = gk20a_fence_install_fd(fence_out); - if (fd < 0) - ret = fd; + ret = gk20a_fence_install_fd(fence_out, fd); + if (ret) + put_unused_fd(fd); else args->fence.fd = fd; } else { args->fence.fd = -1; + put_unused_fd(fd); } } else { if (fence_out) { diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c index b9c9554b..81b3db82 100644 --- a/drivers/gpu/nvgpu/common/linux/module.c +++ b/drivers/gpu/nvgpu/common/linux/module.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "platform_gk20a.h" #include "sysfs.h" @@ -252,13 +253,22 @@ int gk20a_pm_finalize_poweron(struct device *dev) return err; err = gk20a_finalize_poweron(g); - set_user_nice(current, nice_value); - if (err) + if (err) { + set_user_nice(current, nice_value); goto done; + } err = nvgpu_finalize_poweron_linux(l); - if (err) + if (err) { + set_user_nice(current, nice_value); goto done; + } + + nvgpu_init_mm_ce_context(g); + + nvgpu_vidmem_thread_unpause(&g->mm); + + set_user_nice(current, nice_value); /* Initialise scaling: it will initialize scaling drive only once */ if (IS_ENABLED(CONFIG_GK20A_DEVFREQ) && -- cgit v1.2.2