From 305f424fda08490e7d63cf59f6b30d3f3fa3fe59 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Tue, 4 Feb 2020 16:29:33 +0800 Subject: [PATCH] mailbox: rockchip: code optimization This change amend the below features. - Checked the mailbox channel status before send message. - Used the con_priv variable to handle the channel private data. - Added the spinlock cfg_lock to protect the register R/W. - Optimized the interrupt handler can receive B2A message proactively. Change-Id: If1939e51e821307788ab59dd4ef874a20a6568e2 Signed-off-by: Frank Wang --- drivers/mailbox/rockchip-mailbox.c | 119 ++++++++++++----------------- 1 file changed, 47 insertions(+), 72 deletions(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index d702a204f5c1..9bb5e560c583 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include @@ -19,6 +11,7 @@ #include #include #include +#include #define MAILBOX_A2B_INTEN 0x00 #define MAILBOX_A2B_STATUS 0x04 @@ -32,7 +25,7 @@ struct rockchip_mbox_msg { u32 cmd; - int rx_size; + u32 data; }; struct rockchip_mbox_data { @@ -42,17 +35,13 @@ struct rockchip_mbox_data { struct rockchip_mbox_chan { int idx; int irq; - struct rockchip_mbox_msg *msg; - struct rockchip_mbox *mb; }; struct rockchip_mbox { struct mbox_controller mbox; struct clk *pclk; void __iomem *mbox_base; - - /* The maximum size of buf for each channel */ - u32 buf_size; + spinlock_t cfg_lock; /* Serialise access to the register */ struct rockchip_mbox_chan *chans; }; @@ -61,24 +50,23 @@ static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); struct rockchip_mbox_msg *msg = data; - struct rockchip_mbox_chan *chans = mb->chans; + struct rockchip_mbox_chan *chans = chan->con_priv; + u32 status; if (!msg) return -EINVAL; - if (msg->rx_size > mb->buf_size) { - dev_err(mb->mbox.dev, "Transmit size over buf size(%d)\n", - mb->buf_size); - return -EINVAL; + status = readl_relaxed(mb->mbox_base + MAILBOX_A2B_STATUS); + if (status & (1U << chans->idx)) { + dev_err(mb->mbox.dev, "The mailbox channel is busy\n"); + return -EBUSY; } - dev_dbg(mb->mbox.dev, "Chan[%d]: A2B message, cmd 0x%08x\n", - chans->idx, msg->cmd); - - mb->chans[chans->idx].msg = msg; + dev_dbg(mb->mbox.dev, "Chan[%d]: A2B message, cmd 0x%08x, data 0x%08x\n", + chans->idx, msg->cmd, msg->data); writel_relaxed(msg->cmd, mb->mbox_base + MAILBOX_A2B_CMD(chans->idx)); - writel_relaxed(msg->rx_size, mb->mbox_base + + writel_relaxed(msg->data, mb->mbox_base + MAILBOX_A2B_DAT(chans->idx)); return 0; @@ -87,10 +75,15 @@ static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data) static int rockchip_mbox_startup(struct mbox_chan *chan) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); + struct rockchip_mbox_chan *chans = chan->con_priv; + u32 val = 0U; - /* Enable all B2A interrupts */ - writel_relaxed((1 << mb->mbox.num_chans) - 1, - mb->mbox_base + MAILBOX_B2A_INTEN); + /* Enable the corresponding B2A interrupt */ + spin_lock(&mb->cfg_lock); + val = readl_relaxed(mb->mbox_base + MAILBOX_B2A_INTEN) | + (1U << chans->idx); + writel_relaxed(val, mb->mbox_base + MAILBOX_B2A_INTEN); + spin_unlock(&mb->cfg_lock); return 0; } @@ -98,12 +91,15 @@ static int rockchip_mbox_startup(struct mbox_chan *chan) static void rockchip_mbox_shutdown(struct mbox_chan *chan) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); - struct rockchip_mbox_chan *chans = mb->chans; + struct rockchip_mbox_chan *chans = chan->con_priv; + u32 val = 0U; - /* Disable all B2A interrupts */ - writel_relaxed(0, mb->mbox_base + MAILBOX_B2A_INTEN); - - mb->chans[chans->idx].msg = NULL; + /* Disable the corresponding B2A interrupt */ + spin_lock(&mb->cfg_lock); + val = readl_relaxed(mb->mbox_base + MAILBOX_B2A_INTEN) & + ~(1U << chans->idx); + writel_relaxed(val, mb->mbox_base + MAILBOX_B2A_INTEN); + spin_unlock(&mb->cfg_lock); } static const struct mbox_chan_ops rockchip_mbox_chan_ops = { @@ -115,47 +111,29 @@ static const struct mbox_chan_ops rockchip_mbox_chan_ops = { static irqreturn_t rockchip_mbox_irq(int irq, void *dev_id) { int idx; + struct rockchip_mbox_msg msg; struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id; u32 status = readl_relaxed(mb->mbox_base + MAILBOX_B2A_STATUS); for (idx = 0; idx < mb->mbox.num_chans; idx++) { - if ((status & (1 << idx)) && (irq == mb->chans[idx].irq)) { + if ((status & (1U << idx)) && irq == mb->chans[idx].irq) { + /* Get cmd/data from the channel of B2A */ + msg.cmd = readl_relaxed(mb->mbox_base + + MAILBOX_B2A_CMD(idx)); + msg.data = readl_relaxed(mb->mbox_base + + MAILBOX_B2A_DAT(idx)); + + mbox_chan_received_data(&mb->mbox.chans[idx], &msg); + + dev_dbg(mb->mbox.dev, "Chan[%d]: B2A message, cmd 0x%08x, data 0x%08x\n", + idx, msg.cmd, msg.data); + /* Clear mbox interrupt */ - writel_relaxed(1 << idx, + writel_relaxed(1U << idx, mb->mbox_base + MAILBOX_B2A_STATUS); - return IRQ_WAKE_THREAD; } } - return IRQ_NONE; -} - -static irqreturn_t rockchip_mbox_isr(int irq, void *dev_id) -{ - int idx; - struct rockchip_mbox_msg *msg = NULL; - struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id; - - for (idx = 0; idx < mb->mbox.num_chans; idx++) { - if (irq != mb->chans[idx].irq) - continue; - - msg = mb->chans[idx].msg; - if (!msg) { - dev_err(mb->mbox.dev, - "Chan[%d]: B2A message is NULL\n", idx); - break; /* spurious */ - } - - mbox_chan_received_data(&mb->mbox.chans[idx], msg); - mb->chans[idx].msg = NULL; - - dev_dbg(mb->mbox.dev, "Chan[%d]: B2A message, cmd 0x%08x\n", - idx, msg->cmd); - - break; - } - return IRQ_HANDLED; } @@ -203,6 +181,7 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->mbox.num_chans = drv_data->num_chans; mb->mbox.ops = &rockchip_mbox_chan_ops; mb->mbox.txdone_irq = true; + spin_lock_init(&mb->cfg_lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -212,9 +191,6 @@ static int rockchip_mbox_probe(struct platform_device *pdev) if (IS_ERR(mb->mbox_base)) return PTR_ERR(mb->mbox_base); - /* Each channel has two buffers for A2B and B2A */ - mb->buf_size = (size_t)resource_size(res) / (drv_data->num_chans * 2); - mb->pclk = devm_clk_get(&pdev->dev, "pclk_mailbox"); if (IS_ERR(mb->pclk)) { ret = PTR_ERR(mb->pclk); @@ -235,16 +211,15 @@ static int rockchip_mbox_probe(struct platform_device *pdev) return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, - rockchip_mbox_irq, - rockchip_mbox_isr, IRQF_ONESHOT, + NULL, + rockchip_mbox_irq, IRQF_ONESHOT, dev_name(&pdev->dev), mb); if (ret < 0) return ret; mb->chans[i].idx = i; mb->chans[i].irq = irq; - mb->chans[i].mb = mb; - mb->chans[i].msg = NULL; + mb->mbox.chans[i].con_priv = &mb->chans[i]; } ret = mbox_controller_register(&mb->mbox);