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

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

Merge "slim_msm: support non-blocking writes from slimbus MSM controller"

parents a36315c4 60852402
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2014, 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
@@ -207,8 +207,7 @@ static irqreturn_t msm_slim_interrupt(int irq, void *d)
		 * signalling completion/exiting ISR
		 */
		mb();
		if (dev->wr_comp)
			complete(dev->wr_comp);
		msm_slim_manage_tx_msgq(dev, false, NULL);
	}
	if (stat & MGR_INT_RX_MSG_RCVD) {
		u32 rx_buf[10];
@@ -372,8 +371,7 @@ static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
		}
	}
	txn->rl--;
	pbuf = msm_get_msg_buf(dev, txn->rl);
	dev->wr_comp = NULL;
	pbuf = msm_get_msg_buf(dev, txn->rl, &done);
	dev->err = 0;

	if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
@@ -438,11 +436,8 @@ static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
	if (txn->mt == SLIM_MSG_MT_CORE &&
		mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
		dev->reconf_busy = true;
	dev->wr_comp = &done;
	msm_send_msg_buf(dev, pbuf, txn->rl, MGR_TX_MSG);
	timeout = wait_for_completion_timeout(&done, HZ);
	if (!timeout)
		dev->wr_comp = NULL;
	if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
		if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
					SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
@@ -505,7 +500,9 @@ static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
retry_laddr:
	init_completion(&done);
	mutex_lock(&dev->tx_lock);
	buf = msm_get_msg_buf(dev, 9);
	buf = msm_get_msg_buf(dev, 9, &done);
	if (buf == NULL)
		return -ENOMEM;
	buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
					SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS,
					SLIM_MSG_DEST_LOGICALADDR,
@@ -513,7 +510,6 @@ retry_laddr:
	buf[1] = ea[3] | (ea[2] << 8) | (ea[1] << 16) | (ea[0] << 24);
	buf[2] = laddr;

	dev->wr_comp = &done;
	ret = msm_send_msg_buf(dev, buf, 9, MGR_TX_MSG);
	timeout = wait_for_completion_timeout(&done, HZ);
	if (!timeout)
@@ -521,7 +517,6 @@ retry_laddr:
	if (dev->err) {
		ret = dev->err;
		dev->err = 0;
		dev->wr_comp = NULL;
	}
	mutex_unlock(&dev->tx_lock);
	if (ret) {
@@ -1183,6 +1178,10 @@ static int msm_slim_probe(struct platform_device *pdev)
		ret = -ENOMEM;
		goto err_get_res_failed;
	}
	dev->wr_comp = kzalloc(sizeof(struct completion *) * MSM_TX_BUFS,
				GFP_KERNEL);
	if (!dev->wr_comp)
		return -ENOMEM;
	dev->dev = &pdev->dev;
	platform_set_drvdata(pdev, dev);
	slim_set_ctrldata(&dev->ctrl, dev);
@@ -1271,7 +1270,8 @@ static int msm_slim_probe(struct platform_device *pdev)
	dev->ctrl.dev.parent = &pdev->dev;
	dev->ctrl.dev.of_node = pdev->dev.of_node;

	ret = request_irq(dev->irq, msm_slim_interrupt, IRQF_TRIGGER_HIGH,
	ret = request_threaded_irq(dev->irq, NULL, msm_slim_interrupt,
				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
				"msm_slim_irq", dev);
	if (ret) {
		dev_err(&pdev->dev, "request IRQ failed\n");
@@ -1400,6 +1400,7 @@ err_of_init_failed:
err_ioremap_bam_failed:
	iounmap(dev->base);
err_ioremap_failed:
	kfree(dev->wr_comp);
	kfree(dev);
err_get_res_failed:
	release_mem_region(bam_mem->start, resource_size(bam_mem));
@@ -1437,6 +1438,7 @@ static int msm_slim_remove(struct platform_device *pdev)
	kthread_stop(dev->rx_msgq_thread);
	iounmap(dev->bam.base);
	iounmap(dev->base);
	kfree(dev->wr_comp);
	kfree(dev);
	bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						"slimbus_bam_physical");
+33 −10
Original line number Diff line number Diff line
@@ -101,15 +101,13 @@ static irqreturn_t ngd_slim_interrupt(int irq, void *d)
								dev->err);
		/* Guarantee that error interrupts are cleared */
		mb();
		if (dev->wr_comp)
			complete(dev->wr_comp);
		msm_slim_manage_tx_msgq(dev, false, NULL);

	} else if (stat & NGD_INT_TX_MSG_SENT) {
		writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
		/* Make sure interrupt is cleared */
		mb();
		if (dev->wr_comp)
			complete(dev->wr_comp);
		msm_slim_manage_tx_msgq(dev, false, NULL);
	}
	if (stat & NGD_INT_RX_MSG_RCVD) {
		u32 rx_buf[10];
@@ -286,6 +284,7 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
	u16 txn_mc = txn->mc;
	u8 wbuf[SLIM_MSGQ_BUF_LEN];
	bool report_sat = false;
	bool sync_wr = true;

	if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
		txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
@@ -439,7 +438,25 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
		txn->rl = txn->len + 4;
	}
	txn->rl--;
	pbuf = msm_get_msg_buf(dev, txn->rl);

	if (txn->mt == SLIM_MSG_MT_CORE && txn->comp &&
		dev->use_tx_msgqs == MSM_MSGQ_ENABLED &&
		(txn_mc != SLIM_MSG_MC_REQUEST_INFORMATION &&
		 txn_mc != SLIM_MSG_MC_REQUEST_VALUE &&
		 txn_mc != SLIM_MSG_MC_REQUEST_CHANGE_VALUE &&
		 txn_mc != SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION)) {
		sync_wr = false;
		pbuf = msm_get_msg_buf(dev, txn->rl, txn->comp);
	} else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
			dev->use_tx_msgqs == MSM_MSGQ_ENABLED &&
			txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
			txn->comp) {
		sync_wr = false;
		pbuf = msm_get_msg_buf(dev, txn->rl, txn->comp);
	} else {
		pbuf = msm_get_msg_buf(dev, txn->rl, &tx_sent);
	}

	if (!pbuf) {
		SLIM_ERR(dev, "Message buffer unavailable\n");
		ret = -ENOMEM;
@@ -510,10 +527,9 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
	 */
	txn_mc = txn->mc;
	txn_mt = txn->mt;
	dev->wr_comp = &tx_sent;
	ret = msm_send_msg_buf(dev, pbuf, txn->rl,
			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
	if (!ret) {
	if (!ret && sync_wr) {
		int timeout = wait_for_completion_timeout(&tx_sent, HZ);
		if (!timeout) {
			ret = -ETIMEDOUT;
@@ -529,7 +545,6 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
			ret = dev->err;
		}
	}
	dev->wr_comp = NULL;
	if (ret) {
		u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
		void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
@@ -1296,6 +1311,10 @@ static int ngd_slim_probe(struct platform_device *pdev)
		dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
		return PTR_ERR(dev);
	}
	dev->wr_comp = kzalloc(sizeof(struct completion *) * MSM_TX_BUFS,
				GFP_KERNEL);
	if (!dev->wr_comp)
		return -ENOMEM;
	dev->dev = &pdev->dev;
	platform_set_drvdata(pdev, dev);
	slim_set_ctrldata(&dev->ctrl, dev);
@@ -1379,6 +1398,7 @@ static int ngd_slim_probe(struct platform_device *pdev)
	init_completion(&dev->reconf);
	init_completion(&dev->ctrl_up);
	mutex_init(&dev->tx_lock);
	mutex_init(&dev->tx_buf_lock);
	spin_lock_init(&dev->rx_lock);
	dev->ee = 1;
	dev->irq = irq->start;
@@ -1406,8 +1426,9 @@ static int ngd_slim_probe(struct platform_device *pdev)
	dev->ctrl.dev.of_node = pdev->dev.of_node;
	dev->state = MSM_CTRL_DOWN;

	ret = request_irq(dev->irq, ngd_slim_interrupt,
			IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
	ret = request_threaded_irq(dev->irq, NULL,
			ngd_slim_interrupt,
			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "ngd_slim_irq", dev);

	if (ret) {
		dev_err(&pdev->dev, "request IRQ failed\n");
@@ -1470,6 +1491,7 @@ err_ioremap_failed:
	if (dev->sysfs_created)
		sysfs_remove_file(&dev->dev->kobj,
				&dev_attr_debug_mask.attr);
	kfree(dev->wr_comp);
	kfree(dev);
	return ret;
}
@@ -1492,6 +1514,7 @@ static int ngd_slim_remove(struct platform_device *pdev)
	kthread_stop(dev->rx_msgq_thread);
	iounmap(dev->bam.base);
	iounmap(dev->base);
	kfree(dev->wr_comp);
	kfree(dev);
	return 0;
}
+110 −22
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 */
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/slimbus/slimbus.h>
#include <linux/msm-sps.h>
#include "slim-msm.h"
@@ -390,9 +391,9 @@ static int msm_slim_post_tx_msgq(struct msm_slim_ctrl *dev, u8 *buf, int len)
	struct msm_slim_endp *endpoint = &dev->tx_msgq;
	struct sps_mem_buffer *mem = &endpoint->buf;
	struct sps_pipe *pipe = endpoint->sps;
	int ix = (buf - (u8 *)mem->base) / SLIM_MSGQ_BUF_LEN;
	int ix = (buf - (u8 *)mem->base);

	phys_addr_t phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
	phys_addr_t phys_addr = mem->phys_base + ix;

	for (ret = 0; ret < ((len + 3) >> 2); ret++)
		pr_debug("BAM TX buf[%d]:0x%x", ret, ((u32 *)buf)[ret]);
@@ -405,29 +406,110 @@ static int msm_slim_post_tx_msgq(struct msm_slim_ctrl *dev, u8 *buf, int len)
	return ret;
}

static u32 *msm_slim_tx_msgq_return(struct msm_slim_ctrl *dev)
void msm_slim_tx_msg_return(struct msm_slim_ctrl *dev)
{
	struct msm_slim_endp *endpoint = &dev->tx_msgq;
	struct sps_mem_buffer *mem = &endpoint->buf;
	struct sps_pipe *pipe = endpoint->sps;
	struct sps_iovec iovec;
	int ret;

	/* first transaction after establishing connection */
	if (dev->tx_idx == -1) {
		dev->tx_idx = 0;
		return mem->base;
	int idx, ret = 0;
	if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED) {
		/* use 1 buffer, non-blocking writes are not possible */
		if (dev->wr_comp[0]) {
			struct completion *comp = dev->wr_comp[0];
			dev->wr_comp[0] = NULL;
			complete(comp);
		}
		return;
	}
	while (!ret) {
		ret = sps_get_iovec(pipe, &iovec);
		if (ret || iovec.addr == 0) {
		dev_err(dev->dev, "sps_get_iovec() failed 0x%x\n", ret);
			if (ret)
				pr_err("SLIM TX get IOVEC failed:%d", ret);
			return;
		}
		idx = (int) ((iovec.addr - mem->phys_base) / SLIM_MSGQ_BUF_LEN);
		if (idx < MSM_TX_BUFS && dev->wr_comp[idx]) {
			struct completion *comp = dev->wr_comp[idx];
			dev->wr_comp[idx] = NULL;
			complete(comp);
		}
		/* reclaim all packets that were delivered out of order */
		if (idx != dev->tx_head)
			pr_err("SLIM OUT OF ORDER TX:idx:%d, head:%d", idx,
								dev->tx_head);
		while (idx == dev->tx_head) {
			dev->tx_head = (dev->tx_head + 1) % MSM_TX_BUFS;
			idx++;
			if (dev->tx_head == dev->tx_tail ||
					dev->wr_comp[idx] != NULL)
				break;
		}
	}
}

static u32 *msm_slim_modify_tx_buf(struct msm_slim_ctrl *dev,
					struct completion *comp)
{
	struct msm_slim_endp *endpoint = &dev->tx_msgq;
	struct sps_mem_buffer *mem = &endpoint->buf;
	u32 *retbuf = NULL;
	if ((dev->tx_tail + 1) % MSM_TX_BUFS == dev->tx_head)
		return NULL;

	retbuf = (u32 *)((u8 *)mem->base +
				(dev->tx_tail * SLIM_MSGQ_BUF_LEN));
	dev->wr_comp[dev->tx_tail] = comp;
	dev->tx_tail = (dev->tx_tail + 1) % MSM_TX_BUFS;
	return retbuf;
}
u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
					struct completion *comp)
{
	int ret = 0;
	int retries = 0;
	u32 *retbuf = NULL;

	/* Calculate buffer index */
	dev->tx_idx = ((int)(iovec.addr - mem->phys_base)) / SLIM_MSGQ_BUF_LEN;
	mutex_lock(&dev->tx_buf_lock);
	if (!getbuf) {
		msm_slim_tx_msg_return(dev);
		mutex_unlock(&dev->tx_buf_lock);
		return NULL;
	}

	retbuf = msm_slim_modify_tx_buf(dev, comp);
	if (retbuf) {
		mutex_unlock(&dev->tx_buf_lock);
		return retbuf;
	}

	return (u32 *)((u8 *)mem->base + (dev->tx_idx * SLIM_MSGQ_BUF_LEN));
	do {
		msm_slim_tx_msg_return(dev);
		retbuf = msm_slim_modify_tx_buf(dev, comp);
		if (!retbuf)
			ret = -EAGAIN;
		else {
			if (retries > 0)
				SLIM_INFO(dev, "SLIM TX retrieved:%d retries",
							retries);
			mutex_unlock(&dev->tx_buf_lock);
			return retbuf;
		}

		/*
		 * superframe size will vary based on clock gear
		 * 1 superframe will consume at least 1 message
		 * if HW is in good condition. With MX_RETRIES,
		 * make sure we wait for a [3, 10] superframes
		 * before deciding HW couldn't process descriptors
		 */
		usleep_range(100, 250);
		retries++;
	} while (ret && (retries < INIT_MX_RETRIES));

	mutex_unlock(&dev->tx_buf_lock);
	return NULL;
}

int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg)
@@ -445,16 +527,19 @@ int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg)
	return msm_slim_post_tx_msgq(dev, (u8 *)buf, len);
}

