Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9a78ae4 authored by Chris Lew's avatar Chris Lew Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarChris Lew <clew@codeaurora.org>
parent 76d9ba5f
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -232,6 +232,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;
@@ -312,6 +314,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)
	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.
@@ -3549,6 +3573,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.
@@ -3956,6 +4035,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);
+54 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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,
							&param);
	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,
							&param);
	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.
@@ -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;
}

/**
@@ -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]) {
+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
@@ -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.
+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
@@ -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)
{
@@ -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_ */