mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-24 10:34:43 +03:00
Open source GPL/LGPL release
This commit is contained in:
69
drivers/gpu/nvgpu/common/engine_queues/engine_dmem_queue.c
Normal file
69
drivers/gpu/nvgpu/common/engine_queues/engine_dmem_queue.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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.
|
||||
*/
|
||||
|
||||
#include <nvgpu/falcon.h>
|
||||
#include <nvgpu/log.h>
|
||||
|
||||
#include "engine_mem_queue_priv.h"
|
||||
#include "engine_dmem_queue.h"
|
||||
|
||||
/* DMEM-Q specific ops */
|
||||
static int engine_dmem_queue_push(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, u32 dst, void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
int err = 0;
|
||||
|
||||
err = nvgpu_falcon_copy_to_dmem(flcn, dst, data, size, 0);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d", queue->flcn_id, queue->id);
|
||||
nvgpu_err(g, "dmem queue write failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_dmem_queue_pop(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, u32 src, void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
int err = 0;
|
||||
|
||||
err = nvgpu_falcon_copy_from_dmem(flcn, src, data, size, 0);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d", queue->flcn_id, queue->id);
|
||||
nvgpu_err(g, "dmem queue read failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* assign DMEM queue type specific ops */
|
||||
void engine_dmem_queue_init(struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
queue->push = engine_dmem_queue_push;
|
||||
queue->pop = engine_dmem_queue_pop;
|
||||
}
|
||||
28
drivers/gpu/nvgpu/common/engine_queues/engine_dmem_queue.h
Normal file
28
drivers/gpu/nvgpu/common/engine_queues/engine_dmem_queue.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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_ENGINE_DMEM_QUEUE_H
|
||||
#define NVGPU_ENGINE_DMEM_QUEUE_H
|
||||
|
||||
void engine_dmem_queue_init(struct nvgpu_engine_mem_queue *queue);
|
||||
|
||||
#endif /* NVGPU_ENGINE_DMEM_QUEUE_H */
|
||||
69
drivers/gpu/nvgpu/common/engine_queues/engine_emem_queue.c
Normal file
69
drivers/gpu/nvgpu/common/engine_queues/engine_emem_queue.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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.
|
||||
*/
|
||||
|
||||
#include <nvgpu/falcon.h>
|
||||
#include <nvgpu/log.h>
|
||||
|
||||
#include "engine_mem_queue_priv.h"
|
||||
#include "engine_emem_queue.h"
|
||||
|
||||
/* EMEM-Q specific ops */
|
||||
static int engine_emem_queue_push(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, u32 dst, void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
int err = 0;
|
||||
|
||||
err = nvgpu_falcon_copy_to_emem(flcn, dst, data, size, 0);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d", queue->flcn_id, queue->id);
|
||||
nvgpu_err(g, "emem queue write failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_emem_queue_pop(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, u32 src, void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
int err = 0;
|
||||
|
||||
err = nvgpu_falcon_copy_from_emem(flcn, src, data, size, 0);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d", queue->flcn_id, queue->id);
|
||||
nvgpu_err(g, "emem queue read failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* assign EMEM queue type specific ops */
|
||||
void engine_emem_queue_init(struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
queue->push = engine_emem_queue_push;
|
||||
queue->pop = engine_emem_queue_pop;
|
||||
}
|
||||
28
drivers/gpu/nvgpu/common/engine_queues/engine_emem_queue.h
Normal file
28
drivers/gpu/nvgpu/common/engine_queues/engine_emem_queue.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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_ENGINE_EMEM_QUEUE_H
|
||||
#define NVGPU_ENGINE_EMEM_QUEUE_H
|
||||
|
||||
void engine_emem_queue_init(struct nvgpu_engine_mem_queue *queue);
|
||||
|
||||
#endif /* NVGPU_ENGINE_EMEM_QUEUE_H */
|
||||
603
drivers/gpu/nvgpu/common/engine_queues/engine_fb_queue.c
Normal file
603
drivers/gpu/nvgpu/common/engine_queues/engine_fb_queue.c
Normal file
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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.
|
||||
*/
|
||||
|
||||
#include <nvgpu/log.h>
|
||||
#include <nvgpu/errno.h>
|
||||
#include <nvgpu/types.h>
|
||||
#include <nvgpu/flcnif_cmn.h>
|
||||
#include <nvgpu/nvgpu_mem.h>
|
||||
#include <nvgpu/string.h>
|
||||
#include <nvgpu/kmem.h>
|
||||
#include <nvgpu/engine_queue.h>
|
||||
#include <nvgpu/engine_fb_queue.h>
|
||||
#include <nvgpu/pmu/pmuif/cmn.h>
|
||||
|
||||
#include "engine_fb_queue_priv.h"
|
||||
|
||||
/* FB-Q ops */
|
||||
static int engine_fb_queue_head(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 *head, bool set)
|
||||
{
|
||||
return queue->queue_head(queue->g, queue->id, queue->index, head, set);
|
||||
}
|
||||
|
||||
static int engine_fb_queue_tail(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 *tail, bool set)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
int err;
|
||||
|
||||
if (set == false && PMU_IS_COMMAND_QUEUE(queue->id)) {
|
||||
*tail = queue->fbq.tail;
|
||||
err = 0;
|
||||
} else {
|
||||
err = queue->queue_tail(g, queue->id, queue->index, tail, set);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline u32 engine_fb_queue_get_next(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 head)
|
||||
{
|
||||
return (head + 1U) % queue->size;
|
||||
}
|
||||
|
||||
static bool engine_fb_queue_has_room(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 size)
|
||||
{
|
||||
u32 head = 0;
|
||||
u32 tail = 0;
|
||||
u32 next_head = 0;
|
||||
int err = 0;
|
||||
|
||||
err = queue->head(queue, &head, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "queue head GET failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = queue->tail(queue, &tail, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "queue tail GET failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
next_head = engine_fb_queue_get_next(queue, head);
|
||||
|
||||
exit:
|
||||
return next_head != tail;
|
||||
}
|
||||
|
||||
static int engine_fb_queue_write(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 offset, u8 *src, u32 size)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
struct nv_falcon_fbq_hdr *fb_q_hdr = (struct nv_falcon_fbq_hdr *)
|
||||
(void *)queue->fbq.work_buffer;
|
||||
u32 entry_offset = 0U;
|
||||
int err = 0;
|
||||
|
||||
if (queue->fbq.work_buffer == NULL) {
|
||||
nvgpu_err(g, "Invalid/Unallocated work buffer");
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Fill out FBQ hdr, that is in the work buffer */
|
||||
fb_q_hdr->element_index = (u8)offset;
|
||||
|
||||
/* check queue entry size */
|
||||
if (fb_q_hdr->heap_size >= (u16)queue->fbq.element_size) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* get offset to this element entry */
|
||||
entry_offset = offset * queue->fbq.element_size;
|
||||
|
||||
/* copy cmd to super-surface */
|
||||
nvgpu_mem_wr_n(g, queue->fbq.super_surface_mem,
|
||||
queue->fbq.fb_offset + entry_offset,
|
||||
queue->fbq.work_buffer, queue->fbq.element_size);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_fb_queue_set_element_use_state(
|
||||
struct nvgpu_engine_fb_queue *queue, u32 queue_pos, bool set)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (queue_pos >= queue->size) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nvgpu_test_bit(queue_pos,
|
||||
(void *)&queue->fbq.element_in_use) && set) {
|
||||
nvgpu_err(queue->g,
|
||||
"FBQ last received queue element not processed yet"
|
||||
" queue_pos %d", queue_pos);
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
nvgpu_set_bit(queue_pos, (void *)&queue->fbq.element_in_use);
|
||||
} else {
|
||||
nvgpu_clear_bit(queue_pos, (void *)&queue->fbq.element_in_use);
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_fb_queue_is_element_in_use(
|
||||
struct nvgpu_engine_fb_queue *queue,
|
||||
u32 queue_pos, bool *in_use)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (queue_pos >= queue->size) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*in_use = nvgpu_test_bit(queue_pos, (void *)&queue->fbq.element_in_use);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_fb_queue_sweep(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
u32 head;
|
||||
u32 tail;
|
||||
bool in_use = false;
|
||||
int err = 0;
|
||||
|
||||
tail = queue->fbq.tail;
|
||||
err = queue->head(queue, &head, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, position GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step from tail forward in the queue,
|
||||
* to see how many consecutive entries
|
||||
* can be made available.
|
||||
*/
|
||||
while (tail != head) {
|
||||
if (engine_fb_queue_is_element_in_use(queue,
|
||||
tail, &in_use) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_use) {
|
||||
break;
|
||||
}
|
||||
|
||||
tail = engine_fb_queue_get_next(queue, tail);
|
||||
}
|
||||
|
||||
/* Update tail */
|
||||
queue->fbq.tail = tail;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
u32 nvgpu_engine_fb_queue_get_position(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
return queue->position;
|
||||
}
|
||||
|
||||
/* return the queue element size */
|
||||
u32 nvgpu_engine_fb_queue_get_element_size(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
return queue->fbq.element_size;
|
||||
}
|
||||
|
||||
/* return the queue offset from super surface FBQ's */
|
||||
u32 nvgpu_engine_fb_queue_get_offset(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
return queue->fbq.fb_offset;
|
||||
}
|
||||
|
||||
/* lock work buffer of queue */
|
||||
void nvgpu_engine_fb_queue_lock_work_buffer(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
/* acquire work buffer mutex */
|
||||
nvgpu_mutex_acquire(&queue->fbq.work_buffer_mutex);
|
||||
}
|
||||
|
||||
/* unlock work buffer of queue */
|
||||
void nvgpu_engine_fb_queue_unlock_work_buffer(
|
||||
struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
/* release work buffer mutex */
|
||||
nvgpu_mutex_release(&queue->fbq.work_buffer_mutex);
|
||||
}
|
||||
|
||||
/* return a pointer of queue work buffer */
|
||||
u8 *nvgpu_engine_fb_queue_get_work_buffer(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
return queue->fbq.work_buffer;
|
||||
}
|
||||
|
||||
int nvgpu_engine_fb_queue_free_element(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 queue_pos)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = engine_fb_queue_set_element_use_state(queue,
|
||||
queue_pos, false);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "fb queue elelment %d free failed",
|
||||
queue_pos);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = engine_fb_queue_sweep(queue);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue is_empty check with lock */
|
||||
bool nvgpu_engine_fb_queue_is_empty(struct nvgpu_engine_fb_queue *queue)
|
||||
{
|
||||
u32 q_head = 0;
|
||||
u32 q_tail = 0;
|
||||
int err = 0;
|
||||
|
||||
if (queue == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = queue->head(queue, &q_head, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, head GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = queue->tail(queue, &q_tail, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, tail GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
|
||||
return q_head == q_tail;
|
||||
}
|
||||
|
||||
static int engine_fb_queue_prepare_write(struct nvgpu_engine_fb_queue *queue,
|
||||
u32 size)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* make sure there's enough free space for the write */
|
||||
if (!engine_fb_queue_has_room(queue, size)) {
|
||||
nvgpu_log_info(queue->g, "queue full: queue-id %d: index %d",
|
||||
queue->id, queue->index);
|
||||
err = -EAGAIN;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = queue->head(queue, &queue->position, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, position GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue push operation with lock */
|
||||
int nvgpu_engine_fb_queue_push(struct nvgpu_engine_fb_queue *queue,
|
||||
void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g;
|
||||
int err = 0;
|
||||
|
||||
if (queue == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g = queue->g;
|
||||
|
||||
nvgpu_log_fn(g, " ");
|
||||
|
||||
if (queue->oflag != OFLAG_WRITE) {
|
||||
nvgpu_err(queue->g, "flcn-%d, queue-%d not opened for write",
|
||||
queue->flcn_id, queue->id);
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = engine_fb_queue_prepare_write(queue, size);
|
||||
if (err != 0) {
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
/* Bounds check size */
|
||||
if (size > queue->fbq.element_size) {
|
||||
nvgpu_err(g, "size too large size=0x%x", size);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
/* Set queue element in use */
|
||||
if (engine_fb_queue_set_element_use_state(queue,
|
||||
queue->position, true) != 0) {
|
||||
nvgpu_err(g,
|
||||
"fb-queue element in use map is in invalid state");
|
||||
err = -EINVAL;
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
/* write data to FB */
|
||||
err = engine_fb_queue_write(queue, queue->position, data, size);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "write to fb-queue failed");
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
queue->position = engine_fb_queue_get_next(queue,
|
||||
queue->position);
|
||||
|
||||
err = queue->head(queue, &queue->position, QUEUE_SET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, position SET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
unlock_mutex:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
exit:
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "falcon id-%d, queue id-%d, failed",
|
||||
queue->flcn_id, queue->id);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue pop operation with lock */
|
||||
int nvgpu_engine_fb_queue_pop(struct nvgpu_engine_fb_queue *queue,
|
||||
void *data, u32 size, u32 *bytes_read)
|
||||
{
|
||||
struct gk20a *g;
|
||||
struct pmu_hdr *hdr;
|
||||
u32 entry_offset = 0U;
|
||||
int err = 0;
|
||||
|
||||
if (queue == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g = queue->g;
|
||||
hdr = (struct pmu_hdr *) (void *) (queue->fbq.work_buffer +
|
||||
sizeof(struct nv_falcon_fbq_msgq_hdr));
|
||||
|
||||
nvgpu_log_fn(g, " ");
|
||||
|
||||
if (queue->oflag != OFLAG_READ) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d, not opened for read",
|
||||
queue->flcn_id, queue->id);
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = queue->tail(queue, &queue->position, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, position GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
*bytes_read = 0U;
|
||||
|
||||
/* Check size */
|
||||
if ((size + queue->fbq.read_position) >= queue->fbq.element_size) {
|
||||
nvgpu_err(g,
|
||||
"Attempt to read > than queue element size "
|
||||
"for queue id-%d", queue->id);
|
||||
err = -EINVAL;
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
entry_offset = queue->position * queue->fbq.element_size;
|
||||
|
||||
/*
|
||||
* If first read for this queue element then read whole queue
|
||||
* element into work buffer.
|
||||
*/
|
||||
if (queue->fbq.read_position == 0U) {
|
||||
nvgpu_mem_rd_n(g, queue->fbq.super_surface_mem,
|
||||
/* source (FBQ data) offset*/
|
||||
queue->fbq.fb_offset + entry_offset,
|
||||
/* destination buffer */
|
||||
(void *)queue->fbq.work_buffer,
|
||||
/* copy size */
|
||||
queue->fbq.element_size);
|
||||
|
||||
/* Check size in hdr of MSG just read */
|
||||
if (hdr->size >= queue->fbq.element_size) {
|
||||
nvgpu_err(g, "Super Surface read failed");
|
||||
err = -ERANGE;
|
||||
goto unlock_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
nvgpu_memcpy((u8 *)data, (u8 *)queue->fbq.work_buffer +
|
||||
queue->fbq.read_position +
|
||||
sizeof(struct nv_falcon_fbq_msgq_hdr),
|
||||
size);
|
||||
|
||||
/* update current position */
|
||||
queue->fbq.read_position += size;
|
||||
|
||||
/* If reached end of this queue element, move on to next. */
|
||||
if (queue->fbq.read_position >= hdr->size) {
|
||||
queue->fbq.read_position = 0U;
|
||||
/* Increment queue index. */
|
||||
queue->position = engine_fb_queue_get_next(queue,
|
||||
queue->position);
|
||||
}
|
||||
|
||||
*bytes_read = size;
|
||||
|
||||
err = queue->tail(queue, &queue->position, QUEUE_SET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, position SET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
unlock_mutex:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
exit:
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "falcon id-%d, queue id-%d, failed",
|
||||
queue->flcn_id, queue->id);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void nvgpu_engine_fb_queue_free(struct nvgpu_engine_fb_queue **queue_p)
|
||||
{
|
||||
struct nvgpu_engine_fb_queue *queue = NULL;
|
||||
struct gk20a *g;
|
||||
|
||||
if ((queue_p == NULL) || (*queue_p == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
queue = *queue_p;
|
||||
|
||||
g = queue->g;
|
||||
|
||||
nvgpu_log_info(g, "flcn id-%d q-id %d: index %d ",
|
||||
queue->flcn_id, queue->id, queue->index);
|
||||
|
||||
nvgpu_kfree(g, queue->fbq.work_buffer);
|
||||
nvgpu_mutex_destroy(&queue->fbq.work_buffer_mutex);
|
||||
|
||||
/* destroy mutex */
|
||||
nvgpu_mutex_destroy(&queue->mutex);
|
||||
|
||||
nvgpu_kfree(g, queue);
|
||||
*queue_p = NULL;
|
||||
}
|
||||
|
||||
int nvgpu_engine_fb_queue_init(struct nvgpu_engine_fb_queue **queue_p,
|
||||
struct nvgpu_engine_fb_queue_params params)
|
||||
{
|
||||
struct nvgpu_engine_fb_queue *queue = NULL;
|
||||
struct gk20a *g = params.g;
|
||||
int err = 0;
|
||||
|
||||
if (queue_p == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue = (struct nvgpu_engine_fb_queue *)
|
||||
nvgpu_kmalloc(g, sizeof(struct nvgpu_engine_fb_queue));
|
||||
|
||||
if (queue == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue->g = params.g;
|
||||
queue->flcn_id = params.flcn_id;
|
||||
queue->id = params.id;
|
||||
queue->index = params.index;
|
||||
queue->size = params.size;
|
||||
queue->oflag = params.oflag;
|
||||
|
||||
queue->fbq.tail = 0U;
|
||||
queue->fbq.element_in_use = 0U;
|
||||
queue->fbq.read_position = 0U;
|
||||
queue->fbq.super_surface_mem = params.super_surface_mem;
|
||||
queue->fbq.element_size = params.fbq_element_size;
|
||||
queue->fbq.fb_offset = params.fbq_offset;
|
||||
|
||||
queue->position = 0U;
|
||||
|
||||
queue->queue_head = params.queue_head;
|
||||
queue->queue_tail = params.queue_tail;
|
||||
|
||||
queue->head = engine_fb_queue_head;
|
||||
queue->tail = engine_fb_queue_tail;
|
||||
|
||||
/* init mutex */
|
||||
nvgpu_mutex_init(&queue->mutex);
|
||||
|
||||
/* init mutex */
|
||||
nvgpu_mutex_init(&queue->fbq.work_buffer_mutex);
|
||||
|
||||
queue->fbq.work_buffer = nvgpu_kzalloc(g, queue->fbq.element_size);
|
||||
if (queue->fbq.work_buffer == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto free_work_mutex;
|
||||
}
|
||||
|
||||
nvgpu_log_info(g,
|
||||
"flcn id-%d q-id %d: index %d, size 0x%08x",
|
||||
queue->flcn_id, queue->id, queue->index,
|
||||
queue->size);
|
||||
|
||||
*queue_p = queue;
|
||||
|
||||
return 0;
|
||||
|
||||
free_work_mutex:
|
||||
nvgpu_mutex_destroy(&queue->fbq.work_buffer_mutex);
|
||||
nvgpu_mutex_destroy(&queue->mutex);
|
||||
nvgpu_kfree(g, queue);
|
||||
|
||||
return err;
|
||||
}
|
||||
108
drivers/gpu/nvgpu/common/engine_queues/engine_fb_queue_priv.h
Normal file
108
drivers/gpu/nvgpu/common/engine_queues/engine_fb_queue_priv.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, 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_ENGINE_FB_QUEUE_PRIV_H
|
||||
#define NVGPU_ENGINE_FB_QUEUE_PRIV_H
|
||||
|
||||
#include <nvgpu/lock.h>
|
||||
|
||||
struct nvgpu_engine_fb_queue {
|
||||
struct gk20a *g;
|
||||
u32 flcn_id;
|
||||
|
||||
/* used by nvgpu, for command LPQ/HPQ */
|
||||
struct nvgpu_mutex mutex;
|
||||
|
||||
/* current write position */
|
||||
u32 position;
|
||||
/* logical queue identifier */
|
||||
u32 id;
|
||||
/* physical queue index */
|
||||
u32 index;
|
||||
/* in bytes */
|
||||
u32 size;
|
||||
/* open-flag */
|
||||
u32 oflag;
|
||||
|
||||
/* members unique to the FB version of the falcon queues */
|
||||
struct {
|
||||
/* Holds super surface base address */
|
||||
struct nvgpu_mem *super_surface_mem;
|
||||
|
||||
/*
|
||||
* Holds the offset of queue data (0th element).
|
||||
* This is used for FB Queues to hold a offset of
|
||||
* Super Surface for this queue.
|
||||
*/
|
||||
u32 fb_offset;
|
||||
|
||||
/*
|
||||
* Define the size of a single queue element.
|
||||
* queues_size above is used for the number of
|
||||
* queue elements.
|
||||
*/
|
||||
u32 element_size;
|
||||
|
||||
/* To keep track of elements in use */
|
||||
u64 element_in_use;
|
||||
|
||||
/*
|
||||
* Define a pointer to a local (SYSMEM) allocated
|
||||
* buffer to hold a single queue element
|
||||
* it is being assembled.
|
||||
*/
|
||||
u8 *work_buffer;
|
||||
struct nvgpu_mutex work_buffer_mutex;
|
||||
|
||||
/*
|
||||
* Tracks how much of the current FB Queue MSG queue
|
||||
* entry have been read. This is needed as functions read
|
||||
* the MSG queue as a byte stream, rather
|
||||
* than reading a whole MSG at a time.
|
||||
*/
|
||||
u32 read_position;
|
||||
|
||||
/*
|
||||
* Tail as tracked on the nvgpu "side". Because the queue
|
||||
* elements and its associated payload (which is also moved
|
||||
* PMU->nvgpu through the FB CMD Queue) can't be free-ed until
|
||||
* the command is complete, response is received and any "out"
|
||||
* payload delivered to the client, it is necessary for the
|
||||
* nvgpu to track it's own version of "tail". This one is
|
||||
* incremented as commands and completed entries are found
|
||||
* following tail.
|
||||
*/
|
||||
u32 tail;
|
||||
} fbq;
|
||||
|
||||
/* engine and queue specific ops */
|
||||
int (*tail)(struct nvgpu_engine_fb_queue *queue, u32 *tail, bool set);
|
||||
int (*head)(struct nvgpu_engine_fb_queue *queue, u32 *head, bool set);
|
||||
|
||||
/* engine specific ops */
|
||||
int (*queue_head)(struct gk20a *g, u32 queue_id, u32 queue_index,
|
||||
u32 *head, bool set);
|
||||
int (*queue_tail)(struct gk20a *g, u32 queue_id, u32 queue_index,
|
||||
u32 *tail, bool set);
|
||||
};
|
||||
|
||||
#endif /* NVGPU_ENGINE_FB_QUEUE_PRIV_H */
|
||||
438
drivers/gpu/nvgpu/common/engine_queues/engine_mem_queue.c
Normal file
438
drivers/gpu/nvgpu/common/engine_queues/engine_mem_queue.c
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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.
|
||||
*/
|
||||
|
||||
#include <nvgpu/errno.h>
|
||||
#include <nvgpu/kmem.h>
|
||||
#include <nvgpu/lock.h>
|
||||
#include <nvgpu/log.h>
|
||||
#include <nvgpu/flcnif_cmn.h>
|
||||
#include <nvgpu/pmu/pmuif/nvgpu_cmdif.h>
|
||||
#include <nvgpu/engine_queue.h>
|
||||
#include <nvgpu/engine_mem_queue.h>
|
||||
#include <nvgpu/pmu/cmd.h>
|
||||
|
||||
#include "engine_mem_queue_priv.h"
|
||||
#include "engine_dmem_queue.h"
|
||||
#include "engine_emem_queue.h"
|
||||
|
||||
static int mem_queue_get_head_tail(struct nvgpu_engine_mem_queue *queue,
|
||||
u32 *q_head, u32 *q_tail)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = queue->head(queue->g, queue->id, queue->index,
|
||||
q_head, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d, queue-%d, head GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = queue->tail(queue->g, queue->id, queue->index,
|
||||
q_tail, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d, queue-%d, tail GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* common falcon queue ops */
|
||||
static bool engine_mem_queue_has_room(struct nvgpu_engine_mem_queue *queue,
|
||||
u32 size, bool *need_rewind)
|
||||
{
|
||||
u32 q_head = 0;
|
||||
u32 q_tail = 0;
|
||||
u32 q_free = 0;
|
||||
bool q_rewind = false;
|
||||
int err = 0;
|
||||
|
||||
size = NVGPU_ALIGN(size, QUEUE_ALIGNMENT);
|
||||
|
||||
err = mem_queue_get_head_tail(queue, &q_head, &q_tail);
|
||||
if (err != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (q_head >= q_tail) {
|
||||
q_free = queue->offset + queue->size - q_head;
|
||||
q_free -= (u32)PMU_CMD_HDR_SIZE;
|
||||
|
||||
if (size > q_free) {
|
||||
q_rewind = true;
|
||||
q_head = queue->offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (q_head < q_tail) {
|
||||
q_free = q_tail - q_head - 1U;
|
||||
}
|
||||
|
||||
if (need_rewind != NULL) {
|
||||
*need_rewind = q_rewind;
|
||||
}
|
||||
|
||||
exit:
|
||||
return size <= q_free;
|
||||
}
|
||||
|
||||
static int engine_mem_queue_rewind(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
struct gk20a *g = queue->g;
|
||||
struct pmu_cmd cmd;
|
||||
int err = 0;
|
||||
|
||||
if (queue->oflag == OFLAG_WRITE) {
|
||||
cmd.hdr.unit_id = PMU_UNIT_REWIND;
|
||||
cmd.hdr.size = (u8)PMU_CMD_HDR_SIZE;
|
||||
err = queue->push(flcn, queue, queue->position,
|
||||
&cmd, cmd.hdr.size);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, rewind request failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
} else {
|
||||
queue->position += nvgpu_safe_cast_u32_to_u8(
|
||||
NVGPU_ALIGN(U32(cmd.hdr.size), QUEUE_ALIGNMENT));
|
||||
nvgpu_log_info(g, "flcn-%d queue-%d, rewinded",
|
||||
queue->flcn_id, queue->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* update queue position */
|
||||
queue->position = queue->offset;
|
||||
|
||||
if (queue->oflag == OFLAG_READ) {
|
||||
err = queue->tail(g, queue->id, queue->index, &queue->position,
|
||||
QUEUE_SET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, position SET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int engine_mem_queue_prepare_write(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, u32 size)
|
||||
{
|
||||
bool q_rewind = false;
|
||||
int err = 0;
|
||||
|
||||
/* make sure there's enough free space for the write */
|
||||
if (!engine_mem_queue_has_room(queue, size, &q_rewind)) {
|
||||
nvgpu_log_info(queue->g, "queue full: queue-id %d: index %d",
|
||||
queue->id, queue->index);
|
||||
err = -EAGAIN;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = queue->head(queue->g, queue->id, queue->index,
|
||||
&queue->position, QUEUE_GET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(queue->g, "flcn-%d queue-%d, position GET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (q_rewind) {
|
||||
err = engine_mem_queue_rewind(flcn, queue);
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue public functions */
|
||||
|
||||
/* queue push operation with lock */
|
||||
int nvgpu_engine_mem_queue_push(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, void *data, u32 size)
|
||||
{
|
||||
struct gk20a *g;
|
||||
int err = 0;
|
||||
|
||||
if ((flcn == NULL) || (queue == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g = queue->g;
|
||||
|
||||
if (queue->oflag != OFLAG_WRITE) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d not opened for write",
|
||||
queue->flcn_id, queue->id);
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = engine_mem_queue_prepare_write(flcn, queue, size);
|
||||
if (err != 0) {
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
err = queue->push(flcn, queue, queue->position, data, size);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, fail to write",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
queue->position += NVGPU_ALIGN(size, QUEUE_ALIGNMENT);
|
||||
|
||||
err = queue->head(g, queue->id, queue->index,
|
||||
&queue->position, QUEUE_SET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, position SET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
}
|
||||
|
||||
unlock_mutex:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue pop operation with lock */
|
||||
int nvgpu_engine_mem_queue_pop(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue, void *data, u32 size,
|
||||
u32 *bytes_read)
|
||||
{
|
||||
struct gk20a *g;
|
||||
u32 q_tail = 0;
|
||||
u32 q_head = 0;
|
||||
u32 used = 0;
|
||||
int err = 0;
|
||||
|
||||
*bytes_read = 0;
|
||||
|
||||
if ((flcn == NULL) || (queue == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g = queue->g;
|
||||
|
||||
if (queue->oflag != OFLAG_READ) {
|
||||
nvgpu_err(g, "flcn-%d, queue-%d, not opened for read",
|
||||
queue->flcn_id, queue->id);
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = mem_queue_get_head_tail(queue, &q_head, &queue->position);
|
||||
if (err != 0) {
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
q_tail = queue->position;
|
||||
|
||||
if (q_head == q_tail) {
|
||||
goto unlock_mutex;
|
||||
} else if (q_head > q_tail) {
|
||||
used = q_head - q_tail;
|
||||
} else {
|
||||
used = queue->offset + queue->size - q_tail;
|
||||
}
|
||||
|
||||
if (size > used) {
|
||||
nvgpu_warn(g, "queue size smaller than request read");
|
||||
size = used;
|
||||
}
|
||||
|
||||
err = queue->pop(flcn, queue, q_tail, data, size);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, fail to read",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
queue->position += NVGPU_ALIGN(size, QUEUE_ALIGNMENT);
|
||||
|
||||
err = queue->tail(g, queue->id, queue->index,
|
||||
&queue->position, QUEUE_SET);
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, position SET failed",
|
||||
queue->flcn_id, queue->id);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
*bytes_read = size;
|
||||
|
||||
unlock_mutex:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
int nvgpu_engine_mem_queue_rewind(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if ((flcn == NULL) || (queue == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = engine_mem_queue_rewind(flcn, queue);
|
||||
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* queue is_empty check with lock */
|
||||
bool nvgpu_engine_mem_queue_is_empty(struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
u32 q_head = 0;
|
||||
u32 q_tail = 0;
|
||||
int err = 0;
|
||||
|
||||
if (queue == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* acquire mutex */
|
||||
nvgpu_mutex_acquire(&queue->mutex);
|
||||
|
||||
err = mem_queue_get_head_tail(queue, &q_head, &q_tail);
|
||||
if (err != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
/* release mutex */
|
||||
nvgpu_mutex_release(&queue->mutex);
|
||||
|
||||
return q_head == q_tail;
|
||||
}
|
||||
|
||||
void nvgpu_engine_mem_queue_free(struct nvgpu_engine_mem_queue **queue_p)
|
||||
{
|
||||
struct nvgpu_engine_mem_queue *queue = NULL;
|
||||
struct gk20a *g;
|
||||
|
||||
if ((queue_p == NULL) || (*queue_p == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
queue = *queue_p;
|
||||
|
||||
g = queue->g;
|
||||
|
||||
nvgpu_log_info(g, "flcn id-%d q-id %d: index %d ",
|
||||
queue->flcn_id, queue->id, queue->index);
|
||||
|
||||
/* destroy mutex */
|
||||
nvgpu_mutex_destroy(&queue->mutex);
|
||||
|
||||
nvgpu_kfree(g, queue);
|
||||
*queue_p = NULL;
|
||||
}
|
||||
|
||||
u32 nvgpu_engine_mem_queue_get_size(struct nvgpu_engine_mem_queue *queue)
|
||||
{
|
||||
return queue->size;
|
||||
}
|
||||
|
||||
int nvgpu_engine_mem_queue_init(struct nvgpu_engine_mem_queue **queue_p,
|
||||
struct nvgpu_engine_mem_queue_params params)
|
||||
{
|
||||
struct nvgpu_engine_mem_queue *queue = NULL;
|
||||
struct gk20a *g = params.g;
|
||||
int err = 0;
|
||||
|
||||
if (queue_p == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue = (struct nvgpu_engine_mem_queue *)
|
||||
nvgpu_kmalloc(g, sizeof(struct nvgpu_engine_mem_queue));
|
||||
|
||||
if (queue == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue->g = params.g;
|
||||
queue->flcn_id = params.flcn_id;
|
||||
queue->id = params.id;
|
||||
queue->index = params.index;
|
||||
queue->offset = params.offset;
|
||||
queue->position = params.position;
|
||||
queue->size = params.size;
|
||||
queue->oflag = params.oflag;
|
||||
queue->queue_type = params.queue_type;
|
||||
|
||||
queue->head = params.queue_head;
|
||||
queue->tail = params.queue_tail;
|
||||
|
||||
nvgpu_log_info(g,
|
||||
"flcn id-%d q-id %d: index %d, offset 0x%08x, size 0x%08x",
|
||||
queue->flcn_id, queue->id, queue->index,
|
||||
queue->offset, queue->size);
|
||||
|
||||
switch (queue->queue_type) {
|
||||
case QUEUE_TYPE_DMEM:
|
||||
engine_dmem_queue_init(queue);
|
||||
break;
|
||||
#ifdef CONFIG_NVGPU_DGPU
|
||||
case QUEUE_TYPE_EMEM:
|
||||
engine_emem_queue_init(queue);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
nvgpu_err(g, "flcn-%d queue-%d, init failed",
|
||||
queue->flcn_id, queue->id);
|
||||
nvgpu_kfree(g, queue);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* init mutex */
|
||||
nvgpu_mutex_init(&queue->mutex);
|
||||
|
||||
*queue_p = queue;
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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_ENGINE_MEM_QUEUE_PRIV_H
|
||||
#define NVGPU_ENGINE_MEM_QUEUE_PRIV_H
|
||||
|
||||
#include <nvgpu/lock.h>
|
||||
#include <nvgpu/types.h>
|
||||
|
||||
struct gk20a;
|
||||
struct nvgpu_falcon;
|
||||
|
||||
struct nvgpu_engine_mem_queue {
|
||||
struct gk20a *g;
|
||||
u32 flcn_id;
|
||||
|
||||
/* Queue Type (queue_type) */
|
||||
u8 queue_type;
|
||||
|
||||
/* used by nvgpu, for command LPQ/HPQ */
|
||||
struct nvgpu_mutex mutex;
|
||||
|
||||
/* current write position */
|
||||
u32 position;
|
||||
/* physical dmem offset where this queue begins */
|
||||
u32 offset;
|
||||
/* logical queue identifier */
|
||||
u32 id;
|
||||
/* physical queue index */
|
||||
u32 index;
|
||||
/* in bytes */
|
||||
u32 size;
|
||||
/* open-flag */
|
||||
u32 oflag;
|
||||
|
||||
/* queue type(DMEM-Q/EMEM-Q) specific ops */
|
||||
int (*push)(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue,
|
||||
u32 dst, void *data, u32 size);
|
||||
int (*pop)(struct nvgpu_falcon *flcn,
|
||||
struct nvgpu_engine_mem_queue *queue,
|
||||
u32 src, void *data, u32 size);
|
||||
|
||||
/* engine specific ops */
|
||||
int (*head)(struct gk20a *g, u32 queue_id, u32 queue_index,
|
||||
u32 *head, bool set);
|
||||
int (*tail)(struct gk20a *g, u32 queue_id, u32 queue_index,
|
||||
u32 *tail, bool set);
|
||||
};
|
||||
|
||||
#endif /* NVGPU_ENGINE_MEM_QUEUE_PRIV_H */
|
||||
Reference in New Issue
Block a user