mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: add dma_fence semaphore support
Support exporting and importing semaphore-based synchronization with the stable dma-fence API. The "Android" sync fence API used until now is deprecated. The Android sync framework is still kept as the default. Jira NVGPU-5353 Change-Id: I9e57947adeb4d2ef5d59135ed7d008553c44f97c Signed-off-by: Konsta Hölttä <kholtta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2336119 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
Alex Waterman
parent
7d6645d7af
commit
23d6b36101
@@ -144,8 +144,13 @@ fence:
|
|||||||
sources: [ os/linux/os_fence_android.c,
|
sources: [ os/linux/os_fence_android.c,
|
||||||
os/linux/os_fence_android_sema.c,
|
os/linux/os_fence_android_sema.c,
|
||||||
os/linux/os_fence_android_syncpt.c,
|
os/linux/os_fence_android_syncpt.c,
|
||||||
|
os/linux/os_fence_dma.c,
|
||||||
|
os/linux/os_fence_dma_sema.c,
|
||||||
|
os/linux/os_fence_dma_syncpt.c,
|
||||||
os/linux/sync_sema_android.c,
|
os/linux/sync_sema_android.c,
|
||||||
os/linux/sync_sema_android.h,
|
os/linux/sync_sema_android.h,
|
||||||
|
os/linux/sync_sema_dma.c,
|
||||||
|
os/linux/sync_sema_dma.h,
|
||||||
include/nvgpu/os_fence.h,
|
include/nvgpu/os_fence.h,
|
||||||
include/nvgpu/os_fence_semas.h,
|
include/nvgpu/os_fence_semas.h,
|
||||||
include/nvgpu/os_fence_syncpts.h ]
|
include/nvgpu/os_fence_syncpts.h ]
|
||||||
@@ -228,6 +233,7 @@ headers:
|
|||||||
include/nvgpu/linux/bitops.h,
|
include/nvgpu/linux/bitops.h,
|
||||||
include/nvgpu/linux/nvgpu_mem.h,
|
include/nvgpu/linux/nvgpu_mem.h,
|
||||||
include/nvgpu/linux/os_fence_android.h,
|
include/nvgpu/linux/os_fence_android.h,
|
||||||
|
include/nvgpu/linux/os_fence_dma.h,
|
||||||
include/nvgpu/linux/rwsem.h,
|
include/nvgpu/linux/rwsem.h,
|
||||||
include/nvgpu/linux/sim.h,
|
include/nvgpu/linux/sim.h,
|
||||||
include/nvgpu/linux/sim_pci.h,
|
include/nvgpu/linux/sim_pci.h,
|
||||||
|
|||||||
@@ -246,6 +246,13 @@ choice
|
|||||||
Select which kernel-provided API is used for sync fds. Matching
|
Select which kernel-provided API is used for sync fds. Matching
|
||||||
support is required for the userspace drivers too.
|
support is required for the userspace drivers too.
|
||||||
|
|
||||||
|
config NVGPU_SYNCFD_STABLE
|
||||||
|
bool "Upstream stabilized SYNC_FILE"
|
||||||
|
depends on SYNC_FILE
|
||||||
|
help
|
||||||
|
Select CONFIG_SYNC_FILE, the cross-driver "Explicit Synchronization
|
||||||
|
Framework" stabilized upstream from the Android sync since v4.9.
|
||||||
|
|
||||||
config NVGPU_SYNCFD_ANDROID
|
config NVGPU_SYNCFD_ANDROID
|
||||||
bool "Android SYNC"
|
bool "Android SYNC"
|
||||||
depends on SYNC
|
depends on SYNC
|
||||||
|
|||||||
@@ -444,9 +444,16 @@ nvgpu-$(CONFIG_NVGPU_SYNCFD_ANDROID) += \
|
|||||||
os/linux/os_fence_android.o \
|
os/linux/os_fence_android.o \
|
||||||
os/linux/os_fence_android_sema.o
|
os/linux/os_fence_android_sema.o
|
||||||
|
|
||||||
|
nvgpu-$(CONFIG_NVGPU_SYNCFD_STABLE) += \
|
||||||
|
os/linux/sync_sema_dma.o \
|
||||||
|
os/linux/os_fence_dma.o \
|
||||||
|
os/linux/os_fence_dma_sema.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_TEGRA_GK20A_NVHOST), y)
|
ifeq ($(CONFIG_TEGRA_GK20A_NVHOST), y)
|
||||||
nvgpu-$(CONFIG_NVGPU_SYNCFD_ANDROID) += \
|
nvgpu-$(CONFIG_NVGPU_SYNCFD_ANDROID) += \
|
||||||
os/linux/os_fence_android_syncpt.o
|
os/linux/os_fence_android_syncpt.o
|
||||||
|
nvgpu-$(CONFIG_NVGPU_SYNCFD_STABLE) += \
|
||||||
|
os/linux/os_fence_dma_syncpt.o
|
||||||
nvgpu-y += common/sync/channel_sync_syncpt.o
|
nvgpu-y += common/sync/channel_sync_syncpt.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -980,8 +980,9 @@ void nvgpu_channel_clean_up_jobs(struct nvgpu_channel *c,
|
|||||||
|
|
||||||
if (c->sync != NULL) {
|
if (c->sync != NULL) {
|
||||||
if (c->has_os_fence_framework_support &&
|
if (c->has_os_fence_framework_support &&
|
||||||
g->os_channel.os_fence_framework_inst_exists(c)) {
|
g->os_channel.os_fence_framework_inst_exists(c)) {
|
||||||
g->os_channel.signal_os_fence_framework(c);
|
g->os_channel.signal_os_fence_framework(c,
|
||||||
|
job->post_fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g->aggressive_sync_destroy_thresh != 0U) {
|
if (g->aggressive_sync_destroy_thresh != 0U) {
|
||||||
|
|||||||
@@ -904,7 +904,8 @@ struct gk20a {
|
|||||||
bool (*os_fence_framework_inst_exists)(struct nvgpu_channel *ch);
|
bool (*os_fence_framework_inst_exists)(struct nvgpu_channel *ch);
|
||||||
int (*init_os_fence_framework)(
|
int (*init_os_fence_framework)(
|
||||||
struct nvgpu_channel *ch, const char *fmt, ...);
|
struct nvgpu_channel *ch, const char *fmt, ...);
|
||||||
void (*signal_os_fence_framework)(struct nvgpu_channel *ch);
|
void (*signal_os_fence_framework)(struct nvgpu_channel *ch,
|
||||||
|
struct nvgpu_fence_type *fence);
|
||||||
void (*destroy_os_fence_framework)(struct nvgpu_channel *ch);
|
void (*destroy_os_fence_framework)(struct nvgpu_channel *ch);
|
||||||
int (*copy_user_gpfifo)(struct nvgpu_gpfifo_entry *dest,
|
int (*copy_user_gpfifo)(struct nvgpu_gpfifo_entry *dest,
|
||||||
struct nvgpu_gpfifo_userdata userdata,
|
struct nvgpu_gpfifo_userdata userdata,
|
||||||
|
|||||||
48
drivers/gpu/nvgpu/include/nvgpu/linux/os_fence_dma.h
Normal file
48
drivers/gpu/nvgpu/include/nvgpu/linux/os_fence_dma.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NVGPU_LINUX_OS_FENCE_DMA_H
|
||||||
|
#define NVGPU_LINUX_OS_FENCE_DMA_H
|
||||||
|
|
||||||
|
struct gk20a;
|
||||||
|
struct nvgpu_os_fence;
|
||||||
|
struct dma_fence;
|
||||||
|
struct nvgpu_channel;
|
||||||
|
|
||||||
|
struct dma_fence *nvgpu_get_dma_fence(struct nvgpu_os_fence *s);
|
||||||
|
|
||||||
|
void nvgpu_os_fence_dma_drop_ref(struct nvgpu_os_fence *s);
|
||||||
|
|
||||||
|
int nvgpu_os_fence_sema_fdget(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, int fd);
|
||||||
|
|
||||||
|
void nvgpu_os_fence_init(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct gk20a *g, const struct nvgpu_os_fence_ops *fops,
|
||||||
|
struct dma_fence *fence);
|
||||||
|
|
||||||
|
void nvgpu_os_fence_dma_install_fd(struct nvgpu_os_fence *s, int fd);
|
||||||
|
|
||||||
|
int nvgpu_os_fence_syncpt_fdget(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, int fd);
|
||||||
|
|
||||||
|
#endif /* NVGPU_LINUX_OS_FENCE_DMA_H */
|
||||||
|
|
||||||
@@ -56,11 +56,16 @@ struct nvgpu_error_notifier {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This struct contains fence_related data.
|
* channel-global data for sync fences created from the hardware
|
||||||
* e.g. sync_timeline for sync_fences.
|
* synchronization primitive in each particular channel.
|
||||||
*/
|
*/
|
||||||
struct nvgpu_os_fence_framework {
|
struct nvgpu_os_fence_framework {
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_ANDROID)
|
||||||
struct sync_timeline *timeline;
|
struct sync_timeline *timeline;
|
||||||
|
#elif defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
u64 context;
|
||||||
|
bool exists;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvgpu_usermode_bufs_linux {
|
struct nvgpu_usermode_bufs_linux {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <nvgpu/gk20a.h>
|
#include <nvgpu/gk20a.h>
|
||||||
#include <nvgpu/channel.h>
|
#include <nvgpu/channel.h>
|
||||||
#include <nvgpu/dma.h>
|
#include <nvgpu/dma.h>
|
||||||
|
#include <nvgpu/fence.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is required for nvgpu_vm_find_buf() which is used in the tracing
|
* This is required for nvgpu_vm_find_buf() which is used in the tracing
|
||||||
@@ -43,6 +44,8 @@
|
|||||||
#include <uapi/linux/nvgpu.h>
|
#include <uapi/linux/nvgpu.h>
|
||||||
|
|
||||||
#include "sync_sema_android.h"
|
#include "sync_sema_android.h"
|
||||||
|
#include "sync_sema_dma.h"
|
||||||
|
#include <nvgpu/linux/os_fence_dma.h>
|
||||||
|
|
||||||
u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags)
|
u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags)
|
||||||
{
|
{
|
||||||
@@ -330,21 +333,42 @@ static int nvgpu_channel_init_os_fence_framework(struct nvgpu_channel *ch,
|
|||||||
(void) vsnprintf(name, sizeof(name), fmt, args);
|
(void) vsnprintf(name, sizeof(name), fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_ANDROID)
|
||||||
fence_framework->timeline = gk20a_sync_timeline_create(name);
|
fence_framework->timeline = gk20a_sync_timeline_create(name);
|
||||||
|
|
||||||
if (!fence_framework->timeline)
|
if (!fence_framework->timeline)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
#elif defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
fence_framework->context = nvgpu_sync_dma_context_create();
|
||||||
|
fence_framework->exists = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static void nvgpu_channel_signal_os_fence_framework(struct nvgpu_channel *ch)
|
static void nvgpu_channel_signal_os_fence_framework(struct nvgpu_channel *ch,
|
||||||
|
struct nvgpu_fence_type *fence)
|
||||||
{
|
{
|
||||||
struct nvgpu_channel_linux *priv = ch->os_priv;
|
struct nvgpu_channel_linux *priv = ch->os_priv;
|
||||||
struct nvgpu_os_fence_framework *fence_framework;
|
struct nvgpu_os_fence_framework *fence_framework;
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
struct dma_fence *f;
|
||||||
|
#endif
|
||||||
|
|
||||||
fence_framework = &priv->fence_framework;
|
fence_framework = &priv->fence_framework;
|
||||||
|
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_ANDROID)
|
||||||
gk20a_sync_timeline_signal(fence_framework->timeline);
|
gk20a_sync_timeline_signal(fence_framework->timeline);
|
||||||
|
#elif defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
f = nvgpu_get_dma_fence(&fence->os_fence);
|
||||||
|
/*
|
||||||
|
* Sometimes the post fence of a job isn't a file. It can be a raw
|
||||||
|
* semaphore for kernel-internal tracking, or a raw syncpoint for
|
||||||
|
* internal tracking or for exposing to user.
|
||||||
|
*/
|
||||||
|
if (f != NULL) {
|
||||||
|
nvgpu_sync_dma_signal(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvgpu_channel_destroy_os_fence_framework(struct nvgpu_channel *ch)
|
static void nvgpu_channel_destroy_os_fence_framework(struct nvgpu_channel *ch)
|
||||||
@@ -354,8 +378,13 @@ static void nvgpu_channel_destroy_os_fence_framework(struct nvgpu_channel *ch)
|
|||||||
|
|
||||||
fence_framework = &priv->fence_framework;
|
fence_framework = &priv->fence_framework;
|
||||||
|
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_ANDROID)
|
||||||
gk20a_sync_timeline_destroy(fence_framework->timeline);
|
gk20a_sync_timeline_destroy(fence_framework->timeline);
|
||||||
fence_framework->timeline = NULL;
|
fence_framework->timeline = NULL;
|
||||||
|
#elif defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
/* fence_framework->context cannot be freed, see linux/dma-fence.h */
|
||||||
|
fence_framework->exists = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nvgpu_channel_fence_framework_exists(struct nvgpu_channel *ch)
|
static bool nvgpu_channel_fence_framework_exists(struct nvgpu_channel *ch)
|
||||||
@@ -365,7 +394,13 @@ static bool nvgpu_channel_fence_framework_exists(struct nvgpu_channel *ch)
|
|||||||
|
|
||||||
fence_framework = &priv->fence_framework;
|
fence_framework = &priv->fence_framework;
|
||||||
|
|
||||||
|
#if defined(CONFIG_NVGPU_SYNCFD_ANDROID)
|
||||||
return (fence_framework->timeline != NULL);
|
return (fence_framework->timeline != NULL);
|
||||||
|
#elif defined(CONFIG_NVGPU_SYNCFD_STABLE)
|
||||||
|
return fence_framework->exists;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvgpu_channel_copy_user_gpfifo(struct nvgpu_gpfifo_entry *dest,
|
static int nvgpu_channel_copy_user_gpfifo(struct nvgpu_gpfifo_entry *dest,
|
||||||
|
|||||||
85
drivers/gpu/nvgpu/os/linux/os_fence_dma.c
Normal file
85
drivers/gpu/nvgpu/os/linux/os_fence_dma.c
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
#include <nvgpu/os_fence.h>
|
||||||
|
#include <nvgpu/linux/os_fence_dma.h>
|
||||||
|
#include <nvgpu/channel.h>
|
||||||
|
#include <nvgpu/nvhost.h>
|
||||||
|
|
||||||
|
#include <linux/dma-fence.h>
|
||||||
|
#include <linux/sync_file.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
|
||||||
|
inline struct dma_fence *nvgpu_get_dma_fence(struct nvgpu_os_fence *s)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = (struct dma_fence *)s->priv;
|
||||||
|
return fence;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nvgpu_os_fence_clear(struct nvgpu_os_fence *fence_out)
|
||||||
|
{
|
||||||
|
fence_out->priv = NULL;
|
||||||
|
fence_out->g = NULL;
|
||||||
|
fence_out->ops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_os_fence_init(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct gk20a *g, const struct nvgpu_os_fence_ops *fops,
|
||||||
|
struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
fence_out->g = g;
|
||||||
|
fence_out->ops = fops;
|
||||||
|
fence_out->priv = (void *)fence;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_os_fence_dma_drop_ref(struct nvgpu_os_fence *s)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = nvgpu_get_dma_fence(s);
|
||||||
|
|
||||||
|
dma_fence_put(fence);
|
||||||
|
|
||||||
|
nvgpu_os_fence_clear(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_os_fence_dma_install_fd(struct nvgpu_os_fence *s, int fd)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = nvgpu_get_dma_fence(s);
|
||||||
|
struct sync_file *file = sync_file_create(fence);
|
||||||
|
|
||||||
|
fd_install(fd, file->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvgpu_os_fence_fdget(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, int fd)
|
||||||
|
{
|
||||||
|
int err = -ENOSYS;
|
||||||
|
|
||||||
|
#ifdef CONFIG_TEGRA_GK20A_NVHOST
|
||||||
|
if (nvgpu_has_syncpoints(c->g)) {
|
||||||
|
err = nvgpu_os_fence_syncpt_fdget(fence_out, c, fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
err = nvgpu_os_fence_sema_fdget(fence_out, c, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(c->g, "error obtaining fence from fd %d", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
87
drivers/gpu/nvgpu/os/linux/os_fence_dma_sema.c
Normal file
87
drivers/gpu/nvgpu/os/linux/os_fence_dma_sema.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nvgpu/errno.h>
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
#include <nvgpu/os_fence.h>
|
||||||
|
#include <nvgpu/os_fence_semas.h>
|
||||||
|
#include <nvgpu/linux/os_fence_dma.h>
|
||||||
|
#include <nvgpu/semaphore.h>
|
||||||
|
#include <nvgpu/gk20a.h>
|
||||||
|
#include <nvgpu/channel.h>
|
||||||
|
|
||||||
|
#include "sync_sema_dma.h"
|
||||||
|
|
||||||
|
static const struct nvgpu_os_fence_ops sema_ops = {
|
||||||
|
.drop_ref = nvgpu_os_fence_dma_drop_ref,
|
||||||
|
.install_fence = nvgpu_os_fence_dma_install_fd,
|
||||||
|
};
|
||||||
|
|
||||||
|
int nvgpu_os_fence_get_semas(struct nvgpu_os_fence_sema *fence_sema_out,
|
||||||
|
struct nvgpu_os_fence *fence_in)
|
||||||
|
{
|
||||||
|
if (fence_in->ops != &sema_ops) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fence_sema_out->fence = fence_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nvgpu_os_fence_sema_get_num_semaphores(struct nvgpu_os_fence_sema *fence)
|
||||||
|
{
|
||||||
|
struct dma_fence *f = nvgpu_get_dma_fence(fence->fence);
|
||||||
|
|
||||||
|
return nvgpu_dma_fence_length(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_os_fence_sema_extract_nth_semaphore(
|
||||||
|
struct nvgpu_os_fence_sema *fence, u32 n,
|
||||||
|
struct nvgpu_semaphore **semaphore_out)
|
||||||
|
{
|
||||||
|
struct dma_fence *f = nvgpu_get_dma_fence(fence->fence);
|
||||||
|
|
||||||
|
*semaphore_out = nvgpu_dma_fence_nth(f, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvgpu_os_fence_sema_create(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, struct nvgpu_semaphore *sema)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = nvgpu_sync_dma_create(c, sema);
|
||||||
|
|
||||||
|
if (!fence) {
|
||||||
|
nvgpu_err(c->g, "error constructing new fence");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvgpu_os_fence_init(fence_out, c->g, &sema_ops, fence);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvgpu_os_fence_sema_fdget(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, int fd)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = nvgpu_sync_dma_fence_fdget(fd);
|
||||||
|
|
||||||
|
if (fence == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nvgpu_os_fence_init(fence_out, c->g, &sema_ops, fence);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
70
drivers/gpu/nvgpu/os/linux/os_fence_dma_syncpt.c
Normal file
70
drivers/gpu/nvgpu/os/linux/os_fence_dma_syncpt.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nvgpu/errno.h>
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
#include <nvgpu/os_fence.h>
|
||||||
|
#include <nvgpu/os_fence_syncpts.h>
|
||||||
|
#include <nvgpu/linux/os_fence_dma.h>
|
||||||
|
#include <nvgpu/nvhost.h>
|
||||||
|
#include <nvgpu/gk20a.h>
|
||||||
|
#include <nvgpu/channel.h>
|
||||||
|
|
||||||
|
static const struct nvgpu_os_fence_ops syncpt_ops = {
|
||||||
|
.drop_ref = nvgpu_os_fence_dma_drop_ref,
|
||||||
|
.install_fence = nvgpu_os_fence_dma_install_fd,
|
||||||
|
};
|
||||||
|
|
||||||
|
int nvgpu_os_fence_syncpt_create(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, struct nvgpu_nvhost_dev *nvhost_dev,
|
||||||
|
u32 id, u32 thresh)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvgpu_os_fence_syncpt_fdget(struct nvgpu_os_fence *fence_out,
|
||||||
|
struct nvgpu_channel *c, int fd)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvgpu_os_fence_get_syncpts(struct nvgpu_os_fence_syncpt *fence_syncpt_out,
|
||||||
|
struct nvgpu_os_fence *fence_in)
|
||||||
|
{
|
||||||
|
if (fence_in->ops != &syncpt_ops) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fence_syncpt_out->fence = fence_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nvgpu_os_fence_syncpt_get_num_syncpoints(
|
||||||
|
struct nvgpu_os_fence_syncpt *fence)
|
||||||
|
{
|
||||||
|
WARN(1, "can't get here until nvhost support exists");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_os_fence_syncpt_extract_nth_syncpt(
|
||||||
|
struct nvgpu_os_fence_syncpt *fence, u32 n,
|
||||||
|
u32 *syncpt_id, u32 *syncpt_threshold)
|
||||||
|
{
|
||||||
|
WARN(1, "can't get here until nvhost support exists");
|
||||||
|
*syncpt_id = 0;
|
||||||
|
*syncpt_threshold = 0;
|
||||||
|
}
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _GK20A_SYNC_H_
|
#ifndef NVGPU_OS_LINUX_SYNC_SEMA_ANDROID_H
|
||||||
#define _GK20A_SYNC_H_
|
#define NVGPU_OS_LINUX_SYNC_SEMA_ANDROID_H
|
||||||
|
|
||||||
struct sync_timeline;
|
struct sync_timeline;
|
||||||
struct sync_fence;
|
struct sync_fence;
|
||||||
|
|||||||
240
drivers/gpu/nvgpu/os/linux/sync_sema_dma.c
Normal file
240
drivers/gpu/nvgpu/os/linux/sync_sema_dma.c
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Semaphore Sync Framework Integration
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, 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,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nvgpu/gk20a.h>
|
||||||
|
#include <nvgpu/semaphore.h>
|
||||||
|
|
||||||
|
#include "channel.h"
|
||||||
|
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/sync_file.h>
|
||||||
|
#include <linux/dma-fence.h>
|
||||||
|
#include <linux/dma-fence-array.h>
|
||||||
|
|
||||||
|
struct nvgpu_dma_fence {
|
||||||
|
struct dma_fence base;
|
||||||
|
spinlock_t lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The origin of this sema (a channel) can get closed before this fence
|
||||||
|
* gets freed. This sema would still hold a reference to the pool where
|
||||||
|
* it was allocated from. Another channel may safely get the same sema
|
||||||
|
* location from the pool; the sema will be and stay expired here.
|
||||||
|
*/
|
||||||
|
struct nvgpu_semaphore *sema;
|
||||||
|
struct gk20a *g;
|
||||||
|
char timeline_name[16]; /* "ch%d-user" */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nvgpu_dma_fence *to_nvgpu_dma_fence(struct dma_fence *fence);
|
||||||
|
|
||||||
|
static const char *nvgpu_dma_fence_get_driver_name(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *nvfence = to_nvgpu_dma_fence(fence);
|
||||||
|
|
||||||
|
return nvfence->g->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *nvgpu_dma_fence_get_timeline_name(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *nvfence = to_nvgpu_dma_fence(fence);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This shouldn't end with a digit because the caller appends the
|
||||||
|
* context number which would then be confusing.
|
||||||
|
*/
|
||||||
|
return nvfence->timeline_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nvgpu_dma_fence_enable_signaling(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *f = to_nvgpu_dma_fence(fence);
|
||||||
|
|
||||||
|
if (nvgpu_semaphore_is_released(f->sema))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* signaling of all semas is always enabled */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nvgpu_dma_fence_signaled(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *f = to_nvgpu_dma_fence(fence);
|
||||||
|
|
||||||
|
return nvgpu_semaphore_is_released(f->sema);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nvgpu_dma_fence_release(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *f = to_nvgpu_dma_fence(fence);
|
||||||
|
struct gk20a *g = f->g;
|
||||||
|
|
||||||
|
nvgpu_semaphore_put(f->sema);
|
||||||
|
|
||||||
|
nvgpu_kfree(g, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dma_fence_ops nvgpu_dma_fence_ops = {
|
||||||
|
.get_driver_name = nvgpu_dma_fence_get_driver_name,
|
||||||
|
.get_timeline_name = nvgpu_dma_fence_get_timeline_name,
|
||||||
|
.enable_signaling = nvgpu_dma_fence_enable_signaling,
|
||||||
|
.signaled = nvgpu_dma_fence_signaled,
|
||||||
|
.wait = dma_fence_default_wait,
|
||||||
|
.release = nvgpu_dma_fence_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nvgpu_dma_fence *to_nvgpu_dma_fence(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
if (fence->ops != &nvgpu_dma_fence_ops)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return container_of(fence, struct nvgpu_dma_fence, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
|
||||||
|
u64 nvgpu_sync_dma_context_create(void)
|
||||||
|
{
|
||||||
|
/* syncs in each context can be compared against each other */
|
||||||
|
return dma_fence_context_alloc(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_nvgpu_dma_fence_array(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct dma_fence_array *farray = to_dma_fence_array(fence);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (farray == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < farray->num_fences; i++) {
|
||||||
|
if (to_nvgpu_dma_fence(farray->fences[i]) == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nvgpu_dma_fence_length(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
if (to_nvgpu_dma_fence(fence) != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_nvgpu_dma_fence_array(fence)) {
|
||||||
|
struct dma_fence_array *farray = to_dma_fence_array(fence);
|
||||||
|
|
||||||
|
return farray->num_fences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this shall be called only after a is_nvgpu_dma_fence_or_array check
|
||||||
|
*/
|
||||||
|
WARN_ON(1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_nvgpu_dma_fence_or_array(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
return to_nvgpu_dma_fence(fence) != NULL ||
|
||||||
|
is_nvgpu_dma_fence_array(fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nvgpu_semaphore *nvgpu_dma_fence_sema(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct nvgpu_dma_fence *f = to_nvgpu_dma_fence(fence);
|
||||||
|
|
||||||
|
if (f != NULL) {
|
||||||
|
nvgpu_semaphore_get(f->sema);
|
||||||
|
return f->sema;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nvgpu_semaphore *nvgpu_dma_fence_nth(struct dma_fence *fence, u32 i)
|
||||||
|
{
|
||||||
|
struct nvgpu_semaphore *s = nvgpu_dma_fence_sema(fence);
|
||||||
|
struct dma_fence_array *farray;
|
||||||
|
|
||||||
|
if (s != NULL && i == 0) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
farray = to_dma_fence_array(fence);
|
||||||
|
nvgpu_assert(i < farray->num_fences);
|
||||||
|
return nvgpu_dma_fence_sema(farray->fences[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvgpu_sync_dma_signal(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
if (WARN_ON(to_nvgpu_dma_fence(fence) == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_fence_signal(fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dma_fence *nvgpu_sync_dma_fence_fdget(int fd)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence = sync_file_get_fence(fd);
|
||||||
|
|
||||||
|
if (fence == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (is_nvgpu_dma_fence_or_array(fence)) {
|
||||||
|
return fence;
|
||||||
|
} else {
|
||||||
|
dma_fence_put(fence);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dma_fence *nvgpu_sync_dma_create(struct nvgpu_channel *c,
|
||||||
|
struct nvgpu_semaphore *sema)
|
||||||
|
{
|
||||||
|
struct nvgpu_channel_linux *os_channel_priv = c->os_priv;
|
||||||
|
struct nvgpu_os_fence_framework *fence_framework;
|
||||||
|
struct nvgpu_dma_fence *f;
|
||||||
|
struct gk20a *g = c->g;
|
||||||
|
u64 context;
|
||||||
|
|
||||||
|
f = nvgpu_kzalloc(g, sizeof(*f));
|
||||||
|
if (f == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->g = g;
|
||||||
|
f->sema = sema;
|
||||||
|
snprintf(f->timeline_name, sizeof(f->timeline_name),
|
||||||
|
"ch%d-user", c->chid);
|
||||||
|
spin_lock_init(&f->lock);
|
||||||
|
|
||||||
|
fence_framework = &os_channel_priv->fence_framework;
|
||||||
|
context = fence_framework->context;
|
||||||
|
|
||||||
|
/* our sema values are u32. The dma fence seqnos are unsigned int. */
|
||||||
|
dma_fence_init(&f->base, &nvgpu_dma_fence_ops, &f->lock, context,
|
||||||
|
(unsigned)nvgpu_semaphore_get_value(sema));
|
||||||
|
nvgpu_semaphore_get(sema);
|
||||||
|
|
||||||
|
return &f->base;
|
||||||
|
}
|
||||||
41
drivers/gpu/nvgpu/os/linux/sync_sema_dma.h
Normal file
41
drivers/gpu/nvgpu/os/linux/sync_sema_dma.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Semaphore Sync Framework Integration
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, 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,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NVGPU_OS_LINUX_SYNC_SEMA_DMA_H
|
||||||
|
#define NVGPU_OS_LINUX_SYNC_SEMA_DMA_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_NVGPU_SYNCFD_STABLE
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
|
||||||
|
struct nvgpu_channel;
|
||||||
|
struct nvgpu_semaphore;
|
||||||
|
struct dma_fence;
|
||||||
|
|
||||||
|
u64 nvgpu_sync_dma_context_create(void);
|
||||||
|
|
||||||
|
struct dma_fence *nvgpu_sync_dma_create(struct nvgpu_channel *c,
|
||||||
|
struct nvgpu_semaphore *sema);
|
||||||
|
|
||||||
|
void nvgpu_sync_dma_signal(struct dma_fence *fence);
|
||||||
|
u32 nvgpu_dma_fence_length(struct dma_fence *fence);
|
||||||
|
struct nvgpu_semaphore *nvgpu_dma_fence_nth(struct dma_fence *fence, u32 i);
|
||||||
|
|
||||||
|
struct dma_fence *nvgpu_sync_dma_fence_fdget(int fd);
|
||||||
|
#endif /* CONFIG_NVGPU_SYNCFD_STABLE */
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user