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

Commit 87b4dbef authored by Chris Lew's avatar Chris Lew
Browse files

rpmsg: glink: Add reset status



Add a status for remote processor reset. Change the intent completion
variable to a waitqueue to check both intent request completion and
processor reset status. This allows rpmsg to cancel threads that are
waiting to send to the remote procssor.

Change-Id: Ic43a8d836f347ab26daec7f906a9a1b0f585a549
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 21ceab94
Loading
Loading
Loading
Loading
+33 −6
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ struct glink_core_rx_intent {
 * @idr_lock:	synchronizes @lcids and @rcids modifications
 * @lcids:	idr of all channels with a known local channel id
 * @rcids:	idr of all channels with a known remote channel id
 * @in_reset:	reset status of this edge
 * @ilc:	ipc logging context reference
 */
struct qcom_glink {
@@ -151,6 +152,8 @@ struct qcom_glink {
	spinlock_t idr_lock;
	struct idr lcids;
	struct idr rcids;

	atomic_t in_reset;
	unsigned long features;

	bool intentless;
@@ -187,7 +190,8 @@ enum {
 * @open_req:	completed once open-request has been received
 * @intent_req_lock: Synchronises multiple intent requests
 * @intent_req_result: Result of intent request
 * @intent_req_comp: Completion for intent_req signalling
 * @intent_req_comp: Status of intent request completion
 * @intent_req_event: Waitqueue for @intent_req_comp
 */
struct glink_channel {
	struct rpmsg_endpoint ept;
@@ -221,7 +225,8 @@ struct glink_channel {

	struct mutex intent_req_lock;
	bool intent_req_result;
	struct completion intent_req_comp;
	atomic_t intent_req_comp;
	wait_queue_head_t intent_req_event;
};

#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
@@ -267,7 +272,8 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,

	init_completion(&channel->open_req);
	init_completion(&channel->open_ack);
	init_completion(&channel->intent_req_comp);
	atomic_set(&channel->intent_req_comp, 0);
	init_waitqueue_head(&channel->intent_req_event);

	INIT_LIST_HEAD(&channel->done_intents);
	kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work);
@@ -286,6 +292,7 @@ static void qcom_glink_channel_release(struct kref *ref)
	unsigned long flags;

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

	spin_lock_irqsave(&channel->intent_lock, flags);
@@ -354,6 +361,11 @@ static int qcom_glink_tx(struct qcom_glink *glink,
			goto out;
		}

		if (atomic_read(&glink->in_reset)) {
			ret = -ECONNRESET;
			goto out;
		}

		/* Wait without holding the tx_lock */
		spin_unlock_irqrestore(&glink->tx_lock, flags);

@@ -425,7 +437,8 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
	}

	channel->intent_req_result = granted;
	complete(&channel->intent_req_comp);
	atomic_inc(&channel->intent_req_comp);
	wake_up(&channel->intent_req_event);
	CH_INFO(channel, "\n");
}

@@ -1371,7 +1384,7 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,

	mutex_lock(&channel->intent_req_lock);

	reinit_completion(&channel->intent_req_comp);
	atomic_set(&channel->intent_req_comp, 0);

	cmd.id = RPM_CMD_RX_INTENT_REQ;
	cmd.cid = channel->lcid;
@@ -1383,10 +1396,15 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
	if (ret)
		goto unlock;

	ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ);
	ret = wait_event_timeout(channel->intent_req_event,
				 atomic_read(&channel->intent_req_comp) ||
				 atomic_read(&glink->in_reset), 10 * HZ);
	if (!ret) {
		dev_err(glink->dev, "intent request timed out\n");
		ret = -ETIMEDOUT;
	} else if (atomic_read(&glink->in_reset)) {
		CH_INFO(channel, "ssr detected\n");
		ret = -ECONNRESET;
	} else {
		ret = channel->intent_req_result ? 0 : -ECANCELED;
	}
@@ -1814,6 +1832,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
	spin_lock_init(&glink->idr_lock);
	idr_init(&glink->lcids);
	idr_init(&glink->rcids);
	atomic_set(&glink->in_reset, 0);

	ret = of_property_read_string(dev->of_node, "label", &glink->name);
	if (ret < 0)
@@ -1879,9 +1898,17 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
	int ret;
	unsigned long flags;

	atomic_inc(&glink->in_reset);
	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);