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

Commit 07447ea6 authored by Mahesh Sivasubramanian's avatar Mahesh Sivasubramanian
Browse files

soc: qcom: rpm-smd: Read ACKs for sleep set on wakeup



The ACKs from sleep set are not read by the driver until after the system
wakeups from suspend and interrupts are enabled. Depending on the number of
outstanding ACKs, the receive buffer could be full with sleep set ACKs and
could result in a crash if clients try to vote for active requests.

Fix by reading the ACKs from sleep set while exiting sleep before drivers
can send additional requests.

Change-Id: Id0894c9b6b637da164a5d3331d9b7e697dffd4bc
Signed-off-by: default avatarMahesh Sivasubramanian <msivasub@codeaurora.org>
parent 049b7256
Loading
Loading
Loading
Loading
+32 −41
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ static struct glink_apps_rpm_data *glink_data;
static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier);
static bool standalone;
static int probe_status = -EPROBE_DEFER;
static int msm_rpm_read_smd_data(char *buf);

int msm_rpm_register_notifier(struct notifier_block *nb)
{
@@ -513,12 +514,31 @@ static int msm_rpm_glink_rx_poll(void *glink_handle)
	return ret;
}

/*
 * Returns
 *	= 0 on successful reads
 *	> 0 on successful reads with no further data
 *	standard Linux error codes on failure.
 */
static int msm_rpm_read_sleep_ack(void)
{
	int ret;
	char buf[MAX_ERR_BUFFER_SIZE] = {0};

	if (glink_enabled)
		ret = msm_rpm_glink_rx_poll(glink_data->glink_handle);
	else {
		ret = msm_rpm_read_smd_data(buf);
		if (!ret)
			ret = smd_is_pkt_avail(msm_rpm_data.ch_info);
	}
	return ret;
}

static int msm_rpm_flush_requests(bool print)
{
	struct rb_node *t;
	int ret;
	int pkt_sz;
	char buf[MAX_ERR_BUFFER_SIZE] = {0};
	int count = 0;

	for (t = rb_first(&tr_root); t; t = rb_next(t)) {
@@ -556,47 +576,12 @@ static int msm_rpm_flush_requests(bool print)
		 * process these sleep set acks.
		 */
		if (count >= MAX_WAIT_ON_ACK) {
			int len;
			int timeout = 10;
			int ret;

			if (glink_enabled) {
				ret = msm_rpm_glink_rx_poll(
						glink_data->glink_handle);
				if (ret < 0)
					return ret;

				count--;
				continue;
			}

			while (timeout) {
				if (smd_is_pkt_avail(msm_rpm_data.ch_info))
					break;
				/*
				 * Sleep for 50us at a time before checking
				 * for packet availability. The 50us is based
				 * on the the time rpm could take to process
				 * and send an ack for the sleep set request.
				 */
				udelay(50);
				timeout--;
			}
			int ret = msm_rpm_read_sleep_ack();

			/*
			 * On timeout return an error and exit the spinlock
			 * control on this cpu. This will allow any other
			 * core that has wokenup and trying to acquire the
			 * spinlock from being locked out.
			 */
			if (!timeout) {
				pr_err("Timed out waiting for RPM ACK\n");
				return -EAGAIN;
			}

			pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
			len = smd_read(msm_rpm_data.ch_info, buf, pkt_sz);
			if (ret >= 0)
				count--;
			else
				return ret;
		}
	}
	return 0;
@@ -1561,9 +1546,15 @@ EXPORT_SYMBOL(msm_rpm_enter_sleep);
 */
void msm_rpm_exit_sleep(void)
{
	int ret;

	if (standalone)
		return;

	do  {
		ret =  msm_rpm_read_sleep_ack();
	} while (ret > 0);

	if (!glink_enabled)
		smd_mask_receive_interrupt(msm_rpm_data.ch_info, false, NULL);
	else