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

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

Merge "slimbus: Optimize transaction handling in the framework"

parents d86e94c9 00e95b69
Loading
Loading
Loading
Loading
+17 −25
Original line number Diff line number Diff line
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -267,16 +267,8 @@ static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
				u8 *tid, struct completion *done)
{
	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
	mutex_lock(&ctrl->m_ctrl);
	spin_lock(&ctrl->txn_lock);
	if (ctrl->last_tid <= 255) {
		ctrl->txnt = krealloc(ctrl->txnt,
				(ctrl->last_tid + 1) *
				sizeof(struct slim_msg_txn *),
				GFP_KERNEL);
		if (!ctrl->txnt) {
			mutex_unlock(&ctrl->m_ctrl);
			return -ENOMEM;
		}
		dev->msg_cnt = ctrl->last_tid;
		ctrl->last_tid++;
	} else {
@@ -288,7 +280,7 @@ static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
		}
		if (i >= 256) {
			dev_err(&ctrl->dev, "out of TID");
			mutex_unlock(&ctrl->m_ctrl);
			spin_unlock(&ctrl->txn_lock);
			return -ENOMEM;
		}
	}
@@ -296,7 +288,7 @@ static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
	txn->tid = dev->msg_cnt;
	txn->comp = done;
	*tid = dev->msg_cnt;
	mutex_unlock(&ctrl->m_ctrl);
	spin_unlock(&ctrl->txn_lock);
	return 0;
}
static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
@@ -655,9 +647,9 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
			SLIM_ERR(dev,
				"connect/disconnect:0x%x,tid:%d err:%d\n",
					txn->mc, txn->tid, ret);
			mutex_lock(&ctrl->m_ctrl);
			spin_lock(&ctrl->txn_lock);
			ctrl->txnt[txn->tid] = NULL;
			mutex_unlock(&ctrl->m_ctrl);
			spin_unlock(&ctrl->txn_lock);
		}
		return ret ? ret : dev->err;
	}
@@ -725,9 +717,9 @@ static int ngd_xferandwait_ack(struct slim_controller *ctrl,
		if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
			SLIM_ERR(dev, "master msg:0x%x,tid:%d ret:%d\n",
				txn->mc, txn->tid, ret);
		mutex_lock(&ctrl->m_ctrl);
		spin_lock(&ctrl->txn_lock);
		ctrl->txnt[txn->tid] = NULL;
		mutex_unlock(&ctrl->m_ctrl);
		spin_unlock(&ctrl->txn_lock);
	}

	return ret;
@@ -1014,30 +1006,30 @@ capability_retry:
		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
		struct slim_msg_txn *txn;
		u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
		mutex_lock(&dev->ctrl.m_ctrl);
		spin_lock(&dev->ctrl.txn_lock);
		txn = dev->ctrl.txnt[buf[3]];
		if (!txn) {
			spin_unlock(&dev->ctrl.txn_lock);
			SLIM_WARN(dev,
				"LADDR response after timeout, tid:0x%x\n",
					buf[3]);
			mutex_unlock(&dev->ctrl.m_ctrl);
			return;
		}
		if (memcmp(&buf[4], failed_ea, 6))
			txn->la = buf[10];
		dev->ctrl.txnt[buf[3]] = NULL;
		mutex_unlock(&dev->ctrl.m_ctrl);
		complete(txn->comp);
		spin_unlock(&dev->ctrl.txn_lock);
	}
	if (mc == SLIM_USR_MC_GENERIC_ACK &&
		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
		struct slim_msg_txn *txn;
		mutex_lock(&dev->ctrl.m_ctrl);
		spin_lock(&dev->ctrl.txn_lock);
		txn = dev->ctrl.txnt[buf[3]];
		if (!txn) {
			spin_unlock(&dev->ctrl.txn_lock);
			SLIM_WARN(dev, "ACK received after timeout, tid:0x%x\n",
				buf[3]);
			mutex_unlock(&dev->ctrl.m_ctrl);
			return;
		}
		dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
@@ -1048,8 +1040,8 @@ capability_retry:
			txn->ec = -EIO;
		}
		dev->ctrl.txnt[buf[3]] = NULL;
		mutex_unlock(&dev->ctrl.m_ctrl);
		complete(txn->comp);
		spin_unlock(&dev->ctrl.txn_lock);
	}
}

