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

Commit a7fcd24f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: rpm-smd: Add a check to validate the rpm message length"

parents ae1bcff1 e7f08c73
Loading
Loading
Loading
Loading
+112 −91
Original line number Diff line number Diff line
@@ -329,12 +329,95 @@ static void tr_update(struct slp_buf *s, char *buf)
		}
	}
}
static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);

struct msm_rpm_request {
	struct rpm_request_header req_hdr;
	struct rpm_message_header msg_hdr;
	struct msm_rpm_kvp_data *kvp;
	uint32_t num_elements;
	uint32_t write_idx;
	uint8_t *buf;
	uint32_t numbytes;
};

/*
 * Data related to message acknowledgment
 */

LIST_HEAD(msm_rpm_wait_list);

struct msm_rpm_wait_data {
	struct list_head list;
	uint32_t msg_id;
	bool ack_recd;
	int errno;
	struct completion ack;
};
DEFINE_SPINLOCK(msm_rpm_list_lock);

struct msm_rpm_ack_msg {
	uint32_t req;
	uint32_t req_len;
	uint32_t rsc_id;
	uint32_t msg_len;
	uint32_t id_ack;
};

LIST_HEAD(msm_rpm_ack_list);

static struct tasklet_struct data_tasklet;

static inline uint32_t msm_rpm_get_msg_id_from_ack(uint8_t *buf)
{
	return ((struct msm_rpm_ack_msg *)buf)->id_ack;
}

int msm_rpm_smd_buffer_request(char *buf, uint32_t size, gfp_t flag)
static inline int msm_rpm_get_error_from_ack(uint8_t *buf)
{
	uint8_t *tmp;
	uint32_t req_len = ((struct msm_rpm_ack_msg *)buf)->req_len;

	struct msm_rpm_ack_msg *tmp_buf = (struct msm_rpm_ack_msg *)buf;
	int rc = -ENODEV;

	req_len -= sizeof(struct msm_rpm_ack_msg);
	req_len += 2 * sizeof(uint32_t);
	if (!req_len)
		return 0;

	pr_err("%s:rpm returned error or nack req_len: %d id_ack: %d\n",
				__func__, tmp_buf->req_len, tmp_buf->id_ack);

	tmp = buf + sizeof(struct msm_rpm_ack_msg);

	if (memcmp(tmp, ERR, sizeof(uint32_t))) {
		pr_err("%s rpm returned error\n", __func__);
		BUG_ON(1);
	}

	tmp += 2 * sizeof(uint32_t);

	if (!(memcmp(tmp, INV_RSC, min_t(uint32_t, req_len,
						sizeof(INV_RSC))-1))) {
		pr_err("%s(): RPM NACK Unsupported resource\n", __func__);
		rc = -EINVAL;
	} else {
		pr_err("%s(): RPM NACK Invalid header\n", __func__);
	}

	return rc;
}

int msm_rpm_smd_buffer_request(struct msm_rpm_request *cdata,
		uint32_t size, gfp_t flag)
{
	struct slp_buf *slp;
	static DEFINE_SPINLOCK(slp_buffer_lock);
	unsigned long flags;
	char *buf;

	buf = cdata->buf;

	if (size > MAX_SLEEP_BUFFER)
		return -ENOMEM;
@@ -356,6 +439,9 @@ int msm_rpm_smd_buffer_request(char *buf, uint32_t size, gfp_t flag)
		/* handle unsent requests */
		tr_update(slp, buf);
	}
	trace_rpm_smd_sleep_set(cdata->msg_hdr.msg_id,
				cdata->msg_hdr.resource_type,
				cdata->msg_hdr.resource_id);

	spin_unlock_irqrestore(&slp_buffer_lock, flags);

@@ -455,15 +541,13 @@ static int msm_rpm_flush_requests(bool print)
					get_buf_len(s->buf), true);

		WARN_ON(ret != get_buf_len(s->buf));
		trace_rpm_smd_send_sleep_set(get_msg_id(s->buf),
					get_rsc_type(s->buf),
					get_rsc_id(s->buf));

		s->valid = false;
		count++;

		trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
				get_rsc_type(s->buf),
				get_rsc_id(s->buf),
				get_msg_id(s->buf));

		/*
		 * RPM acks need to be handled here if we have sent 24
		 * messages such that we do not overrun SMD buffer. Since
@@ -518,45 +602,6 @@ static int msm_rpm_flush_requests(bool print)
	return 0;
}

static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);

struct msm_rpm_request {
	struct rpm_request_header req_hdr;
	struct rpm_message_header msg_hdr;
	struct msm_rpm_kvp_data *kvp;
	uint32_t num_elements;
	uint32_t write_idx;
	uint8_t *buf;
	uint32_t numbytes;
};

/*
 * Data related to message acknowledgement
 */

LIST_HEAD(msm_rpm_wait_list);

struct msm_rpm_wait_data {
	struct list_head list;
	uint32_t msg_id;
	bool ack_recd;
	int errno;
	struct completion ack;
};
DEFINE_SPINLOCK(msm_rpm_list_lock);

