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

Commit d2711722 authored by Chris Lew's avatar Chris Lew
Browse files

mailbox: msm_qmp: Add IPC Logging support



Create an IPC Logging context for each QMP mailbox to record transfers
between light weight remote processors and this processor. Add logging
for state transitions within in the mailbox.

Change-Id: I5ecf99c7de3deed51a132298c1fc61022209cba5
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 4fee7f40
Loading
Loading
Loading
Loading
+52 −17
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/mailbox/qmp.h>
#include <linux/ipc_logging.h>

#define QMP_MAGIC	0x4d41494c	/* MAIL */
#define QMP_VERSION	0x1
@@ -37,6 +38,20 @@

#define MSG_RAM_ALIGN_BYTES 3

#define QMP_IPC_LOG_PAGE_CNT 2
#define QMP_INFO(ctxt, x, ...)						  \
do {									  \
	if (ctxt)							  \
		ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \
} while (0)

#define QMP_ERR(ctxt, x, ...)						  \
do {									  \
	pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__);		  \
	if (ctxt)							  \
		ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \
} while (0)

/**
 * enum qmp_local_state - definition of the local state machine
 * @LINK_DISCONNECTED:		Init state, waiting for ucore to start
@@ -172,6 +187,7 @@ struct qmp_mbox {
 * @rx_work:		Work to be executed when an irq is received
 * @tx_irq_count:	Number of tx interrupts triggered
 * @rx_irq_count:	Number of rx interrupts received
 * @ilc:		IPC logging context
 */