@@ -1191,16 +1183,16 @@ static int ngd_slim_power_down(struct msm_slim_ctrl *dev)
{
	int i;
	struct slim_controller *ctrl = &dev->ctrl;
	mutex_lock(&ctrl->m_ctrl);
	spin_lock(&ctrl->txn_lock);
	/* Pending response for a message */
	for (i = 0; i < ctrl->last_tid; i++) {
		if (ctrl->txnt[i]) {
			spin_unlock(&ctrl->txn_lock);
			SLIM_INFO(dev, "NGD down:txn-rsp for %d pending", i);
			mutex_unlock(&ctrl->m_ctrl);
			return -EBUSY;
		}
	}
	mutex_unlock(&ctrl->m_ctrl);
	spin_unlock(&ctrl->txn_lock);
	return msm_slim_qmi_power_request(dev, false);
}

+119 −123
Original line number Diff line number Diff line
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -43,6 +43,14 @@ static DEFINE_IDR(ctrl_idr);
static struct device_type slim_dev_type;
static struct device_type slim_ctrl_type;

#define DEFINE_SLIM_LDEST_TXN(name, mc, len, rl, rbuf, wbuf, la) \
	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_LOGICALADDR, 0,\
					len, 0, la, false, rbuf, wbuf, NULL, }

#define DEFINE_SLIM_BCAST_TXN(name, mc, len, rl, rbuf, wbuf, la) \
	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_BROADCAST, 0,\
					len, 0, la, false, rbuf, wbuf, NULL, }

static const struct slim_device_id *slim_match(const struct slim_device_id *id,
					const struct slim_device *slim_dev)
{
@@ -450,6 +458,7 @@ static int slim_register_controller(struct slim_controller *ctrl)
		ctrl->min_cg = SLIM_MIN_CLK_GEAR;
	if (!ctrl->max_cg)
		ctrl->max_cg = SLIM_MAX_CLK_GEAR;
	spin_lock_init(&ctrl->txn_lock);
	mutex_init(&ctrl->m_ctrl);
	mutex_init(&ctrl->sched.m_reconf);
	ret = device_register(&ctrl->dev);
@@ -677,80 +686,56 @@ EXPORT_SYMBOL(slim_framer_booted);
void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len)
{
	int i;
	bool async;
	struct slim_msg_txn *txn;

	mutex_lock(&ctrl->m_ctrl);
	spin_lock(&ctrl->txn_lock);
	txn = ctrl->txnt[tid];
	if (txn == NULL || txn->rbuf == NULL) {
		spin_unlock(&ctrl->txn_lock);
		if (txn == NULL)
			dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
				tid, len);
		else
			dev_err(&ctrl->dev, "Invalid client buffer passed\n");
		mutex_unlock(&ctrl->m_ctrl);
		return;
	}
	async = txn->async;
	for (i = 0; i < len; i++)
		txn->rbuf[i] = reply[i];
	if (txn->comp)
		complete(txn->comp);
	ctrl->txnt[tid] = NULL;
	mutex_unlock(&ctrl->m_ctrl);
	spin_unlock(&ctrl->txn_lock);
	if (async)
		kfree(txn);
}
EXPORT_SYMBOL_GPL(slim_msg_response);

static int slim_processtxn(struct slim_controller *ctrl, u8 dt, u16 mc, u16 ec,
			u8 mt, u8 *rbuf, const u8 *wbuf, u8 len, u8 mlen,
			struct completion *comp, u8 la, u8 *tid)
static int slim_processtxn(struct slim_controller *ctrl,
				struct slim_msg_txn *txn, bool need_tid)
{
	u8 i = 0;
	int ret = 0;
	struct slim_msg_txn *txn = kmalloc(sizeof(struct slim_msg_txn),
					GFP_KERNEL);
	if (!txn)
		return -ENOMEM;
	if (tid) {
		mutex_lock(&ctrl->m_ctrl);
	if (need_tid) {
		spin_lock(&ctrl->txn_lock);
		for (i = 0; i < ctrl->last_tid; i++) {
			if (ctrl->txnt[i] == NULL)
				break;
		}
		if (i >= ctrl->last_tid) {
			if (ctrl->last_tid == 255) {
				mutex_unlock(&ctrl->m_ctrl);
				kfree(txn);
				return -ENOMEM;
			}
			ctrl->txnt = krealloc(ctrl->txnt,
					(i + 1) * sizeof(struct slim_msg_txn *),
					GFP_KERNEL);
			if (!ctrl->txnt) {
				mutex_unlock(&ctrl->m_ctrl);
				kfree(txn);
				spin_unlock(&ctrl->txn_lock);
				return -ENOMEM;
			}
			ctrl->last_tid++;
		}
		ctrl->txnt[i] = txn;
		mutex_unlock(&ctrl->m_ctrl);
		spin_unlock(&ctrl->txn_lock);
		txn->tid = i;
		*tid = i;
	}
	txn->mc = mc;
	txn->mt = mt;
	txn->dt = dt;
	txn->ec = ec;
	txn->la = la;
	txn->rbuf = rbuf;
	txn->wbuf = wbuf;
	txn->rl = mlen;
	txn->len = len;
	txn->comp = comp;
	}