u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len)
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
			struct completion *comp)
{
	/*
	 * Currently we block a transaction until the current one completes.
	 * In case we need multiple transactions, use message Q
	 */
	if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED)
	if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED) {
		dev->wr_comp[0] = comp;
		return dev->tx_buf;
	}

	return msm_slim_tx_msgq_return(dev);
	return msm_slim_manage_tx_msgq(dev, true, comp);
}

static void
@@ -604,7 +689,8 @@ int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
		}
		dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
	} else {
		dev->tx_idx = -1;
		dev->tx_tail = 0;
		dev->tx_head = 0;
		dev->use_tx_msgqs = MSM_MSGQ_ENABLED;
	}

@@ -711,16 +797,18 @@ static int msm_slim_init_tx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
	config->options = SPS_O_ERROR | SPS_O_NO_Q |
				SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;

	/* Desc and TX buf are circular queues */
	/* Allocate memory for the FIFO descriptors */
	ret = msm_slim_sps_mem_alloc(dev, descr,
				MSM_TX_BUFS * sizeof(struct sps_iovec));
				(MSM_TX_BUFS + 1) * sizeof(struct sps_iovec));
	if (ret) {
		dev_err(dev->dev, "unable to allocate SPS descriptors\n");
		goto alloc_descr_failed;
	}

	/* Allocate memory for the message buffer(s), N descrs, 40-byte mesg */
	ret = msm_slim_sps_mem_alloc(dev, mem, MSM_TX_BUFS * SLIM_MSGQ_BUF_LEN);
	/* Allocate TX buffer from which descriptors are created */
	ret = msm_slim_sps_mem_alloc(dev, mem, ((MSM_TX_BUFS + 1) *
					SLIM_MSGQ_BUF_LEN));
	if (ret) {
		dev_err(dev->dev, "dma_alloc_coherent failed\n");
		goto alloc_buffer_failed;
+9 −4
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
/* Per spec.max 40 bytes per received message */
#define SLIM_MSGQ_BUF_LEN	40

#define MSM_TX_BUFS	2
#define MSM_TX_BUFS		32

#define SLIM_USR_MC_GENERIC_ACK		0x25
#define SLIM_USR_MC_MASTER_CAPABILITY	0x0
@@ -236,14 +236,15 @@ struct msm_slim_ctrl {
	u8			msg_cnt;
	u32			tx_buf[10];
	u8			rx_msgs[MSM_CONCUR_MSG][SLIM_MSGQ_BUF_LEN];
	int			tx_idx;
	int			tx_tail;
	int			tx_head;
	spinlock_t		rx_lock;
	int			head;
	int			tail;
	int			irq;
	int			err;
	int			ee;
	struct completion	*wr_comp;
	struct completion	**wr_comp;
	struct msm_slim_sat	*satd[MSM_MAX_NSATS];
	struct msm_slim_endp	pipes[7];
	struct msm_slim_sps_bam	bam;
@@ -254,6 +255,7 @@ struct msm_slim_ctrl {
	struct clk		*rclk;
	struct clk		*hclk;
	struct mutex		tx_lock;
	struct mutex		tx_buf_lock;
	u8			pgdla;
	enum msm_slim_msgq	use_rx_msgqs;
	enum msm_slim_msgq	use_tx_msgqs;
@@ -372,7 +374,10 @@ enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
			u32 len, struct completion *comp);
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len);
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
			struct completion *comp);
u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
			struct completion *comp);
int msm_slim_rx_msgq_get(struct msm_slim_ctrl *dev, u32 *data, int offset);
int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
			u32 pipe_reg, bool remote);
+1 −1
Original line number Diff line number Diff line
@@ -1088,7 +1088,7 @@ int slim_xfer_msg(struct slim_controller *ctrl, struct slim_device *sbdev,
	} else
		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR, mc, ec,
				SLIM_MSG_MT_CORE, rbuf, wbuf, len, mlen,
				NULL, sbdev->laddr, NULL);
				msg->comp, sbdev->laddr, NULL);
xfer_err:
	return ret;
}