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

Commit 377b9aa0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes I9e8dcd26,I94f018e0 into msm-next

* changes:
  rpmsg: glink: Handle remote rx done command
  rpmsg: glink: Request for intents when unavailable
parents 38846d8e 13436ce3
Loading
Loading
Loading
Loading
+116 −2
Original line number Diff line number Diff line
@@ -149,6 +149,9 @@ enum {
 * @buf_size:	size of current @buf
 * @open_ack:	completed once remote has acked the open-request
 * @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
 */
struct glink_channel {
	struct rpmsg_endpoint ept;
@@ -176,6 +179,10 @@ struct glink_channel {

	struct completion open_ack;
	struct completion open_req;

	struct mutex intent_req_lock;
	bool intent_req_result;
	struct completion intent_req_comp;
};

#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
@@ -342,6 +349,24 @@ static void qcom_glink_send_open_ack(struct qcom_glink *glink,
	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
}

static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
					     unsigned int cid, bool granted)
{
	struct glink_channel *channel;
	unsigned long flags;

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);
	if (!channel) {
		dev_err(glink->dev, "unable to find channel\n");
		return;
	}

	channel->intent_req_result = granted;
	complete(&channel->intent_req_comp);
}

/**
 * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
 * @glink: Ptr to the glink edge
@@ -632,6 +657,40 @@ qcom_glink_alloc_intent(struct qcom_glink *glink,
	return intent;
}

static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
				      u32 cid, uint32_t iid,
				      bool reuse)
{
	struct glink_core_rx_intent *intent;
	struct glink_channel *channel;
	unsigned long flags;

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);
	if (!channel) {
		dev_err(glink->dev, "invalid channel id received\n");
		return;
	}

	spin_lock_irqsave(&channel->intent_lock, flags);
	intent = idr_find(&channel->riids, iid);

	if (!intent) {
		spin_unlock_irqrestore(&channel->intent_lock, flags);
		dev_err(glink->dev, "invalid intent id received\n");
		return;
	}

	intent->in_use = false;

	if (!reuse) {
		idr_remove(&channel->riids, intent->id);
		kfree(intent);
	}
	spin_unlock_irqrestore(&channel->intent_lock, flags);
}

/**
 * qcom_glink_handle_intent_req() - Receive a request for rx_intent
 *					    from remote side
@@ -940,6 +999,18 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
		case RPM_CMD_INTENT:
			qcom_glink_handle_intent(glink, param1, param2, avail);
			break;
		case RPM_CMD_RX_DONE:
			qcom_glink_handle_rx_done(glink, param1, param2, false);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		case RPM_CMD_RX_DONE_W_REUSE:
			qcom_glink_handle_rx_done(glink, param1, param2, true);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		case RPM_CMD_RX_INTENT_REQ_ACK:
			qcom_glink_handle_intent_req_ack(glink, param1, param2);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		default:
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
@@ -1106,6 +1177,42 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
	qcom_glink_send_close_req(glink, channel);
}

static int qcom_glink_request_intent(struct qcom_glink *glink,
				     struct glink_channel *channel,
				     size_t size)
{
	struct {
		u16 id;
		u16 cid;
		u32 size;
	} __packed cmd;

	int ret;

	mutex_lock(&channel->intent_req_lock);

	reinit_completion(&channel->intent_req_comp);

	cmd.id = RPM_CMD_RX_INTENT_REQ;
	cmd.cid = channel->lcid;
	cmd.size = size;

	ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
	if (ret)
		return ret;

	ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ);
	if (!ret) {
		dev_err(glink->dev, "intent request timed out\n");
		ret = -ETIMEDOUT;
	} else {
		ret = channel->intent_req_result ? 0 : -ECANCELED;
	}

	mutex_unlock(&channel->intent_req_lock);
	return ret;
}

static int __qcom_glink_send(struct glink_channel *channel,
			     void *data, int len, bool wait)
{
@@ -1122,7 +1229,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
	unsigned long flags;

	if (!glink->intentless) {
		if (!intent) {
		while (!intent) {
			spin_lock_irqsave(&channel->intent_lock, flags);
			idr_for_each_entry(&channel->riids, tmp, iid) {
				if (tmp->size >= len && !tmp->in_use) {
@@ -1134,8 +1241,15 @@ static int __qcom_glink_send(struct glink_channel *channel,
			spin_unlock_irqrestore(&channel->intent_lock, flags);

			/* We found an available intent */
			if (!intent)
			if (intent)
				break;

			if (!wait)
				return -EBUSY;

			ret = qcom_glink_request_intent(glink, channel, len);
			if (ret < 0)
				return ret;
		}

		iid = intent->id;