Files
linux-nv-oot/drivers/platform/tegra/dce/dce-os-ivc.c
anupamg cd31698771 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>
2025-07-24 10:19:12 +00:00

192 lines
3.9 KiB
C

// 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;
}