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

Commit 424874ce authored by Chris Lew's avatar Chris Lew
Browse files

rpmsg: glink: Add early reset notifier



Register glink with the early reset notifier provided by the SSR
framework. SSR is traditionally handed in a single work context to
ease cleanup dependencies from SSR. This because an issue when multiple
processors reset at the same time. Glink sends to an unresponsive proc
will block until the 10 second intent timeout. Receiving an early
notification allows GLINK to cancel any current and future tx to the
unrepsonsive proc until a full cleanup happens from unregister.

Change-Id: Ie7a76a9e88696d9dac2837e68a2ec2f6eaf45204
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent ab26f345
Loading
Loading
Loading
Loading
+37 −12
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_client.h>
#include <linux/ipc_logging.h>
#include <linux/ipc_logging.h>
#include <soc/qcom/subsystem_notif.h>


#include "rpmsg_internal.h"
#include "rpmsg_internal.h"
#include "qcom_glink_native.h"
#include "qcom_glink_native.h"
@@ -1828,6 +1829,23 @@ static void qcom_glink_set_affinity(struct qcom_glink *glink, u32 *arr,
		dev_err(glink->dev, "failed to set task affinity\n");
		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,
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
					   unsigned long features,
					   unsigned long features,
@@ -1886,6 +1904,13 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
		return ERR_CAST(glink->task);
		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);
	irq = of_irq_get(dev->of_node, 0);
	ret = devm_request_irq(dev, irq,
	ret = devm_request_irq(dev, irq,
			       qcom_glink_native_intr,
			       qcom_glink_native_intr,
@@ -1893,7 +1918,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
			       "glink-native", glink);
			       "glink-native", glink);
	if (ret) {
	if (ret) {
		dev_err(dev, "failed to request IRQ\n");
		dev_err(dev, "failed to request IRQ\n");
		return ERR_PTR(ret);
		goto unregister;
	}
	}


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


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


	return glink;
	return glink;

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


@@ -1940,17 +1971,11 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
	int ret;
	int ret;
	unsigned long flags;
	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);
	disable_irq(glink->irq);
	cancel_work_sync(&glink->rx_work);
	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);
	ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
	if (ret)
	if (ret)
		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);