DCE-KMD: dce-ipc.c: Abstract out iosys

- Abstract out iosys_* dependencies for writing/reading to/from
  message header and memcpy to os specific implementation.
    - Add new dce-os-ipc.c

- Cannot add these functions to existing 'dce-os-ivc.h' as
  static inline functions because these functions access
  dce_ipc_channel defined in dce_ipc.h.
    - Cannot include dce_ipc.h to this file as it creates
      a circular dependency.

- Also fix exsisting issue of not defining 'tegra_dce' inside
  dce-ipc.h
    - This is exposed now because we're including dce-ipc.h to
      dce-os-ipc.c which doesn't include any prior headers which
      define tegra_dce.
    - Fix by doing forward define to avoid circular dependency
      with dce.h

- Additionally fix below iosys issues:
1) Change Iabebef33719c38a8aa4db8573a0dd7dd7e5f83f6 introduced
   an issue because NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP demands
   different prototypes for below functions:
     - dce_os_ivc_get_next_write_frame()
     - dce_os_ivc_get_next_read_frame()

2) Now since dce_ipc_is_data_available() uses
   dce_os_ivc_get_next_read_frame(), it needs to define
   frame with iosys_map for IOSYS Linux 6.2 usecase. So need
   to creata a OS abstraction for this too.

JIRA TDS-16126

Change-Id: I55594d8e34c3b572129119d1f7240cde76cf37bd
Signed-off-by: anupamg <anupamg@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3233117
Reviewed-by: Mahesh Kumar <mahkumar@nvidia.com>
Reviewed-by: Arun Swain <arswain@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
anupamg
2024-10-18 11:08:55 -07:00
committed by Jon Hunter
parent 7b46601f2e
commit cd31698771
5 changed files with 245 additions and 158 deletions

View File

@@ -36,6 +36,7 @@ tegra-dce-$(CONFIG_TEGRA_DCE) += dce-pm.o
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-os-utils.o tegra-dce-$(CONFIG_TEGRA_DCE) += dce-os-utils.o
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-smb-t264.o tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-smb-t264.o
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-ss-t264.o tegra-dce-$(CONFIG_TEGRA_DCE) += dce-hsp-ss-t264.o
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-os-ivc.o
ifeq ($(CONFIG_DEBUG_FS),y) ifeq ($(CONFIG_DEBUG_FS),y)
tegra-dce-$(CONFIG_TEGRA_DCE) += dce-debug.o tegra-dce-$(CONFIG_TEGRA_DCE) += dce-debug.o

View File