struct msm_rpm_ack_msg {
	uint32_t req;
	uint32_t req_len;
	uint32_t rsc_id;
	uint32_t msg_len;
	uint32_t id_ack;
};

LIST_HEAD(msm_rpm_ack_list);

static struct tasklet_struct data_tasklet;

static void msm_rpm_notify_sleep_chain(struct rpm_message_header *hdr,
		struct msm_rpm_kvp_data *kvp)
{
@@ -750,6 +795,7 @@ static void msm_rpm_notify(void *data, unsigned event)
	switch (event) {
	case SMD_EVENT_DATA:
		tasklet_schedule(&data_tasklet);
		trace_rpm_smd_interrupt_notify("interrupt notification");
		break;
	case SMD_EVENT_OPEN:
		complete(&pdata->smd_open);
@@ -865,7 +911,7 @@ static void msm_rpm_process_ack(uint32_t msg_id, int errno)
	 * entering RPM assisted power collapse.
	 */
	if (!elem)
		trace_rpm_ack_recd(0, msg_id);
		trace_rpm_smd_ack_recvd(0, msg_id, 0xDEADBEEF);

	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
}
@@ -876,40 +922,6 @@ struct msm_rpm_kvp_packet {
	uint32_t val;
};

static inline uint32_t msm_rpm_get_msg_id_from_ack(uint8_t *buf)
{
	return ((struct msm_rpm_ack_msg *)buf)->id_ack;
}

static inline int msm_rpm_get_error_from_ack(uint8_t *buf)
{
	uint8_t *tmp;
	uint32_t req_len = ((struct msm_rpm_ack_msg *)buf)->req_len;

	int rc = -ENODEV;

	req_len -= sizeof(struct msm_rpm_ack_msg);
	req_len += 2 * sizeof(uint32_t);
	if (!req_len)
		return 0;

	tmp = buf + sizeof(struct msm_rpm_ack_msg);

	BUG_ON(memcmp(tmp, ERR, sizeof(uint32_t)));

	tmp += 2 * sizeof(uint32_t);

	if (!(memcmp(tmp, INV_RSC, min_t(uint32_t, req_len,
						sizeof(INV_RSC))-1))) {
		pr_err("RPM NACK Unsupported resource\n");
		rc = -EINVAL;
	} else {
		pr_err("RPM NACK Invalid header\n");
	}

	return rc;
}

static int msm_rpm_read_smd_data(char *buf)
{
	int pkt_sz;
@@ -920,7 +932,10 @@ static int msm_rpm_read_smd_data(char *buf)
	if (!pkt_sz)
		return -EAGAIN;

	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
	if (pkt_sz > MAX_ERR_BUFFER_SIZE) {
		pr_err("rpm_smd pkt_sz is greater than max size\n");
		goto error;
	}

	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
		return -EAGAIN;
@@ -934,7 +949,13 @@ static int msm_rpm_read_smd_data(char *buf)

	} while (pkt_sz > 0);

	BUG_ON(pkt_sz < 0);
	if (pkt_sz < 0) {
		pr_err("rpm_smd pkt_sz is less than zero\n");
		goto error;
	}
	return 0;
error:
	BUG_ON(1);

	return 0;
}
@@ -951,6 +972,7 @@ static void data_fn_tasklet(unsigned long data)
			break;
		msg_id = msm_rpm_get_msg_id_from_ack(buf);
		errno = msm_rpm_get_error_from_ack(buf);
		trace_rpm_smd_ack_recvd(0, msg_id, errno);
		msm_rpm_process_ack(msg_id, errno);
	}
	spin_unlock(&msm_rpm_data.smd_lock_read);
@@ -1216,7 +1238,7 @@ static int msm_rpm_send_data(struct msm_rpm_request *cdata,
	memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);

	if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
		!msm_rpm_smd_buffer_request(cdata->buf, msg_size,
		!msm_rpm_smd_buffer_request(cdata, msg_size,
			GFP_FLAG(noirq)))
		return 1;

