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

Commit 0cccdad8 authored by Chris Lew's avatar Chris Lew Committed by Gerrit - the friendly Code Review server
Browse files

net: qrtr: mhi: Register for early notifications



Register for status callback to receive fatal error notifications.
Cancel any pending transactions and assume all future transactions
will return immediately with an error.

Early notification can be called from atomic context, change spin_lock
APIs to irqsave/irqrestore variants.

Change-Id: I17ed3a800411eef1bdcaf22c088cb1c9dbd393a6
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent f60b827c
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */

#include <linux/module.h>
#include <linux/skbuff.h>
@@ -16,6 +16,7 @@ struct qrtr_mhi_dev {
	struct device *dev;
	spinlock_t ul_lock;		/* lock to protect ul_pkts */
	struct list_head ul_pkts;
	atomic_t in_reset;
};

struct qrtr_mhi_pkt {
@@ -59,14 +60,33 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev,
{
	struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
	struct qrtr_mhi_pkt *pkt;
	unsigned long flags;

	spin_lock_bh(&qdev->ul_lock);
	spin_lock_irqsave(&qdev->ul_lock, flags);
	pkt = list_first_entry(&qdev->ul_pkts, struct qrtr_mhi_pkt, node);
	list_del(&pkt->node);
	complete_all(&pkt->done);

	kref_put(&pkt->refcount, qrtr_mhi_pkt_release);
	spin_unlock_bh(&qdev->ul_lock);
	spin_unlock_irqrestore(&qdev->ul_lock, flags);
}

/* fatal error */
static void qcom_mhi_qrtr_status_callback(struct mhi_device *mhi_dev,
					  enum MHI_CB mhi_cb)
{
	struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
	struct qrtr_mhi_pkt *pkt;
	unsigned long flags;

	if (mhi_cb != MHI_CB_FATAL_ERROR)
		return;

	atomic_inc(&qdev->in_reset);
	spin_lock_irqsave(&qdev->ul_lock, flags);
	list_for_each_entry(pkt, &qdev->ul_pkts, node)
		complete_all(&pkt->done);
	spin_unlock_irqrestore(&qdev->ul_lock, flags);
}

/* from qrtr to mhi */
@@ -109,10 +129,12 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
		sock_hold(skb->sk);

	rc = wait_for_completion_interruptible_timeout(&pkt->done, HZ * 5);
	if (rc > 0)
		rc = 0;
	if (atomic_read(&qdev->in_reset))
		rc = -ECONNRESET;
	else if (rc == 0)
		rc = -ETIMEDOUT;
	else if (rc > 0)
		rc = 0;

	kref_put(&pkt->refcount, qrtr_mhi_pkt_release);
	return rc;
@@ -132,6 +154,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
	qdev->mhi_dev = mhi_dev;
	qdev->dev = &mhi_dev->dev;
	qdev->ep.xmit = qcom_mhi_qrtr_send;
	atomic_set(&qdev->in_reset, 0);

	rc = of_property_read_u32(mhi_dev->dev.of_node, "qcom,net-id", &net_id);
	if (rc < 0)
@@ -169,6 +192,7 @@ static struct mhi_driver qcom_mhi_qrtr_driver = {
	.remove = qcom_mhi_qrtr_remove,
	.dl_xfer_cb = qcom_mhi_qrtr_dl_callback,
	.ul_xfer_cb = qcom_mhi_qrtr_ul_callback,
	.status_cb = qcom_mhi_qrtr_status_callback,
	.id_table = qcom_mhi_qrtr_mhi_match,
	.driver = {
		.name = "qcom_mhi_qrtr",