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

Commit 1da83c05 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "rpmsg: glink: Fix reuse intents memory leak issue"

parents bcc63c15 91cffe5a
Loading
Loading
Loading
Loading
+63 −17
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/mailbox_client.h>
#include <linux/ipc_logging.h>
#include <soc/qcom/subsystem_notif.h>

#include "rpmsg_internal.h"
#include "qcom_glink_native.h"
@@ -284,13 +285,22 @@ static void qcom_glink_channel_release(struct kref *ref)
{
	struct glink_channel *channel = container_of(ref, struct glink_channel,
						     refcount);
	struct glink_core_rx_intent *tmp;
	unsigned long flags;
	int iid;

	CH_INFO(channel, "\n");
	wake_up(&channel->intent_req_event);

	spin_lock_irqsave(&channel->intent_lock, flags);
	idr_for_each_entry(&channel->liids, tmp, iid) {
		kfree(tmp->data);
		kfree(tmp);
	}
	idr_destroy(&channel->liids);

	idr_for_each_entry(&channel->riids, tmp, iid)
		kfree(tmp);
	idr_destroy(&channel->riids);
	spin_unlock_irqrestore(&channel->intent_lock, flags);

@@ -813,9 +823,11 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
					 u32 cid, size_t size)
{
	struct glink_core_rx_intent *intent;
	struct glink_core_rx_intent *intent = NULL;
	struct glink_core_rx_intent *tmp;
	struct glink_channel *channel;
	unsigned long flags;
	int iid;

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, cid);
@@ -826,6 +838,19 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
		return;
	}

	spin_lock_irqsave(&channel->intent_lock, flags);
	idr_for_each_entry(&channel->liids, tmp, iid) {
		if (tmp->size >= size && tmp->reuse) {
			intent = tmp;
			break;
		}
	}
	spin_unlock_irqrestore(&channel->intent_lock, flags);
	if (intent) {
		qcom_glink_send_intent_req_ack(glink, channel, !!intent);
		return;
	}

	intent = qcom_glink_alloc_intent(glink, channel, size, false);
	if (intent)
		qcom_glink_advertise_intent(glink, channel, intent);
@@ -1614,7 +1639,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,

		ret = rpmsg_register_device(rpdev);
		if (ret)
			goto free_rpdev;
			goto rcid_remove;

		channel->rpdev = rpdev;
	}
@@ -1622,9 +1647,6 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,

	return 0;

free_rpdev:
	CH_INFO(channel, "free_rpdev\n");
	kfree(rpdev);
rcid_remove:
	CH_INFO(channel, "rcid_remove\n");
	spin_lock_irqsave(&glink->idr_lock, flags);
@@ -1816,6 +1838,23 @@ static void qcom_glink_set_affinity(struct qcom_glink *glink, u32 *arr,
		dev_err(glink->dev, "failed to set task affinity\n");
}

static void qcom_glink_notif_reset(void *data)
{
	struct qcom_glink *glink = data;
	struct glink_channel *channel;
	unsigned long flags;
	int cid;

	if (!glink)
		return;
	atomic_inc(&glink->in_reset);

	spin_lock_irqsave(&glink->idr_lock, flags);
	idr_for_each_entry(&glink->lcids, channel, cid) {
		wake_up(&channel->intent_req_event);
	}
	spin_unlock_irqrestore(&glink->idr_lock, flags);
}

struct qcom_glink *qcom_glink_native_probe(struct device *dev,
					   unsigned long features,
@@ -1874,6 +1913,13 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
		return ERR_CAST(glink->task);
	}

	ret = subsys_register_early_notifier(glink->name, XPORT_LAYER_NOTIF,
					     qcom_glink_notif_reset, glink);
	if (ret) {
		dev_err(dev, "failed to register early notif %d\n", ret);
		return ERR_PTR(ret);
	}

	irq = of_irq_get(dev->of_node, 0);
	ret = devm_request_irq(dev, irq,
			       qcom_glink_native_intr,
@@ -1881,7 +1927,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
			       "glink-native", glink);
	if (ret) {
		dev_err(dev, "failed to request IRQ\n");
		return ERR_PTR(ret);
		goto unregister;
	}

	glink->irq = irq;
@@ -1889,8 +1935,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
	size = of_property_count_u32_elems(dev->of_node, "cpu-affinity");
	if (size > 0) {
		arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
		if (!arr)
			return ERR_PTR(-ENOMEM);
		if (!arr) {
			ret = -ENOMEM;
			goto unregister;
		}
		ret = of_property_read_u32_array(dev->of_node, "cpu-affinity",
						 arr, size);
		if (!ret)
@@ -1901,7 +1949,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
	ret = qcom_glink_send_version(glink);
	if (ret) {
		dev_err(dev, "failed to send version %d\n", ret);
		return ERR_PTR(ret);
		goto unregister;
	}

	ret = qcom_glink_create_chrdev(glink);
@@ -1911,6 +1959,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
	glink->ilc = ipc_log_context_create(GLINK_LOG_PAGE_CNT, glink->name, 0);

	return glink;

unregister:
	subsys_unregister_early_notifier(glink->name, XPORT_LAYER_NOTIF);
	return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(qcom_glink_native_probe);

@@ -1928,17 +1980,11 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
	int ret;
	unsigned long flags;

	atomic_inc(&glink->in_reset);
	subsys_unregister_early_notifier(glink->name, XPORT_LAYER_NOTIF);
	qcom_glink_notif_reset(glink);
	disable_irq(glink->irq);
	cancel_work_sync(&glink->rx_work);

	/* Signal all threads to cancel tx */
	spin_lock_irqsave(&glink->idr_lock, flags);
	idr_for_each_entry(&glink->lcids, channel, cid) {
		wake_up(&channel->intent_req_event);
	}
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
	if (ret)
		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);