Files
linux-nvgpu/drivers/gpu/nvgpu/os/linux/sync_sema_dma.c
Jinesh Parakh dd1a2fde91 gpu: nvgpu: Fix CERT-C Violations
Fix the following CERT-C Violations:
sync_sema_dma.c : CERT ERR33-C
sync_sema_dma.c : CERT EXP34-C

CID 350599
CID 368398
CID 392851
CID 464018
CID 465039
CID 467205
CID 468342

Bug 3512546

Signed-off-by: Jinesh Parakh <jparakh@nvidia.com>
Change-Id: Ibc6276d57550a3d2dd477decf82a7ac4b2ac3535
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2724762
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Sagar Kamble <skamble@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
GVS: Gerrit_Virtual_Submit
2022-06-06 14:15:09 -07:00

251 lines
5.9 KiB
C

/*
* Semaphore Sync Framework Integration
*
* Copyright (c) 2020-2022, 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);
nvgpu_assert(nvfence != NULL);
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);
nvgpu_assert(f != NULL);
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);
nvgpu_assert(f != NULL);
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;
nvgpu_assert(f != NULL);
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);
nvgpu_assert(farray != NULL);
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(farray != NULL && 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;
int err;
f = nvgpu_kzalloc(g, sizeof(*f));
if (f == NULL) {
return NULL;
}
f->g = g;
f->sema = sema;
err = snprintf(f->timeline_name, sizeof(f->timeline_name),
"ch%d-user", c->chid);
nvgpu_assert(err > 0);
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;
}