Re: [PATCH V2 4/6] slim: qcom: Add Qualcomm Slimbus controller driver

From: Sagar Dharia
Date: Sun Jun 28 2015 - 15:13:57 EST


On 6/17/2015 7:53 AM, Mark Brown wrote:
On Tue, Jun 16, 2015 at 07:46:02PM -0600, Sagar Dharia wrote:

+ - dmaengine, and pipes used to communicate between controller and memory if
+ sps-BAM HW is used
This needs more detail.
+ */
+ mb();
+ if (notify_rx)
+ complete(&dev->rx_msgq_notify);
+ }
+ return IRQ_HANDLED;
This interrupt handler unconditionally returns IRQ_HANDLED regardless of
if that's true or not.

Some interrupt handling is done in ISR itself. RX-msgq thread notifier/workQ is only used for items that can sleep/operations that can take longer. (e.g. assignment of logical address based on report_present message)
That's the reason IRQ_HANDLED is always true here.

+static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
+{
+ int msec_per_frm = 0;
+ int sfr_per_sec;
+
+ /* Wait for 1 superframe, or default time and then retry */
+ sfr_per_sec = dev->framer.superfreq /
+ (1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
+ if (sfr_per_sec)
+ msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
+ if (msec_per_frm < DEF_RETRY_MS)
+ msec_per_frm = DEF_RETRY_MS;
+ msleep(msec_per_frm);
+}
Is this device specific?

This is seen on most of the Qualcomm-controllers I've worked with, where retries in early initialization were needed to avoid issues due to noise.

+static void msm_slim_cb(void *ctx, int err)
+{
+ if (err)
+ pr_err("MSM-slim completion reported err:%d\n", err);
dev_err()?

+ else if (ctx)
+ complete(ctx);
+}
That's weird, if we get an error we don't signal whatever's waiting -
won't it just time out at best then? Also, what happens if we get
neither an error nor context?

+ if (txn->msg->wbuf)
+ memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes);
+ msm_slim_queue_tx(dev, pbuf, txn->rl, MGR_TX_MSG);
+ timeout = wait_for_completion_timeout(&done,
+ msecs_to_jiffies(txn->rl + 100));
+
+ if (!timeout)
+ dev_err(dev->dev, "TX timed out:MC:0x%x,mt:0x%x\n", txn->mc,
+ txn->mt);
+
+ mutex_unlock(&dev->txn_lock);
+ return timeout ? 0 : -ETIMEDOUT;
+}
Shouldn't we provide a route for error reports here (and might some of
this timeout stuff go into the core)?

Sure, good point. If I move it to core, all controllers will be expected to have 'write-done' notification. If that's a fair assumption, I will move it to core.
That will also mean the above callback/completion will move to framework.

+
+ if ((msm_slim_put_rx(dev, (u8 *)buf)) != -ENODATA) {
+ len = buf[0] & 0x1F;
+ mt = (buf[0] >> 5) & 0x7;
+ mc = buf[1];
+ if (mt == SLIM_MSG_MT_CORE &&
+ mc == SLIM_MSG_MC_REPORT_PRESENT) {
Looks like a switch statement.

+static int msm_slim_rx_msgq_thread(void *data)
+{
+ struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
+ struct completion *notify = &dev->rx_msgq_notify;
+ int ret;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ ret = wait_for_completion_interruptible(notify);
+
+ if (ret)
+ dev_err(dev->dev, "rx thread wait error:%d\n", ret);
+ else
+ msm_slim_rxwq(dev);
+ }
+
+ return 0;
+}
It's not entirely clear to me why this is a kthread rather than a
workqueue or something. I'm also unclear what happens if more than one
piece of work is queued prior to msm_slim_rxwq() running, it looks like
it only handles a single operation.

Sure, I will change this to workqueue. That should not be a problem.

+ /* SLEW RATE register for this slimbus */
+ dev->slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "slimbus_slew_reg");
+ if (!dev->slew_mem) {
+ dev_err(&pdev->dev, "no slimbus slew resource\n");
+ return;
+ }
Warning not an error isn't it?

+ hclk = clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(hclk))
+ return PTR_ERR(hclk);
devm_clk_get()

+ ret = clk_set_rate(rclk, SLIM_ROOT_FREQ);
You're ignoring this error in spite of assigning to ret.

+ slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "slimbus_physical");
+ if (!slim_mem) {
+ dev_err(&pdev->dev, "no slimbus physical memory resource\n");
+ ret = ENODEV;
+ goto err_get_mem_failed;
+ }
+ slim_io = request_mem_region(slim_mem->start, resource_size(slim_mem),
+ pdev->name);
+ if (!slim_io) {
+ dev_err(&pdev->dev, "slimbus memory already claimed\n");
+ ret = EBUSY;
+ goto err_get_mem_failed;
+ }
devm_ioremap_resource() and a lot of this starts looking simpler.

+ dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
devm_kzalloc()

+ if (pdev->dev.of_node) {
+
+ ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
+ &dev->ctrl.nr);
Was that in the binding?

+ /* Register with framework before enabling frame, clock */
+ ret = slim_add_numbered_controller(&dev->ctrl);
+ if (ret) {
+ dev_err(dev->dev, "error adding controller\n");
+ goto err_ctrl_failed;
+ }
This is suspicious - why are you adding a numbered controller with DT?
And looking at this interface why is it a separate call to add a
numbered controller, why not just register the controller using the same
API and handle any number that was set when doing that?

Agreed, I will change add_numbered_controller to register_controller. That will also mean the 'cell-index' property above is not needed.

+ dev->ver = readl_relaxed(dev->base);
+ /* Version info in 16 MSbits */
+ dev->ver >>= 16;
+ /* Component register initialization */
+ writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
+ writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
+ dev->base + CFG_PORT(COMP_TRUST_CFG, dev->ver));
You've registered the device with the core prior to initialising the
hardware - I'd expect this means the generic code will start trying to
register slaves immediately. The normal pattern would be to initialise
the hardware then register it.

This is for handling the logical-address assignment. That's only possible after registering controller.
The internal controller has 2 in-built slimbus devices (interface, framer) which will start to report-present right-away if I initialize the HW. Now if register_controller is not done, the logical-address assignment will not happen and as per spec, the devices will keep sending report_present until they get an assignment.

Registering slaves immediately is not an issue since that part will not be waiting on logical-address assignment (due to device_up callback)

+#ifdef CONFIG_PM_SLEEP
+static int msm_slim_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int msm_slim_resume(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
Omit empty functions.

+static int msm_slim_init(void)
+{
+ return platform_driver_register(&msm_slim_driver);
+}
+module_init(msm_slim_init);
module_platform_driver().

+u8 *msm_slim_get_tx(struct msm_slim_ctrl *dev, struct msm_wr_cb *cur)
+{
+ unsigned long flags;
+ int idx;
+
+ spin_lock_irqsave(&dev->tx.lock, flags);
+ if (((dev->tx.head + 1) % MSM_TX_MSGS) == dev->tx.tail) {
+ spin_unlock_irqrestore(&dev->tx.lock, flags);
+ return NULL;
+ }
+ idx = dev->tx.tail;
+ dev->tx.tail = (dev->tx.tail + 1) % MSM_TX_MSGS;
+ spin_unlock_irqrestore(&dev->tx.lock, flags);
+ dev->pending_wr[idx] = cur;
+ return dev->tx.base + (idx * SLIM_MSGQ_BUF_LEN);
+}
Would just using a regular list hurt?

This provides O(1) circular buffer access rather than a list with O(n).
I will address other comments and upload patch later today/tomorrow.

Thanks for your comments
Sagar


--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/