Merge "slim_msm: Support TX message queues"
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 86ae8db..6962d53 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -222,7 +221,7 @@
u8 *puc;
int ret = 0;
u8 la = txn->la;
- u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
@@ -235,17 +234,14 @@
*/
ngd_slim_runtime_resume(dev->dev);
}
- if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
- SLIM_MSG_MC_RECONFIGURE_NOW)) {
- if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
- ret = sps_disconnect(dev->rx_msgq.sps);
- dev->use_rx_msgqs = MSM_MSGQ_RESET;
- }
- if (!ret)
- ret = msm_slim_qmi_power_request(dev, false);
- else
- pr_err("SPS pipe disconnect error:%d", ret);
- return ret;
+ if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
+ SLIM_MSG_MC_RECONFIGURE_NOW)) &&
+ dev->state <= MSM_CTRL_SLEEPING) {
+ msm_slim_disconnect_endp(dev, &dev->rx_msgq,
+ &dev->use_rx_msgqs);
+ msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+ &dev->use_tx_msgqs);
+ return msm_slim_qmi_power_request(dev, false);
}
else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
return 0;
@@ -389,10 +385,19 @@
NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
if (!ret) {
int timeout = wait_for_completion_timeout(&tx_sent, HZ);
- if (!timeout)
+ if (!timeout) {
ret = -ETIMEDOUT;
- else
+ /*
+ * disconnect/recoonect pipe so that subsequent
+ * transactions don't timeout due to unavailable
+ * descriptors
+ */
+ msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+ &dev->use_tx_msgqs);
+ msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
+ } else {
ret = dev->err;
+ }
}
dev->wr_comp = NULL;
if (ret) {
@@ -469,7 +474,7 @@
struct slim_msg_txn txn;
struct slim_controller *ctrl = sb->ctrl;
DECLARE_COMPLETION_ONSTACK(done);
- u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
*clkgear = ctrl->clkgear;
*subfrmc = 0;
@@ -631,24 +636,26 @@
return ret;
}
-static void ngd_slim_setup_rx_path(struct msm_slim_ctrl *dev)
+static void ngd_slim_setup_msg_path(struct msm_slim_ctrl *dev)
{
- int ret;
if (dev->state == MSM_CTRL_DOWN) {
msm_slim_sps_init(dev, dev->bam_mem,
NGD_BASE(dev->ctrl.nr,
dev->ver) + NGD_STATUS, true);
} else {
if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
- return;
- ret = msm_slim_connect_endp(dev, &dev->rx_msgq,
+ goto setup_tx_msg_path;
+ msm_slim_connect_endp(dev, &dev->rx_msgq,
&dev->rx_msgq_notify);
- if (!ret)
- dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
- else
- pr_err("RX msgq not being used:%d", ret);
+
+setup_tx_msg_path:
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
+ return;
+ msm_slim_connect_endp(dev, &dev->tx_msgq,
+ NULL);
}
}
+
static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
{
u8 mc, mt, len;
@@ -677,9 +684,11 @@
txn.len = 4;
pr_info("SLIM SAT: Received master capability");
if (dev->state >= MSM_CTRL_ASLEEP) {
- ngd_slim_setup_rx_path(dev);
+ ngd_slim_setup_msg_path(dev);
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
msgq_en |= NGD_CFG_RX_MSGQ_EN;
+ if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+ msgq_en |= NGD_CFG_TX_MSGQ_EN;
writel_relaxed(msgq_en, dev->base +
NGD_BASE(dev->ctrl.nr, dev->ver));
/* make sure NGD MSG-Q config goes through */
@@ -793,7 +802,7 @@
* ADSP power collapse case, where HW wasn't reset.
* Reconnect BAM pipes if disconnected
*/
- ngd_slim_setup_rx_path(dev);
+ ngd_slim_setup_msg_path(dev);
return 0;
} else if (cur_state != MSM_CTRL_DOWN) {
pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
@@ -806,6 +815,12 @@
sps_free_endpoint(endpoint->sps);
dev->use_rx_msgqs = MSM_MSGQ_RESET;
}
+ if (dev->use_tx_msgqs == MSM_MSGQ_DOWN) {
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ sps_disconnect(endpoint->sps);
+ sps_free_endpoint(endpoint->sps);
+ dev->use_tx_msgqs = MSM_MSGQ_RESET;
+ }
/*
* ADSP power collapse case (OR SSR), where HW was reset
* BAM programming will happen when capability message is received
@@ -957,6 +972,8 @@
/* disconnect BAM pipes */
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
dev->use_rx_msgqs = MSM_MSGQ_DOWN;
+ if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+ dev->use_tx_msgqs = MSM_MSGQ_DOWN;
msm_slim_sps_exit(dev, false);
mutex_lock(&ctrl->m_ctrl);
/* device up should be called again after SSR */
@@ -1083,6 +1100,10 @@
dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
else
dev->use_rx_msgqs = MSM_MSGQ_RESET;
+
+ /* Enable TX message queues by default as recommended by HW */
+ dev->use_tx_msgqs = MSM_MSGQ_RESET;
+
init_completion(&dev->rx_msgq_notify);
/* Register with framework */
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 30341e2..0166196 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -269,16 +269,66 @@
return ret;
}
+/* Queue up Tx message buffer */
+static int msm_slim_post_tx_msgq(struct msm_slim_ctrl *dev, u8 *buf, int len)
+{
+ int ret;
+ 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;
+
+ u32 phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
+
+ for (ret = 0; ret < ((len + 3) >> 2); ret++)
+ pr_debug("BAM TX buf[%d]:0x%x", ret, ((u32 *)buf)[ret]);
+
+ ret = sps_transfer_one(pipe, phys_addr, ((len + 3) & 0xFC), NULL,
+ SPS_IOVEC_FLAG_EOT);
+ if (ret)
+ dev_err(dev->dev, "transfer_one() failed 0x%x, %d\n", ret, ix);
+
+ return ret;
+}
+
+static u32 *msm_slim_tx_msgq_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;
+ }
+ ret = sps_get_iovec(pipe, &iovec);
+ if (ret || iovec.addr == 0) {
+ dev_err(dev->dev, "sps_get_iovec() failed 0x%x\n", ret);
+ return NULL;
+ }
+
+ /* Calculate buffer index */
+ dev->tx_idx = (iovec.addr - mem->phys_base) / SLIM_MSGQ_BUF_LEN;
+
+ return (u32 *)((u8 *)mem->base + (dev->tx_idx * SLIM_MSGQ_BUF_LEN));
+}
+
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg)
{
- int i;
- for (i = 0; i < (len + 3) >> 2; i++) {
- dev_dbg(dev->dev, "TX data:0x%x\n", buf[i]);
- writel_relaxed(buf[i], dev->base + tx_reg + (i * 4));
+ if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED) {
+ int i;
+ for (i = 0; i < (len + 3) >> 2; i++) {
+ dev_dbg(dev->dev, "AHB TX data:0x%x\n", buf[i]);
+ writel_relaxed(buf[i], dev->base + tx_reg + (i * 4));
+ }
+ /* Guarantee that message is sent before returning */
+ mb();
+ return 0;
}
- /* Guarantee that message is sent before returning */
- mb();
- return 0;
+ return msm_slim_post_tx_msgq(dev, (u8 *)buf, len);
}
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len)
@@ -287,7 +337,10 @@
* Currently we block a transaction until the current one completes.
* In case we need multiple transactions, use message Q
*/
- return dev->tx_buf;
+ if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED)
+ return dev->tx_buf;
+
+ return msm_slim_tx_msgq_return(dev);
}
static void
@@ -394,15 +447,17 @@
memset(&sps_descr_event, 0x00, sizeof(sps_descr_event));
- sps_descr_event.mode = SPS_TRIGGER_CALLBACK;
- sps_descr_event.options = SPS_O_DESC_DONE;
- sps_descr_event.user = (void *)dev;
- sps_descr_event.xfer_done = notify;
+ if (notify) {
+ sps_descr_event.mode = SPS_TRIGGER_CALLBACK;
+ sps_descr_event.options = SPS_O_DESC_DONE;
+ sps_descr_event.user = (void *)dev;
+ sps_descr_event.xfer_done = notify;
- ret = sps_register_event(endpoint->sps, &sps_descr_event);
- if (ret) {
- dev_err(dev->dev, "sps_connect() failed 0x%x\n", ret);
- goto sps_reg_event_failed;
+ ret = sps_register_event(endpoint->sps, &sps_descr_event);
+ if (ret) {
+ dev_err(dev->dev, "sps_connect() failed 0x%x\n", ret);
+ goto sps_reg_event_failed;
+ }
}
/* Register callback for errors */
@@ -423,13 +478,20 @@
* Use (buf->size/4) - 1 for the number of buffer to post
*/
- /* Setup the transfer */
- for (i = 0; i < (MSM_SLIM_DESC_NUM - 1); i++) {
- ret = msm_slim_post_rx_msgq(dev, i);
- if (ret) {
- dev_err(dev->dev, "post_rx_msgq() failed 0x%x\n", ret);
- goto sps_transfer_failed;
+ if (endpoint == &dev->rx_msgq) {
+ /* Setup the transfer */
+ for (i = 0; i < (MSM_SLIM_DESC_NUM - 1); i++) {
+ ret = msm_slim_post_rx_msgq(dev, i);
+ if (ret) {
+ dev_err(dev->dev,
+ "post_rx_msgq() failed 0x%x\n", ret);
+ goto sps_transfer_failed;
+ }
}
+ dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ } else {
+ dev->tx_idx = -1;
+ dev->use_tx_msgqs = MSM_MSGQ_ENABLED;
}
return 0;
@@ -440,6 +502,7 @@
sps_disconnect(endpoint->sps);
return ret;
}
+
static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
{
int ret;
@@ -489,10 +552,8 @@
ret = msm_slim_connect_endp(dev, endpoint, notify);
- if (!ret) {
- dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ if (!ret)
return 0;
- }
msm_slim_sps_mem_free(dev, mem);
alloc_buffer_failed:
@@ -504,6 +565,67 @@
return ret;
}
+static int msm_slim_init_tx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+{
+ int ret;
+ u32 pipe_offset;
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ struct sps_connect *config = &endpoint->config;
+ struct sps_mem_buffer *descr = &config->desc;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
+ return 0;
+
+ /* Allocate the endpoint */
+ ret = msm_slim_init_endpoint(dev, endpoint);
+ if (ret) {
+ dev_err(dev->dev, "init_endpoint failed 0x%x\n", ret);
+ goto sps_init_endpoint_failed;
+ }
+
+ /* Get the pipe indices for the message queues */
+ pipe_offset = (readl_relaxed(dev->base + pipe_reg) & 0xfc) >> 2;
+ pipe_offset += 1;
+ dev_dbg(dev->dev, "TX Message queue pipe offset %d\n", pipe_offset);
+
+ config->mode = SPS_MODE_DEST;
+ config->source = SPS_DEV_HANDLE_MEM;
+ config->destination = dev->bam.hdl;
+ config->dest_pipe_index = pipe_offset;
+ config->src_pipe_index = 0;
+ config->options = SPS_O_ERROR | SPS_O_NO_Q |
+ SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
+
+ /* Allocate memory for the FIFO descriptors */
+ ret = msm_slim_sps_mem_alloc(dev, descr,
+ MSM_TX_BUFS * 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);
+ if (ret) {
+ dev_err(dev->dev, "dma_alloc_coherent failed\n");
+ goto alloc_buffer_failed;
+ }
+ ret = msm_slim_connect_endp(dev, endpoint, NULL);
+
+ if (!ret)
+ return 0;
+
+ msm_slim_sps_mem_free(dev, mem);
+alloc_buffer_failed:
+ msm_slim_sps_mem_free(dev, descr);
+alloc_descr_failed:
+ msm_slim_free_endpoint(endpoint);
+sps_init_endpoint_failed:
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+ return ret;
+}
+
/* Registers BAM h/w resource with SPS driver and initializes msgq endpoints */
int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
u32 pipe_reg, bool remote)
@@ -529,8 +651,10 @@
},
};
- if (dev->bam.hdl)
- goto init_rx_msgq;
+ if (dev->bam.hdl) {
+ bam_handle = dev->bam.hdl;
+ goto init_msgq;
+ }
bam_props.ee = dev->ee;
bam_props.virt_addr = dev->bam.base;
bam_props.phys_addr = bam_mem->start;
@@ -563,40 +687,68 @@
if (ret) {
dev_err(dev->dev, "disabling BAM: reg-bam failed 0x%x\n", ret);
dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
- goto init_rx_msgq;
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+ return ret;
}
dev->bam.hdl = bam_handle;
dev_dbg(dev->dev, "SLIM BAM registered, handle = 0x%x\n", bam_handle);
-init_rx_msgq:
+init_msgq:
ret = msm_slim_init_rx_msgq(dev, pipe_reg);
if (ret)
dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret);
- if (ret && bam_handle) {
+ if (ret && bam_handle)
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
+
+ ret = msm_slim_init_tx_msgq(dev, pipe_reg);
+ if (ret)
+ dev_err(dev->dev, "msm_slim_init_tx_msgq failed 0x%x\n", ret);
+ if (ret && bam_handle)
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED &&
+ dev->use_rx_msgqs == MSM_MSGQ_DISABLED && bam_handle) {
sps_deregister_bam_device(bam_handle);
dev->bam.hdl = 0L;
}
+
return ret;
}
+void msm_slim_disconnect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag)
+{
+ if (*msgq_flag == MSM_MSGQ_ENABLED) {
+ sps_disconnect(endpoint->sps);
+ *msgq_flag = MSM_MSGQ_RESET;
+ }
+}
+
+static void msm_slim_remove_ep(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag)
+{
+ struct sps_connect *config = &endpoint->config;
+ struct sps_mem_buffer *descr = &config->desc;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+ struct sps_register_event sps_event;
+ memset(&sps_event, 0x00, sizeof(sps_event));
+ msm_slim_sps_mem_free(dev, mem);
+ sps_register_event(endpoint->sps, &sps_event);
+ if (*msgq_flag == MSM_MSGQ_ENABLED) {
+ msm_slim_disconnect_endp(dev, endpoint, msgq_flag);
+ msm_slim_free_endpoint(endpoint);
+ }
+ msm_slim_sps_mem_free(dev, descr);
+}
+
void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
{
- if (dev->use_rx_msgqs >= MSM_MSGQ_ENABLED) {
- struct msm_slim_endp *endpoint = &dev->rx_msgq;
- struct sps_connect *config = &endpoint->config;
- struct sps_mem_buffer *descr = &config->desc;
- struct sps_mem_buffer *mem = &endpoint->buf;
- struct sps_register_event sps_event;
- memset(&sps_event, 0x00, sizeof(sps_event));
- msm_slim_sps_mem_free(dev, mem);
- sps_register_event(endpoint->sps, &sps_event);
- if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
- sps_disconnect(endpoint->sps);
- msm_slim_free_endpoint(endpoint);
- dev->use_rx_msgqs = MSM_MSGQ_RESET;
- }
- msm_slim_sps_mem_free(dev, descr);
- }
+ if (dev->use_rx_msgqs >= MSM_MSGQ_ENABLED)
+ msm_slim_remove_ep(dev, &dev->rx_msgq, &dev->use_rx_msgqs);
+ if (dev->use_tx_msgqs >= MSM_MSGQ_ENABLED)
+ msm_slim_remove_ep(dev, &dev->tx_msgq, &dev->use_tx_msgqs);
if (dereg) {
sps_deregister_bam_device(dev->bam.hdl);
dev->bam.hdl = 0L;
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index cf2d26f..f8f625e 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -17,7 +17,9 @@
#include <mach/msm_qmi_interface.h>
/* Per spec.max 40 bytes per received message */
-#define SLIM_RX_MSGQ_BUF_LEN 40
+#define SLIM_MSGQ_BUF_LEN 40
+
+#define MSM_TX_BUFS 2
#define SLIM_USR_MC_GENERIC_ACK 0x25
#define SLIM_USR_MC_MASTER_CAPABILITY 0x0
@@ -200,7 +202,8 @@
u32 curr_bw;
u8 msg_cnt;
u32 tx_buf[10];
- u8 rx_msgs[MSM_CONCUR_MSG][SLIM_RX_MSGQ_BUF_LEN];
+ u8 rx_msgs[MSM_CONCUR_MSG][SLIM_MSGQ_BUF_LEN];
+ int tx_idx;
spinlock_t rx_lock;
int head;
int tail;
@@ -211,6 +214,7 @@
struct msm_slim_sat *satd[MSM_MAX_NSATS];
struct msm_slim_endp pipes[7];
struct msm_slim_sps_bam bam;
+ struct msm_slim_endp tx_msgq;
struct msm_slim_endp rx_msgq;
struct completion rx_msgq_notify;
struct task_struct *rx_msgq_thread;
@@ -219,6 +223,7 @@
struct mutex tx_lock;
u8 pgdla;
enum msm_slim_msgq use_rx_msgqs;
+ enum msm_slim_msgq use_tx_msgqs;
int pipe_b;
struct completion reconf;
bool reconf_busy;
@@ -285,6 +290,9 @@
int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
struct msm_slim_endp *endpoint,
struct completion *notify);
+void msm_slim_disconnect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag);
void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);