	ret = ctrl->xfer_msg(ctrl, txn);
	if (!tid)
		kfree(txn);
	return ret;
}

@@ -1035,10 +1020,23 @@ int slim_xfer_msg(struct slim_controller *ctrl, struct slim_device *sbdev,
			const u8 *wbuf, u8 len)
{
	DECLARE_COMPLETION_ONSTACK(complete);
	DEFINE_SLIM_LDEST_TXN(txn_stack, mc, len, 6, rbuf, wbuf, sbdev->laddr);
	struct slim_msg_txn *txn;
	int ret;
	u16 sl, cur;
	u16 ec;
	u8 tid, mlen = 6;
	if (msg->comp && rbuf) {
		txn = kmalloc(sizeof(struct slim_msg_txn),
						GFP_KERNEL);
		if (IS_ERR_OR_NULL(txn))
			return PTR_ERR(txn);
		*txn = txn_stack;
		txn->async = true;
		txn->comp = msg->comp;
	} else {
		txn = &txn_stack;
		if (rbuf)
			txn->comp = &complete;
	}

	ret = slim_ele_access_sanity(msg, mc, rbuf, wbuf, len);
	if (ret)
@@ -1049,50 +1047,36 @@ int slim_xfer_msg(struct slim_controller *ctrl, struct slim_device *sbdev,
				msg->start_offset, len, mc, sl);

	cur = slim_slicecodefromsize(sl);
	ec = ((sl | (1 << 3)) | ((msg->start_offset & 0xFFF) << 4));
	txn->ec = ((sl | (1 << 3)) | ((msg->start_offset & 0xFFF) << 4));

	if (wbuf)
		mlen += len;
		txn->rl += len;
	if (rbuf) {
		mlen++;
		if (!msg->comp)
			ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR,
				mc, ec, SLIM_MSG_MT_CORE, rbuf, wbuf, len, mlen,
				&complete, sbdev->laddr, &tid);
		else
			ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR,
				mc, ec, SLIM_MSG_MT_CORE, rbuf, wbuf, len, mlen,
				msg->comp, sbdev->laddr, &tid);
		txn->rl++;
		ret = slim_processtxn(ctrl, txn, true);

		/* sync read */
		if (!ret && !msg->comp) {
			ret = wait_for_completion_timeout(&complete, HZ);
			if (!ret) {
				struct slim_msg_txn *txn;
				dev_err(&ctrl->dev, "slimbus Read timed out");
				mutex_lock(&ctrl->m_ctrl);
				txn = ctrl->txnt[tid];
				spin_lock(&ctrl->txn_lock);
				/* Invalidate the transaction */
				ctrl->txnt[tid] = NULL;
				mutex_unlock(&ctrl->m_ctrl);
				kfree(txn);
				ctrl->txnt[txn->tid] = NULL;
				spin_unlock(&ctrl->txn_lock);
				ret = -ETIMEDOUT;
			} else
				ret = 0;
		} else if (ret < 0 && !msg->comp) {
			struct slim_msg_txn *txn;
			dev_err(&ctrl->dev, "slimbus Read error");
			mutex_lock(&ctrl->m_ctrl);
			txn = ctrl->txnt[tid];
			spin_lock(&ctrl->txn_lock);
			/* Invalidate the transaction */
			ctrl->txnt[tid] = NULL;
			mutex_unlock(&ctrl->m_ctrl);
			kfree(txn);
			ctrl->txnt[txn->tid] = NULL;
			spin_unlock(&ctrl->txn_lock);
		}

	} else
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR, mc, ec,
				SLIM_MSG_MT_CORE, rbuf, wbuf, len, mlen,
				msg->comp, sbdev->laddr, NULL);
		ret = slim_processtxn(ctrl, txn, false);