@@ -1243,19 +1265,18 @@ static int msm_rpm_send_data(struct msm_rpm_request *cdata,
	ret = msm_rpm_send_buffer(&cdata->buf[0], msg_size, noirq);

	if (ret == msg_size) {
		trace_rpm_send_message(noirq, cdata->msg_hdr.set,
				cdata->msg_hdr.resource_type,
				cdata->msg_hdr.resource_id,
				cdata->msg_hdr.msg_id);
		for (i = 0; (i < cdata->write_idx); i++)
			cdata->kvp[i].valid = false;
		cdata->msg_hdr.data_len = 0;
		ret = cdata->msg_hdr.msg_id;
		trace_rpm_smd_send_active_set(cdata->msg_hdr.msg_id,
					cdata->msg_hdr.resource_type,
					cdata->msg_hdr.resource_id);
	} else if (ret < msg_size) {
		struct msm_rpm_wait_data *rc;
		ret = 0;
		pr_err("Failed to write data msg_size:%d ret:%d\n",
				msg_size, ret);
		pr_err("Failed to write data msg_size:%d ret:%d msg_id:%d\n",
				msg_size, ret, cdata->msg_hdr.msg_id);
		rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
		if (rc)
			msm_rpm_free_list_entry(rc);
@@ -1318,7 +1339,7 @@ int msm_rpm_wait_for_ack(uint32_t msg_id)
		return rc;

	wait_for_completion(&elem->ack);
	trace_rpm_ack_recd(0, msg_id);
	trace_rpm_smd_ack_recvd(0, msg_id, 0xDEADFEED);

	rc = elem->errno;
	msm_rpm_free_list_entry(elem);
@@ -1339,6 +1360,7 @@ static void msm_rpm_smd_read_data_noirq(uint32_t msg_id)
			msm_rpm_read_smd_data(buf);
			id = msm_rpm_get_msg_id_from_ack(buf);
			errno = msm_rpm_get_error_from_ack(buf);
			trace_rpm_smd_ack_recvd(1, msg_id, errno);
			msm_rpm_process_ack(id, errno);
		}
	}
@@ -1405,7 +1427,6 @@ int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
		msm_rpm_glink_read_data_noirq(elem);

	rc = elem->errno;
	trace_rpm_ack_recd(1, msg_id);

	msm_rpm_free_list_entry(elem);
wait_ack_cleanup:
+54 −20
Original line number Diff line number Diff line
/* Copyright (c) 2012, 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012, 2014-2015, 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
@@ -18,60 +18,94 @@

#include <linux/tracepoint.h>

TRACE_EVENT(rpm_ack_recd,
TRACE_EVENT(rpm_smd_ack_recvd,

	TP_PROTO(unsigned int irq, unsigned int msg_id),
	TP_PROTO(unsigned int irq, unsigned int msg_id, int errno),

	TP_ARGS(irq, msg_id),
	TP_ARGS(irq, msg_id, errno),

	TP_STRUCT__entry(
		__field(int, irq)
		__field(int, msg_id)
		__field(int, errno)
	),

	TP_fast_assign(
		__entry->irq = irq;
		__entry->msg_id = msg_id;
		__entry->errno = errno;
	),

	TP_printk("ctx:%s id:%d",
	TP_printk("ctx:%s msg_id:%d errno:%08x",
		__entry->irq ? "noslp" : "sleep",
		__entry->msg_id)
		__entry->msg_id,
		__entry->errno)
);

TRACE_EVENT(rpm_send_message,
TRACE_EVENT(rpm_smd_interrupt_notify,

	TP_PROTO(unsigned int irq, unsigned int set, unsigned int rsc_type,
		unsigned int rsc_id, unsigned int msg_id),
	TP_PROTO(char *dummy),

	TP_ARGS(irq, set, rsc_type, rsc_id, msg_id),
	TP_ARGS(dummy),

	TP_STRUCT__entry(
		__field(u32, irq)
		__field(u32, set)
		__field(char *, dummy)
	),

	TP_fast_assign(
		__entry->dummy = dummy;
	),

	TP_printk("%s", __entry->dummy)
);

DECLARE_EVENT_CLASS(rpm_send_msg,

	TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
		unsigned int rsc_id),

	TP_ARGS(msg_id, rsc_type, rsc_id),

	TP_STRUCT__entry(
		__field(u32, msg_id)
		__field(u32, rsc_type)
		__field(u32, rsc_id)
		__field(u32, msg_id)
		__array(char, name, 5)
	),

	TP_fast_assign(
		__entry->irq	= irq;
		__entry->msg_id = msg_id;
		__entry->name[4] = 0;
		__entry->set = set;
		__entry->rsc_type = rsc_type;
		__entry->rsc_id = rsc_id;
		__entry->msg_id = msg_id;
		memcpy(__entry->name, &rsc_type, sizeof(uint32_t));

	),

	TP_printk("ctx:%s set:%s rsc_type:0x%08x(%s), rsc_id:0x%08x, id:%d",
			__entry->irq ? "noslp" : "sleep",
			__entry->set ? "slp" : "act",
	TP_printk("msg_id:%d, rsc_type:0x%08x(%s), rsc_id:0x%08x",
			__entry->msg_id,
			__entry->rsc_type, __entry->name,
			__entry->rsc_id, __entry->msg_id)
			__entry->rsc_id)
);

DEFINE_EVENT(rpm_send_msg, rpm_smd_sleep_set,
	TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
		unsigned int rsc_id),
	TP_ARGS(msg_id, rsc_type, rsc_id)
);

DEFINE_EVENT(rpm_send_msg, rpm_smd_send_sleep_set,
	TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
		unsigned int rsc_id),
	TP_ARGS(msg_id, rsc_type, rsc_id)
);

DEFINE_EVENT(rpm_send_msg, rpm_smd_send_active_set,
	TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
		unsigned int rsc_id),
	TP_ARGS(msg_id, rsc_type, rsc_id)
);

#endif
#define TRACE_INCLUDE_FILE trace_rpm_smd
#include <trace/define_trace.h>