Commit 6e10aa1f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rpmsg updates from Bjorn Andersson:

 - Minor cleanup/refactor to the Qualcomm GLINK code, in order to add
   trace events related to the messages exchange with the remote side,
   useful for debugging a range of interoperability issues

 - Rewrite the nested structs with flexible array members in order to
   avoid the risk of invalid accesses

* tag 'rpmsg-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux:
  rpmsg: glink: Avoid -Wflex-array-member-not-at-end warnings
  rpmsg: glink: Introduce packet tracepoints
  rpmsg: glink: Pass channel to qcom_glink_send_close_ack()
  rpmsg: glink: Tidy up RX advance handling
parents 5c480f1d c1ddb297
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
obj-$(CONFIG_RPMSG_CTRL)	+= rpmsg_ctrl.o
obj-$(CONFIG_RPMSG_NS)		+= rpmsg_ns.o
obj-$(CONFIG_RPMSG_MTK_SCP)	+= mtk_rpmsg.o
CFLAGS_qcom_glink_native.o	:= -I$(src)
qcom_glink-objs			:= qcom_glink_native.o qcom_glink_ssr.o
obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
+135 −31
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#include "rpmsg_internal.h"
#include "qcom_glink_native.h"

#define CREATE_TRACE_POINTS
#include "qcom_glink_trace.h"

#define GLINK_NAME_SIZE		32
#define GLINK_VERSION_1		1

@@ -30,11 +33,16 @@
#define RPM_GLINK_CID_MAX	65536

struct glink_msg {
	/* New members MUST be added within the __struct_group() macro below. */
	__struct_group(glink_msg_hdr, hdr, __packed,
		__le16 cmd;
		__le16 param1;
		__le32 param2;
	);
	u8 data[];
} __packed;
static_assert(offsetof(struct glink_msg, data) == sizeof(struct glink_msg_hdr),
	      "struct member likely outside of __struct_group()");