@@ -436,48 +436,6 @@ static int _dce_ipc_get_next_write_buff(struct dce_ipc_channel *ch)
return err; return err;
} }
/**
* dce_ipc_write_channel - Writes to an ivc channel.
*
* @ch : Pointer to the pertinent channel.
* @data : Pointer to the data to be written.
* @size : Size of the data to be written.
*
* Return : 0 if successful.
*/
static int _dce_ipc_write_channel(struct dce_ipc_channel *ch,
const void *data, size_t size)
{
struct dce_ipc_header *hdr;
/**
* Add actual length information to the top
* of the IVC frame
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
iosys_map_wr_field(&ch->obuff, 0, struct dce_ipc_header, length,
size);
iosys_map_incr(&ch->obuff, sizeof(*hdr));
}
if (data && size > 0)
iosys_map_memcpy_to(&ch->obuff, 0, data, size);
#else
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
hdr = (struct dce_ipc_header *)ch->obuff;
hdr->length = (uint32_t)size;
ch->obuff = (void *)(hdr + 1U);
}
if (data && size > 0)
memcpy(ch->obuff, data, size);
#endif
return dce_os_ivc_write_advance(&ch->d_ivc);
}
/** /**
* dce_ipc_send_message - Sends messages over ipc. * dce_ipc_send_message - Sends messages over ipc.
* *
@@ -505,7 +463,7 @@ int dce_ipc_send_message(struct tegra_dce *d, u32 ch_type,
goto out; goto out;
} }
ret = _dce_ipc_write_channel(ch, data, size); ret = dce_os_ivc_write_channel(ch, data, size);
if (ret) { if (ret) {
dce_os_err(ch->d, "Error writing to channel"); dce_os_err(ch->d, "Error writing to channel");
goto out; goto out;
@@ -540,47 +498,6 @@ static int _dce_ipc_get_next_read_buff(struct dce_ipc_channel *ch)
return err; return err;
} }
/**
* dce_ipc_read_channel - Writes to an ivc channel.
*
* @ch : Pointer to the pertinent channel.
* @data : Pointer to the data to be read.
* @size : Size of the data to be read.
*
* Return : 0 if successful.
*/
static int _dce_ipc_read_channel(struct dce_ipc_channel *ch,
void *data, size_t size)
{
struct dce_ipc_header *hdr;
/**
* Get actual length information from the top
* of the IVC frame
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
iosys_map_wr_field(&ch->ibuff, 0, struct dce_ipc_header, length,
size);
iosys_map_incr(&ch->ibuff, sizeof(*hdr));
}
if (data && size > 0)
iosys_map_memcpy_from(data, &ch->ibuff, 0, size);
#else
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
hdr = (struct dce_ipc_header *)ch->ibuff;
size = (size_t)(hdr->length);
ch->ibuff = (void *)(hdr + 1U);
}
if (data && size > 0)
memcpy(data, ch->ibuff, size);
#endif
return dce_os_ivc_read_advance(&ch->d_ivc);
}
/** /**
* dce_ipc_read_message - Reads messages over ipc. * dce_ipc_read_message - Reads messages over ipc.
* *
@@ -607,7 +524,7 @@ int dce_ipc_read_message(struct tegra_dce *d, u32 ch_type,
goto out; goto out;
} }
ret = _dce_ipc_read_channel(ch, data, size); ret = dce_os_ivc_read_channel(ch, data, size);
if (ret) { if (ret) {
dce_os_err(ch->d, "Error reading from channel"); dce_os_err(ch->d, "Error reading from channel");
goto out; goto out;
@@ -711,25 +628,22 @@ int dce_ipc_get_region_iova_info(struct tegra_dce *d, u64 *iova, u32 *size)
} }
/* /*
* dce_ipc_handle_notification - Handles the notification from remote * dce_ipc_is_data_available - Check if IVC channel has new data
* avaialble for reading.
* *
* @d : Pointer to tegra_dce struct * @d : Pointer to tegra_dce struct
* @id : Channel Index * @id : Channel Index
* *
* Return : True if the worker thread needs to wake up * Return : true if the worker thread needs to wake up
*/ */
bool dce_ipc_is_data_available(struct tegra_dce *d, u32 ch_type) bool dce_ipc_is_data_available(struct tegra_dce *d, u32 ch_type)
{ {
bool ret = false; bool ret = false;
void *frame;
int err = 0;
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type]; struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
dce_os_mutex_lock(&ch->lock); dce_os_mutex_lock(&ch->lock);
err = dce_os_ivc_get_next_read_frame(&ch->d_ivc, &frame); ret = dce_os_ivc_is_data_available(ch);
if (err == 0)
ret = true;
dce_os_mutex_unlock(&ch->lock); dce_os_mutex_unlock(&ch->lock);

View File

@@ -0,0 +1,191 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <dce-ipc.h>
#include <dce-os-ivc.h>
#include <interface/dce-ipc-header.h>
/**
* dce_os_ivc_write_channel - Writes to an ivc channel.
*
* @ch : Pointer to the pertinent channel.
* @data : Pointer to the data to be written.
* @size : Size of the data to be written.
*
* Return : 0 if successful.
*/
int dce_os_ivc_write_channel(struct dce_ipc_channel *ch,
const void *data, size_t size)
{
struct dce_ipc_header *hdr;
/**
* Add actual length information to the top
* of the IVC frame
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
iosys_map_wr_field(&ch->obuff, 0, struct dce_ipc_header, length,
size);
iosys_map_incr(&ch->obuff, sizeof(*hdr));
}
if (data && size > 0)
iosys_map_memcpy_to(&ch->obuff, 0, data, size);
#else
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
hdr = (struct dce_ipc_header *)ch->obuff;
hdr->length = (uint32_t)size;
ch->obuff = (void *)(hdr + 1U);
}
if (data && size > 0)
memcpy(ch->obuff, data, size);
#endif
return dce_os_ivc_write_advance(&ch->d_ivc);
}
/**
* dce_os_ivc_read_channel - Writes to an ivc channel.
*
* @ch : Pointer to the pertinent channel.
* @data : Pointer to the data to be read.
* @size : Size of the data to be read.
*
* Return : 0 if successful.
*/
int dce_os_ivc_read_channel(struct dce_ipc_channel *ch,
void *data, size_t size)
{
struct dce_ipc_header *hdr;
/**
* Get actual length information from the top
* of the IVC frame
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
iosys_map_wr_field(&ch->ibuff, 0, struct dce_ipc_header, length,
size);
iosys_map_incr(&ch->ibuff, sizeof(*hdr));
}
if (data && size > 0)
iosys_map_memcpy_from(data, &ch->ibuff, 0, size);
#else
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
hdr = (struct dce_ipc_header *)ch->ibuff;
size = (size_t)(hdr->length);
ch->ibuff = (void *)(hdr + 1U);
}
if (data && size > 0)
memcpy(data, ch->ibuff, size);
#endif
return dce_os_ivc_read_advance(&ch->d_ivc);
}
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
int dce_os_ivc_get_next_write_frame(dce_os_ivc_t *ivc, struct iosys_map *ppframe)
{
int err = 0;
struct iosys_map pframe;
err = tegra_ivc_write_get_next_frame(ivc, &pframe);
if (err) {
iosys_map_clear(&pframe);
goto done;
}
*ppframe = pframe;
done:
return err;
}
/**
* dce_os_ivc_get_next_read_frame - Get next read frame.
*
* @ivc : Pointer to IVC struct
* @ppFrame : Pointer to frame reference.
*
* Return : 0 if successful.
*/
int dce_os_ivc_get_next_read_frame(dce_os_ivc_t *ivc, struct iosys_map *ppframe)
{
int err = 0;
struct iosys_map pframe;
err = tegra_ivc_read_get_next_frame(ivc, &pframe);
if (err) {
iosys_map_clear(&pframe);
goto done;
}
*ppframe = pframe;
done:
return err;
}
#else /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
int dce_os_ivc_get_next_write_frame(dce_os_ivc_t *ivc, void **ppframe)
{
int err = 0;
void *pframe = NULL;
pframe = tegra_ivc_write_get_next_frame(ivc);
if (IS_ERR(pframe)) {
err = -ENOMEM;
goto done;
}
*ppframe = pframe;
done:
return err;
}
int dce_os_ivc_get_next_read_frame(dce_os_ivc_t *ivc, void **ppframe)
{
int err = 0;
void *pframe = NULL;
pframe = tegra_ivc_read_get_next_frame(ivc);
if (IS_ERR(pframe)) {
err = -ENOMEM;
goto done;
}
*ppframe = pframe;
done:
return err;
}
#endif /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
bool dce_os_ivc_is_data_available(struct dce_ipc_channel *ch)
{
bool ret = false;
int err = 0;
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
struct iosys_map frame;
#else
void *frame;
#endif
err = dce_os_ivc_get_next_read_frame(&ch->d_ivc, &frame);
if (err == 0)
ret = true;
return ret;
}

View File

@@ -15,6 +15,8 @@
#include <interface/dce-ipc-state.h> #include <interface/dce-ipc-state.h>
#include <linux/platform/tegra/dce/dce-client-ipc.h> #include <linux/platform/tegra/dce/dce-client-ipc.h>
struct tegra_dce;
#define DCE_IPC_CHANNEL_TYPE_ADMIN 0U #define DCE_IPC_CHANNEL_TYPE_ADMIN 0U
#define DCE_IPC_CHANNEL_TYPE_CPU_CLIENTS 1U #define DCE_IPC_CHANNEL_TYPE_CPU_CLIENTS 1U

View File

@@ -9,6 +9,8 @@
#include <soc/tegra/ivc.h> #include <soc/tegra/ivc.h>
#include <nvidia/conftest.h> #include <nvidia/conftest.h>
struct dce_ipc_channel;
typedef struct tegra_ivc dce_os_ivc_t; typedef struct tegra_ivc dce_os_ivc_t;
/* /*
@@ -56,78 +58,12 @@ static inline int dce_os_ivc_notified(dce_os_ivc_t *ivc)
return tegra_ivc_notified(ivc); return tegra_ivc_notified(ivc);
} }
/*
* Return negative err code on Failure, or 0 on Success.
* This function will populate address of next write frame
* info functions ppframe input argument.
*/
static inline int dce_os_ivc_get_next_write_frame(dce_os_ivc_t *ivc, void **ppframe)
{
int err = 0;
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
struct iosys_map pframe;
err = tegra_ivc_write_get_next_frame(ivc, &pframe);
if (err) {
iosys_map_clear(&pframe);
goto done;
}
#else
void *pframe = NULL;
pframe = tegra_ivc_write_get_next_frame(ivc);
if (IS_ERR(pframe)) {
err = -ENOMEM;
goto done;
}
#endif
*ppframe = pframe;
done:
return err;
}
/* Returns 0, or a negative error value if failed. */ /* Returns 0, or a negative error value if failed. */
static inline int dce_os_ivc_write_advance(dce_os_ivc_t *ivc) static inline int dce_os_ivc_write_advance(dce_os_ivc_t *ivc)
{ {
return tegra_ivc_write_advance(ivc); return tegra_ivc_write_advance(ivc);
} }
/*
* Return negative err code on Failure, or 0 on Success.
* This function will populate address of next read frame
* info functions ppframe input argument.
*/
static inline int dce_os_ivc_get_next_read_frame(dce_os_ivc_t *ivc, void **ppframe)
{
int err = 0;
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
struct iosys_map pframe;
err = tegra_ivc_read_get_next_frame(ivc, &pframe);
if (err) {
iosys_map_clear(&pframe);
goto done;
}
#else
void *pframe = NULL;
pframe = tegra_ivc_read_get_next_frame(ivc);
if (IS_ERR(pframe)) {
err = -ENOMEM;
goto done;
}
#endif
*ppframe = pframe;
done:
return err;
}
/* Returns 0, or a negative error value if failed. */ /* Returns 0, or a negative error value if failed. */
static inline int dce_os_ivc_read_advance(dce_os_ivc_t *ivc) static inline int dce_os_ivc_read_advance(dce_os_ivc_t *ivc)
{ {
@@ -145,4 +81,47 @@ static inline uint32_t dce_os_ivc_total_queue_size(uint32_t size)
return tegra_ivc_total_queue_size(size); return tegra_ivc_total_queue_size(size);
} }
int dce_os_ivc_write_channel(struct dce_ipc_channel *ch,
const void *data, size_t size);
int dce_os_ivc_read_channel(struct dce_ipc_channel *ch,
void *data, size_t size);
/**
* dce_os_ivc_is_data_available - Check if data is avaialble for reading.
*
* @ch : Pointer to DCE IPC channel struct
*
* Return : true if success and data is available, false otherwise
*/
bool dce_os_ivc_is_data_available(struct dce_ipc_channel *ch);
/**
* dce_os_ivc_get_next_write_frame - Get next write frame.
*
* @ivc : Pointer to IVC struct
* @ppFrame : Pointer to frame reference.
*
* Return : 0 if successful.
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
int dce_os_ivc_get_next_write_frame(dce_os_ivc_t *ivc, struct iosys_map *ppframe);
#else /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
int dce_os_ivc_get_next_write_frame(dce_os_ivc_t *ivc, void **ppframe);
#endif /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
/**
* dce_os_ivc_get_next_read_frame - Get next read frame.
*
* @ivc : Pointer to IVC struct
* @ppFrame : Pointer to frame reference.
*
* Return : 0 if successful.
*/
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP) /* Linux v6.2 */
int dce_os_ivc_get_next_read_frame(dce_os_ivc_t *ivc, struct iosys_map *ppframe);
#else /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
int dce_os_ivc_get_next_read_frame(dce_os_ivc_t *ivc, void **ppframe);
#endif /* NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP */
#endif /* DCE_OS_IVC_H */ #endif /* DCE_OS_IVC_H */