xfer_err:
	return ret;
}
@@ -1268,22 +1252,20 @@ static int connect_port_ch(struct slim_controller *ctrl, u8 ch, u32 ph,
				enum slim_port_flow flow)
{
	int ret;
	u16 mc;
	u8 buf[2];
	u32 la = SLIM_HDL_TO_LA(ph);
	u8 pn = (u8)SLIM_HDL_TO_PORT(ph);
	DEFINE_SLIM_LDEST_TXN(txn, 0, 2, 6, NULL, buf, la);

	if (flow == SLIM_SRC)
		mc = SLIM_MSG_MC_CONNECT_SOURCE;
		txn.mc = SLIM_MSG_MC_CONNECT_SOURCE;
	else
		mc = SLIM_MSG_MC_CONNECT_SINK;
		txn.mc = SLIM_MSG_MC_CONNECT_SINK;
	buf[0] = pn;
	buf[1] = ctrl->chans[ch].chan;
	if (la == SLIM_LA_MANAGER)
		ctrl->ports[pn].flow = flow;
	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR, mc, 0,
				SLIM_MSG_MT_CORE, NULL, buf, 2, 6, NULL, la,
				NULL);
	ret = slim_processtxn(ctrl, &txn, false);
	if (!ret && la == SLIM_LA_MANAGER)
		ctrl->ports[pn].state = SLIM_P_CFG;
	return ret;
@@ -1292,14 +1274,12 @@ static int connect_port_ch(struct slim_controller *ctrl, u8 ch, u32 ph,
static int disconnect_port_ch(struct slim_controller *ctrl, u32 ph)
{
	int ret;
	u16 mc;
	u32 la = SLIM_HDL_TO_LA(ph);
	u8 pn = (u8)SLIM_HDL_TO_PORT(ph);
	DEFINE_SLIM_LDEST_TXN(txn, 0, 1, 5, NULL, &pn, la);

	mc = SLIM_MSG_MC_DISCONNECT_PORT;
	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR, mc, 0,
				SLIM_MSG_MT_CORE, NULL, &pn, 1, 5,
				NULL, la, NULL);
	txn.mc = SLIM_MSG_MC_DISCONNECT_PORT;
	ret = slim_processtxn(ctrl, &txn, false);
	if (ret)
		return ret;
	if (la == SLIM_LA_MANAGER)
@@ -2741,6 +2721,8 @@ int slim_reconfigure_now(struct slim_device *sb)
	u32 expshft;
	u32 segdist;
	struct slim_pending_ch *pch;
	DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION, 0, 3,
				NULL, NULL, sb->laddr);

	mutex_lock(&ctrl->sched.m_reconf);
	/*
@@ -2809,25 +2791,27 @@ int slim_reconfigure_now(struct slim_device *sb)
		ret = slim_allocbw(sb, &subframe, &clkgear);

	if (!ret) {
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
			SLIM_MSG_MC_BEGIN_RECONFIGURATION, 0, SLIM_MSG_MT_CORE,
			NULL, NULL, 0, 3, NULL, 0, NULL);
		ret = slim_processtxn(ctrl, &txn, false);
		dev_dbg(&ctrl->dev, "sending begin_reconfig:ret:%d\n", ret);
	}

	if (!ret && subframe != ctrl->sched.subfrmcode) {
		wbuf[0] = (u8)(subframe & 0xFF);
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
			SLIM_MSG_MC_NEXT_SUBFRAME_MODE, 0, SLIM_MSG_MT_CORE,
			NULL, (u8 *)&subframe, 1, 4, NULL, 0, NULL);
		txn.mc = SLIM_MSG_MC_NEXT_SUBFRAME_MODE;
		txn.len = 1;
		txn.rl = 4;
		txn.wbuf = wbuf;
		ret = slim_processtxn(ctrl, &txn, false);
		dev_dbg(&ctrl->dev, "sending subframe:%d,ret:%d\n",
				(int)wbuf[0], ret);
	}
	if (!ret && clkgear != ctrl->clkgear) {
		wbuf[0] = (u8)(clkgear & 0xFF);
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
			SLIM_MSG_MC_NEXT_CLOCK_GEAR, 0, SLIM_MSG_MT_CORE,
			NULL, wbuf, 1, 4, NULL, 0, NULL);
		txn.mc = SLIM_MSG_MC_NEXT_CLOCK_GEAR;
		txn.len = 1;
		txn.rl = 4;
		txn.wbuf = wbuf;
		ret = slim_processtxn(ctrl, &txn, false);
		dev_dbg(&ctrl->dev, "sending clkgear:%d,ret:%d\n",
				(int)wbuf[0], ret);
	}
@@ -2843,20 +2827,21 @@ int slim_reconfigure_now(struct slim_device *sb)
		wbuf[1] = slc->prrate;
		wbuf[2] = slc->prop.dataf | (slc->prop.auxf << 4);
		wbuf[3] = slc->prop.sampleszbits / SLIM_CL_PER_SL;
		txn.mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT;
		txn.len = 4;
		txn.rl = 7;
		txn.wbuf = wbuf;
		dev_dbg(&ctrl->dev, "define content, activate:%x, %x, %x, %x\n",
				wbuf[0], wbuf[1], wbuf[2], wbuf[3]);
		/* Right now, channel link bit is not supported */
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
				SLIM_MSG_MC_NEXT_DEFINE_CONTENT, 0,
				SLIM_MSG_MT_CORE, NULL, (u8 *)&wbuf, 4, 7,
				NULL, 0, NULL);
		ret = slim_processtxn(ctrl, &txn, false);
		if (ret)
			goto revert_reconfig;

		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
				SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL, 0,
				SLIM_MSG_MT_CORE, NULL, (u8 *)&wbuf, 1, 4,
				NULL, 0, NULL);
		txn.mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL;
		txn.len = 1;
		txn.rl = 4;
		ret = slim_processtxn(ctrl, &txn, false);
		if (ret)
			goto revert_reconfig;
	}