struct qmp_device {
	struct device *dev;
@@ -190,6 +206,8 @@ struct qmp_device {
	u32 rx_irq_line;
	u32 tx_irq_count;
	u32 rx_irq_count;

	void *ilc;
};

/**
@@ -247,7 +265,7 @@ static void qmp_notify_timeout(struct work_struct *work)
		spin_unlock_irqrestore(&mbox->tx_lock, flags);
		return;
	}
	pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight);
	QMP_ERR(mbox->mdev->ilc, "tx timeout for %d\n", mbox->idx_in_flight);
	iowrite32(0, mbox->mdev->msgram + mbox->mcore_mbox_offset);
	mbox->tx_sent = false;
	spin_unlock_irqrestore(&mbox->tx_lock, flags);
@@ -380,6 +398,8 @@ static int qmp_send_data(struct mbox_chan *chan, void *data)
		if (chan == &mbox->ctrl.chans[i])
			mbox->idx_in_flight = i;
	}
	QMP_INFO(mdev->ilc, "Copied buffer to msgram sz:%d i:%d\n",
		 pkt->size, mbox->idx_in_flight);
	send_irq(mdev);
	qmp_schedule_tx_timeout(mbox);
	spin_unlock_irqrestore(&mbox->tx_lock, flags);
@@ -453,13 +473,14 @@ static void qmp_recv_data(struct qmp_mbox *mbox, u32 mbox_of)
	pkt->size = ioread32(addr);

	if (pkt->size > mbox->mcore_mbox_size)
		pr_err("%s: Invalid mailbox packet\n", __func__);
		QMP_ERR(mbox->mdev->ilc, "Invalid mailbox packet\n");
	else {
		memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size);
		mbox_chan_received_data(&mbox->ctrl.chans[mbox->idx_in_flight],
				pkt);
	}
	iowrite32(0, addr);
	QMP_INFO(mbox->mdev->ilc, "recv sz:%d\n", pkt->size);
	send_irq(mbox->mdev);
}

@@ -530,61 +551,67 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox)
						 desc.ucore.mailbox_size,
						 GFP_KERNEL);
		if (!mbox->rx_pkt.data) {
			pr_err("In %s: failed to allocate rx pkt\n", __func__);
			QMP_ERR(mdev->ilc, "Failed to allocate rx pkt\n");
			break;
		}
		QMP_INFO(mdev->ilc, "Set to link negotiation\n");
		send_irq(mdev);
		break;
	case LINK_NEGOTIATION:
		if (desc.mcore.link_state_ack != QMP_MBOX_LINK_UP ||
				desc.mcore.link_state != QMP_MBOX_LINK_UP) {
			pr_err("In %s: rx interrupt without negotiation ack\n",
					__func__);
			QMP_ERR(mdev->ilc, "RX int without negotiation ack\n");
			break;
		}
		mbox->local_state = LINK_CONNECTED;
		complete_all(&mbox->link_complete);
		QMP_INFO(mdev->ilc, "Set to link connected\n");
		break;
	case LINK_CONNECTED:
		if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
			pr_err("In %s: rx interrupt without channel open\n",
					__func__);
			QMP_ERR(mdev->ilc, "RX int without ch open\n");
			break;
		}
		set_ucore_ch_ack(mbox, desc.ucore.ch_state);
		send_irq(mdev);
		QMP_INFO(mdev->ilc, "Received remote ch open\n");
		break;
	case LOCAL_CONNECTING:
		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED &&
				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED)
				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED) {
			mbox->local_state = LOCAL_CONNECTED;
			QMP_INFO(mdev->ilc, "Received local ch open ack\n");
		}

		if (desc.ucore.ch_state != desc.ucore.ch_state_ack) {
			set_ucore_ch_ack(mbox, desc.ucore.ch_state);
			send_irq(mdev);
			QMP_INFO(mdev->ilc, "Received remote channel open\n");
		}
		if (mbox->local_state == LOCAL_CONNECTED &&
				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED &&
				desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) {
			mbox->local_state = CHANNEL_CONNECTED;
			complete_all(&mbox->ch_complete);
			QMP_INFO(mdev->ilc, "Set to channel connected\n");
		}
		break;
	case LOCAL_CONNECTED:
		if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
			pr_err("In %s: rx interrupt without remote channel open\n",
					__func__);
			QMP_ERR(mdev->ilc, "RX int without remote ch open\n");
			break;
		}
		set_ucore_ch_ack(mbox, desc.ucore.ch_state);
		mbox->local_state = CHANNEL_CONNECTED;
		send_irq(mdev);
		complete_all(&mbox->ch_complete);
		QMP_INFO(mdev->ilc, "Set to channel connected\n");
		break;
	case CHANNEL_CONNECTED:
		if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) {
			set_ucore_ch_ack(mbox, desc.ucore.ch_state);
			mbox->local_state = LOCAL_CONNECTED;
			QMP_INFO(mdev->ilc, "REMOTE DISCONNECT\n");
			send_irq(mdev);
		}

@@ -600,6 +627,9 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox)
			if (msg_len == 0) {
				mbox->tx_sent = false;
				cancel_delayed_work(&mbox->dwork);
				QMP_INFO(mdev->ilc, "TX flag cleared, idx%d\n",
					 idx);

				spin_unlock_irqrestore(&mbox->tx_lock, flags);
				mbox_chan_txdone(&mbox->ctrl.chans[idx], 0);
				spin_lock_irqsave(&mbox->tx_lock, flags);
@@ -609,12 +639,15 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox)
		break;
	case LOCAL_DISCONNECTING:
		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED &&
				desc.mcore.ch_state == desc.mcore.ch_state_ack)
			desc.mcore.ch_state == desc.mcore.ch_state_ack) {

			mbox->local_state = LINK_CONNECTED;
			QMP_INFO(mdev->ilc, "Channel closed\n");
			reinit_completion(&mbox->ch_complete);
		}
		break;
	default:
		pr_err("In %s: Local Channel State corrupted\n", __func__);
		QMP_ERR(mdev->ilc, "Local Channel State corrupted\n");
	}
	mutex_unlock(&mbox->state_lock);
}
@@ -903,6 +936,8 @@ static int qmp_mbox_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0);

	kthread_init_work(&mdev->kwork, rx_worker);
	kthread_init_worker(&mdev->kworker);
	mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s",
@@ -913,13 +948,13 @@ static int qmp_mbox_probe(struct platform_device *pdev)
		edge_node->name, mdev);
	if (ret < 0) {
		qmp_mbox_remove(pdev);
		pr_err("%s: request irq on %d failed: %d\n", __func__,
		QMP_ERR(mdev->ilc, "request irq on %d failed: %d\n",
			mdev->rx_irq_line, ret);
		return ret;
	}
	ret = enable_irq_wake(mdev->rx_irq_line);
	if (ret < 0)
		pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__,
		QMP_ERR(mdev->ilc, "enable_irq_wake on %d failed: %d\n",
			mdev->rx_irq_line, ret);

	/* Trigger fake RX in case of missed interrupt */