slim: msm: Support multiple satellites per MSM controller
Supporting multiple satellites per 1 controller enables communication
with more than 1 ADSP on target. There may be upto 2 ADSPs that MSM
controller driver needs to communicate with.
Change-Id: I9de96341ba0eee9da69bb48dc6d276374773633f
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6c5b380..7b29362 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -75,6 +75,7 @@
#define SAT_MSG_VER 0x1
#define SAT_MSG_PROT 0x1
#define MSM_SAT_SUCCSS 0x20
+#define MSM_MAX_NSATS 2
#define QC_MFGID_LSB 0x2
#define QC_MFGID_MSB 0x17
@@ -225,7 +226,7 @@
int err;
int ee;
struct completion *wr_comp;
- struct msm_slim_sat *satd;
+ struct msm_slim_sat *satd[MSM_MAX_NSATS];
struct msm_slim_endp pipes[7];
struct msm_slim_sps_bam bam;
struct msm_slim_endp rx_msgq;
@@ -240,6 +241,7 @@
bool reconf_busy;
bool chan_active;
enum msm_ctrl_state state;
+ int nsats;
};
struct msm_slim_sat {
@@ -258,6 +260,8 @@
spinlock_t lock;
};
+static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev);
+
static int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len)
{
spin_lock(&dev->rx_lock);
@@ -364,6 +368,18 @@
#endif
}
+static struct msm_slim_sat *addr_to_sat(struct msm_slim_ctrl *dev, u8 laddr)
+{
+ struct msm_slim_sat *sat = NULL;
+ int i = 0;
+ while (!sat && i < dev->nsats) {
+ if (laddr == dev->satd[i]->satcl.laddr)
+ sat = dev->satd[i];
+ i++;
+ }
+ return sat;
+}
+
static irqreturn_t msm_slim_interrupt(int irq, void *d)
{
struct msm_slim_ctrl *dev = d;
@@ -403,8 +419,13 @@
dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
- struct msm_slim_sat *sat = dev->satd;
- msm_sat_enqueue(sat, rx_buf, len);
+ u8 laddr = (u8)((rx_buf[0] >> 16) & 0xFF);
+ struct msm_slim_sat *sat = addr_to_sat(dev, laddr);
+ if (sat)
+ msm_sat_enqueue(sat, rx_buf, len);
+ else
+ dev_err(dev->dev, "unknown sat:%d message",
+ laddr);
writel_relaxed(MGR_INT_RX_MSG_RCVD,
dev->base + MGR_INT_CLR);
/*
@@ -412,37 +433,21 @@
* queuing work
*/
mb();
- queue_work(sat->wq, &sat->wd);
+ if (sat)
+ queue_work(sat->wq, &sat->wd);
} else if (mt == SLIM_MSG_MT_CORE &&
mc == SLIM_MSG_MC_REPORT_PRESENT) {
u8 e_addr[6];
msm_get_eaddr(e_addr, rx_buf);
- if (msm_is_sat_dev(e_addr)) {
- /*
- * Consider possibility that this device may
- * be reporting more than once?
- */
- struct msm_slim_sat *sat = dev->satd;
- msm_sat_enqueue(sat, rx_buf, len);
- writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
- MGR_INT_CLR);
- /*
- * Guarantee that CLR bit write goes through
- * before queuing work
- */
- mb();
- queue_work(sat->wq, &sat->wd);
- } else {
- msm_slim_rx_enqueue(dev, rx_buf, len);
- writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
- MGR_INT_CLR);
- /*
- * Guarantee that CLR bit write goes through
- * before signalling completion
- */
- mb();
- complete(&dev->rx_msgq_notify);
- }
+ msm_slim_rx_enqueue(dev, rx_buf, len);
+ writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
+ MGR_INT_CLR);
+ /*
+ * Guarantee that CLR bit write goes through
+ * before signalling completion
+ */
+ mb();
+ complete(&dev->rx_msgq_notify);
} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
mc == SLIM_MSG_MC_REPLY_VALUE) {
msm_slim_rx_enqueue(dev, rx_buf, len);
@@ -1029,6 +1034,18 @@
laddr == (QC_MSM_DEVS - 1))
pm_runtime_enable(dev->dev);
+ if (!ret && msm_is_sat_dev(e_addr)) {
+ struct msm_slim_sat *sat = addr_to_sat(dev,
+ laddr);
+ if (!sat)
+ sat = msm_slim_alloc_sat(dev);
+ if (!sat)
+ return;
+
+ sat->satcl.laddr = laddr;
+ msm_sat_enqueue(sat, (u32 *)buf, len);
+ queue_work(sat->wq, &sat->wd);
+ }
} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
mc == SLIM_MSG_MC_REPLY_VALUE) {
u8 tid = buf[3];
@@ -1112,8 +1129,12 @@
continue;
}
/* send a Manager capability msg */
- if (sat->sent_capability)
- continue;
+ if (sat->sent_capability) {
+ if (mt == SLIM_MSG_MT_CORE)
+ goto send_capability;
+ else
+ continue;
+ }
ret = slim_add_device(&dev->ctrl, &sat->satcl);
if (ret) {
dev_err(dev->dev,
@@ -1126,6 +1147,7 @@
/* alloc all sat chans */
for (i = 0; i < 21; i++)
slim_alloc_ch(&sat->satcl, &sat->satch[i]);
+send_capability:
txn.mc = SLIM_USR_MC_MASTER_CAPABILITY;
txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
txn.la = sat->satcl.laddr;
@@ -1243,6 +1265,44 @@
}
}
+static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev)
+{
+ struct msm_slim_sat *sat;
+ char *name;
+ if (dev->nsats >= MSM_MAX_NSATS)
+ return NULL;
+
+ sat = kzalloc(sizeof(struct msm_slim_sat), GFP_KERNEL);
+ if (!sat) {
+ dev_err(dev->dev, "no memory for satellite");
+ return NULL;
+ }
+ name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
+ if (!name) {
+ dev_err(dev->dev, "no memory for satellite name");
+ kfree(sat);
+ return NULL;
+ }
+ dev->satd[dev->nsats] = sat;
+ sat->dev = dev;
+ snprintf(name, SLIMBUS_NAME_SIZE, "msm_sat%d", dev->nsats);
+ sat->satcl.name = name;
+ spin_lock_init(&sat->lock);
+ INIT_WORK(&sat->wd, slim_sat_rxprocess);
+ sat->wq = create_singlethread_workqueue(sat->satcl.name);
+ if (!sat->wq) {
+ kfree(name);
+ kfree(sat);
+ return NULL;
+ }
+ /*
+ * Both sats will be allocated from RX thread and RX thread will
+ * process messages sequentially. No synchronization necessary
+ */
+ dev->nsats++;
+ return sat;
+}
+
static void
msm_slim_rx_msgq_event(struct msm_slim_ctrl *dev, struct sps_event_notify *ev)
{
@@ -1375,18 +1435,13 @@
mc = (buffer[0] >> 8) & 0xff;
dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
- mt == SLIM_MSG_MT_SRC_REFERRED_USER)
- sat = dev->satd;
-
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+ u8 laddr;
+ laddr = (u8)((buffer[0] >> 16) & 0xff);
+ sat = addr_to_sat(dev, laddr);
+ }
} else if ((index * 4) >= msg_len) {
index = 0;
- if (mt == SLIM_MSG_MT_CORE &&
- mc == SLIM_MSG_MC_REPORT_PRESENT) {
- u8 e_addr[6];
- msm_get_eaddr(e_addr, buffer);
- if (msm_is_sat_dev(e_addr))
- sat = dev->satd;
- }
if (sat) {
msm_sat_enqueue(sat, buffer, msg_len);
queue_work(sat->wq, &sat->wd);
@@ -1756,21 +1811,10 @@
goto err_request_irq_failed;
}
- dev->satd = kzalloc(sizeof(struct msm_slim_sat), GFP_KERNEL);
- if (!dev->satd) {
- ret = -ENOMEM;
- goto err_sat_failed;
- }
-
msm_slim_prg_slew(pdev, dev);
clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
clk_enable(dev->rclk);
- dev->satd->dev = dev;
- dev->satd->satcl.name = "msm_sat_dev";
- spin_lock_init(&dev->satd->lock);
- INIT_WORK(&dev->satd->wd, slim_sat_rxprocess);
- dev->satd->wq = create_singlethread_workqueue("msm_slim_sat");
/* Component register initialization */
writel_relaxed(1, dev->base + COMP_CFG);
writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
@@ -1856,8 +1900,6 @@
err_ctrl_failed:
writel_relaxed(0, dev->base + COMP_CFG);
kfree(dev->satd);
-err_sat_failed:
- free_irq(dev->irq, dev);
err_request_irq_failed:
clk_disable(dev->rclk);
clk_put(dev->rclk);
@@ -1882,13 +1924,17 @@
struct resource *bam_mem;
struct resource *slim_mem;
struct resource *slew_mem = dev->slew_mem;
- struct msm_slim_sat *sat = dev->satd;
- slim_remove_device(&sat->satcl);
+ int i;
+ for (i = 0; i < dev->nsats; i++) {
+ struct msm_slim_sat *sat = dev->satd[i];
+ slim_remove_device(&sat->satcl);
+ kfree(sat->satch);
+ destroy_workqueue(sat->wq);
+ kfree(sat->satcl.name);
+ kfree(sat);
+ }
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- kfree(sat->satch);
- destroy_workqueue(sat->wq);
- kfree(sat);
free_irq(dev->irq, dev);
slim_del_controller(&dev->ctrl);
clk_put(dev->rclk);