/**
 * struct glink_defer_cmd - deferred incoming control message
@@ -48,7 +56,7 @@ struct glink_msg {
struct glink_defer_cmd {
	struct list_head node;

	struct glink_msg msg;
	struct glink_msg_hdr msg;
	u8 data[];
};

@@ -78,6 +86,7 @@ struct glink_core_rx_intent {
/**
 * struct qcom_glink - driver context, relates to one remote subsystem
 * @dev:	reference to the associated struct device
 * @label:	identifier of the glink edge
 * @rx_pipe:	pipe object for receive FIFO
 * @tx_pipe:	pipe object for transmit FIFO
 * @rx_work:	worker for handling received control messages
@@ -96,6 +105,8 @@ struct glink_core_rx_intent {
struct qcom_glink {
	struct device *dev;

	const char *label;

	struct qcom_glink_pipe *rx_pipe;
	struct qcom_glink_pipe *tx_pipe;

@@ -392,6 +403,8 @@ static int qcom_glink_send_version(struct qcom_glink *glink)
	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
	msg.param2 = cpu_to_le32(glink->features);

	trace_qcom_glink_cmd_version_tx(glink->label, GLINK_VERSION_1, glink->features);

	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
}

@@ -403,6 +416,8 @@ static void qcom_glink_send_version_ack(struct qcom_glink *glink)
	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
	msg.param2 = cpu_to_le32(glink->features);

	trace_qcom_glink_cmd_version_ack_tx(glink->label, msg.param1, msg.param2);

	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
}

@@ -415,6 +430,9 @@ static void qcom_glink_send_open_ack(struct qcom_glink *glink,
	msg.param1 = cpu_to_le16(channel->rcid);
	msg.param2 = cpu_to_le32(0);

	trace_qcom_glink_cmd_open_ack_tx(glink->label, channel->name,
					 channel->lcid, channel->rcid);

	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
}

@@ -424,9 +442,16 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
	struct glink_channel *channel;
	unsigned long flags;

	qcom_glink_rx_advance(glink, ALIGN(sizeof(struct glink_msg), 8));

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_rx_intent_req_ack_rx(glink->label,
						  channel ? channel->name : NULL,
						  channel ? channel->lcid : 0,
						  cid, granted);
	if (!channel) {
		dev_err(glink->dev, "unable to find channel\n");
		return;
@@ -455,12 +480,9 @@ static void qcom_glink_intent_req_abort(struct glink_channel *channel)
static int qcom_glink_send_open_req(struct qcom_glink *glink,
				    struct glink_channel *channel)
{
	struct {
		struct glink_msg msg;
		u8 name[GLINK_NAME_SIZE];
	} __packed req;
	DEFINE_RAW_FLEX(struct glink_msg, req, data, GLINK_NAME_SIZE);
	int name_len = strlen(channel->name) + 1;
	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
	int req_len = ALIGN(sizeof(*req) + name_len, 8);
	int ret;
	unsigned long flags;

@@ -476,12 +498,15 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,

	channel->lcid = ret;

	req.msg.cmd = cpu_to_le16(GLINK_CMD_OPEN);
	req.msg.param1 = cpu_to_le16(channel->lcid);
	req.msg.param2 = cpu_to_le32(name_len);
	strcpy(req.name, channel->name);
	req->cmd = cpu_to_le16(GLINK_CMD_OPEN);
	req->param1 = cpu_to_le16(channel->lcid);
	req->param2 = cpu_to_le32(name_len);
	strcpy(req->data, channel->name);

	trace_qcom_glink_cmd_open_tx(glink->label, channel->name,
				     channel->lcid, channel->rcid);

	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
	ret = qcom_glink_tx(glink, req, req_len, NULL, 0, true);
	if (ret)
		goto remove_idr;

@@ -505,18 +530,24 @@ static void qcom_glink_send_close_req(struct qcom_glink *glink,
	req.param1 = cpu_to_le16(channel->lcid);
	req.param2 = 0;

	trace_qcom_glink_cmd_close_tx(glink->label, channel->name,
				      channel->lcid, channel->rcid);

	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
}

static void qcom_glink_send_close_ack(struct qcom_glink *glink,
				      unsigned int rcid)
				      struct glink_channel *channel)
{
	struct glink_msg req;

	req.cmd = cpu_to_le16(GLINK_CMD_CLOSE_ACK);
	req.param1 = cpu_to_le16(rcid);
	req.param1 = cpu_to_le16(channel->rcid);
	req.param2 = 0;

	trace_qcom_glink_cmd_close_ack_tx(glink->label, channel->name,
					  channel->lcid, channel->rcid);

	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
}

@@ -548,6 +579,9 @@ static void qcom_glink_rx_done_work(struct work_struct *work)
		cmd.lcid = cid;
		cmd.liid = iid;

		trace_qcom_glink_cmd_rx_done_tx(glink->label, channel->name,
						channel->lcid, channel->rcid, cmd.liid, reuse);

		qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
		if (!reuse) {
			kfree(intent->data);
@@ -598,6 +632,8 @@ static void qcom_glink_receive_version(struct qcom_glink *glink,
				       u32 version,
				       u32 features)
{
	trace_qcom_glink_cmd_version_rx(glink->label, version, features);

	switch (version) {
	case 0:
		break;
@@ -625,6 +661,8 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
					   u32 version,
					   u32 features)
{
	trace_qcom_glink_cmd_version_ack_rx(glink->label, version, features);

	switch (version) {
	case 0:
		/* Version negotiation failed */
@@ -656,6 +694,10 @@ static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
{
	struct glink_msg msg;

	trace_qcom_glink_cmd_rx_intent_req_ack_tx(glink->label, channel->name,
						  channel->lcid, channel->rcid,
						  granted);

	msg.cmd = cpu_to_le16(GLINK_CMD_RX_INTENT_REQ_ACK);
	msg.param1 = cpu_to_le16(channel->lcid);
	msg.param2 = cpu_to_le32(granted);
@@ -693,6 +735,10 @@ static int qcom_glink_advertise_intent(struct qcom_glink *glink,
	cmd.size = cpu_to_le32(intent->size);
	cmd.liid = cpu_to_le32(intent->id);

	trace_qcom_glink_cmd_intent_tx(glink->label, channel->name,
				       channel->lcid, channel->rcid,
				       cmd.count, cmd.size, cmd.liid);

	qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);

	return 0;
@@ -745,9 +791,14 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
	struct glink_channel *channel;
	unsigned long flags;

	qcom_glink_rx_advance(glink, ALIGN(sizeof(struct glink_msg), 8));

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_rx_done_rx(glink->label, channel ? channel->name : NULL,
					channel ? channel->lcid : 0, cid, iid, reuse);
	if (!channel) {
		dev_err(glink->dev, "invalid channel id received\n");
		return;
@@ -797,6 +848,10 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_rx_intent_req_rx(glink->label,
					      channel ? channel->name : NULL,
					      channel ? channel->lcid : 0,
					      cid, size);
	if (!channel) {
		pr_err("%s channel not found for cid %d\n", __func__, cid);
		return;
@@ -826,7 +881,9 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)

	INIT_LIST_HEAD(&dcmd->node);

	qcom_glink_rx_peek(glink, &dcmd->msg, 0, sizeof(dcmd->msg) + extra);
	qcom_glink_rx_peek(glink,
			   container_of(&dcmd->msg, struct glink_msg, hdr), 0,
			   sizeof(dcmd->msg) + extra);

	spin_lock(&glink->rx_lock);
	list_add_tail(&dcmd->node, &glink->rx_queue);
@@ -843,7 +900,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
	struct glink_core_rx_intent *intent;
	struct glink_channel *channel;
	struct {
		struct glink_msg msg;
		struct glink_msg_hdr msg;
		__le32 chunk_size;
		__le32 left_size;
	} __packed hdr;
@@ -869,9 +926,15 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
	}

	rcid = le16_to_cpu(hdr.msg.param1);
	liid = le32_to_cpu(hdr.msg.param2);
	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, rcid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_tx_data_rx(glink->label, channel ? channel->name : NULL,
					channel ? channel->lcid : 0, rcid,
					liid, chunk_size, left_size,
					hdr.msg.cmd == GLINK_CMD_TX_DATA_CONT);
	if (!channel) {
		dev_dbg(glink->dev, "Data on non-existing channel\n");

@@ -902,8 +965,6 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
			intent = channel->buf;
		}
	} else {
		liid = le32_to_cpu(hdr.msg.param2);

		spin_lock_irqsave(&channel->intent_lock, flags);
		intent = idr_find(&channel->liids, liid);
		spin_unlock_irqrestore(&channel->intent_lock, flags);
@@ -952,6 +1013,14 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
	return ret;
}