@@ -2865,10 +2850,11 @@ int slim_reconfigure_now(struct slim_device *sb)
		struct slim_ich *slc = &ctrl->chans[pch->chan];
		dev_dbg(&ctrl->dev, "remove chan:%x\n", pch->chan);
		wbuf[0] = slc->chan;
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
				SLIM_MSG_MC_NEXT_REMOVE_CHANNEL, 0,
				SLIM_MSG_MT_CORE, NULL, wbuf, 1, 4,
				NULL, 0, NULL);
		txn.mc = SLIM_MSG_MC_NEXT_REMOVE_CHANNEL;
		txn.len = 1;
		txn.rl = 4;
		txn.wbuf = wbuf;
		ret = slim_processtxn(ctrl, &txn, false);
		if (ret)
			goto revert_reconfig;
	}
@@ -2876,10 +2862,11 @@ int slim_reconfigure_now(struct slim_device *sb)
		struct slim_ich *slc = &ctrl->chans[pch->chan];
		dev_dbg(&ctrl->dev, "suspend chan:%x\n", pch->chan);
		wbuf[0] = slc->chan;
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
				SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL, 0,
				SLIM_MSG_MT_CORE, NULL, wbuf, 1, 4,
				NULL, 0, NULL);
		txn.mc = SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL;
		txn.len = 1;
		txn.rl = 4;
		txn.wbuf = wbuf;
		ret = slim_processtxn(ctrl, &txn, false);
		if (ret)
			goto revert_reconfig;
	}
@@ -2908,10 +2895,11 @@ int slim_reconfigure_now(struct slim_device *sb)
			wbuf[2] = (u8)((segdist & 0xF00) >> 8) |
					(slc->prop.prot << 4);
			wbuf[3] = slc->seglen;
			ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
					SLIM_MSG_MC_NEXT_DEFINE_CHANNEL, 0,
					SLIM_MSG_MT_CORE, NULL, (u8 *)wbuf, 4,
					7, NULL, 0, NULL);
			txn.mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL;
			txn.len = 4;
			txn.rl = 7;
			txn.wbuf = wbuf;
			ret = slim_processtxn(ctrl, &txn, false);
			if (ret)
				goto revert_reconfig;
		}
