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

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

Merge "mailbox: msm_qmp: Add IPC Logging support"

parents 3bacbd32 d2711722
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 */