Commit 9c96bacf authored by Bjorn Andersson's avatar Bjorn Andersson Committed by Bjorn Andersson
Browse files

rpmsg: glink: Fail qcom_glink_tx() once remove has been initiated



Upon removing the glink edge, communication is at best one-way. This
means that the very common scenario of glink requesting intents will not
be possible to serve.

Typically a successful transmission results in the client waiting for a
response, with some timeout and a mechanism for aborting that timeout.

Because of this, once the glink edge is defunct once removal is
commenced it's better to fail transmissions fast.

Reviewed-by: default avatarChris Lew <quic_clew@quicinc.com>
Signed-off-by: default avatarBjorn Andersson <quic_bjorande@quicinc.com>
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230213155215.1237059-6-quic_bjorande@quicinc.com
parent f424d1cb
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ struct glink_core_rx_intent {
 * @intentless:	flag to indicate that there is no intent
 * @tx_avail_notify: Waitqueue for pending tx tasks
 * @sent_read_notify: flag to check cmd sent or not
 * @abort_tx:	flag indicating that all tx attempts should fail
 */
struct qcom_glink {
	struct device *dev;
@@ -111,6 +112,8 @@ struct qcom_glink {
	bool intentless;
	wait_queue_head_t tx_avail_notify;
	bool sent_read_notify;

	bool abort_tx;
};

enum {
@@ -326,12 +329,22 @@ static int qcom_glink_tx(struct qcom_glink *glink,

	spin_lock_irqsave(&glink->tx_lock, flags);

	if (glink->abort_tx) {
		ret = -EIO;
		goto out;
	}

	while (qcom_glink_tx_avail(glink) < tlen) {
		if (!wait) {
			ret = -EAGAIN;
			goto out;
		}

		if (glink->abort_tx) {
			ret = -EIO;
			goto out;
		}

		if (!glink->sent_read_notify) {
			glink->sent_read_notify = true;
			qcom_glink_send_read_notify(glink);
@@ -1763,11 +1776,18 @@ static int qcom_glink_remove_device(struct device *dev, void *data)
void qcom_glink_native_remove(struct qcom_glink *glink)
{
	struct glink_channel *channel;
	unsigned long flags;
	int cid;
	int ret;

	qcom_glink_cancel_rx_work(glink);

	/* Fail all attempts at sending messages */
	spin_lock_irqsave(&glink->tx_lock, flags);
	glink->abort_tx = true;
	wake_up_all(&glink->tx_avail_notify);
	spin_unlock_irqrestore(&glink->tx_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);