diff options
Diffstat (limited to 'drivers/mailbox')
-rw-r--r-- | drivers/mailbox/Kconfig | 4 | ||||
-rw-r--r-- | drivers/mailbox/arm_mhu.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/arm_mhu_db.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/arm_mhuv2.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/exynos-mailbox.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/imx-mailbox.c | 21 | ||||
-rw-r--r-- | drivers/mailbox/mailbox-altera.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/mailbox.c | 29 | ||||
-rw-r--r-- | drivers/mailbox/mailbox.h | 2 | ||||
-rw-r--r-- | drivers/mailbox/mtk-cmdq-mailbox.c | 51 | ||||
-rw-r--r-- | drivers/mailbox/pcc.c | 113 | ||||
-rw-r--r-- | drivers/mailbox/pl320-ipc.c | 14 |
12 files changed, 115 insertions, 129 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index ed52db272f4d..e8445cda7c61 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -191,8 +191,8 @@ config POLARFIRE_SOC_MAILBOX config MCHP_SBI_IPC_MBOX tristate "Microchip Inter-processor Communication (IPC) SBI driver" - depends on RISCV_SBI || COMPILE_TEST - depends on ARCH_MICROCHIP + depends on RISCV_SBI + depends on ARCH_MICROCHIP || COMPILE_TEST help Mailbox implementation for Microchip devices with an Inter-process communication (IPC) controller. diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index 537f7bfb7b06..0950b7bce184 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -153,7 +153,7 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) return 0; } -static struct amba_id mhu_ids[] = { +static const struct amba_id mhu_ids[] = { { .id = 0x1bb098, .mask = 0xffffff, diff --git a/drivers/mailbox/arm_mhu_db.c b/drivers/mailbox/arm_mhu_db.c index 27a510d46908..9e937b09c5fb 100644 --- a/drivers/mailbox/arm_mhu_db.c +++ b/drivers/mailbox/arm_mhu_db.c @@ -328,7 +328,7 @@ static int mhu_db_probe(struct amba_device *adev, const struct amba_id *id) return 0; } -static struct amba_id mhu_ids[] = { +static const struct amba_id mhu_ids[] = { { .id = 0x1bb098, .mask = 0xffffff, diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c index cff7c343ee08..f035284944c0 100644 --- a/drivers/mailbox/arm_mhuv2.c +++ b/drivers/mailbox/arm_mhuv2.c @@ -1107,7 +1107,7 @@ static void mhuv2_remove(struct amba_device *adev) writel_relaxed(0x0, &mhu->send->access_request); } -static struct amba_id mhuv2_ids[] = { +static const struct amba_id mhuv2_ids[] = { { /* 2.0 */ .id = 0xbb0d1, diff --git a/drivers/mailbox/exynos-mailbox.c b/drivers/mailbox/exynos-mailbox.c index 20049f0ec5ff..2320649bf60c 100644 --- a/drivers/mailbox/exynos-mailbox.c +++ b/drivers/mailbox/exynos-mailbox.c @@ -57,7 +57,7 @@ static int exynos_mbox_send_data(struct mbox_chan *chan, void *data) if (msg->chan_type != EXYNOS_MBOX_CHAN_TYPE_DOORBELL) { dev_err(dev, "Unsupported channel type [%d]\n", msg->chan_type); return -EINVAL; - }; + } writel(BIT(msg->chan_id), exynos_mbox->regs + EXYNOS_MBOX_INTGR1); diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 6ef8338add0d..6778afc64a04 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -226,7 +226,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv, { u32 *arg = data; u32 val; - int ret; + int ret, count; switch (cp->type) { case IMX_MU_TYPE_TX: @@ -240,11 +240,20 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv, case IMX_MU_TYPE_TXDB_V2: imx_mu_write(priv, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), priv->dcfg->xCR[IMX_MU_GCR]); - ret = readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val, - !(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)), - 0, 1000); - if (ret) - dev_warn_ratelimited(priv->dev, "channel type: %d failure\n", cp->type); + ret = -ETIMEDOUT; + count = 0; + while (ret && (count < 10)) { + ret = + readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val, + !(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)), + 0, 10000); + + if (ret) { + dev_warn_ratelimited(priv->dev, + "channel type: %d timeout, %d times, retry\n", + cp->type, ++count); + } + } break; default: dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type); diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c index afb320e9d69c..748128661892 100644 --- a/drivers/mailbox/mailbox-altera.c +++ b/drivers/mailbox/mailbox-altera.c @@ -270,7 +270,7 @@ static void altera_mbox_shutdown(struct mbox_chan *chan) writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG); free_irq(mbox->irq, chan); } else if (!mbox->is_sender) { - del_timer_sync(&mbox->rxpoll_timer); + timer_delete_sync(&mbox->rxpoll_timer); } } diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index d3d26a2c9895..aea0e690b63e 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -6,18 +6,15 @@ * Author: Jassi Brar <jassisinghbrar@gmail.com> */ -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> #include <linux/delay.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/module.h> #include <linux/device.h> -#include <linux/bitops.h> +#include <linux/err.h> #include <linux/mailbox_client.h> #include <linux/mailbox_controller.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/of.h> +#include <linux/spinlock.h> #include "mailbox.h" @@ -413,15 +410,15 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) return ERR_PTR(-ENODEV); } - mutex_lock(&con_mutex); - - if (of_parse_phandle_with_args(dev->of_node, "mboxes", - "#mbox-cells", index, &spec)) { + ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", + index, &spec); + if (ret) { dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__); - mutex_unlock(&con_mutex); - return ERR_PTR(-ENODEV); + return ERR_PTR(ret); } + mutex_lock(&con_mutex); + chan = ERR_PTR(-EPROBE_DEFER); list_for_each_entry(mbox, &mbox_cons, node) if (mbox->dev->of_node == spec.np) { @@ -489,8 +486,8 @@ void mbox_free_channel(struct mbox_chan *chan) if (chan->txdone_method == TXDONE_BY_ACK) chan->txdone_method = TXDONE_BY_POLL; - module_put(chan->mbox->dev->driver->owner); spin_unlock_irqrestore(&chan->lock, flags); + module_put(chan->mbox->dev->driver->owner); } EXPORT_SYMBOL_GPL(mbox_free_channel); @@ -534,9 +531,7 @@ int mbox_controller_register(struct mbox_controller *mbox) return -EINVAL; } - hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - mbox->poll_hrt.function = txdone_hrtimer; + hrtimer_setup(&mbox->poll_hrt, txdone_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); spin_lock_init(&mbox->poll_hrt_lock); } diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h index 046d6d258b32..e1ec4efab693 100644 --- a/drivers/mailbox/mailbox.h +++ b/drivers/mailbox/mailbox.h @@ -3,6 +3,8 @@ #ifndef __MAILBOX_H #define __MAILBOX_H +#include <linux/bits.h> + #define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ #define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ #define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index d186865b8dce..ab4e8d1954a1 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -92,18 +92,6 @@ struct gce_plat { u32 gce_num; }; -static void cmdq_sw_ddr_enable(struct cmdq *cmdq, bool enable) -{ - WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks)); - - if (enable) - writel(GCE_DDR_EN | GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE); - else - writel(GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE); - - clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks); -} - u8 cmdq_get_shift_pa(struct mbox_chan *chan) { struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox); @@ -112,6 +100,19 @@ u8 cmdq_get_shift_pa(struct mbox_chan *chan) } EXPORT_SYMBOL(cmdq_get_shift_pa); +static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable) +{ + u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0; + + if (!cmdq->pdata->control_by_sw && !cmdq->pdata->sw_ddr_en) + return; + + if (cmdq->pdata->sw_ddr_en && ddr_enable) + val |= GCE_DDR_EN; + + writel(val, cmdq->base + GCE_GCTL_VALUE); +} + static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread) { u32 status; @@ -140,16 +141,10 @@ static void cmdq_thread_resume(struct cmdq_thread *thread) static void cmdq_init(struct cmdq *cmdq) { int i; - u32 gctl_regval = 0; WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks)); - if (cmdq->pdata->control_by_sw) - gctl_regval = GCE_CTRL_BY_SW; - if (cmdq->pdata->sw_ddr_en) - gctl_regval |= GCE_DDR_EN; - if (gctl_regval) - writel(gctl_regval, cmdq->base + GCE_GCTL_VALUE); + cmdq_gctl_value_toggle(cmdq, true); writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES); for (i = 0; i <= CMDQ_MAX_EVENT; i++) @@ -315,14 +310,21 @@ static irqreturn_t cmdq_irq_handler(int irq, void *dev) static int cmdq_runtime_resume(struct device *dev) { struct cmdq *cmdq = dev_get_drvdata(dev); + int ret; - return clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks); + ret = clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks); + if (ret) + return ret; + + cmdq_gctl_value_toggle(cmdq, true); + return 0; } static int cmdq_runtime_suspend(struct device *dev) { struct cmdq *cmdq = dev_get_drvdata(dev); + cmdq_gctl_value_toggle(cmdq, false); clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks); return 0; } @@ -347,9 +349,6 @@ static int cmdq_suspend(struct device *dev) if (task_running) dev_warn(dev, "exist running task(s) in suspend\n"); - if (cmdq->pdata->sw_ddr_en) - cmdq_sw_ddr_enable(cmdq, false); - return pm_runtime_force_suspend(dev); } @@ -360,9 +359,6 @@ static int cmdq_resume(struct device *dev) WARN_ON(pm_runtime_force_resume(dev)); cmdq->suspended = false; - if (cmdq->pdata->sw_ddr_en) - cmdq_sw_ddr_enable(cmdq, true); - return 0; } @@ -370,9 +366,6 @@ static void cmdq_remove(struct platform_device *pdev) { struct cmdq *cmdq = platform_get_drvdata(pdev); - if (cmdq->pdata->sw_ddr_en) - cmdq_sw_ddr_enable(cmdq, false); - if (!IS_ENABLED(CONFIG_PM)) cmdq_runtime_suspend(&pdev->dev); diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 82102a4c5d68..f6714c233f5a 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -117,8 +117,6 @@ struct pcc_chan_info { static struct pcc_chan_info *chan_info; static int pcc_chan_count; -static int pcc_send_data(struct mbox_chan *chan, void *data); - /* * PCC can be used with perf critical drivers such as CPPC * So it makes sense to locally cache the virtual address and @@ -245,13 +243,13 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) u64 val; int ret; + if (!pchan->cmd_complete.gas) + return true; + ret = pcc_chan_reg_read(&pchan->cmd_complete, &val); if (ret) return false; - if (!pchan->cmd_complete.gas) - return true; - /* * Judge if the channel respond the interrupt based on the value of * command complete. @@ -269,33 +267,43 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) return !!val; } -static void check_and_ack(struct pcc_chan_info *pchan, struct mbox_chan *chan) +static int pcc_mbox_error_check_and_clear(struct pcc_chan_info *pchan) +{ + u64 val; + int ret; + + ret = pcc_chan_reg_read(&pchan->error, &val); + if (ret) + return ret; + + val &= pchan->error.status_mask; + if (val) { + val &= ~pchan->error.status_mask; + pcc_chan_reg_write(&pchan->error, val); + return -EIO; + } + + return 0; +} + +static void pcc_chan_acknowledge(struct pcc_chan_info *pchan) { - struct acpi_pcct_ext_pcc_shared_memory pcc_hdr; + struct acpi_pcct_ext_pcc_shared_memory __iomem *pcc_hdr; if (pchan->type != ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) return; - /* If the memory region has not been mapped, we cannot - * determine if we need to send the message, but we still - * need to set the cmd_update flag before returning. - */ - if (pchan->chan.shmem == NULL) { - pcc_chan_reg_read_modify_write(&pchan->cmd_update); - return; - } - memcpy_fromio(&pcc_hdr, pchan->chan.shmem, - sizeof(struct acpi_pcct_ext_pcc_shared_memory)); + + pcc_chan_reg_read_modify_write(&pchan->cmd_update); + + pcc_hdr = pchan->chan.shmem; + /* - * The PCC slave subspace channel needs to set the command complete bit - * after processing message. If the PCC_ACK_FLAG is set, it should also - * ring the doorbell. - * - * The PCC master subspace channel clears chan_in_use to free channel. + * The PCC slave subspace channel needs to set the command + * complete bit after processing message. If the PCC_ACK_FLAG + * is set, it should also ring the doorbell. */ - if (le32_to_cpup(&pcc_hdr.flags) & PCC_ACK_FLAG_MASK) - pcc_send_data(chan, NULL); - else - pcc_chan_reg_read_modify_write(&pchan->cmd_update); + if (ioread32(&pcc_hdr->flags) & PCC_CMD_COMPLETION_NOTIFY) + pcc_chan_reg_read_modify_write(&pchan->db); } /** @@ -309,10 +317,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) { struct pcc_chan_info *pchan; struct mbox_chan *chan = p; - u64 val; - int ret; pchan = chan->con_priv; + + if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) + return IRQ_NONE; + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && !pchan->chan_in_use) return IRQ_NONE; @@ -320,23 +330,19 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) if (!pcc_mbox_cmd_complete_check(pchan)) return IRQ_NONE; - ret = pcc_chan_reg_read(&pchan->error, &val); - if (ret) - return IRQ_NONE; - val &= pchan->error.status_mask; - if (val) { - val &= ~pchan->error.status_mask; - pcc_chan_reg_write(&pchan->error, val); - return IRQ_NONE; - } - - if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) + if (pcc_mbox_error_check_and_clear(pchan)) return IRQ_NONE; + /* + * Clear this flag after updating interrupt ack register and just + * before mbox_chan_received_data() which might call pcc_send_data() + * where the flag is set again to start new transfer. This is + * required to avoid any possible race in updatation of this flag. + */ + pchan->chan_in_use = false; mbox_chan_received_data(chan, NULL); - check_and_ack(pchan, chan); - pchan->chan_in_use = false; + pcc_chan_acknowledge(pchan); return IRQ_HANDLED; } @@ -356,6 +362,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) struct pcc_mbox_chan * pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) { + struct pcc_mbox_chan *pcc_mchan; struct pcc_chan_info *pchan; struct mbox_chan *chan; int rc; @@ -374,7 +381,14 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) if (rc) return ERR_PTR(rc); - return &pchan->chan; + pcc_mchan = &pchan->chan; + pcc_mchan->shmem = acpi_os_ioremap(pcc_mchan->shmem_base_addr, + pcc_mchan->shmem_size); + if (pcc_mchan->shmem) + return pcc_mchan; + + mbox_free_channel(chan); + return ERR_PTR(-ENXIO); } EXPORT_SYMBOL_GPL(pcc_mbox_request_channel); @@ -403,21 +417,6 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) } EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); -int pcc_mbox_ioremap(struct mbox_chan *chan) -{ - struct pcc_chan_info *pchan_info; - struct pcc_mbox_chan *pcc_mbox_chan; - - if (!chan || !chan->cl) - return -1; - pchan_info = chan->con_priv; - pcc_mbox_chan = &pchan_info->chan; - pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr, - pcc_mbox_chan->shmem_size); - return 0; -} -EXPORT_SYMBOL_GPL(pcc_mbox_ioremap); - /** * pcc_send_data - Called from Mailbox Controller code. Used * here only to ring the channel doorbell. The PCC client diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c index fbcf07930390..606f26a2a6fd 100644 --- a/drivers/mailbox/pl320-ipc.c +++ b/drivers/mailbox/pl320-ipc.c @@ -45,18 +45,6 @@ static DEFINE_MUTEX(ipc_m1_lock); static DECLARE_COMPLETION(ipc_completion); static ATOMIC_NOTIFIER_HEAD(ipc_notifier); -static inline void set_destination(int source, int mbox) -{ - writel_relaxed(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox)); - writel_relaxed(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox)); -} - -static inline void clear_destination(int source, int mbox) -{ - writel_relaxed(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox)); - writel_relaxed(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox)); -} - static void __ipc_send(int mbox, u32 *data) { int i; @@ -164,7 +152,7 @@ err: return ret; } -static struct amba_id pl320_ids[] = { +static const struct amba_id pl320_ids[] = { { .id = 0x00041320, .mask = 0x000fffff, |