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 */