static void qcom_glink_rx_read_notif(struct qcom_glink *glink)
{
	trace_qcom_glink_cmd_read_notif_rx(glink->label);

	qcom_glink_rx_advance(glink, ALIGN(sizeof(struct glink_msg), 8));
	qcom_glink_tx_kick(glink);
}

static void qcom_glink_handle_intent(struct qcom_glink *glink,
				     unsigned int cid,
				     unsigned int count,
@@ -965,7 +1034,7 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,
	};

	struct {
		struct glink_msg msg;
		struct glink_msg_hdr msg;
		struct intent_pair intents[];
	} __packed * msg;

@@ -983,6 +1052,7 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,
	channel = idr_find(&glink->rcids, cid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);
	if (!channel) {
		trace_qcom_glink_cmd_intent_rx(glink->label, NULL, 0, cid, count, 0, 0);
		dev_err(glink->dev, "intents for non-existing channel\n");
		qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
		return;
@@ -994,6 +1064,11 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,

	qcom_glink_rx_peek(glink, msg, 0, msglen);

	trace_qcom_glink_cmd_intent_rx(glink->label, channel->name,
				       channel->lcid, cid, count,
				       count > 0 ? msg->intents[0].size : 0,
				       count > 0 ? msg->intents[0].iid : 0);

	for (i = 0; i < count; ++i) {
		intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
		if (!intent)
@@ -1022,9 +1097,14 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
{
	struct glink_channel *channel;

	qcom_glink_rx_advance(glink, ALIGN(sizeof(struct glink_msg), 8));

	spin_lock(&glink->idr_lock);
	channel = idr_find(&glink->lcids, lcid);
	spin_unlock(&glink->idr_lock);

	trace_qcom_glink_cmd_open_ack_rx(glink->label, channel ? channel->name : NULL,
					 lcid, channel ? channel->rcid : 0);
	if (!channel) {
		dev_err(glink->dev, "Invalid open ack packet\n");
		return -EINVAL;
@@ -1057,6 +1137,9 @@ static int qcom_glink_set_flow_control(struct rpmsg_endpoint *ept, bool pause, u
	msg.param1 = cpu_to_le16(channel->lcid);
	msg.param2 = cpu_to_le32(sigs);

	trace_qcom_glink_cmd_signal_tx(glink->label, channel->name,
				       channel->lcid, channel->rcid, sigs);

	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
}

@@ -1067,9 +1150,14 @@ static void qcom_glink_handle_signals(struct qcom_glink *glink,
	unsigned long flags;
	bool enable;

	qcom_glink_rx_advance(glink, ALIGN(sizeof(struct glink_msg), 8));

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, rcid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_signal_rx(glink->label, channel ? channel->name : NULL,
				       channel ? channel->lcid : 0, rcid, sigs);
	if (!channel) {
		dev_err(glink->dev, "signal for non-existing channel\n");
		return;
@@ -1114,7 +1202,6 @@ void qcom_glink_native_rx(struct qcom_glink *glink)
			break;
		case GLINK_CMD_OPEN_ACK:
			ret = qcom_glink_rx_open_ack(glink, param1);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		case GLINK_CMD_OPEN:
			ret = qcom_glink_rx_defer(glink, param2);
@@ -1124,27 +1211,22 @@ void qcom_glink_native_rx(struct qcom_glink *glink)
			ret = qcom_glink_rx_data(glink, avail);
			break;
		case GLINK_CMD_READ_NOTIF:
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			qcom_glink_tx_kick(glink);
			qcom_glink_rx_read_notif(glink);
			break;
		case GLINK_CMD_INTENT:
			qcom_glink_handle_intent(glink, param1, param2, avail);
			break;
		case GLINK_CMD_RX_DONE:
			qcom_glink_handle_rx_done(glink, param1, param2, false);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		case GLINK_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 GLINK_CMD_RX_INTENT_REQ_ACK:
			qcom_glink_handle_intent_req_ack(glink, param1, param2);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		case GLINK_CMD_SIGNALS:
			qcom_glink_handle_signals(glink, param1, param2);
			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
			break;
		default:
			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
@@ -1349,6 +1431,10 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
	cmd.cid = channel->lcid;
	cmd.size = size;

	trace_qcom_glink_cmd_rx_intent_req_tx(glink->label, channel->name,
					      channel->lcid, channel->rcid,
					      cmd.size);

	ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
	if (ret)
		goto unlock;
@@ -1377,7 +1463,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
	struct glink_core_rx_intent *tmp;
	int iid = 0;
	struct {
		struct glink_msg msg;
		struct glink_msg_hdr msg;
		__le32 chunk_size;
		__le32 left_size;
	} __packed req;
@@ -1429,6 +1515,12 @@ static int __qcom_glink_send(struct glink_channel *channel,
		req.chunk_size = cpu_to_le32(chunk_size);
		req.left_size = cpu_to_le32(len - offset - chunk_size);

		trace_qcom_glink_cmd_tx_data_tx(glink->label, channel->name,
						channel->lcid, channel->rcid,
						iid, chunk_size,
						len - offset - chunk_size,
						offset > 0);

		ret = qcom_glink_tx(glink, &req, sizeof(req), data + offset, chunk_size, wait);
		if (ret) {
			/* Mark intent available if we failed */
@@ -1544,6 +1636,8 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
		create_device = true;
	}

	trace_qcom_glink_cmd_open_rx(glink->label, name, channel->lcid, rcid);

	spin_lock_irqsave(&glink->idr_lock, flags);
	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_ATOMIC);
	if (ret < 0) {
@@ -1605,6 +1699,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->rcids, rcid);
	spin_unlock_irqrestore(&glink->idr_lock, flags);

	trace_qcom_glink_cmd_close_rx(glink->label, channel ? channel->name : NULL,
				      channel ? channel->lcid : 0, rcid);
	if (WARN(!channel, "close request on unknown channel\n"))
		return;

@@ -1620,7 +1717,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
	}
	channel->rpdev = NULL;

	qcom_glink_send_close_ack(glink, channel->rcid);
	qcom_glink_send_close_ack(glink, channel);

	spin_lock_irqsave(&glink->idr_lock, flags);
	idr_remove(&glink->rcids, channel->rcid);
@@ -1641,6 +1738,9 @@ static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)

	spin_lock_irqsave(&glink->idr_lock, flags);
	channel = idr_find(&glink->lcids, lcid);

	trace_qcom_glink_cmd_close_ack_rx(glink->label, channel ? channel->name : NULL,
					  lcid, channel ? channel->rcid : 0);
	if (WARN(!channel, "close ack on unknown channel\n")) {
		spin_unlock_irqrestore(&glink->idr_lock, flags);
		return;
@@ -1685,7 +1785,7 @@ static void qcom_glink_work(struct work_struct *work)
		list_del(&dcmd->node);
		spin_unlock_irqrestore(&glink->rx_lock, flags);

		msg = &dcmd->msg;
		msg = container_of(&dcmd->msg, struct glink_msg, hdr);
		cmd = le16_to_cpu(msg->cmd);
		param1 = le16_to_cpu(msg->param1);
		param2 = le32_to_cpu(msg->param2);
@@ -1815,6 +1915,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
	idr_init(&glink->lcids);
	idr_init(&glink->rcids);

	ret = of_property_read_string(dev->of_node, "label", &glink->label);
	if (ret < 0)
		glink->label = dev->of_node->name;

	glink->dev->groups = qcom_glink_groups;

	ret = device_add_groups(dev, qcom_glink_groups);
+406 −0

File added.

Preview size limit exceeded, changes collapsed.