@@ -2941,17 +2929,20 @@ int slim_reconfigure_now(struct slim_device *sb)
			wbuf[2] = (u8)((segdist & 0xF00) >> 8) |
					(slc->prop.prot << 4);
			wbuf[3] = (u8)(slc->seglen);
			ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
					SLIM_MSG_MC_NEXT_DEFINE_CHANNEL, 0,
					SLIM_MSG_MT_CORE, NULL, (u8 *)wbuf, 4,
					7, NULL, 0, NULL);
			txn.mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL;
			txn.len = 4;
			txn.rl = 7;
			txn.wbuf = wbuf;
			ret = slim_processtxn(ctrl, &txn, false);
			if (ret)
				goto revert_reconfig;
		}
	}
	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
			SLIM_MSG_MC_RECONFIGURE_NOW, 0, SLIM_MSG_MT_CORE, NULL,
			NULL, 0, 3, NULL, 0, NULL);
	txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
	txn.len = 0;
	txn.rl = 3;
	txn.wbuf = NULL;
	ret = slim_processtxn(ctrl, &txn, false);
	dev_dbg(&ctrl->dev, "reconfig now:ret:%d\n", ret);
	if (!ret) {
		ctrl->sched.subfrmcode = subframe;
@@ -3128,6 +3119,9 @@ int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
{
	int ret = 0;
	int i;
	DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_CLK_PAUSE_SEQ_FLG |
				SLIM_MSG_MC_BEGIN_RECONFIGURATION, 0, 3,
				NULL, NULL, 0);

	if (wakeup == false && restart > SLIM_CLK_UNSPECIFIED)
		return -EINVAL;
@@ -3211,21 +3205,23 @@ int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
		goto clk_pause_ret;
	}

	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
		SLIM_MSG_CLK_PAUSE_SEQ_FLG | SLIM_MSG_MC_BEGIN_RECONFIGURATION,
		0, SLIM_MSG_MT_CORE, NULL, NULL, 0, 3, NULL, 0, NULL);
	ret = slim_processtxn(ctrl, &txn, false);
	if (ret)
		goto clk_pause_ret;

	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
		SLIM_MSG_CLK_PAUSE_SEQ_FLG | SLIM_MSG_MC_NEXT_PAUSE_CLOCK, 0,
		SLIM_MSG_MT_CORE, NULL, &restart, 1, 4, NULL, 0, NULL);
	txn.mc = SLIM_MSG_CLK_PAUSE_SEQ_FLG | SLIM_MSG_MC_NEXT_PAUSE_CLOCK;
	txn.len = 1;
	txn.rl = 4;
	txn.wbuf = &restart;
	ret = slim_processtxn(ctrl, &txn, false);
	if (ret)
		goto clk_pause_ret;

	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
		SLIM_MSG_CLK_PAUSE_SEQ_FLG | SLIM_MSG_MC_RECONFIGURE_NOW, 0,
		SLIM_MSG_MT_CORE, NULL, NULL, 0, 3, NULL, 0, NULL);
	txn.mc = SLIM_MSG_CLK_PAUSE_SEQ_FLG | SLIM_MSG_MC_RECONFIGURE_NOW;
	txn.len = 0;
	txn.rl = 3;
	txn.wbuf = NULL;
	ret = slim_processtxn(ctrl, &txn, false);
	if (ret)
		goto clk_pause_ret;

+6 −2
Original line number Diff line number Diff line
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@ extern struct bus_type slimbus_type;
/* Standard values per SLIMbus spec needed by controllers and devices */
#define SLIM_CL_PER_SUPERFRAME		6144
#define SLIM_CL_PER_SUPERFRAME_DIV8	(SLIM_CL_PER_SUPERFRAME >> 3)
#define SLIM_MAX_TXNS			256
#define SLIM_MAX_CLK_GEAR		10
#define SLIM_MIN_CLK_GEAR		1
#define SLIM_CL_PER_SL			4
@@ -171,6 +172,7 @@ struct slim_addrt {
 *	(e.g. relevant for mc = SLIM_MSG_MC_REQUEST_INFORMATION)
 * @la: Logical address of the device this message is going to.
 *	(Not used when destination type is broadcast.)
 * @async: If this transaction is async
 * @rbuf: Buffer to be populated by controller when response is received.
 * @wbuf: Payload of the message. (e.g. channel number for DATA channel APIs)
 * @comp: Completion structure. Used by controller to notify response.
@@ -185,6 +187,7 @@ struct slim_msg_txn {
	u8			len;
	u8			tid;
	u8			la;
	bool			async;
	u8			*rbuf;
	const u8		*wbuf;
	struct completion	*comp;
@@ -544,8 +547,9 @@ struct slim_controller {
	u8			num_dev;
	struct list_head	devs;
	struct workqueue_struct *wq;
	struct slim_msg_txn	**txnt;
	struct slim_msg_txn	*txnt[SLIM_MAX_TXNS];
	u8			last_tid;
	spinlock_t		txn_lock;
	struct slim_port	*ports;
	int			nports;
	struct slim_ich		*chans;