diff options
| author | Chris Lew <clew@codeaurora.org> | 2017-05-11 16:47:37 -0700 |
|---|---|---|
| committer | Chris Lew <clew@codeaurora.org> | 2017-05-23 10:45:33 -0700 |
| commit | a3b6b4e493804e18d98f92e160978fd2634d7b84 (patch) | |
| tree | 04672db2bd78976ba61c8d09743dc5cc00040d0c /drivers/soc/qcom | |
| parent | 60be71604a84d2e047215cb702d6324379a353bb (diff) | |
soc: qcom: glink: Add new APIs to toggle RX thread priority
Low latency use cases are failing because glink RX thread to handle
the TX Done command is not being scheduled during high system load.
These new APIs allow clients to specify if they need the RX glink
thread to be Realtime
CRs-Fixed: 2050701
Change-Id: I6bd4023394e9ee617797826687f34abaee3fe65d
Signed-off-by: Chris Lew <clew@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom')
| -rw-r--r-- | drivers/soc/qcom/glink.c | 85 | ||||
| -rw-r--r-- | drivers/soc/qcom/glink_smem_native_xprt.c | 54 | ||||
| -rw-r--r-- | drivers/soc/qcom/glink_xprt_if.h | 4 |
3 files changed, 141 insertions, 2 deletions
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index 72f5829d1eb6..561b9074f2ee 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -232,7 +232,9 @@ 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; struct list_head port_list_node; @@ -311,6 +313,9 @@ struct channel_ctx { unsigned long req_rate_kBps; uint32_t tx_intent_cnt; uint32_t tx_cnt; + + uint32_t rt_vote_on; + uint32_t rt_vote_off; uint32_t magic_number; }; @@ -2418,6 +2423,25 @@ static int dummy_power_unvote(struct glink_transport_if *if_ptr) } /** + * 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. * @@ -3543,6 +3567,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, false); + 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, false); + 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, false); + 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, false); + return ret; +} + /** * glink_rpm_rx_poll() - Poll and receive any available events * @handle: Channel handle in which this operation is performed. @@ -3950,6 +4029,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); diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 3f969234b705..168db46084df 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -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. @@ -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; @@ -2093,6 +2097,52 @@ static int power_unvote(struct glink_transport_if *if_ptr) } /** + * 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. * @version: The version negotiated. @@ -2137,6 +2187,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; } /** @@ -2310,6 +2362,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]) { diff --git a/drivers/soc/qcom/glink_xprt_if.h b/drivers/soc/qcom/glink_xprt_if.h index f4d5a3b303db..47c15807e379 100644 --- a/drivers/soc/qcom/glink_xprt_if.h +++ b/drivers/soc/qcom/glink_xprt_if.h @@ -1,4 +1,4 @@ -/* 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 @@ -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. |
