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

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

Merge "net: qrtr: mhi: Create list for pending ul transfers"

parents b8ed334e 76663f56
Loading
Loading
Loading
Loading
+62 −17
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/skbuff.h>
#include <linux/mod_devicetable.h>
#include <linux/mhi.h>
#include <net/sock.h>

#include "qrtr.h"

@@ -21,9 +22,29 @@ struct qrtr_mhi_dev {
	struct qrtr_endpoint ep;
	struct mhi_device *mhi_dev;
	struct device *dev;
	struct completion ul_done;
	spinlock_t ul_lock;		/* lock to protect ul_pkts */
	struct list_head ul_pkts;
};

struct qrtr_mhi_pkt {
	struct list_head node;
	struct sk_buff *skb;
	struct kref refcount;
	struct completion done;
};

static void qrtr_mhi_pkt_release(struct kref *ref)
{
	struct qrtr_mhi_pkt *pkt = container_of(ref, struct qrtr_mhi_pkt,
						refcount);
	struct sock *sk = pkt->skb->sk;

	consume_skb(pkt->skb);
	if (sk)
		sock_put(sk);
	kfree(pkt);
}

/* from mhi to qrtr */
static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
				      struct mhi_result *mhi_res)
@@ -45,39 +66,63 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev,
				      struct mhi_result *mhi_res)
{
	struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
	struct sk_buff *skb = mhi_res->buf_addr;
	struct qrtr_mhi_pkt *pkt;

	if (!mhi_res->transaction_status) {
		complete(&qdev->ul_done);
		consume_skb(skb);
	} else {
		kfree_skb(skb);
	}
	spin_lock_bh(&qdev->ul_lock);
	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);
}

/* from qrtr to mhi */
static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
{
	struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep);
	struct qrtr_mhi_pkt *pkt;
	int rc;

	rc = skb_linearize(skb);
	if (rc)
		goto out;
	if (rc) {
		kfree_skb(skb);
		return rc;
	}

	pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
	if (!pkt) {
		kfree_skb(skb);
		return -ENOMEM;
	}

	reinit_completion(&qdev->ul_done);
	init_completion(&pkt->done);
	kref_init(&pkt->refcount);
	kref_get(&pkt->refcount);
	pkt->skb = skb;

	spin_lock_bh(&qdev->ul_lock);
	list_add_tail(&pkt->node, &qdev->ul_pkts);
	rc = mhi_queue_transfer(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len,
				MHI_EOT);
	if (rc)
		goto out;
	if (rc) {
		list_del(&pkt->node);
		kfree_skb(skb);
		kfree(pkt);
		spin_unlock_bh(&qdev->ul_lock);
		return rc;
	}
	spin_unlock_bh(&qdev->ul_lock);
	if (skb->sk)
		sock_hold(skb->sk);

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

out:
	kref_put(&pkt->refcount, qrtr_mhi_pkt_release);
	return rc;
}

@@ -95,7 +140,8 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
	qdev->dev = &mhi_dev->dev;
	qdev->ep.xmit = qcom_mhi_qrtr_send;

	init_completion(&qdev->ul_done);
	INIT_LIST_HEAD(&qdev->ul_pkts);
	spin_lock_init(&qdev->ul_lock);

	rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
	if (rc)
@@ -113,7 +159,6 @@ static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev)
	struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);

	qrtr_endpoint_unregister(&qdev->ep);
	complete(&qdev->ul_done);
	dev_set_drvdata(&mhi_dev->dev, NULL);
}