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

Commit faf7c82f authored by Srinivasarao Pathipati's avatar Srinivasarao Pathipati
Browse files

virt: haven: rm_core: Always allocate a connection for notifications



Currently, there is an optimized path to directly use the message queue
buffer when a received notification fits within a single message and
there aren't any fragments. This greatly complicates buffer management
and might not provide any measurable benefit.
Suppose Linux receives a notification with one fragment then a
notification with 3 fragments. In current flow, there is 1 alloc for the
first notification and 4 allocations for the 2nd notification (1 for
each message + 1 for overall combined buffer). In the new flow, we could
optimize this to 0 allocations for each message because we can re-use
the same message buffer for each fragment and then a single alloc for
the entire payload.
There is, however, a slightly increased cost for single-message
notifications in the form of an extra memcpy from the message buffer to
notification buffer. Under the code optimizations and simplifications
that come with this cost, it is a worthy cost.

Change-Id: Ib52bd332f59b108d7dab9121c0beefed0aa66994
Signed-off-by: default avatarElliot Berman <quic_eberman@quicinc.com>
Signed-off-by: default avatarSrinivasarao Pathipati <quic_c_spathi@quicinc.com>
parent 840766fa
Loading
Loading
Loading
Loading
+19 −56
Original line number Diff line number Diff line
@@ -132,73 +132,36 @@ int hh_rm_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL(hh_rm_unregister_notifier);

static struct hh_rm_connection *
hh_rm_wait_for_notif_fragments(void *recv_buff, size_t recv_buff_size)
static int hh_rm_process_notif(void *msg, size_t msg_size)
{
	struct hh_rm_rpc_hdr *hdr = recv_buff;
	struct hh_rm_rpc_hdr *hdr = msg;
	struct hh_rm_connection *connection;
	u32 notification;
	size_t payload_size;
	void *payload;
	int ret = 0;

	connection = hh_rm_alloc_connection(hdr->msg_id);
	if (IS_ERR_OR_NULL(connection))
		return connection;

	payload_size = recv_buff_size - sizeof(*hdr);
	curr_connection = connection;

	ret = hh_rm_init_connection_buff(connection, recv_buff,
					sizeof(*hdr), payload_size);
	if (ret < 0)
		goto out;

	if (wait_for_completion_interruptible(&connection->seq_done)) {
		ret = -ERESTARTSYS;
		goto out;
	if (curr_connection) {
		pr_err("Received new notification from RM-VM before completing last connection\n");
		return -EINVAL;
	}

	return connection;
	connection = hh_rm_alloc_connection(hdr->msg_id);
	if (!connection)
		return -EINVAL;

out:
	if (hh_rm_init_connection_buff(connection, msg, sizeof(*hdr), msg_size - sizeof(*hdr))) {
		kfree(connection);
	return ERR_PTR(ret);
}

static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size)
{
	struct hh_rm_connection *connection = NULL;
	struct hh_rm_rpc_hdr *hdr = recv_buff;
	u32 notification = hdr->msg_id;
	void *payload = NULL;
	size_t payload_size;
	int ret = 0;

	pr_debug("Notification received from RM-VM: %x\n", notification);

	if (curr_connection) {
		pr_err("Received new notification from RM-VM before completing last connection\n");
		return -EINVAL;
	}

	if (recv_buff_size > sizeof(*hdr))
		payload = recv_buff + sizeof(*hdr);

	/* If the notification payload is split-up into
	 * fragments, wait until all them arrive.
	 */
	if (hdr->fragments) {
		connection = hh_rm_wait_for_notif_fragments(recv_buff,
								recv_buff_size);
		if (IS_ERR_OR_NULL(connection))
	if (hdr->fragments)
		return PTR_ERR(connection);

		/* In the case of fragments, the complete payload
		 * is contained under connection->recv_buff
		 */
	payload = connection->recv_buff;
		recv_buff_size = connection->recv_buff_size;
	}
	payload_size = recv_buff_size - sizeof(*hdr);
	payload_size = connection->recv_buff_size;
	notification = connection->msg_id;
	pr_debug("Notification received from RM-VM: %x\n", notification);

	switch (notification) {
	case HH_RM_NOTIF_VM_STATUS:
@@ -297,7 +260,7 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size)

err:
	if (connection) {
		kfree(connection->recv_buff);
		kfree(payload);
		kfree(connection);
	}