From cd3169877146496ef996831dc7c70ab2a2e4e992 Mon Sep 17 00:00:00 2001 From: anupamg Date: Fri, 18 Oct 2024 11:08:55 -0700 Subject: [PATCH] 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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3233117 Reviewed-by: Mahesh Kumar Reviewed-by: Arun Swain GVS: buildbot_gerritrpt --- drivers/platform/tegra/dce/Makefile | 1 + drivers/platform/tegra/dce/dce-ipc.c | 98 +-------- drivers/platform/tegra/dce/dce-os-ivc.c | 191 ++++++++++++++++++ drivers/platform/tegra/dce/include/dce-ipc.h | 2 + .../tegra/dce/os/linux/include/dce-os-ivc.h | 111 +++++----- 5 files changed, 245 insertions(+), 158 deletions(-) create mode 100644 drivers/platform/tegra/dce/dce-os-ivc.c diff --git a/drivers/platform/tegra/dce/Makefile b/drivers/platform/tegra/dce/Makefile index 6c27b5c3..2e7c73ee 100644 --- a/drivers/platform/tegra/dce/Makefile +++ b/drivers/platform/tegra/dce/Makefile @@ -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-hsp-smb-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) tegra-dce-$(CONFIG_TEGRA_DCE) += dce-debug.o diff --git a/drivers/platform/tegra/dce/dce-ipc.c b/drivers/platform/tegra/dce/dce-ipc.c index 548a7901..1f9f7a4f 100644 --- a/drivers/platform/tegra/dce/dce-ipc.c +++ b/drivers/platform/tegra/dce/dce-ipc.c @@ -436,48 +436,6 @@ static int _dce_ipc_get_next_write_buff(struct dce_ipc_channel *ch) 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. * @@ -505,7 +463,7 @@ int dce_ipc_send_message(struct tegra_dce *d, u32 ch_type, goto out; } - ret = _dce_ipc_write_channel(ch, data, size); + ret = dce_os_ivc_write_channel(ch, data, size); if (ret) { dce_os_err(ch->d, "Error writing to channel"); goto out; @@ -540,47 +498,6 @@ static int _dce_ipc_get_next_read_buff(struct dce_ipc_channel *ch) 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. * @@ -607,7 +524,7 @@ int dce_ipc_read_message(struct tegra_dce *d, u32 ch_type, goto out; } - ret = _dce_ipc_read_channel(ch, data, size); + ret = dce_os_ivc_read_channel(ch, data, size); if (ret) { dce_os_err(ch->d, "Error reading from channel"); 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 * @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 ret = false; - void *frame; - int err = 0; struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type]; dce_os_mutex_lock(&ch->lock); - err = dce_os_ivc_get_next_read_frame(&ch->d_ivc, &frame); - if (err == 0) - ret = true; + ret = dce_os_ivc_is_data_available(ch); dce_os_mutex_unlock(&ch->lock); diff --git a/drivers/platform/tegra/dce/dce-os-ivc.c b/drivers/platform/tegra/dce/dce-os-ivc.c new file mode 100644 index 00000000..f8d4cfce --- /dev/null +++ b/drivers/platform/tegra/dce/dce-os-ivc.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include + +/** + * 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; +} diff --git a/drivers/platform/tegra/dce/include/dce-ipc.h b/drivers/platform/tegra/dce/include/dce-ipc.h index 46aa2cba..76f46fd5 100644 --- a/drivers/platform/tegra/dce/include/dce-ipc.h +++ b/drivers/platform/tegra/dce/include/dce-ipc.h @@ -15,6 +15,8 @@ #include #include +struct tegra_dce; + #define DCE_IPC_CHANNEL_TYPE_ADMIN 0U #define DCE_IPC_CHANNEL_TYPE_CPU_CLIENTS 1U diff --git a/drivers/platform/tegra/dce/os/linux/include/dce-os-ivc.h b/drivers/platform/tegra/dce/os/linux/include/dce-os-ivc.h index 39ec9504..87bef86a 100644 --- a/drivers/platform/tegra/dce/os/linux/include/dce-os-ivc.h +++ b/drivers/platform/tegra/dce/os/linux/include/dce-os-ivc.h @@ -9,6 +9,8 @@ #include #include +struct dce_ipc_channel; + 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 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. */ static inline int dce_os_ivc_write_advance(dce_os_ivc_t *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. */ 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); } +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 */