Loading drivers/soc/qcom/glink.c +113 −53 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include "glink_private.h" #include "glink_xprt_if.h" #define GLINK_CTX_CANARY 0x58544324 /* "$CTX" */ /* Number of internal IPC Logging log pages */ #define NUM_LOG_PAGES 10 #define GLINK_PM_QOS_HOLDOFF_MS 10 Loading @@ -40,7 +39,6 @@ #define GLINK_KTHREAD_PRIO 1 static rwlock_t magic_lock; /** * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * @max_rate_kBps: Maximum rate supported by the priority bucket. Loading Loading @@ -232,6 +230,8 @@ static DEFINE_MUTEX(edge_list_lock_lhd0); * @req_rate_kBps: Current QoS request by the channel. * @tx_intent_cnt: Intent count to transmit soon in future. * @tx_cnt: Packets to be picked by tx scheduler. * @rt_vote_on: Number of times RT vote on is called. * @rt_vote_off: Number of times RT vote off is called. */ struct channel_ctx { struct rwref_lock ch_state_lhb2; Loading Loading @@ -312,7 +312,9 @@ struct channel_ctx { unsigned long req_rate_kBps; uint32_t tx_intent_cnt; uint32_t tx_cnt; uint32_t magic_number; uint32_t rt_vote_on; uint32_t rt_vote_off; }; static struct glink_core_if core_impl; Loading Loading @@ -443,33 +445,15 @@ static void glink_core_deinit_xprt_qos_cfg( static int glink_get_ch_ctx(struct channel_ctx *ctx) { unsigned long flags; if (!ctx) return -EINVAL; read_lock_irqsave(&magic_lock, flags); if (ctx->magic_number != GLINK_CTX_CANARY) { read_unlock_irqrestore(&magic_lock, flags); return -EINVAL; } rwref_get(&ctx->ch_state_lhb2); read_unlock_irqrestore(&magic_lock, flags); return 0; } static int glink_put_ch_ctx(struct channel_ctx *ctx, bool update_magic) static void glink_put_ch_ctx(struct channel_ctx *ctx) { unsigned long flags; if (!update_magic) { rwref_put(&ctx->ch_state_lhb2); return 0; } write_lock_irqsave(&magic_lock, flags); ctx->magic_number = 0; rwref_put(&ctx->ch_state_lhb2); write_unlock_irqrestore(&magic_lock, flags); return 0; } /** Loading Loading @@ -2418,6 +2402,25 @@ static int dummy_power_unvote(struct glink_transport_if *if_ptr) return -EOPNOTSUPP; } /** * dummy_rx_rt_vote() - Dummy RX Realtime thread vote * @if_ptr: The transport to transmit on. */ static int dummy_rx_rt_vote(struct glink_transport_if *if_ptr) { return -EOPNOTSUPP; } /** * dummy_rx_rt_unvote() - Dummy RX Realtime thread unvote * @if_ptr: The transport to transmit on. */ static int dummy_rx_rt_unvote(struct glink_transport_if *if_ptr) { return -EOPNOTSUPP; } /** * notif_if_up_all_xprts() - Check and notify existing transport state if up * @notif_info: Data structure containing transport information to be notified. Loading Loading @@ -2600,7 +2603,6 @@ void *glink_open(const struct glink_open_config *cfg) ctx->notify_tx_abort = cfg->notify_tx_abort; ctx->notify_rx_tracer_pkt = cfg->notify_rx_tracer_pkt; ctx->notify_remote_rx_intent = cfg->notify_remote_rx_intent; ctx->magic_number = GLINK_CTX_CANARY; if (!ctx->notify_rx_intent_req) ctx->notify_rx_intent_req = glink_dummy_notify_rx_intent_req; Loading Loading @@ -2742,13 +2744,13 @@ int glink_close(void *handle) GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx); if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) { /* close already pending */ glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading Loading @@ -2813,7 +2815,7 @@ relock: xprt_ctx = ctx->transport_ptr; rwref_put(&ctx->ch_state_lhb2); rwref_read_put(&xprt_ctx->xprt_state_lhb0); glink_put_ch_ctx(ctx, true); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_close); Loading Loading @@ -3029,13 +3031,13 @@ static int glink_tx_common(void *handle, void *pkt_priv, xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info); rwref_read_put(&ctx->ch_state_lhb2); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; glink_tx_common_err: rwref_read_put(&ctx->ch_state_lhb2); glink_tx_common_err_2: glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); kfree(tx_info); return ret; } Loading Loading @@ -3085,7 +3087,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) /* Can only queue rx intents if channel is fully opened */ GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3094,14 +3096,14 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) GLINK_ERR_CH(ctx, "%s: Intent pointer allocation failed size[%zu]\n", __func__, size); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -ENOMEM; } GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id, intent_ptr->intent_size); if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } Loading @@ -3111,7 +3113,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) if (ret) /* unable to transmit, dequeue intent */ ch_remove_local_rx_intent(ctx, intent_ptr->id); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_queue_rx_intent); Loading Loading @@ -3143,12 +3145,12 @@ bool glink_rx_intent_exists(void *handle, size_t size) if (size <= intent->intent_size) { spin_unlock_irqrestore( &ctx->local_rx_intent_lst_lock_lhc1, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return true; } } spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return false; } EXPORT_SYMBOL(glink_rx_intent_exists); Loading Loading @@ -3177,7 +3179,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) if (IS_ERR_OR_NULL(liid_ptr)) { /* invalid pointer */ GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EINVAL; } Loading @@ -3203,7 +3205,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) /* send rx done */ ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops, ctx->lcid, id, reuse); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_rx_done); Loading Loading @@ -3257,7 +3259,7 @@ int glink_sigs_set(void *handle, uint32_t sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3267,7 +3269,7 @@ int glink_sigs_set(void *handle, uint32_t sigs) ctx->lcid, ctx->lsigs); GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_sigs_set); Loading @@ -3293,12 +3295,12 @@ int glink_sigs_local_get(void *handle, uint32_t *sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } *sigs = ctx->lsigs; glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } EXPORT_SYMBOL(glink_sigs_local_get); Loading @@ -3325,12 +3327,12 @@ int glink_sigs_remote_get(void *handle, uint32_t *sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } *sigs = ctx->rsigs; glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } EXPORT_SYMBOL(glink_sigs_remote_get); Loading Loading @@ -3434,7 +3436,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3444,7 +3446,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) if (ret < 0) GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n", __func__, latency_us, pkt_size); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_latency); Loading @@ -3468,12 +3470,12 @@ int glink_qos_cancel(void *handle) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } ret = glink_qos_reset_priority(ctx); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_cancel); Loading @@ -3500,7 +3502,7 @@ int glink_qos_start(void *handle) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3509,7 +3511,7 @@ int glink_qos_start(void *handle) ret = glink_qos_add_ch_tx_intent(ctx); spin_unlock(&ctx->tx_lists_lock_lhc3); spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_start); Loading Loading @@ -3537,11 +3539,11 @@ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return (unsigned long)-EBUSY; } glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ctx->transport_ptr->ops->get_power_vote_ramp_time( ctx->transport_ptr->ops, glink_prio_to_power_state(ctx->transport_ptr, Loading @@ -3549,6 +3551,61 @@ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) } EXPORT_SYMBOL(glink_qos_get_ramp_time); /** * glink_start_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_start_rx_rt(void *handle) { struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; ret = glink_get_ch_ctx(ctx); if (ret) return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx); return -EBUSY; } ret = ctx->transport_ptr->ops->rx_rt_vote(ctx->transport_ptr->ops); ctx->rt_vote_on++; GLINK_INFO_CH(ctx, "%s: Voting RX Realtime Thread %d", __func__, ret); glink_put_ch_ctx(ctx); return ret; } /** * glink_end_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_end_rx_rt(void *handle) { struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; ret = glink_get_ch_ctx(ctx); if (ret) return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx); return -EBUSY; } ret = ctx->transport_ptr->ops->rx_rt_unvote(ctx->transport_ptr->ops); ctx->rt_vote_off++; GLINK_INFO_CH(ctx, "%s: Unvoting RX Realtime Thread %d", __func__, ret); glink_put_ch_ctx(ctx); return ret; } /** * glink_rpm_rx_poll() - Poll and receive any available events * @handle: Channel handle in which this operation is performed. Loading Loading @@ -3631,10 +3688,10 @@ int glink_wait_link_down(void *handle) if (ret) return ret; if (!ctx->transport_ptr) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EOPNOTSUPP; } glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops); } EXPORT_SYMBOL(glink_wait_link_down); Loading Loading @@ -3956,6 +4013,10 @@ int glink_core_register_transport(struct glink_transport_if *if_ptr, if_ptr->power_vote = dummy_power_vote; if (!if_ptr->power_unvote) if_ptr->power_unvote = dummy_power_unvote; if (!if_ptr->rx_rt_vote) if_ptr->rx_rt_vote = dummy_rx_rt_vote; if (!if_ptr->rx_rt_unvote) if_ptr->rx_rt_unvote = dummy_rx_rt_unvote; xprt_ptr->capabilities = 0; xprt_ptr->ops = if_ptr; spin_lock_init(&xprt_ptr->xprt_ctx_lock_lhb1); Loading Loading @@ -6175,7 +6236,6 @@ EXPORT_SYMBOL(glink_get_xprt_log_ctx); static int glink_init(void) { log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0); rwlock_init(&magic_lock); if (!log_ctx) GLINK_ERR("%s: unable to create log context\n", __func__); glink_debugfs_init(); Loading drivers/soc/qcom/glink_smem_native_xprt.c +54 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,8 @@ struct mailbox_config_info { * @deferred_cmds: List of deferred commands that need to be * processed in process context. * @deferred_cmds_cnt: Number of deferred commands in queue. * @rt_vote_lock: Serialize access to RT rx votes * @rt_votes: Vote count for RT rx thread priority * @num_pw_states: Size of @ramp_time_us. * @ramp_time_us: Array of ramp times in microseconds where array * index position represents a power state. Loading Loading @@ -221,6 +223,8 @@ struct edge_info { spinlock_t rx_lock; struct list_head deferred_cmds; uint32_t deferred_cmds_cnt; spinlock_t rt_vote_lock; uint32_t rt_votes; uint32_t num_pw_states; unsigned long *ramp_time_us; struct mailbox_config_info *mailbox; Loading Loading @@ -2124,6 +2128,52 @@ static int power_unvote(struct glink_transport_if *if_ptr) return 0; } /** * rx_rt_vote() - Increment and RX thread RT vote * @if_ptr: The transport interface on which power voting is requested. * * Return: 0 on Success, standard error otherwise. */ static int rx_rt_vote(struct glink_transport_if *if_ptr) { struct edge_info *einfo; struct sched_param param = { .sched_priority = 1 }; int ret = 0; unsigned long flags; einfo = container_of(if_ptr, struct edge_info, xprt_if); spin_lock_irqsave(&einfo->rt_vote_lock, flags); if (!einfo->rt_votes) ret = sched_setscheduler_nocheck(einfo->task, SCHED_FIFO, ¶m); einfo->rt_votes++; spin_unlock_irqrestore(&einfo->rt_vote_lock, flags); return ret; } /** * rx_rt_unvote() - Remove a RX thread RT vote * @if_ptr: The transport interface on which power voting is requested. * * Return: 0 on Success, standard error otherwise. */ static int rx_rt_unvote(struct glink_transport_if *if_ptr) { struct edge_info *einfo; struct sched_param param = { .sched_priority = 0 }; int ret = 0; unsigned long flags; einfo = container_of(if_ptr, struct edge_info, xprt_if); spin_lock_irqsave(&einfo->rt_vote_lock, flags); einfo->rt_votes--; if (!einfo->rt_votes) ret = sched_setscheduler_nocheck(einfo->task, SCHED_NORMAL, ¶m); spin_unlock_irqrestore(&einfo->rt_vote_lock, flags); return ret; } /** * negotiate_features_v1() - determine what features of a version can be used * @if_ptr: The transport for which features are negotiated for. Loading Loading @@ -2169,6 +2219,8 @@ static void init_xprt_if(struct edge_info *einfo) einfo->xprt_if.get_power_vote_ramp_time = get_power_vote_ramp_time; einfo->xprt_if.power_vote = power_vote; einfo->xprt_if.power_unvote = power_unvote; einfo->xprt_if.rx_rt_vote = rx_rt_vote; einfo->xprt_if.rx_rt_unvote = rx_rt_unvote; } /** Loading Loading @@ -2341,6 +2393,8 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_srcu_struct(&einfo->use_ref); spin_lock_init(&einfo->rx_lock); INIT_LIST_HEAD(&einfo->deferred_cmds); spin_lock_init(&einfo->rt_vote_lock); einfo->rt_votes = 0; mutex_lock(&probe_lock); if (edge_infos[einfo->remote_proc_id]) { Loading drivers/soc/qcom/glink_xprt_if.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. /* 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 Loading Loading @@ -141,6 +141,8 @@ struct glink_transport_if { struct glink_transport_if *if_ptr, uint32_t state); int (*power_vote)(struct glink_transport_if *if_ptr, uint32_t state); int (*power_unvote)(struct glink_transport_if *if_ptr); int (*rx_rt_vote)(struct glink_transport_if *if_ptr); int (*rx_rt_unvote)(struct glink_transport_if *if_ptr); /* * Keep data pointers at the end of the structure after all function * pointer to allow for in-place initialization. Loading include/soc/qcom/glink.h +28 −1 Original line number Diff line number Diff line /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. /* 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 Loading Loading @@ -340,6 +340,22 @@ int glink_qos_start(void *handle); */ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size); /** * glink_start_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_start_rx_rt(void *handle); /** * glink_end_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_end_rx_rt(void *handle); #else /* CONFIG_MSM_GLINK */ static inline void *glink_open(const struct glink_open_config *cfg_ptr) { Loading Loading @@ -428,5 +444,16 @@ static inline unsigned long glink_qos_get_ramp_time(void *handle, { return 0; } static inline int glink_start_rx_rt(void *handle) { return -ENODEV; } static inline int glink_end_rx_rt(void *handle) { return -ENODEV; } #endif /* CONFIG_MSM_GLINK */ #endif /* _SOC_QCOM_GLINK_H_ */ Loading
drivers/soc/qcom/glink.c +113 −53 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include "glink_private.h" #include "glink_xprt_if.h" #define GLINK_CTX_CANARY 0x58544324 /* "$CTX" */ /* Number of internal IPC Logging log pages */ #define NUM_LOG_PAGES 10 #define GLINK_PM_QOS_HOLDOFF_MS 10 Loading @@ -40,7 +39,6 @@ #define GLINK_KTHREAD_PRIO 1 static rwlock_t magic_lock; /** * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * @max_rate_kBps: Maximum rate supported by the priority bucket. Loading Loading @@ -232,6 +230,8 @@ static DEFINE_MUTEX(edge_list_lock_lhd0); * @req_rate_kBps: Current QoS request by the channel. * @tx_intent_cnt: Intent count to transmit soon in future. * @tx_cnt: Packets to be picked by tx scheduler. * @rt_vote_on: Number of times RT vote on is called. * @rt_vote_off: Number of times RT vote off is called. */ struct channel_ctx { struct rwref_lock ch_state_lhb2; Loading Loading @@ -312,7 +312,9 @@ struct channel_ctx { unsigned long req_rate_kBps; uint32_t tx_intent_cnt; uint32_t tx_cnt; uint32_t magic_number; uint32_t rt_vote_on; uint32_t rt_vote_off; }; static struct glink_core_if core_impl; Loading Loading @@ -443,33 +445,15 @@ static void glink_core_deinit_xprt_qos_cfg( static int glink_get_ch_ctx(struct channel_ctx *ctx) { unsigned long flags; if (!ctx) return -EINVAL; read_lock_irqsave(&magic_lock, flags); if (ctx->magic_number != GLINK_CTX_CANARY) { read_unlock_irqrestore(&magic_lock, flags); return -EINVAL; } rwref_get(&ctx->ch_state_lhb2); read_unlock_irqrestore(&magic_lock, flags); return 0; } static int glink_put_ch_ctx(struct channel_ctx *ctx, bool update_magic) static void glink_put_ch_ctx(struct channel_ctx *ctx) { unsigned long flags; if (!update_magic) { rwref_put(&ctx->ch_state_lhb2); return 0; } write_lock_irqsave(&magic_lock, flags); ctx->magic_number = 0; rwref_put(&ctx->ch_state_lhb2); write_unlock_irqrestore(&magic_lock, flags); return 0; } /** Loading Loading @@ -2418,6 +2402,25 @@ static int dummy_power_unvote(struct glink_transport_if *if_ptr) return -EOPNOTSUPP; } /** * dummy_rx_rt_vote() - Dummy RX Realtime thread vote * @if_ptr: The transport to transmit on. */ static int dummy_rx_rt_vote(struct glink_transport_if *if_ptr) { return -EOPNOTSUPP; } /** * dummy_rx_rt_unvote() - Dummy RX Realtime thread unvote * @if_ptr: The transport to transmit on. */ static int dummy_rx_rt_unvote(struct glink_transport_if *if_ptr) { return -EOPNOTSUPP; } /** * notif_if_up_all_xprts() - Check and notify existing transport state if up * @notif_info: Data structure containing transport information to be notified. Loading Loading @@ -2600,7 +2603,6 @@ void *glink_open(const struct glink_open_config *cfg) ctx->notify_tx_abort = cfg->notify_tx_abort; ctx->notify_rx_tracer_pkt = cfg->notify_rx_tracer_pkt; ctx->notify_remote_rx_intent = cfg->notify_remote_rx_intent; ctx->magic_number = GLINK_CTX_CANARY; if (!ctx->notify_rx_intent_req) ctx->notify_rx_intent_req = glink_dummy_notify_rx_intent_req; Loading Loading @@ -2742,13 +2744,13 @@ int glink_close(void *handle) GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx); if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) { /* close already pending */ glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading Loading @@ -2813,7 +2815,7 @@ relock: xprt_ctx = ctx->transport_ptr; rwref_put(&ctx->ch_state_lhb2); rwref_read_put(&xprt_ctx->xprt_state_lhb0); glink_put_ch_ctx(ctx, true); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_close); Loading Loading @@ -3029,13 +3031,13 @@ static int glink_tx_common(void *handle, void *pkt_priv, xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info); rwref_read_put(&ctx->ch_state_lhb2); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; glink_tx_common_err: rwref_read_put(&ctx->ch_state_lhb2); glink_tx_common_err_2: glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); kfree(tx_info); return ret; } Loading Loading @@ -3085,7 +3087,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) /* Can only queue rx intents if channel is fully opened */ GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3094,14 +3096,14 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) GLINK_ERR_CH(ctx, "%s: Intent pointer allocation failed size[%zu]\n", __func__, size); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -ENOMEM; } GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id, intent_ptr->intent_size); if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } Loading @@ -3111,7 +3113,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) if (ret) /* unable to transmit, dequeue intent */ ch_remove_local_rx_intent(ctx, intent_ptr->id); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_queue_rx_intent); Loading Loading @@ -3143,12 +3145,12 @@ bool glink_rx_intent_exists(void *handle, size_t size) if (size <= intent->intent_size) { spin_unlock_irqrestore( &ctx->local_rx_intent_lst_lock_lhc1, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return true; } } spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return false; } EXPORT_SYMBOL(glink_rx_intent_exists); Loading Loading @@ -3177,7 +3179,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) if (IS_ERR_OR_NULL(liid_ptr)) { /* invalid pointer */ GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EINVAL; } Loading @@ -3203,7 +3205,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) /* send rx done */ ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops, ctx->lcid, id, reuse); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_rx_done); Loading Loading @@ -3257,7 +3259,7 @@ int glink_sigs_set(void *handle, uint32_t sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3267,7 +3269,7 @@ int glink_sigs_set(void *handle, uint32_t sigs) ctx->lcid, ctx->lsigs); GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_sigs_set); Loading @@ -3293,12 +3295,12 @@ int glink_sigs_local_get(void *handle, uint32_t *sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } *sigs = ctx->lsigs; glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } EXPORT_SYMBOL(glink_sigs_local_get); Loading @@ -3325,12 +3327,12 @@ int glink_sigs_remote_get(void *handle, uint32_t *sigs) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } *sigs = ctx->rsigs; glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return 0; } EXPORT_SYMBOL(glink_sigs_remote_get); Loading Loading @@ -3434,7 +3436,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3444,7 +3446,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) if (ret < 0) GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n", __func__, latency_us, pkt_size); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_latency); Loading @@ -3468,12 +3470,12 @@ int glink_qos_cancel(void *handle) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } ret = glink_qos_reset_priority(ctx); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_cancel); Loading @@ -3500,7 +3502,7 @@ int glink_qos_start(void *handle) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EBUSY; } Loading @@ -3509,7 +3511,7 @@ int glink_qos_start(void *handle) ret = glink_qos_add_ch_tx_intent(ctx); spin_unlock(&ctx->tx_lists_lock_lhc3); spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ret; } EXPORT_SYMBOL(glink_qos_start); Loading Loading @@ -3537,11 +3539,11 @@ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return (unsigned long)-EBUSY; } glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ctx->transport_ptr->ops->get_power_vote_ramp_time( ctx->transport_ptr->ops, glink_prio_to_power_state(ctx->transport_ptr, Loading @@ -3549,6 +3551,61 @@ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) } EXPORT_SYMBOL(glink_qos_get_ramp_time); /** * glink_start_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_start_rx_rt(void *handle) { struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; ret = glink_get_ch_ctx(ctx); if (ret) return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx); return -EBUSY; } ret = ctx->transport_ptr->ops->rx_rt_vote(ctx->transport_ptr->ops); ctx->rt_vote_on++; GLINK_INFO_CH(ctx, "%s: Voting RX Realtime Thread %d", __func__, ret); glink_put_ch_ctx(ctx); return ret; } /** * glink_end_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_end_rx_rt(void *handle) { struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; ret = glink_get_ch_ctx(ctx); if (ret) return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); glink_put_ch_ctx(ctx); return -EBUSY; } ret = ctx->transport_ptr->ops->rx_rt_unvote(ctx->transport_ptr->ops); ctx->rt_vote_off++; GLINK_INFO_CH(ctx, "%s: Unvoting RX Realtime Thread %d", __func__, ret); glink_put_ch_ctx(ctx); return ret; } /** * glink_rpm_rx_poll() - Poll and receive any available events * @handle: Channel handle in which this operation is performed. Loading Loading @@ -3631,10 +3688,10 @@ int glink_wait_link_down(void *handle) if (ret) return ret; if (!ctx->transport_ptr) { glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return -EOPNOTSUPP; } glink_put_ch_ctx(ctx, false); glink_put_ch_ctx(ctx); return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops); } EXPORT_SYMBOL(glink_wait_link_down); Loading Loading @@ -3956,6 +4013,10 @@ int glink_core_register_transport(struct glink_transport_if *if_ptr, if_ptr->power_vote = dummy_power_vote; if (!if_ptr->power_unvote) if_ptr->power_unvote = dummy_power_unvote; if (!if_ptr->rx_rt_vote) if_ptr->rx_rt_vote = dummy_rx_rt_vote; if (!if_ptr->rx_rt_unvote) if_ptr->rx_rt_unvote = dummy_rx_rt_unvote; xprt_ptr->capabilities = 0; xprt_ptr->ops = if_ptr; spin_lock_init(&xprt_ptr->xprt_ctx_lock_lhb1); Loading Loading @@ -6175,7 +6236,6 @@ EXPORT_SYMBOL(glink_get_xprt_log_ctx); static int glink_init(void) { log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0); rwlock_init(&magic_lock); if (!log_ctx) GLINK_ERR("%s: unable to create log context\n", __func__); glink_debugfs_init(); Loading
drivers/soc/qcom/glink_smem_native_xprt.c +54 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,8 @@ struct mailbox_config_info { * @deferred_cmds: List of deferred commands that need to be * processed in process context. * @deferred_cmds_cnt: Number of deferred commands in queue. * @rt_vote_lock: Serialize access to RT rx votes * @rt_votes: Vote count for RT rx thread priority * @num_pw_states: Size of @ramp_time_us. * @ramp_time_us: Array of ramp times in microseconds where array * index position represents a power state. Loading Loading @@ -221,6 +223,8 @@ struct edge_info { spinlock_t rx_lock; struct list_head deferred_cmds; uint32_t deferred_cmds_cnt; spinlock_t rt_vote_lock; uint32_t rt_votes; uint32_t num_pw_states; unsigned long *ramp_time_us; struct mailbox_config_info *mailbox; Loading Loading @@ -2124,6 +2128,52 @@ static int power_unvote(struct glink_transport_if *if_ptr) return 0; } /** * rx_rt_vote() - Increment and RX thread RT vote * @if_ptr: The transport interface on which power voting is requested. * * Return: 0 on Success, standard error otherwise. */ static int rx_rt_vote(struct glink_transport_if *if_ptr) { struct edge_info *einfo; struct sched_param param = { .sched_priority = 1 }; int ret = 0; unsigned long flags; einfo = container_of(if_ptr, struct edge_info, xprt_if); spin_lock_irqsave(&einfo->rt_vote_lock, flags); if (!einfo->rt_votes) ret = sched_setscheduler_nocheck(einfo->task, SCHED_FIFO, ¶m); einfo->rt_votes++; spin_unlock_irqrestore(&einfo->rt_vote_lock, flags); return ret; } /** * rx_rt_unvote() - Remove a RX thread RT vote * @if_ptr: The transport interface on which power voting is requested. * * Return: 0 on Success, standard error otherwise. */ static int rx_rt_unvote(struct glink_transport_if *if_ptr) { struct edge_info *einfo; struct sched_param param = { .sched_priority = 0 }; int ret = 0; unsigned long flags; einfo = container_of(if_ptr, struct edge_info, xprt_if); spin_lock_irqsave(&einfo->rt_vote_lock, flags); einfo->rt_votes--; if (!einfo->rt_votes) ret = sched_setscheduler_nocheck(einfo->task, SCHED_NORMAL, ¶m); spin_unlock_irqrestore(&einfo->rt_vote_lock, flags); return ret; } /** * negotiate_features_v1() - determine what features of a version can be used * @if_ptr: The transport for which features are negotiated for. Loading Loading @@ -2169,6 +2219,8 @@ static void init_xprt_if(struct edge_info *einfo) einfo->xprt_if.get_power_vote_ramp_time = get_power_vote_ramp_time; einfo->xprt_if.power_vote = power_vote; einfo->xprt_if.power_unvote = power_unvote; einfo->xprt_if.rx_rt_vote = rx_rt_vote; einfo->xprt_if.rx_rt_unvote = rx_rt_unvote; } /** Loading Loading @@ -2341,6 +2393,8 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_srcu_struct(&einfo->use_ref); spin_lock_init(&einfo->rx_lock); INIT_LIST_HEAD(&einfo->deferred_cmds); spin_lock_init(&einfo->rt_vote_lock); einfo->rt_votes = 0; mutex_lock(&probe_lock); if (edge_infos[einfo->remote_proc_id]) { Loading
drivers/soc/qcom/glink_xprt_if.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. /* 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 Loading Loading @@ -141,6 +141,8 @@ struct glink_transport_if { struct glink_transport_if *if_ptr, uint32_t state); int (*power_vote)(struct glink_transport_if *if_ptr, uint32_t state); int (*power_unvote)(struct glink_transport_if *if_ptr); int (*rx_rt_vote)(struct glink_transport_if *if_ptr); int (*rx_rt_unvote)(struct glink_transport_if *if_ptr); /* * Keep data pointers at the end of the structure after all function * pointer to allow for in-place initialization. Loading
include/soc/qcom/glink.h +28 −1 Original line number Diff line number Diff line /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. /* 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 Loading Loading @@ -340,6 +340,22 @@ int glink_qos_start(void *handle); */ unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size); /** * glink_start_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_start_rx_rt(void *handle); /** * glink_end_rx_rt() - Vote for RT thread priority on RX. * @handle: Channel handle for which transaction are occurring. * * Return: 0 on success, standard Linux error codes on failure */ int glink_end_rx_rt(void *handle); #else /* CONFIG_MSM_GLINK */ static inline void *glink_open(const struct glink_open_config *cfg_ptr) { Loading Loading @@ -428,5 +444,16 @@ static inline unsigned long glink_qos_get_ramp_time(void *handle, { return 0; } static inline int glink_start_rx_rt(void *handle) { return -ENODEV; } static inline int glink_end_rx_rt(void *handle) { return -ENODEV; } #endif /* CONFIG_MSM_GLINK */ #endif /* _SOC_QCOM_GLINK_H_ */