| /* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| #ifndef _SOC_QCOM_GLINK_PRIVATE_H_ |
| #define _SOC_QCOM_GLINK_PRIVATE_H_ |
| |
| #include <linux/bug.h> |
| #include <linux/completion.h> |
| #include <linux/dcache.h> |
| #include <linux/ipc_logging.h> |
| #include <linux/kernel.h> |
| #include <linux/kref.h> |
| #include <linux/ratelimit.h> |
| #include <linux/sched.h> |
| #include <linux/seq_file.h> |
| #include <linux/spinlock.h> |
| #include <linux/types.h> |
| #include <soc/qcom/glink.h> |
| |
| struct glink_core_xprt_ctx; |
| struct channel_ctx; |
| enum transport_state_e; |
| enum local_channel_state_e; |
| |
| /* Logging Macros */ |
| enum { |
| QCOM_GLINK_INFO = 1U << 0, |
| QCOM_GLINK_DEBUG = 1U << 1, |
| QCOM_GLINK_GPIO = 1U << 2, |
| QCOM_GLINK_PERF = 1U << 3, |
| }; |
| |
| enum glink_dbgfs_ss { |
| GLINK_DBGFS_MPSS, |
| GLINK_DBGFS_APSS, |
| GLINK_DBGFS_LPASS, |
| GLINK_DBGFS_DSPS, |
| GLINK_DBGFS_RPM, |
| GLINK_DBGFS_WCNSS, |
| GLINK_DBGFS_LLOOP, |
| GLINK_DBGFS_MOCK, |
| GLINK_DBGFS_MAX_NUM_SUBS |
| }; |
| |
| enum glink_dbgfs_xprt { |
| GLINK_DBGFS_SMEM, |
| GLINK_DBGFS_SMD, |
| GLINK_DBGFS_XLLOOP, |
| GLINK_DBGFS_XMOCK, |
| GLINK_DBGFS_XMOCK_LOW, |
| GLINK_DBGFS_XMOCK_HIGH, |
| GLINK_DBGFS_MAX_NUM_XPRTS |
| }; |
| |
| struct glink_dbgfs { |
| const char *curr_name; |
| const char *par_name; |
| bool b_dir_create; |
| }; |
| |
| struct glink_dbgfs_data { |
| struct list_head flist; |
| struct dentry *dent; |
| void (*o_func)(struct seq_file *s); |
| void *priv_data; |
| bool b_priv_free_req; |
| }; |
| |
| struct xprt_ctx_iterator { |
| struct list_head *xprt_list; |
| struct glink_core_xprt_ctx *i_curr; |
| unsigned long xprt_list_flags; |
| }; |
| |
| struct ch_ctx_iterator { |
| struct list_head *ch_list; |
| struct channel_ctx *i_curr; |
| unsigned long ch_list_flags; |
| }; |
| |
| struct glink_ch_intent_info { |
| spinlock_t *li_lst_lock; |
| struct list_head *li_avail_list; |
| struct list_head *li_used_list; |
| spinlock_t *ri_lst_lock; |
| struct list_head *ri_list; |
| }; |
| |
| /* Tracer Packet Event IDs for G-Link */ |
| enum glink_tracer_pkt_events { |
| GLINK_CORE_TX = 1, |
| GLINK_QUEUE_TO_SCHEDULER = 2, |
| GLINK_SCHEDULER_TX = 3, |
| GLINK_XPRT_TX = 4, |
| GLINK_XPRT_RX = 5, |
| GLINK_CORE_RX = 6, |
| }; |
| |
| /** |
| * glink_get_ss_enum_string() - get the name of the subsystem based on enum |
| * value |
| * @enum_id: enum id of a specific subsystem. |
| * |
| * Return: name of the subsystem, NULL in case of invalid input |
| */ |
| const char *glink_get_ss_enum_string(unsigned int enum_id); |
| |
| /** |
| * glink_get_xprt_enum_string() - get the name of the transport based on enum |
| * value |
| * @enum_id: enum id of a specific transport. |
| * |
| * Return: name of the transport, NULL in case of invalid input |
| */ |
| const char *glink_get_xprt_enum_string(unsigned int enum_id); |
| |
| /** |
| * glink_get_xprt_state_string() - get the name of the transport based on enum |
| * value |
| * @enum_id: enum id of the state of the transport. |
| * |
| * Return: name of the transport state, NULL in case of invalid input |
| */ |
| const char *glink_get_xprt_state_string(enum transport_state_e enum_id); |
| |
| /** |
| * glink_get_ch_state_string() - get the name of the transport based on enum |
| * value |
| * @enum_id: enum id of a specific state of the channel. |
| * |
| * Return: name of the channel state, NULL in case of invalid input |
| */ |
| const char *glink_get_ch_state_string(enum local_channel_state_e enum_id); |
| |
| #define GLINK_IPC_LOG_STR(x...) do { \ |
| if (glink_get_log_ctx()) \ |
| ipc_log_string(glink_get_log_ctx(), x); \ |
| } while (0) |
| |
| #define GLINK_DBG(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_IPC_LOG_STR(x); \ |
| } while (0) |
| |
| #define GLINK_INFO(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_IPC_LOG_STR(x); \ |
| } while (0) |
| |
| #define GLINK_INFO_PERF(x...) do { \ |
| if (glink_get_debug_mask() & (QCOM_GLINK_INFO | QCOM_GLINK_PERF)) \ |
| GLINK_IPC_LOG_STR(x); \ |
| } while (0) |
| |
| #define GLINK_PERF(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_PERF) \ |
| GLINK_IPC_LOG_STR("<PERF> " x); \ |
| } while (0) |
| |
| #define GLINK_UT_ERR(x...) do { \ |
| if (!(glink_get_debug_mask() & QCOM_GLINK_PERF)) \ |
| pr_err("<UT> " x); \ |
| GLINK_IPC_LOG_STR("<UT> " x); \ |
| } while (0) |
| |
| #define GLINK_UT_DBG(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_IPC_LOG_STR("<UT> " x); \ |
| } while (0) |
| |
| #define GLINK_UT_INFO(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_IPC_LOG_STR("<UT> " x); \ |
| } while (0) |
| |
| #define GLINK_UT_INFO_PERF(x...) do { \ |
| if (glink_get_debug_mask() & (QCOM_GLINK_INFO | QCOM_GLINK_PERF)) \ |
| GLINK_IPC_LOG_STR("<UT> " x); \ |
| } while (0) |
| |
| #define GLINK_UT_PERF(x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_PERF) \ |
| GLINK_IPC_LOG_STR("<PERF> " x); \ |
| } while (0) |
| |
| #define GLINK_XPRT_IPC_LOG_STR(xprt, x...) do { \ |
| if (glink_get_xprt_log_ctx(xprt)) \ |
| ipc_log_string(glink_get_xprt_log_ctx(xprt), x); \ |
| } while (0) |
| |
| #define GLINK_XPRT_IF_INFO(xprt_if, x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt_if.glink_core_priv, "<XPRT> " x); \ |
| } while (0) |
| |
| #define GLINK_XPRT_IF_DBG(xprt_if, x...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt_if.glink_core_priv, "<XPRT> " x); \ |
| } while (0) |
| |
| #define GLINK_XPRT_IF_ERR(xprt_if, x...) do { \ |
| pr_err("<XPRT> " x); \ |
| GLINK_XPRT_IPC_LOG_STR(xprt_if.glink_core_priv, "<XPRT> " x); \ |
| } while (0) |
| |
| #define GLINK_PERF_XPRT(xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_PERF) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, "<PERF> %s:%s " fmt, \ |
| xprt->name, xprt->edge, args); \ |
| } while (0) |
| |
| #define GLINK_PERF_CH(ctx, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_PERF) \ |
| GLINK_XPRT_IPC_LOG_STR(ctx->transport_ptr, \ |
| "<PERF> %s:%s:%s[%u:%u] " fmt, \ |
| ctx->transport_ptr->name, \ |
| ctx->transport_ptr->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_PERF_CH_XPRT(ctx, xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_PERF) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, \ |
| "<PERF> %s:%s:%s[%u:%u] " fmt, \ |
| xprt->name, \ |
| xprt->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_PERF_XPRT(xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & (QCOM_GLINK_INFO | QCOM_GLINK_PERF)) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, "<CORE> %s:%s " fmt, \ |
| xprt->name, xprt->edge, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_PERF_CH(ctx, fmt, args...) do { \ |
| if (glink_get_debug_mask() & (QCOM_GLINK_INFO | QCOM_GLINK_PERF)) \ |
| GLINK_XPRT_IPC_LOG_STR(ctx->transport_ptr, \ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| ctx->transport_ptr->name, \ |
| ctx->transport_ptr->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_PERF_CH_XPRT(ctx, xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & (QCOM_GLINK_INFO | QCOM_GLINK_PERF)) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt,\ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| xprt->name, \ |
| xprt->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_XPRT(xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, "<CORE> %s:%s " fmt, \ |
| xprt->name, xprt->edge, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_CH(ctx, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_XPRT_IPC_LOG_STR(ctx->transport_ptr, \ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| ctx->transport_ptr->name, \ |
| ctx->transport_ptr->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_INFO_CH_XPRT(ctx, xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_INFO) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, \ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| xprt->name, \ |
| xprt->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_DBG_XPRT(xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, "<CORE> %s:%s " fmt, \ |
| xprt->name, xprt->edge, args); \ |
| } while (0) |
| |
| #define GLINK_DBG_CH(ctx, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_XPRT_IPC_LOG_STR(ctx->transport_ptr, \ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| ctx->transport_ptr->name, \ |
| ctx->transport_ptr->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_DBG_CH_XPRT(ctx, xprt, fmt, args...) do { \ |
| if (glink_get_debug_mask() & QCOM_GLINK_DEBUG) \ |
| GLINK_XPRT_IPC_LOG_STR(xprt, \ |
| "<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| xprt->name, \ |
| xprt->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| } while (0) |
| |
| #define GLINK_ERR(x...) do { \ |
| pr_err_ratelimited("<CORE> " x); \ |
| GLINK_IPC_LOG_STR("<CORE> " x); \ |
| } while (0) |
| |
| #define GLINK_ERR_XPRT(xprt, fmt, args...) do { \ |
| pr_err_ratelimited("<CORE> %s:%s " fmt, \ |
| xprt->name, xprt->edge, args); \ |
| GLINK_INFO_XPRT(xprt, fmt, args); \ |
| } while (0) |
| |
| #define GLINK_ERR_CH(ctx, fmt, args...) do { \ |
| pr_err_ratelimited("<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| ctx->transport_ptr->name, \ |
| ctx->transport_ptr->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| GLINK_INFO_CH(ctx, fmt, args); \ |
| } while (0) |
| |
| #define GLINK_ERR_CH_XPRT(ctx, xprt, fmt, args...) do { \ |
| pr_err_ratelimited("<CORE> %s:%s:%s[%u:%u] " fmt, \ |
| xprt->name, \ |
| xprt->edge, \ |
| ctx->name, \ |
| ctx->lcid, \ |
| ctx->rcid, args); \ |
| GLINK_INFO_CH_XPRT(ctx, xprt, fmt, args); \ |
| } while (0) |
| |
| /** |
| * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow |
| * |
| * type: type to check for overflow |
| * a: left value to use |
| * b: right value to use |
| * returns: true if a + b will result in overflow; false otherwise |
| */ |
| #define OVERFLOW_ADD_UNSIGNED(type, a, b) \ |
| (((type)~0 - (a)) < (b) ? true : false) |
| |
| /** |
| * glink_get_debug_mask() - Return debug mask attribute |
| * |
| * Return: debug mask attribute |
| */ |
| unsigned int glink_get_debug_mask(void); |
| |
| /** |
| * glink_get_log_ctx() - Return log context for other GLINK modules. |
| * |
| * Return: Log context or NULL if none. |
| */ |
| void *glink_get_log_ctx(void); |
| |
| /** |
| * glink_get_xprt_log_ctx() - Return log context for other GLINK modules. |
| * |
| * Return: Log context or NULL if none. |
| */ |
| void *glink_get_xprt_log_ctx(struct glink_core_xprt_ctx *xprt); |
| |
| /** |
| * glink_get_channel_id_for_handle() - Get logical channel ID |
| * |
| * @handle: handle of channel |
| * |
| * Used internally by G-Link debugfs. |
| * |
| * Return: Logical Channel ID or standard Linux error code |
| */ |
| int glink_get_channel_id_for_handle(void *handle); |
| |
| /** |
| * glink_get_channel_name_for_handle() - return channel name |
| * |
| * @handle: handle of channel |
| * |
| * Used internally by G-Link debugfs. |
| * |
| * Return: Channel name or NULL |
| */ |
| char *glink_get_channel_name_for_handle(void *handle); |
| |
| /** |
| * glink_debugfs_init() - initialize glink debugfs directory |
| * |
| * Return: error code or success. |
| */ |
| int glink_debugfs_init(void); |
| |
| /** |
| * glink_debugfs_exit() - removes glink debugfs directory |
| */ |
| void glink_debugfs_exit(void); |
| |
| /** |
| * glink_debugfs_create() - create the debugfs file |
| * @name: debugfs file name |
| * @show: pointer to the actual function which will be invoked upon |
| * opening this file. |
| * @dir: pointer to a structure debugfs_dir |
| * @dbgfs_data: pointer to any private data need to be associated with debugfs |
| * @b_free_req: boolean value to decide to free the memory associated with |
| * @dbgfs_data during deletion of the file |
| * |
| * Return: pointer to the file/directory created, NULL in case of error |
| * |
| * This function checks which directory will be used to create the debugfs file |
| * and calls glink_dfs_create_file. Anybody who intend to allocate some memory |
| * for the dbgfs_data and required to free it in deletion, need to set |
| * b_free_req to true. Otherwise, there will be a memory leak. |
| */ |
| struct dentry *glink_debugfs_create(const char *name, |
| void (*show)(struct seq_file *), |
| struct glink_dbgfs *dir, void *dbgfs_data, bool b_free_req); |
| |
| /** |
| * glink_debugfs_remove_recur() - remove the the directory & files recursively |
| * @rm_dfs: pointer to the structure glink_dbgfs |
| * |
| * This function removes the files & directories. This also takes care of |
| * freeing any memory associated with the debugfs file. |
| */ |
| void glink_debugfs_remove_recur(struct glink_dbgfs *dfs); |
| |
| /** |
| * glink_debugfs_remove_channel() - remove all channel specific files & folder |
| * in debugfs when channel is fully closed |
| * @ch_ctx: pointer to the channel_contenxt |
| * @xprt_ctx: pointer to the transport_context |
| * |
| * This function is invoked when any channel is fully closed. It removes the |
| * folders & other files in debugfs for that channel. |
| */ |
| void glink_debugfs_remove_channel(struct channel_ctx *ch_ctx, |
| struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_debugfs_add_channel() - create channel specific files & folder in |
| * debugfs when channel is added |
| * @ch_ctx: pointer to the channel_contenxt |
| * @xprt_ctx: pointer to the transport_context |
| * |
| * This function is invoked when a new channel is created. It creates the |
| * folders & other files in debugfs for that channel |
| */ |
| void glink_debugfs_add_channel(struct channel_ctx *ch_ctx, |
| struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_debugfs_add_xprt() - create transport specific files & folder in |
| * debugfs when new transport is registered |
| * @xprt_ctx: pointer to the transport_context |
| * |
| * This function is invoked when a new transport is registered. It creates the |
| * folders & other files in debugfs for that transport |
| */ |
| void glink_debugfs_add_xprt(struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_xprt_ctx_iterator_init() - Initializes the transport context list |
| * iterator |
| * @xprt_i: pointer to the transport context iterator. |
| * |
| * Return: None |
| * |
| * This function acquires the transport context lock which must then be |
| * released by glink_xprt_ctx_iterator_end() |
| */ |
| void glink_xprt_ctx_iterator_init(struct xprt_ctx_iterator *xprt_i); |
| |
| /** |
| * glink_xprt_ctx_iterator_end() - Ends the transport context list iteration |
| * @xprt_i: pointer to the transport context iterator. |
| * |
| * Return: None |
| */ |
| void glink_xprt_ctx_iterator_end(struct xprt_ctx_iterator *xprt_i); |
| |
| /** |
| * glink_xprt_ctx_iterator_next() - iterates element by element in transport |
| * context list |
| * @xprt_i: pointer to the transport context iterator. |
| * |
| * Return: pointer to the transport context structure |
| */ |
| struct glink_core_xprt_ctx *glink_xprt_ctx_iterator_next( |
| struct xprt_ctx_iterator *xprt_i); |
| |
| /** |
| * glink_get_xprt_name() - get the transport name |
| * @xprt_ctx: pointer to the transport context. |
| * |
| * Return: name of the transport |
| */ |
| char *glink_get_xprt_name(struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_get_xprt_edge_name() - get the name of the remote processor/edge |
| * of the transport |
| * @xprt_ctx: pointer to the transport context. |
| * |
| * Return: name of the remote processor/edge |
| */ |
| char *glink_get_xprt_edge_name(struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_get_xprt_state() - get the state of the transport |
| * @xprt_ctx: pointer to the transport context. |
| * |
| * Return: name of the transport state, NULL in case of invalid input |
| */ |
| const char *glink_get_xprt_state(struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_get_xprt_version_features() - get the version and feature set |
| * of local transport in glink |
| * @xprt_ctx: pointer to the transport context. |
| * |
| * Return: pointer to the glink_core_version |
| */ |
| const struct glink_core_version *glink_get_xprt_version_features( |
| struct glink_core_xprt_ctx *xprt_ctx); |
| |
| /** |
| * glink_ch_ctx_iterator_init() - Initializes the channel context list iterator |
| * @ch_iter: pointer to the channel context iterator. |
| * @xprt: pointer to the transport context that holds the channel list |
| * |
| * This function acquires the channel context lock which must then be |
| * released by glink_ch_ctx_iterator_end() |
| */ |
| void glink_ch_ctx_iterator_init(struct ch_ctx_iterator *ch_iter, |
| struct glink_core_xprt_ctx *xprt); |
| |
| /** |
| * glink_ch_ctx_iterator_end() - Ends the channel context list iteration |
| * @ch_iter: pointer to the channel context iterator. |
| * |
| */ |
| void glink_ch_ctx_iterator_end(struct ch_ctx_iterator *ch_iter, |
| struct glink_core_xprt_ctx *xprt); |
| |
| /** |
| * glink_ch_ctx_iterator_next() - iterates element by element in channel |
| * context list |
| * @c_i: pointer to the channel context iterator. |
| * |
| * Return: pointer to the channel context structure |
| */ |
| struct channel_ctx *glink_ch_ctx_iterator_next(struct ch_ctx_iterator *ch_iter); |
| |
| /** |
| * glink_get_ch_name() - get the channel name |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: name of the channel, NULL in case of invalid input |
| */ |
| char *glink_get_ch_name(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_edge_name() - get the name of the remote processor/edge |
| * of the channel |
| * @xprt_ctx: pointer to the channel context. |
| * |
| * Return: name of the remote processor/edge |
| */ |
| char *glink_get_ch_edge_name(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_rcid() - get the remote channel ID |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: remote channel id, -EINVAL in case of invalid input |
| */ |
| int glink_get_ch_lcid(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_rcid() - get the remote channel ID |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: remote channel id, -EINVAL in case of invalid input |
| */ |
| int glink_get_ch_rcid(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_lstate() - get the local channel state |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: name of the local channel state, NULL in case of invalid input |
| */ |
| const char *glink_get_ch_lstate(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_rstate() - get the remote channel state |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: true if remote side is opened false otherwise |
| */ |
| bool glink_get_ch_rstate(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_xprt_name() - get the name of the transport to which |
| * the channel belongs |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: name of the export, NULL in case of invalid input |
| */ |
| char *glink_get_ch_xprt_name(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_tx_pkt_count() - get the total number of packets sent |
| * through this channel |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: number of packets transmitted, -EINVAL in case of invalid input |
| */ |
| int glink_get_ch_tx_pkt_count(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_rx_pkt_count() - get the total number of packets |
| * received at this channel |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: number of packets received, -EINVAL in case of invalid input |
| */ |
| int glink_get_ch_rx_pkt_count(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_lintents_queued() - get the total number of intents queued |
| * at local side |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: number of intents queued, -EINVAL in case of invalid input |
| */ |
| int glink_get_ch_lintents_queued(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_rintents_queued() - get the total number of intents queued |
| * from remote side |
| * @ch_ctx: pointer to the channel context. |
| * |
| * Return: number of intents queued |
| */ |
| int glink_get_ch_rintents_queued(struct channel_ctx *ch_ctx); |
| |
| /** |
| * glink_get_ch_intent_info() - get the intent details of a channel |
| * @ch_ctx: pointer to the channel context. |
| * @ch_ctx_i: pointer to a structure that will contain intent details |
| * |
| * This function is used to get all the channel intent details including locks. |
| */ |
| void glink_get_ch_intent_info(struct channel_ctx *ch_ctx, |
| struct glink_ch_intent_info *ch_ctx_i); |
| |
| /** |
| * enum ssr_command - G-Link SSR protocol commands |
| */ |
| enum ssr_command { |
| GLINK_SSR_DO_CLEANUP, |
| GLINK_SSR_CLEANUP_DONE, |
| }; |
| |
| /** |
| * struct ssr_notify_data - Contains private data used for client notifications |
| * from G-Link. |
| * tx_done: Indicates whether or not the tx_done notification has |
| * been received. |
| * event: The state notification event received. |
| * responded: Indicates whether or not a cleanup_done response was |
| * received. |
| * edge: The G-Link edge name for the channel associated with |
| * this callback data |
| * do_cleanup_data: Structure containing the G-Link SSR do_cleanup message. |
| * cb_kref: Kref object to maintain cb_data reference. |
| */ |
| struct ssr_notify_data { |
| bool tx_done; |
| unsigned int event; |
| bool responded; |
| const char *edge; |
| struct do_cleanup_msg *do_cleanup_data; |
| struct kref cb_kref; |
| }; |
| |
| /** |
| * struct subsys_info - Subsystem info structure |
| * ssr_name: name of the subsystem recognized by the SSR framework |
| * edge: name of the G-Link edge |
| * xprt: name of the G-Link transport |
| * handle: glink_ssr channel used for this subsystem |
| * link_state_handle: link state handle for this edge, used to unregister |
| * from receiving link state callbacks |
| * link_info: Transport info used in link state callback registration |
| * cb_data: Private callback data structure for notification |
| * functions |
| * subsystem_list_node: used to chain this structure in a list of subsystem |
| * info structures |
| * notify_list: list of subsys_info_leaf structures, containing the |
| * subsystems to notify if this subsystem undergoes SSR |
| * notify_list_len: length of notify_list |
| * link_up: Flag indicating whether transport is up or not |
| * link_up_lock: Lock for protecting the link_up flag |
| */ |
| struct subsys_info { |
| const char *ssr_name; |
| const char *edge; |
| const char *xprt; |
| void *handle; |
| void *link_state_handle; |
| struct glink_link_info *link_info; |
| struct ssr_notify_data *cb_data; |
| struct list_head subsystem_list_node; |
| struct list_head notify_list; |
| int notify_list_len; |
| bool link_up; |
| spinlock_t link_up_lock; |
| spinlock_t cb_lock; |
| }; |
| |
| /** |
| * struct subsys_info_leaf - Subsystem info leaf structure (a subsystem on the |
| * notify list of a subsys_info structure) |
| * ssr_name: Name of the subsystem recognized by the SSR framework |
| * edge: Name of the G-Link edge |
| * xprt: Name of the G-Link transport |
| * restarted: Indicates whether a restart has been triggered for this edge |
| * cb_data: Private callback data structure for notification functions |
| * notify_list_node: used to chain this structure in the notify list |
| */ |
| struct subsys_info_leaf { |
| const char *ssr_name; |
| const char *edge; |
| const char *xprt; |
| bool restarted; |
| struct ssr_notify_data *cb_data; |
| struct list_head notify_list_node; |
| }; |
| |
| /** |
| * struct do_cleanup_msg - The data structure for an SSR do_cleanup message |
| * version: The G-Link SSR protocol version |
| * command: The G-Link SSR command - do_cleanup |
| * seq_num: Sequence number |
| * name_len: Length of the name of the subsystem being restarted |
| * name: G-Link edge name of the subsystem being restarted |
| */ |
| struct do_cleanup_msg { |
| uint32_t version; |
| uint32_t command; |
| uint32_t seq_num; |
| uint32_t name_len; |
| char name[32]; |
| }; |
| |
| /** |
| * struct cleanup_done_msg - The data structure for an SSR cleanup_done message |
| * version: The G-Link SSR protocol version |
| * response: The G-Link SSR response to a do_cleanup command, cleanup_done |
| * seq_num: Sequence number |
| */ |
| struct cleanup_done_msg { |
| uint32_t version; |
| uint32_t response; |
| uint32_t seq_num; |
| }; |
| |
| /** |
| * get_info_for_subsystem() - Retrieve information about a subsystem from the |
| * global subsystem_info_list |
| * @subsystem: The name of the subsystem recognized by the SSR |
| * framework |
| * |
| * Return: subsys_info structure containing info for the requested subsystem; |
| * NULL if no structure can be found for the requested subsystem |
| */ |
| struct subsys_info *get_info_for_subsystem(const char *subsystem); |
| |
| /** |
| * get_info_for_edge() - Retrieve information about a subsystem from the |
| * global subsystem_info_list |
| * @edge: The name of the edge recognized by G-Link |
| * |
| * Return: subsys_info structure containing info for the requested subsystem; |
| * NULL if no structure can be found for the requested subsystem |
| */ |
| struct subsys_info *get_info_for_edge(const char *edge); |
| |
| /** |
| * glink_ssr_get_seq_num() - Get the current SSR sequence number |
| * |
| * Return: The current SSR sequence number |
| */ |
| uint32_t glink_ssr_get_seq_num(void); |
| |
| /* |
| * glink_ssr() - SSR cleanup function. |
| * |
| * Return: Standard error code. |
| */ |
| int glink_ssr(const char *subsystem); |
| |
| /** |
| * notify for subsystem() - Notify other subsystems that a subsystem is being |
| * restarted |
| * @ss_info: Subsystem info structure for the subsystem being restarted |
| * |
| * This function sends notifications to affected subsystems that the subsystem |
| * in ss_info is being restarted, and waits for the cleanup done response from |
| * all of those subsystems. It also initiates any local cleanup that is |
| * necessary. |
| * |
| * Return: 0 on success, standard error codes otherwise |
| */ |
| int notify_for_subsystem(struct subsys_info *ss_info); |
| |
| /** |
| * glink_ssr_wait_cleanup_done() - Get the value of the |
| * notifications_successful flag in glink_ssr. |
| * @timeout_multiplier: timeout multiplier for waiting on all processors |
| * |
| * |
| * Return: True if cleanup_done received from all processors, false otherwise |
| */ |
| bool glink_ssr_wait_cleanup_done(unsigned int ssr_timeout_multiplier); |
| |
| struct channel_lcid { |
| struct list_head list_node; |
| uint32_t lcid; |
| }; |
| |
| /** |
| * struct rwref_lock - Read/Write Reference Lock |
| * |
| * kref: reference count |
| * read_count: number of readers that own the lock |
| * write_count: number of writers (max 1) that own the lock |
| * count_zero: used for internal signaling for non-atomic locks |
| * |
| * A Read/Write Reference Lock is a combination of a read/write spinlock and a |
| * reference count. The main difference is that no locks are held in the |
| * critical section and the lifetime of the object is guaranteed. |
| * |
| * Read Locking |
| * Multiple readers may access the lock at any given time and a read lock will |
| * also ensure that the object exists for the life of the lock. |
| * |
| * rwref_read_get() |
| * use resource in "critical section" (no locks are held) |
| * rwref_read_put() |
| * |
| * Write Locking |
| * A single writer may access the lock at any given time and a write lock will |
| * also ensure that the object exists for the life of the lock. |
| * |
| * rwref_write_get() |
| * use resource in "critical section" (no locks are held) |
| * rwref_write_put() |
| * |
| * Reference Lock |
| * To ensure the lifetime of the lock (and not affect the read or write lock), |
| * a simple reference can be done. By default, rwref_lock_init() will set the |
| * reference count to 1. |
| * |
| * rwref_lock_init() Reference count is 1 |
| * rwref_get() Reference count is 2 |
| * rwref_put() Reference count is 1 |
| * rwref_put() Reference count goes to 0 and object is destroyed |
| */ |
| struct rwref_lock { |
| struct kref kref; |
| unsigned int read_count; |
| unsigned int write_count; |
| spinlock_t lock; |
| wait_queue_head_t count_zero; |
| |
| void (*release)(struct rwref_lock *); |
| }; |
| |
| /** |
| * rwref_lock_release() - Initialize rwref_lock |
| * lock_ptr: pointer to lock structure |
| */ |
| static inline void rwref_lock_release(struct kref *kref_ptr) |
| { |
| struct rwref_lock *lock_ptr; |
| |
| if (WARN_ON(kref_ptr == NULL)) |
| return; |
| |
| lock_ptr = container_of(kref_ptr, struct rwref_lock, kref); |
| if (lock_ptr->release) |
| lock_ptr->release(lock_ptr); |
| } |
| |
| /** |
| * rwref_lock_init() - Initialize rwref_lock |
| * lock_ptr: pointer to lock structure |
| * release: release function called when reference count goes to 0 |
| */ |
| static inline void rwref_lock_init(struct rwref_lock *lock_ptr, |
| void (*release)(struct rwref_lock *)) |
| { |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| kref_init(&lock_ptr->kref); |
| lock_ptr->read_count = 0; |
| lock_ptr->write_count = 0; |
| spin_lock_init(&lock_ptr->lock); |
| init_waitqueue_head(&lock_ptr->count_zero); |
| lock_ptr->release = release; |
| } |
| |
| /** |
| * rwref_get() - gains a reference count for the object |
| * lock_ptr: pointer to lock structure |
| */ |
| static inline void rwref_get(struct rwref_lock *lock_ptr) |
| { |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| kref_get(&lock_ptr->kref); |
| } |
| |
| /** |
| * rwref_put() - puts a reference count for the object |
| * lock_ptr: pointer to lock structure |
| * |
| * If the reference count goes to zero, the release function is called. |
| */ |
| static inline void rwref_put(struct rwref_lock *lock_ptr) |
| { |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| kref_put(&lock_ptr->kref, rwref_lock_release); |
| } |
| |
| /** |
| * rwref_read_get_atomic() - gains a reference count for a read operation |
| * lock_ptr: pointer to lock structure |
| * is_atomic: if True, do not wait when acquiring lock |
| * |
| * Multiple readers may acquire the lock as long as the write count is zero. |
| */ |
| static inline void rwref_read_get_atomic(struct rwref_lock *lock_ptr, |
| bool is_atomic) |
| { |
| unsigned long flags; |
| |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| kref_get(&lock_ptr->kref); |
| while (1) { |
| spin_lock_irqsave(&lock_ptr->lock, flags); |
| if (lock_ptr->write_count == 0) { |
| lock_ptr->read_count++; |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| break; |
| } |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| if (!is_atomic) { |
| wait_event(lock_ptr->count_zero, |
| lock_ptr->write_count == 0); |
| } |
| } |
| } |
| |
| /** |
| * rwref_read_get() - gains a reference count for a read operation |
| * lock_ptr: pointer to lock structure |
| * |
| * Multiple readers may acquire the lock as long as the write count is zero. |
| */ |
| static inline void rwref_read_get(struct rwref_lock *lock_ptr) |
| { |
| rwref_read_get_atomic(lock_ptr, false); |
| } |
| |
| /** |
| * rwref_read_put() - returns a reference count for a read operation |
| * lock_ptr: pointer to lock structure |
| * |
| * Must be preceded by a call to rwref_read_get(). |
| */ |
| static inline void rwref_read_put(struct rwref_lock *lock_ptr) |
| { |
| unsigned long flags; |
| |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| spin_lock_irqsave(&lock_ptr->lock, flags); |
| if (WARN_ON(lock_ptr->read_count == 0)) { |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| return; |
| } |
| if (--lock_ptr->read_count == 0) |
| wake_up(&lock_ptr->count_zero); |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| kref_put(&lock_ptr->kref, rwref_lock_release); |
| } |
| |
| /** |
| * rwref_write_get_atomic() - gains a reference count for a write operation |
| * lock_ptr: pointer to lock structure |
| * is_atomic: if True, do not wait when acquiring lock |
| * |
| * Only one writer may acquire the lock as long as the reader count is zero. |
| */ |
| static inline void rwref_write_get_atomic(struct rwref_lock *lock_ptr, |
| bool is_atomic) |
| { |
| unsigned long flags; |
| |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| kref_get(&lock_ptr->kref); |
| while (1) { |
| spin_lock_irqsave(&lock_ptr->lock, flags); |
| if (lock_ptr->read_count == 0 && lock_ptr->write_count == 0) { |
| lock_ptr->write_count++; |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| break; |
| } |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| if (!is_atomic) { |
| wait_event(lock_ptr->count_zero, |
| (lock_ptr->read_count == 0 && |
| lock_ptr->write_count == 0)); |
| } |
| } |
| } |
| |
| /** |
| * rwref_write_get() - gains a reference count for a write operation |
| * lock_ptr: pointer to lock structure |
| * |
| * Only one writer may acquire the lock as long as the reader count is zero. |
| */ |
| static inline void rwref_write_get(struct rwref_lock *lock_ptr) |
| { |
| rwref_write_get_atomic(lock_ptr, false); |
| } |
| |
| /** |
| * rwref_write_put() - returns a reference count for a write operation |
| * lock_ptr: pointer to lock structure |
| * |
| * Must be preceded by a call to rwref_write_get(). |
| */ |
| static inline void rwref_write_put(struct rwref_lock *lock_ptr) |
| { |
| unsigned long flags; |
| |
| if (WARN_ON(lock_ptr == NULL)) |
| return; |
| |
| spin_lock_irqsave(&lock_ptr->lock, flags); |
| if (WARN_ON(lock_ptr->write_count != 1)) { |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| return; |
| } |
| if (--lock_ptr->write_count == 0) |
| wake_up(&lock_ptr->count_zero); |
| spin_unlock_irqrestore(&lock_ptr->lock, flags); |
| kref_put(&lock_ptr->kref, rwref_lock_release); |
| } |
| |
| #endif /* _SOC_QCOM_GLINK_PRIVATE_H_ */ |