Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/3] ASoC: sun4i-codec: Distinguish sun4i from sun7i
From: Maxime Ripard @ 2016-09-22  8:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-1-dannym@scratchpost.org>

Hi,

On Thu, Sep 22, 2016 at 09:13:10AM +0200, Danny Milosavljevic wrote:
> ASoC: sun4i-codec: Introduce mechanism to detect sun7i and provide a
> different regmap different compared to sun4i Allwinner A10.
>  
> The controls will be extended in a forthcoming patch - it is necessary
> to distinguish between sun4i and sun7i controls because they have different
> registers.
>  
> Renamed SUN4I_CODEC_AC_SYS_VERI to SUN7I_CODEC_AC_DAC_CAL and renamed
> SUN4I_CODEC_AC_MIC_PHONE_CAL to SUN7I_CODEC_AC_MIC_PHONE_CAL because these
> are actually not present on Allwinner A10.
> 
> Handle quirks by regmap config and codec and select the correct quirks
> automatically.  

Usually, you would set the history of changes from one version to the
other here.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/2b5924b5/attachment.sig>

^ permalink raw reply

* [PATCH v5 3/3] ASoC: sun4i-codec: Add custom regmap configs
From: Maxime Ripard @ 2016-09-22  8:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-4-dannym@scratchpost.org>

On Thu, Sep 22, 2016 at 09:13:13AM +0200, Danny Milosavljevic wrote:
> The A20 has a few extra registers that the A10 doesn't have.
> Therefore, use different regmaps for A10 as compared to A20.
> 
> Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/630d1516/attachment.sig>

^ permalink raw reply

* [PATCH v5 2/3] ASoC: sun4i-codec: Rename some sun7i-only registers
From: Maxime Ripard @ 2016-09-22  8:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-3-dannym@scratchpost.org>

On Thu, Sep 22, 2016 at 09:13:12AM +0200, Danny Milosavljevic wrote:
> Some of the registers defined in the driver are only usable on the
> A20. Rename these registers.
> 
> Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/cc7c9e50/attachment.sig>

^ permalink raw reply

* [PATCH v14 2/4] CMDQ: Mediatek CMDQ driver
From: Jassi Brar @ 2016-09-22  8:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473039885-24009-3-git-send-email-hs.liao@mediatek.com>

On Mon, Sep 5, 2016 at 7:14 AM, HS Liao <hs.liao@mediatek.com> wrote:
> This patch is first version of Mediatek Command Queue(CMDQ) driver. The
> CMDQ is used to help write registers with critical time limitation,
> such as updating display configuration during the vblank. It controls
> Global Command Engine (GCE) hardware to achieve this requirement.
> Currently, CMDQ only supports display related hardwares, but we expect
> it can be extended to other hardwares for future requirements.
>
> Signed-off-by: HS Liao <hs.liao@mediatek.com>
> Signed-off-by: CK Hu <ck.hu@mediatek.com>
> ---
>  drivers/mailbox/Kconfig          |  10 +
>  drivers/mailbox/Makefile         |   2 +
>  drivers/mailbox/mtk-cmdq.c       | 927 +++++++++++++++++++++++++++++++++++++++
>  include/linux/mailbox/mtk-cmdq.h | 180 ++++++++
>  4 files changed, 1119 insertions(+)
>  create mode 100644 drivers/mailbox/mtk-cmdq.c
>  create mode 100644 include/linux/mailbox/mtk-cmdq.h
>
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> index 97c3729..c987382 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -132,4 +132,14 @@ config BCM_PDC_MBOX
>           Mailbox implementation for the Broadcom PDC ring manager,
>           which provides access to various offload engines on Broadcom
>           SoCs. Say Y here if you want to use the Broadcom PDC.
> +
> +config MTK_CMDQ
> +       bool "MediaTek CMDQ Support"
> +       depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
> +       select MTK_INFRACFG
> +       help
> +         Say yes here to add support for the MediaTek Command Queue (CMDQ)
> +         driver. The CMDQ is used to help read/write registers with critical
> +         time limitation, such as updating display configuration during the
> +         vblank.
>  endif
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> index 66c38e3..eb5e04e 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -27,3 +27,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
>  obj-$(CONFIG_HI6220_MBOX)      += hi6220-mailbox.o
>
>  obj-$(CONFIG_BCM_PDC_MBOX)     += bcm-pdc-mailbox.o
> +
> +obj-$(CONFIG_MTK_CMDQ)         += mtk-cmdq.o
> diff --git a/drivers/mailbox/mtk-cmdq.c b/drivers/mailbox/mtk-cmdq.c
> new file mode 100644
> index 0000000..daf5561
> --- /dev/null
> +++ b/drivers/mailbox/mtk-cmdq.c
> @@ -0,0 +1,927 @@
> +/*
> + * Copyright (c) 2015 MediaTek Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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 <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/completion.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/errno.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/mailbox/mtk-cmdq.h>
> +#include <linux/mutex.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/suspend.h>
> +#include <linux/timer.h>
> +
> +#define CMDQ_THR_MAX_COUNT             3 /* main, sub, general(misc) */
> +#define CMDQ_INST_SIZE                 8 /* instruction is 64-bit */
> +#define CMDQ_TIMEOUT_MS                        1000
> +#define CMDQ_IRQ_MASK                  0xffff
> +#define CMDQ_NUM_CMD(t)                        (t->cmd_buf_size / CMDQ_INST_SIZE)
> +
> +#define CMDQ_CURR_IRQ_STATUS           0x10
> +#define CMDQ_THR_SLOT_CYCLES           0x30
> +
> +#define CMDQ_THR_BASE                  0x100
> +#define CMDQ_THR_SIZE                  0x80
> +#define CMDQ_THR_WARM_RESET            0x00
> +#define CMDQ_THR_ENABLE_TASK           0x04
> +#define CMDQ_THR_SUSPEND_TASK          0x08
> +#define CMDQ_THR_CURR_STATUS           0x0c
> +#define CMDQ_THR_IRQ_STATUS            0x10
> +#define CMDQ_THR_IRQ_ENABLE            0x14
> +#define CMDQ_THR_CURR_ADDR             0x20
> +#define CMDQ_THR_END_ADDR              0x24
> +#define CMDQ_THR_WAIT_TOKEN            0x30
> +
> +#define CMDQ_THR_ENABLED               0x1
> +#define CMDQ_THR_DISABLED              0x0
> +#define CMDQ_THR_SUSPEND               0x1
> +#define CMDQ_THR_RESUME                        0x0
> +#define CMDQ_THR_STATUS_SUSPENDED      BIT(1)
> +#define CMDQ_THR_DO_WARM_RESET         BIT(0)
> +#define CMDQ_THR_ACTIVE_SLOT_CYCLES    0x3200
> +#define CMDQ_THR_IRQ_DONE              0x1
> +#define CMDQ_THR_IRQ_ERROR             0x12
> +#define CMDQ_THR_IRQ_EN                        (CMDQ_THR_IRQ_ERROR | CMDQ_THR_IRQ_DONE)
> +#define CMDQ_THR_IS_WAITING            BIT(31)
> +
> +#define CMDQ_OP_CODE_SHIFT             24
> +#define CMDQ_SUBSYS_SHIFT              16
> +
> +#define CMDQ_ARG_A_WRITE_MASK          0xffff
> +#define CMDQ_OP_CODE_MASK              (0xff << CMDQ_OP_CODE_SHIFT)
> +
> +#define CMDQ_WRITE_ENABLE_MASK         BIT(0)
> +#define CMDQ_JUMP_BY_OFFSET            0x10000000
> +#define CMDQ_JUMP_BY_PA                        0x10000001
> +#define CMDQ_JUMP_PASS                 CMDQ_INST_SIZE
> +#define CMDQ_WFE_UPDATE                        BIT(31)
> +#define CMDQ_WFE_WAIT                  BIT(15)
> +#define CMDQ_WFE_WAIT_VALUE            0x1
> +#define CMDQ_EOC_IRQ_EN                        BIT(0)
> +
> +/*
> + * CMDQ_CODE_MASK:
> + *   set write mask
> + *   format: op mask
> + * CMDQ_CODE_WRITE:
> + *   write value into target register
> + *   format: op subsys address value
> + * CMDQ_CODE_JUMP:
> + *   jump by offset
> + *   format: op offset
> + * CMDQ_CODE_WFE:
> + *   wait for event and clear
> + *   it is just clear if no wait
> + *   format: [wait]  op event update:1 to_wait:1 wait:1
> + *           [clear] op event update:1 to_wait:0 wait:0
> + * CMDQ_CODE_EOC:
> + *   end of command
> + *   format: op irq_flag
> + */
> +enum cmdq_code {
> +       CMDQ_CODE_MASK = 0x02,
> +       CMDQ_CODE_WRITE = 0x04,
> +       CMDQ_CODE_JUMP = 0x10,
> +       CMDQ_CODE_WFE = 0x20,
> +       CMDQ_CODE_EOC = 0x40,
> +};
> +
> +struct cmdq_task_cb {
> +       cmdq_async_flush_cb     cb;
> +       void                    *data;
> +};
> +
> +struct cmdq_thread {
> +       struct mbox_chan        *chan;
> +       void __iomem            *base;
> +       struct list_head        task_busy_list;
> +       struct timer_list       timeout;
> +       bool                    atomic_exec;
> +};
> +
> +struct cmdq_task {
> +       struct cmdq             *cmdq;
> +       struct list_head        list_entry;
> +       void                    *va_base;
> +       dma_addr_t              pa_base;
> +       size_t                  cmd_buf_size; /* command occupied size */
> +       size_t                  buf_size; /* real buffer size */
> +       bool                    finalized;
> +       struct cmdq_thread      *thread;
> +       struct cmdq_task_cb     cb;
> +};
> +
> +struct cmdq {
> +       struct mbox_controller  mbox;
> +       void __iomem            *base;
> +       u32                     irq;
> +       struct cmdq_thread      thread[CMDQ_THR_MAX_COUNT];
> +       struct mutex            task_mutex;
> +       struct clk              *clock;
> +       bool                    suspended;
> +};
> +
> +struct cmdq_subsys {
> +       u32     base;
> +       int     id;
> +};
> +
> +static const struct cmdq_subsys gce_subsys[] = {
> +       {0x1400, 1},
> +       {0x1401, 2},
> +       {0x1402, 3},
> +};
> +
> +static int cmdq_subsys_base_to_id(u32 base)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(gce_subsys); i++)
> +               if (gce_subsys[i].base == base)
> +                       return gce_subsys[i].id;
> +       return -EFAULT;
> +}
> +
> +static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
> +{
> +       u32 status;
> +
> +       writel(CMDQ_THR_SUSPEND, thread->base + CMDQ_THR_SUSPEND_TASK);
> +
> +       /* If already disabled, treat as suspended successful. */
> +       if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
> +               return 0;
> +
> +       if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_STATUS,
> +                       status, status & CMDQ_THR_STATUS_SUSPENDED, 0, 10)) {
> +               dev_err(cmdq->mbox.dev, "suspend GCE thread 0x%x failed\n",
> +                       (u32)(thread->base - cmdq->base));
> +               return -EFAULT;
> +       }
> +
> +       return 0;
> +}
> +
> +static void cmdq_thread_resume(struct cmdq_thread *thread)
> +{
> +       writel(CMDQ_THR_RESUME, thread->base + CMDQ_THR_SUSPEND_TASK);
> +}
> +
> +static int cmdq_thread_reset(struct cmdq *cmdq, struct cmdq_thread *thread)
> +{
> +       u32 warm_reset;
> +
> +       writel(CMDQ_THR_DO_WARM_RESET, thread->base + CMDQ_THR_WARM_RESET);
> +       if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_WARM_RESET,
> +                       warm_reset, !(warm_reset & CMDQ_THR_DO_WARM_RESET),
> +                       0, 10)) {
> +               dev_err(cmdq->mbox.dev, "reset GCE thread 0x%x failed\n",
> +                       (u32)(thread->base - cmdq->base));
> +               return -EFAULT;
> +       }
> +       writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
> +       return 0;
> +}
> +
> +static void cmdq_thread_disable(struct cmdq *cmdq, struct cmdq_thread *thread)
> +{
> +       cmdq_thread_reset(cmdq, thread);
> +       writel(CMDQ_THR_DISABLED, thread->base + CMDQ_THR_ENABLE_TASK);
> +}
> +
> +/* notify GCE to re-fetch commands by setting GCE thread PC */
> +static void cmdq_thread_invalidate_fetched_data(struct cmdq_thread *thread)
> +{
> +       writel(readl(thread->base + CMDQ_THR_CURR_ADDR),
> +              thread->base + CMDQ_THR_CURR_ADDR);
> +}
> +
> +static void cmdq_task_insert_into_thread(struct cmdq_task *task)
> +{
> +       struct device *dev = task->cmdq->mbox.dev;
> +       struct cmdq_thread *thread = task->thread;
> +       struct cmdq_task *prev_task = list_last_entry(
> +                       &thread->task_busy_list, typeof(*task), list_entry);
> +       u64 *prev_task_base = prev_task->va_base;
> +
> +       /* let previous task jump to this task */
> +       dma_sync_single_for_cpu(dev, prev_task->pa_base,
> +                               prev_task->cmd_buf_size, DMA_TO_DEVICE);
> +       prev_task_base[CMDQ_NUM_CMD(prev_task) - 1] =
> +               (u64)CMDQ_JUMP_BY_PA << 32 | task->pa_base;
> +       dma_sync_single_for_device(dev, prev_task->pa_base,
> +                                  prev_task->cmd_buf_size, DMA_TO_DEVICE);
> +
> +       cmdq_thread_invalidate_fetched_data(thread);
> +}
> +
> +static bool cmdq_command_is_wfe(u64 cmd)
> +{
> +       u64 wfe_option = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
> +       u64 wfe_op = (u64)(CMDQ_CODE_WFE << CMDQ_OP_CODE_SHIFT) << 32;
> +       u64 wfe_mask = (u64)CMDQ_OP_CODE_MASK << 32 | 0xffffffff;
> +
> +       return ((cmd & wfe_mask) == (wfe_op | wfe_option));
> +}
> +
> +/* we assume tasks in the same display GCE thread are waiting the same event. */
> +static void cmdq_task_remove_wfe(struct cmdq_task *task)
> +{
> +       struct device *dev = task->cmdq->mbox.dev;
> +       u64 *base = task->va_base;
> +       int i;
> +
> +       dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
> +                               DMA_TO_DEVICE);
> +       for (i = 0; i < CMDQ_NUM_CMD(task); i++)
> +               if (cmdq_command_is_wfe(base[i]))
> +                       base[i] = (u64)CMDQ_JUMP_BY_OFFSET << 32 |
> +                                 CMDQ_JUMP_PASS;
> +       dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
> +                                  DMA_TO_DEVICE);
> +}
> +
> +static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread)
> +{
> +       return readl(thread->base + CMDQ_THR_WAIT_TOKEN) & CMDQ_THR_IS_WAITING;
> +}
> +
> +static void cmdq_thread_wait_end(struct cmdq_thread *thread,
> +                                unsigned long end_pa)
> +{
> +       struct device *dev = thread->chan->mbox->dev;
> +       unsigned long curr_pa;
> +
> +       if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_ADDR,
> +                       curr_pa, curr_pa == end_pa, 1, 20))
> +               dev_err(dev, "GCE thread cannot run to end.\n");
> +}
> +
> +static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
> +{
> +       struct cmdq *cmdq = task->cmdq;
> +       unsigned long curr_pa, end_pa;
> +
> +       task->thread = thread;
> +       if (list_empty(&thread->task_busy_list)) {
> +               WARN_ON(clk_enable(cmdq->clock) < 0);
> +               WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
> +
> +               writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
> +               writel(task->pa_base + task->cmd_buf_size,
> +                      thread->base + CMDQ_THR_END_ADDR);
> +               writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
> +               writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
> +
> +               mod_timer(&thread->timeout,
> +                         jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
> +       } else {
> +               WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
> +               curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
> +               end_pa = readl(thread->base + CMDQ_THR_END_ADDR);
> +
> +               /*
> +                * Atomic execution should remove the following wfe, i.e. only
> +                * wait event at first task, and prevent to pause when running.
> +                */
> +               if (thread->atomic_exec) {
> +                       /* GCE is executing if command is not WFE */
> +                       if (!cmdq_thread_is_in_wfe(thread)) {
> +                               cmdq_thread_resume(thread);
> +                               cmdq_thread_wait_end(thread, end_pa);
> +                               WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
> +                               /* set to this task directly */
> +                               writel(task->pa_base,
> +                                      thread->base + CMDQ_THR_CURR_ADDR);
> +                       } else {
> +                               cmdq_task_insert_into_thread(task);
> +                               cmdq_task_remove_wfe(task);
> +                               smp_mb(); /* modify jump before enable thread */
> +                       }
> +               } else {
> +                       /* check boundary */
> +                       if (curr_pa == end_pa - CMDQ_INST_SIZE ||
> +                           curr_pa == end_pa) {
> +                               /* set to this task directly */
> +                               writel(task->pa_base,
> +                                      thread->base + CMDQ_THR_CURR_ADDR);
> +                       } else {
> +                               cmdq_task_insert_into_thread(task);
> +                               smp_mb(); /* modify jump before enable thread */
> +                       }
> +               }
> +               writel(task->pa_base + task->cmd_buf_size,
> +                      thread->base + CMDQ_THR_END_ADDR);
> +               cmdq_thread_resume(thread);
> +       }
> +       list_move_tail(&task->list_entry, &thread->task_busy_list);
> +}
> +
> +static void cmdq_task_exec_done(struct cmdq_task *task, bool err)
> +{
> +       struct device *dev = task->cmdq->mbox.dev;
> +       struct cmdq_cb_data cmdq_cb_data;
> +
> +       if (task->cb.cb) {
> +               cmdq_cb_data.err = err;
> +               cmdq_cb_data.data = task->cb.data;
> +               task->cb.cb(cmdq_cb_data);
> +       }
> +       list_del(&task->list_entry);
> +       dma_unmap_single(dev, task->pa_base, task->cmd_buf_size, DMA_TO_DEVICE);
> +       kfree(task->va_base);
> +}
> +
> +static void cmdq_task_handle_error(struct cmdq_task *task)
> +{
> +       struct cmdq_thread *thread = task->thread;
> +       struct cmdq_task *next_task;
> +
> +       dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task);
> +       WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0);
> +       next_task = list_first_entry_or_null(&thread->task_busy_list,
> +                       struct cmdq_task, list_entry);
> +       if (next_task)
> +               writel(next_task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
> +       cmdq_thread_resume(thread);
> +}
> +
> +static void cmdq_thread_irq_handler(struct cmdq *cmdq,
> +                                   struct cmdq_thread *thread)
> +{
> +       struct cmdq_task *task, *tmp, *curr_task = NULL;
> +       u32 curr_pa, irq_flag, task_end_pa;
> +       bool err;
> +
> +       irq_flag = readl(thread->base + CMDQ_THR_IRQ_STATUS);
> +       writel(~irq_flag, thread->base + CMDQ_THR_IRQ_STATUS);
> +
> +       /*
> +        * When ISR call this function, another CPU core could run
> +        * "release task" right before we acquire the spin lock, and thus
> +        * reset / disable this GCE thread, so we need to check the enable
> +        * bit of this GCE thread.
> +        */
> +       if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
> +               return;
> +
> +       if (irq_flag & CMDQ_THR_IRQ_ERROR)
> +               err = true;
> +       else if (irq_flag & CMDQ_THR_IRQ_DONE)
> +               err = false;
> +       else
> +               return;
> +
> +       curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
> +
> +       list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
> +                                list_entry) {
> +               task_end_pa = task->pa_base + task->cmd_buf_size;
> +               if (curr_pa >= task->pa_base && curr_pa < task_end_pa)
> +                       curr_task = task;
> +
> +               if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
> +                       cmdq_task_exec_done(task, false);
> +                       kfree(task);
> +               } else if (err) {
> +                       cmdq_task_exec_done(task, true);
> +                       cmdq_task_handle_error(curr_task);
> +                       kfree(task);
> +               }
> +
> +               if (curr_task)
> +                       break;
> +       }
> +
> +       if (list_empty(&thread->task_busy_list)) {
> +               cmdq_thread_disable(cmdq, thread);
> +               clk_disable(cmdq->clock);
> +       } else {
> +               mod_timer(&thread->timeout,
> +                         jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
> +       }
> +}
> +
> +static irqreturn_t cmdq_irq_handler(int irq, void *dev)
> +{
> +       struct cmdq *cmdq = dev;
> +       unsigned long irq_status, flags = 0L;
> +       int bit;
> +
> +       irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK;
> +       if (!(irq_status ^ CMDQ_IRQ_MASK))
> +               return IRQ_NONE;
> +
> +       for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) {
> +               struct cmdq_thread *thread = &cmdq->thread[bit];
> +
> +               spin_lock_irqsave(&thread->chan->lock, flags);
> +               cmdq_thread_irq_handler(cmdq, thread);
> +               spin_unlock_irqrestore(&thread->chan->lock, flags);
> +       }
> +       return IRQ_HANDLED;
> +}
> +
> +static void cmdq_thread_handle_timeout(unsigned long data)
> +{
> +       struct cmdq_thread *thread = (struct cmdq_thread *)data;
> +       struct cmdq *cmdq = container_of(thread->chan->mbox, struct cmdq, mbox);
> +       struct cmdq_task *task, *tmp;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&thread->chan->lock, flags);
> +       WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
> +
> +       /*
> +        * Although IRQ is disabled, GCE continues to execute.
> +        * It may have pending IRQ before GCE thread is suspended,
> +        * so check this condition again.
> +        */
> +       cmdq_thread_irq_handler(cmdq, thread);
> +
> +       if (list_empty(&thread->task_busy_list)) {
> +               cmdq_thread_resume(thread);
> +               spin_unlock_irqrestore(&thread->chan->lock, flags);
> +               return;
> +       }
> +
> +       dev_err(cmdq->mbox.dev, "timeout\n");
> +       list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
> +                                list_entry) {
> +               cmdq_task_exec_done(task, true);
> +               kfree(task);
> +       }
> +
> +       cmdq_thread_resume(thread);
> +       cmdq_thread_disable(cmdq, thread);
> +       clk_disable(cmdq->clock);
> +       spin_unlock_irqrestore(&thread->chan->lock, flags);
> +}
> +
> +static int cmdq_task_realloc_cmd_buffer(struct cmdq_task *task, size_t size)
> +{
> +       void *new_buf;
> +
> +       new_buf = krealloc(task->va_base, size, GFP_KERNEL | __GFP_ZERO);
> +       if (!new_buf)
> +               return -ENOMEM;
> +       task->va_base = new_buf;
> +       task->buf_size = size;
> +       return 0;
> +}
> +
> +struct cmdq_base *cmdq_register_device(struct device *dev)
> +{
> +       struct cmdq_base *cmdq_base;
> +       struct resource res;
> +       int subsys;
> +       u32 base;
> +
> +       if (of_address_to_resource(dev->of_node, 0, &res))
> +               return NULL;
> +       base = (u32)res.start;
> +
> +       subsys = cmdq_subsys_base_to_id(base >> 16);
> +       if (subsys < 0)
> +               return NULL;
> +
> +       cmdq_base = devm_kmalloc(dev, sizeof(*cmdq_base), GFP_KERNEL);
> +       if (!cmdq_base)
> +               return NULL;
> +       cmdq_base->subsys = subsys;
> +       cmdq_base->base = base;
> +
> +       return cmdq_base;
> +}
> +EXPORT_SYMBOL(cmdq_register_device);
> +
> +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
> +{
> +       struct cmdq_client *client;
> +
> +       client = kzalloc(sizeof(*client), GFP_KERNEL);
> +       client->client.dev = dev;
> +       client->client.tx_block = false;
> +       client->chan = mbox_request_channel(&client->client, index);
> +       return client;
> +}
> +EXPORT_SYMBOL(cmdq_mbox_create);
> +
> +int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr)
> +{
> +       struct cmdq_task *task;
> +       int err;
> +
> +       task = kzalloc(sizeof(*task), GFP_KERNEL);
> +       if (!task)
> +               return -ENOMEM;
> +       task->cmdq = dev_get_drvdata(dev);
> +       err = cmdq_task_realloc_cmd_buffer(task, PAGE_SIZE);
> +       if (err < 0) {
> +               kfree(task);
> +               return err;
> +       }
> +       *task_ptr = task;
> +       return 0;
> +}
> +EXPORT_SYMBOL(cmdq_task_create);
> +
> +static int cmdq_task_append_command(struct cmdq_task *task, enum cmdq_code code,
> +                                   u32 arg_a, u32 arg_b)
> +{
> +       u64 *cmd_ptr;
> +       int err;
> +
> +       if (WARN_ON(task->finalized))
> +               return -EBUSY;
> +       if (unlikely(task->cmd_buf_size + CMDQ_INST_SIZE > task->buf_size)) {
> +               err = cmdq_task_realloc_cmd_buffer(task, task->buf_size * 2);
> +               if (err < 0)
> +                       return err;
> +       }
> +       cmd_ptr = task->va_base + task->cmd_buf_size;
> +       (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
> +       task->cmd_buf_size += CMDQ_INST_SIZE;
> +       return 0;
> +}
> +
> +int cmdq_task_write(struct cmdq_task *task, u32 value, struct cmdq_base *base,
> +                   u32 offset)
> +{
> +       u32 arg_a = ((base->base + offset) & CMDQ_ARG_A_WRITE_MASK) |
> +                   (base->subsys << CMDQ_SUBSYS_SHIFT);
> +       return cmdq_task_append_command(task, CMDQ_CODE_WRITE, arg_a, value);
> +}
> +EXPORT_SYMBOL(cmdq_task_write);
> +
> +int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
> +                        struct cmdq_base *base, u32 offset, u32 mask)
> +{
> +       u32 offset_mask = offset;
> +       int err;
> +
> +       if (mask != 0xffffffff) {
> +               err = cmdq_task_append_command(task, CMDQ_CODE_MASK, 0, ~mask);
> +               if (err < 0)
> +                       return err;
> +               offset_mask |= CMDQ_WRITE_ENABLE_MASK;
> +       }
> +       return cmdq_task_write(task, value, base, offset_mask);
> +}
> +EXPORT_SYMBOL(cmdq_task_write_mask);
> +
> +static const u32 cmdq_event_value[CMDQ_MAX_EVENT] = {
> +       /* Display start of frame(SOF) events */
> +       [CMDQ_EVENT_DISP_OVL0_SOF] = 11,
> +       [CMDQ_EVENT_DISP_OVL1_SOF] = 12,
> +       [CMDQ_EVENT_DISP_RDMA0_SOF] = 13,
> +       [CMDQ_EVENT_DISP_RDMA1_SOF] = 14,
> +       [CMDQ_EVENT_DISP_RDMA2_SOF] = 15,
> +       [CMDQ_EVENT_DISP_WDMA0_SOF] = 16,
> +       [CMDQ_EVENT_DISP_WDMA1_SOF] = 17,
> +       /* Display end of frame(EOF) events */
> +       [CMDQ_EVENT_DISP_OVL0_EOF] = 39,
> +       [CMDQ_EVENT_DISP_OVL1_EOF] = 40,
> +       [CMDQ_EVENT_DISP_RDMA0_EOF] = 41,
> +       [CMDQ_EVENT_DISP_RDMA1_EOF] = 42,
> +       [CMDQ_EVENT_DISP_RDMA2_EOF] = 43,
> +       [CMDQ_EVENT_DISP_WDMA0_EOF] = 44,
> +       [CMDQ_EVENT_DISP_WDMA1_EOF] = 45,
> +       /* Mutex end of frame(EOF) events */
> +       [CMDQ_EVENT_MUTEX0_STREAM_EOF] = 53,
> +       [CMDQ_EVENT_MUTEX1_STREAM_EOF] = 54,
> +       [CMDQ_EVENT_MUTEX2_STREAM_EOF] = 55,
> +       [CMDQ_EVENT_MUTEX3_STREAM_EOF] = 56,
> +       [CMDQ_EVENT_MUTEX4_STREAM_EOF] = 57,
> +       /* Display underrun events */
> +       [CMDQ_EVENT_DISP_RDMA0_UNDERRUN] = 63,
> +       [CMDQ_EVENT_DISP_RDMA1_UNDERRUN] = 64,
> +       [CMDQ_EVENT_DISP_RDMA2_UNDERRUN] = 65,
> +};
> +
> +int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event)
> +{
> +       u32 arg_b;
> +
> +       if (event >= CMDQ_MAX_EVENT || event < 0)
> +               return -EINVAL;
> +
> +       /*
> +        * WFE arg_b
> +        * bit 0-11: wait value
> +        * bit 15: 1 - wait, 0 - no wait
> +        * bit 16-27: update value
> +        * bit 31: 1 - update, 0 - no update
> +        */
> +       arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
> +       return cmdq_task_append_command(task, CMDQ_CODE_WFE,
> +                       cmdq_event_value[event], arg_b);
> +}
> +EXPORT_SYMBOL(cmdq_task_wfe);
> +
> +int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event)
> +{
> +       if (event >= CMDQ_MAX_EVENT || event < 0)
> +               return -EINVAL;
> +
> +       return cmdq_task_append_command(task, CMDQ_CODE_WFE,
> +                       cmdq_event_value[event], CMDQ_WFE_UPDATE);
> +}
> +EXPORT_SYMBOL(cmdq_task_clear_event);
> +
> +static int cmdq_task_finalize(struct cmdq_task *task)
> +{
> +       int err;
> +
> +       if (task->finalized)
> +               return 0;
> +
> +       /* insert EOC and generate IRQ for each command iteration */
> +       err = cmdq_task_append_command(task, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
> +       if (err < 0)
> +               return err;
> +
> +       /* JUMP to end */
> +       err = cmdq_task_append_command(task, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
> +       if (err < 0)
> +               return err;
> +
> +       task->finalized = true;
> +       return 0;
> +}
> +
> +int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
> +                         cmdq_async_flush_cb cb, void *data)
> +{
> +       struct cmdq *cmdq = task->cmdq;
> +       int err;
> +
> +       mutex_lock(&cmdq->task_mutex);
> +       if (cmdq->suspended) {
> +               dev_err(cmdq->mbox.dev, "%s is called after suspended\n",
> +                       __func__);
> +               mutex_unlock(&cmdq->task_mutex);
> +               return -EPERM;
> +       }
> +
> +       err = cmdq_task_finalize(task);
> +       if (err < 0) {
> +               mutex_unlock(&cmdq->task_mutex);
> +               return err;
> +       }
> +
> +       INIT_LIST_HEAD(&task->list_entry);
> +       task->cb.cb = cb;
> +       task->cb.data = data;
> +       task->pa_base = dma_map_single(cmdq->mbox.dev, task->va_base,
> +                                      task->cmd_buf_size, DMA_TO_DEVICE);
> +
> +       mbox_send_message(client->chan, task);
> +       /* We can send next task immediately, so just call txdone. */
> +       mbox_client_txdone(client->chan, 0);
> +       mutex_unlock(&cmdq->task_mutex);
> +       return 0;
> +}
> +EXPORT_SYMBOL(cmdq_task_flush_async);
> +
> +struct cmdq_flush_completion {
> +       struct completion cmplt;
> +       bool err;
> +};
> +
> +static void cmdq_task_flush_cb(struct cmdq_cb_data data)
> +{
> +       struct cmdq_flush_completion *cmplt = data.data;
> +
> +       cmplt->err = data.err;
> +       complete(&cmplt->cmplt);
> +}
> +
> +int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task)
> +{
> +       struct cmdq_flush_completion cmplt;
> +       int err;
> +
> +       init_completion(&cmplt.cmplt);
> +       err = cmdq_task_flush_async(client, task, cmdq_task_flush_cb, &cmplt);
> +       if (err < 0)
> +               return err;
> +       wait_for_completion(&cmplt.cmplt);
> +       return cmplt.err ? -EFAULT : 0;
> +}
> +EXPORT_SYMBOL(cmdq_task_flush);
> +
> +void cmdq_mbox_free(struct cmdq_client *client)
> +{
> +       mbox_free_channel(client->chan);
> +       kfree(client);
> +}
> +EXPORT_SYMBOL(cmdq_mbox_free);
> +
All these exported functions implement the protocol, so should not be
a part of this controller driver. That should go into
drivers/soc/mediatek/

The controller driver (mtk-cmdq.c) should implement mainly the
mbox_chan_ops and mbox.of_xlate.


> +static int cmdq_suspend(struct device *dev)
> +{
> +       struct cmdq *cmdq = dev_get_drvdata(dev);
> +       struct cmdq_thread *thread;
> +       int i;
> +       bool task_running = false;
> +
> +       mutex_lock(&cmdq->task_mutex);
> +       cmdq->suspended = true;
> +       mutex_unlock(&cmdq->task_mutex);
> +
> +       for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
> +               thread = &cmdq->thread[i];
> +               if (!list_empty(&thread->task_busy_list)) {
> +                       mod_timer(&thread->timeout, jiffies + 1);
> +                       task_running = true;
> +               }
> +       }
> +
> +       if (task_running) {
> +               dev_warn(dev, "exist running task(s) in suspend\n");
> +               msleep(20);
> +       }
> +
> +       clk_unprepare(cmdq->clock);
> +       return 0;
> +}
> +
> +static int cmdq_resume(struct device *dev)
> +{
> +       struct cmdq *cmdq = dev_get_drvdata(dev);
> +
> +       WARN_ON(clk_prepare(cmdq->clock) < 0);
> +       cmdq->suspended = false;
> +       return 0;
> +}
> +
> +static int cmdq_remove(struct platform_device *pdev)
> +{
> +       struct cmdq *cmdq = platform_get_drvdata(pdev);
> +
> +       mbox_controller_unregister(&cmdq->mbox);
> +       clk_unprepare(cmdq->clock);
> +       return 0;
> +}
> +
> +static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
> +{
> +       cmdq_task_exec(data, chan->con_priv);
> +       return 0;
> +}
> +
> +static int cmdq_mbox_startup(struct mbox_chan *chan)
> +{
> +       return 0;
> +}
> +
> +static void cmdq_mbox_shutdown(struct mbox_chan *chan)
> +{
> +}
> +
> +static bool cmdq_mbox_last_tx_done(struct mbox_chan *chan)
> +{
> +       return true;
> +}
> +
> +static const struct mbox_chan_ops cmdq_mbox_chan_ops = {
> +       .send_data = cmdq_mbox_send_data,
> +       .startup = cmdq_mbox_startup,
> +       .shutdown = cmdq_mbox_shutdown,
> +       .last_tx_done = cmdq_mbox_last_tx_done,
> +};
> +
> +static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
> +               const struct of_phandle_args *sp)
> +{
> +       int ind = sp->args[0];
> +       struct cmdq_thread *thread;
> +
> +       if (ind >= mbox->num_chans)
> +               return ERR_PTR(-EINVAL);
> +
> +       thread = mbox->chans[ind].con_priv;
> +       thread->atomic_exec = (sp->args[1] != 0);
> +       thread->chan = &mbox->chans[ind];
> +
> +       return &mbox->chans[ind];
> +}
> +
> +static int cmdq_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct device_node *node = dev->of_node;
> +       struct resource *res;
> +       struct cmdq *cmdq;
> +       int err, i;
> +
> +       cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
> +       if (!cmdq)
> +               return -ENOMEM;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       cmdq->base = devm_ioremap_resource(dev, res);
> +       if (IS_ERR(cmdq->base)) {
> +               dev_err(dev, "failed to ioremap gce\n");
> +               return PTR_ERR(cmdq->base);
> +       }
> +
> +       cmdq->irq = irq_of_parse_and_map(node, 0);
>
why not,  cmdq->irq = platform_get_irq(pdev, 0);

> +       if (!cmdq->irq) {
> +               dev_err(dev, "failed to get irq\n");
> +               return -EINVAL;
> +       }
> +       err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED,
> +                              "mtk_cmdq", cmdq);
> +       if (err < 0) {
> +               dev_err(dev, "failed to register ISR (%d)\n", err);
> +               return err;
> +       }
> +
> +       dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
> +               dev, cmdq->base, cmdq->irq);
> +
> +       cmdq->clock = devm_clk_get(dev, "gce");
> +       if (IS_ERR(cmdq->clock)) {
> +               dev_err(dev, "failed to get gce clk\n");
> +               return PTR_ERR(cmdq->clock);
> +       }
> +
> +       mutex_init(&cmdq->task_mutex);
> +
> +       cmdq->mbox.dev = dev;
> +       cmdq->mbox.chans = devm_kcalloc(dev, CMDQ_THR_MAX_COUNT,
> +                                       sizeof(*cmdq->mbox.chans), GFP_KERNEL);
> +       if (!cmdq->mbox.chans)
> +               return -ENOMEM;
> +
> +       cmdq->mbox.num_chans = CMDQ_THR_MAX_COUNT;
> +       cmdq->mbox.ops = &cmdq_mbox_chan_ops;
> +       cmdq->mbox.of_xlate = cmdq_xlate;
> +
> +       /* make use of TXDONE_BY_ACK */
> +       cmdq->mbox.txdone_irq = false;
> +       cmdq->mbox.txdone_poll = false;
> +
> +       for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
> +               cmdq->thread[i].base = cmdq->base + CMDQ_THR_BASE +
> +                               CMDQ_THR_SIZE * i;
> +               INIT_LIST_HEAD(&cmdq->thread[i].task_busy_list);
> +               init_timer(&cmdq->thread[i].timeout);
> +               cmdq->thread[i].timeout.function = cmdq_thread_handle_timeout;
> +               cmdq->thread[i].timeout.data = (unsigned long)&cmdq->thread[i];
> +               cmdq->mbox.chans[i].con_priv = &cmdq->thread[i];
> +       }
> +
> +       err = mbox_controller_register(&cmdq->mbox);
> +       if (err < 0) {
> +               dev_err(dev, "failed to register mailbox: %d\n", err);
> +               return err;
> +       }
> +
> +       platform_set_drvdata(pdev, cmdq);
> +       WARN_ON(clk_prepare(cmdq->clock) < 0);
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops cmdq_pm_ops = {
> +       .suspend = cmdq_suspend,
> +       .resume = cmdq_resume,
> +};
> +
> +static const struct of_device_id cmdq_of_ids[] = {
> +       {.compatible = "mediatek,mt8173-gce",},
> +       {}
> +};
> +
> +static struct platform_driver cmdq_drv = {
> +       .probe = cmdq_probe,
> +       .remove = cmdq_remove,
> +       .driver = {
> +               .name = "mtk_cmdq",
> +               .owner = THIS_MODULE,
>
please remove the unnecessary .owner field.

> +               .pm = &cmdq_pm_ops,
> +               .of_match_table = cmdq_of_ids,
> +       }
> +};
> +
> +builtin_platform_driver(cmdq_drv);
> diff --git a/include/linux/mailbox/mtk-cmdq.h b/include/linux/mailbox/mtk-cmdq.h
> new file mode 100644
> index 0000000..c3c924d
> --- /dev/null
> +++ b/include/linux/mailbox/mtk-cmdq.h
>
The api implemented is Mediateck proprietary, so I think it should be
include/linux/soc/mediatek/cmdq.h


> @@ -0,0 +1,180 @@
> +/*
> + * Copyright (c) 2015 MediaTek Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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.
> + */
> +
> +#ifndef __MTK_CMDQ_H__
> +#define __MTK_CMDQ_H__
> +
> +#include <linux/mailbox_client.h>
> +#include <linux/mailbox_controller.h>
>
Clients should not need to include mailbox_controller.h

> +#include <linux/platform_device.h>
> +#include <linux/types.h>
> +
> +/* display events in command queue(CMDQ) */
> +enum cmdq_event {
> +       /* Display start of frame(SOF) events */
> +       CMDQ_EVENT_DISP_OVL0_SOF,
>
you may want to explicitly initialise the first element.

> +       CMDQ_EVENT_DISP_OVL1_SOF,
> +       CMDQ_EVENT_DISP_RDMA0_SOF,
> +       CMDQ_EVENT_DISP_RDMA1_SOF,
> +       CMDQ_EVENT_DISP_RDMA2_SOF,
> +       CMDQ_EVENT_DISP_WDMA0_SOF,
> +       CMDQ_EVENT_DISP_WDMA1_SOF,
> +       /* Display end of frame(EOF) events */
> +       CMDQ_EVENT_DISP_OVL0_EOF,
> +       CMDQ_EVENT_DISP_OVL1_EOF,
> +       CMDQ_EVENT_DISP_RDMA0_EOF,
> +       CMDQ_EVENT_DISP_RDMA1_EOF,
> +       CMDQ_EVENT_DISP_RDMA2_EOF,
> +       CMDQ_EVENT_DISP_WDMA0_EOF,
> +       CMDQ_EVENT_DISP_WDMA1_EOF,
> +       /* Mutex end of frame(EOF) events */
> +       CMDQ_EVENT_MUTEX0_STREAM_EOF,
> +       CMDQ_EVENT_MUTEX1_STREAM_EOF,
> +       CMDQ_EVENT_MUTEX2_STREAM_EOF,
> +       CMDQ_EVENT_MUTEX3_STREAM_EOF,
> +       CMDQ_EVENT_MUTEX4_STREAM_EOF,
> +       /* Display underrun events */
> +       CMDQ_EVENT_DISP_RDMA0_UNDERRUN,
> +       CMDQ_EVENT_DISP_RDMA1_UNDERRUN,
> +       CMDQ_EVENT_DISP_RDMA2_UNDERRUN,
> +       /* Keep this at the end */
> +       CMDQ_MAX_EVENT,
> +};
> +

^ permalink raw reply

* [PATCH 2/2] musb: sunxi: Force session end on babble errors in host-mode
From: Hans de Goede @ 2016-09-22  8:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922023344.GE3981@uda0271908>

Hi,

On 09/22/2016 05:33 AM, Bin Liu wrote:
> Hi,
>
> On Sun, Sep 18, 2016 at 06:50:18PM +0200, Hans de Goede wrote:
>> The sunxi musb has a bug where sometimes it will generate a babble
>> error on device disconnect instead of a disconnect irq. When this
>> happens the musb-controller switches from host mode to device mode
>> (it clears MUSB_DEVCTL_SESSION and sets MUSB_DEVCTL_BDEVICE) and
>> gets stuck in this state.
>>
>> Clearing this requires reporting Vbus low for 200 or more ms, but
>> on some devices Vbus is simply always high (host-only mode, no Vbus
>> control).
>>
>> This commit calls sun4i_usb_phy_force_session_end() on babble errors
>> in host-mode, fixing the musb controller being stuck in this state
>> on systems without Vbus control; and also fixes the need to unplug
>> the usb-b -> usb-a cable to get out of this state on systems with
>> Vbus control.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>  drivers/usb/musb/sunxi.c | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
>> index 1408245..5079d90 100644
>> --- a/drivers/usb/musb/sunxi.c
>> +++ b/drivers/usb/musb/sunxi.c
>> @@ -192,8 +192,18 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
>>  	 * normally babble never happens treat it as disconnect.
>>  	 */
>>  	if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) {
>
> musb_interrupt() handle BABBLE in host mode, and has a glue hook
> musb_platform_recover() in musb_recover_from_babble().
>
> Maybe you can use it?

Ah yes, I looked at this at the past, but that was before the babble
recover rework by Felipe Balbi which got commited on 2015-03-10.

With this rework the sunxi code should indeed be able to use the core
recovery, and we can use the musb_platform_recover() to force a
session end.

And thinking more about you're other remark, I do think I can
actually modify the sun4i phy_set_mode callback so that it can
be used for this.

I'll post a v2 with these changes soon-ish.

Regards,

Hans


>> +		struct sunxi_glue *glue =
>> +				dev_get_drvdata(musb->controller->parent);
>> +
>> +		dev_warn(musb->controller->parent, "babble, treating as disconnect\n");
>> +
>>  		musb->int_usb &= ~MUSB_INTR_BABBLE;
>>  		musb->int_usb |= MUSB_INTR_DISCONNECT;
>> +		/*
>> +		 * Fix the musb controller sometimes getting stuck in
>> +		 * bdevice state after a babble error.
>> +		 */
>> +		sun4i_usb_phy_force_session_end(glue->phy);
>
> As I commented in PATCH 1/2, can you somehow reuse
> sun4i_usb_phy_set_mode() instead?
>
>>  	}
>>
>>  	if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) {
>> --
>> 2.9.3
>
> Regards,
> -Bin.
>

^ permalink raw reply

* [PATCH] clocksource/drivers/ti-32k: Prevent ftrace recursion
From: Jisheng Zhang @ 2016-09-22  7:56 UTC (permalink / raw)
  To: linux-arm-kernel

Currently ti-32k can be used as a scheduler clock. We properly marked
omap_32k_read_sched_clock() as notrace but we then call another
function ti_32k_read_cycles() that _wasn't_ notrace.

Having a traceable function in the sched_clock() path leads to a
recursion within ftrace and a kernel crash.

Fix this by adding notrace attribute to the ti_32k_read_cycles()
function.

Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
---
 drivers/clocksource/timer-ti-32k.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c
index 92b7e39..cf5b14e 100644
--- a/drivers/clocksource/timer-ti-32k.c
+++ b/drivers/clocksource/timer-ti-32k.c
@@ -65,7 +65,7 @@ static inline struct ti_32k *to_ti_32k(struct clocksource *cs)
 	return container_of(cs, struct ti_32k, cs);
 }
 
-static cycle_t ti_32k_read_cycles(struct clocksource *cs)
+static cycle_t notrace ti_32k_read_cycles(struct clocksource *cs)
 {
 	struct ti_32k *ti = to_ti_32k(cs);
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH v14 4/4] CMDQ: save more energy in idle
From: Jassi Brar @ 2016-09-22  7:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473039885-24009-5-git-send-email-hs.liao@mediatek.com>

On Mon, Sep 5, 2016 at 7:14 AM, HS Liao <hs.liao@mediatek.com> wrote:
> Use clk_disable_unprepare instead of clk_disable to save more energy
> when CMDQ is idle.
>
> Signed-off-by: HS Liao <hs.liao@mediatek.com>
> ---
>  drivers/mailbox/mtk-cmdq.c | 54 +++++++++++++++++++++++++++++++++++++++-------

The driver is introduced by second patch of the set, so it makes sense
to merge this patch into patch 2/4.

^ permalink raw reply

* [PATCH] tty/serial: atmel: fix fractional baud rate computation
From: Boris Brezillon @ 2016-09-22  7:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922070746.65nzezj3fwunu55s@pengutronix.de>

On Thu, 22 Sep 2016 09:07:46 +0200
Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de> wrote:

> On Wed, Sep 21, 2016 at 12:44:14PM +0200, Nicolas Ferre wrote:
> > From: Alexey Starikovskiy <aystarik@gmail.com>
> > 
> > The problem with previous code was it rounded values in wrong
> > place and produced wrong baud rate in some cases.
> > 
> > Signed-off-by: Alexey Starikovskiy <aystarik@gmail.com>
> > [nicolas.ferre at atmel.com: port to newer kernel and add commit log]
> > Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> > ---
> >  drivers/tty/serial/atmel_serial.c | 10 ++++++----
> >  include/linux/atmel_serial.h      |  1 +
> >  2 files changed, 7 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> > index 5f550d9feed9..fd8aa1f4ba78 100644
> > --- a/drivers/tty/serial/atmel_serial.c
> > +++ b/drivers/tty/serial/atmel_serial.c
> > @@ -2170,13 +2170,15 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> >  	 * accurately. This feature is enabled only when using normal mode.
> >  	 * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8))
> >  	 * Currently, OVER is always set to 0 so we get
> > -	 * baudrate = selected clock (16 * (CD + FP / 8))
> > +	 * baudrate = selected clock / (16 * (CD + FP / 8))
> > +	 * then
> > +	 * 8 CD + FP = selected clock / (2 * baudrate)
> >  	 */
> >  	if (atmel_port->has_frac_baudrate &&
> >  	    (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) {
> > -		div = DIV_ROUND_CLOSEST(port->uartclk, baud);
> > -		cd = div / 16;
> > -		fp = DIV_ROUND_CLOSEST(div % 16, 2);
> > +		div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2);
> > +		cd = div >> 3;
> > +		fp = div & ATMEL_US_FP_MASK;  
> 
> given baud = 115200 and uartclk = 5414300 this results in:
> 
> 	div = DIV_ROUND_CLOSEST(5414300, 115200 * 2) = 23
> 	cd = 2
> 	fp = 7

How about:

	div = DIV_ROUND_CLOSEST(port->uartclk, baud);
	cd = div / 16;
	fp = (div % 16) / 2;

	best_baud = port->uartclk / ((16 * cd) +  (8 * fp));

	/* Check if we can get a better approximation by rounding up. */
	if (div % 2) {
		int alt_baud, alt_fp, alt_cd;

		alt_fp = fp++;
		alt_cd = cd;
		if (alt_fp > 7) {
			alt_cd++;
			alt_fp = 0;
		}

		alt_baud = port->uartclk / ((16 * alt_cd) +  (8 *alt_fp));
		if (abs(best_baud - baud) > abs(alt_baud - baud)) {
			best_baud = alt_baud;
			fp = alt_fp;
			cd = alt_cd;
		}
	}

> 
> which yields a rate of 5414300 / 46 = 117702.17. With cd = 3 and fp = 0
> however the resulting rate is 5414300 / 48 = 112797.92.
> 
> Which one is better?
> 
> >  	} else {
> >  		cd = uart_get_divisor(port, baud);
> >  	}
> > diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h
> > index f8e452aa48d7..bd2560502f3c 100644
> > --- a/include/linux/atmel_serial.h
> > +++ b/include/linux/atmel_serial.h
> > @@ -119,6 +119,7 @@
> >  #define ATMEL_US_BRGR		0x20	/* Baud Rate Generator Register */
> >  #define	ATMEL_US_CD		GENMASK(15, 0)	/* Clock Divider */
> >  #define ATMEL_US_FP_OFFSET	16	/* Fractional Part */
> > +#define ATMEL_US_FP_MASK	0x7  
> 
> Is there another user of this header? If not, this can be folded into
> the driver.
> 
> Best regards
> Uwe
> 

^ permalink raw reply

* [PATCH 1/2] phy-sun4i-usb: Add sun4i_usb_phy_force_session_end() function
From: Hans de Goede @ 2016-09-22  7:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922022854.GD3981@uda0271908>

Hi,

On 09/22/2016 05:28 AM, Bin Liu wrote:
> Hi,
>
> On Wed, Sep 21, 2016 at 11:05:33AM +0300, Hans de Goede wrote:
>> Hi,
>>
>> On 09/20/2016 07:45 AM, Kishon Vijay Abraham I wrote:
>>> Hi,
>>>
>>> On Sunday 18 September 2016 10:20 PM, Hans de Goede wrote:
>>>> The sunxi musb has a bug where sometimes it will generate a babble
>>>> error on device disconnect instead of a disconnect irq. When this
>>>> happens the musb-controller switches from host mode to device mode
>>>> (it clears MUSB_DEVCTL_SESSION and sets MUSB_DEVCTL_BDEVICE) and
>>>> gets stuck in this state.
>>>>
>>>> Clearing this requires reporting Vbus low for 200 or more ms, but
>>>> on some devices Vbus is simply always high (host-only mode, no Vbus
>>>> control). The phy-sun4i-usb code already has code to force a session
>>>> end for devices without Vbus control.
>>>>
>>>> This commit adds a sun4i_usb_phy_force_session_end() function exporting
>>>> this functionality to the sunxi-musb glue, so that it can force a session
>>>> end to fixup the stuck state after a babble error.
>>>>
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>> drivers/phy/phy-sun4i-usb.c       | 11 +++++++++++
>>>> include/linux/phy/phy-sun4i-usb.h |  7 +++++++
>>>> 2 files changed, 18 insertions(+)
>>>>
>>>> diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
>>>> index 43c0d98..06f4e11a 100644
>>>> --- a/drivers/phy/phy-sun4i-usb.c
>>>> +++ b/drivers/phy/phy-sun4i-usb.c
>>>> @@ -470,6 +470,17 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
>>>> }
>>>> EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
>>>>
>>>> +void sun4i_usb_phy_force_session_end(struct phy *_phy)
>>>> +{
>>>> +	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
>>>> +	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
>>>> +
>>>> +	data->id_det = -1;
>>>> +	data->force_session_end = true;
>>>> +	queue_delayed_work(system_wq, &data->detect, 0);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(sun4i_usb_phy_force_session_end);
>>>
>>> Er.. one more export symbol :-(
>>
>> Yes unfortunately we need one more to work around sunxi musb / phy bugs.
>
> Instead, can you somehow reuse sun4i_usb_phy_set_mode()?

That was my first thought too, and I looked into this, but it did not
work out.

Regards,

Hans

>
> Regards,
> -Bin.
>
>>
>>>> +
>>>> static const struct phy_ops sun4i_usb_phy_ops = {
>>>> 	.init		= sun4i_usb_phy_init,
>>>> 	.exit		= sun4i_usb_phy_exit,
>>>> diff --git a/include/linux/phy/phy-sun4i-usb.h b/include/linux/phy/phy-sun4i-usb.h
>>>> index 50aed92..3bb773f 100644
>>>> --- a/include/linux/phy/phy-sun4i-usb.h
>>>> +++ b/include/linux/phy/phy-sun4i-usb.h
>>>> @@ -23,4 +23,11 @@
>>>>  */
>>>> void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled);
>>>>
>>>> +/**
>>>> + * sun4i_usb_force_session_end() - Force the current session to end
>>>> + *				   by reporting VBus low for 200+ ms
>>>> + * @phy: reference to a sun4i usb phy
>>>> + */
>>>> +void sun4i_usb_phy_force_session_end(struct phy *phy);
>>>
>>> Should we include a static inline function if sun4i phy is not defined?
>>
>> No, we're also not doing that for the already exported
>> sun4i_usb_phy_set_squelch_detect()
>>
>> And it is not necessary since the only caller is drivers/usb/musb/sunxi.c,
>> and drivers/usb/musb/Kconfig has:
>>
>> config USB_MUSB_SUNXI
>>         tristate "Allwinner (sunxi)"
>>         depends on PHY_SUN4I_USB
>>
>> Regards,
>>
>> Hans

^ permalink raw reply

* [PATCH 2/4] drivers: iio: ti_am335x_adc: add dma support
From: Peter Ujfalusi @ 2016-09-22  7:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921161134.6951-3-mugunthanvnm@ti.com>

On 09/21/16 19:11, Mugunthan V N wrote:
> This patch adds the required pieces to ti_am335x_adc driver for
> DMA support
> 
> Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
> ---
>  drivers/iio/adc/ti_am335x_adc.c      | 160 ++++++++++++++++++++++++++++++++++-
>  include/linux/mfd/ti_am335x_tscadc.h |   7 ++
>  2 files changed, 164 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> index c3cfacca..89d0b07 100644
> --- a/drivers/iio/adc/ti_am335x_adc.c
> +++ b/drivers/iio/adc/ti_am335x_adc.c
> @@ -30,10 +30,32 @@
>  #include <linux/iio/buffer.h>
>  #include <linux/iio/kfifo_buf.h>
>  
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +
> +#define DMA_BUFFER_SIZE		SZ_2K
> +
> +struct tiadc_dma {
> +	/* Filter function */
> +	dma_filter_fn		fn;
> +	/* Parameter to the filter function */
> +	void			*param;
> +	struct dma_slave_config	conf;
> +	struct dma_chan		*chan;
> +	dma_addr_t		addr;
> +	dma_cookie_t		cookie;
> +	u8			*buf;
> +	bool			valid_buf_seg;
> +	int			buf_offset;
> +	u8			fifo_thresh;
> +};
> +
>  struct tiadc_device {
>  	struct ti_tscadc_dev *mfd_tscadc;
> +	struct tiadc_dma dma;
>  	struct mutex fifo1_lock; /* to protect fifo access */
>  	int channels;
> +	int total_ch_enabled;
>  	u8 channel_line[8];
>  	u8 channel_step[8];
>  	int buffer_en_ch_steps;
> @@ -184,6 +206,7 @@ static irqreturn_t tiadc_worker_h(int irq, void *private)
>  	u16 *data = adc_dev->data;
>  
>  	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
> +
>  	for (k = 0; k < fifo1count; k = k + i) {
>  		for (i = 0; i < (indio_dev->scan_bytes)/2; i++) {
>  			read = tiadc_readl(adc_dev, REG_FIFO1);
> @@ -198,6 +221,68 @@ static irqreturn_t tiadc_worker_h(int irq, void *private)
>  	return IRQ_HANDLED;
>  }
>  
> +static void tiadc_dma_rx_complete(void *param)
> +{
> +	struct iio_dev *indio_dev = param;
> +	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
> +	u8 *data;
> +	int i;
> +
> +	data = dma->valid_buf_seg ? dma->buf + dma->buf_offset : dma->buf;

bool valid_buf_seg ? The buffer segment is valid or not valid? Which buffer
segment is valid when valid_buf_seg is true?

I know what this is doing, but it is logically not correct.

Instead you could have:

int current_period; /* The period the DMA is working on */

When you start the DMA:
dma->current_period = 0; /* We start to fill period 0 */

In here:

u8 *data = dma->buf + (dma->current_period * dma_period_size);

> +	dma->valid_buf_seg = !dma->valid_buf_seg;

/* Currently we have only two periods, so we can just */
dma->current_period = !dma->current_period;
/* or */
dma->current_period = 1 - dma->current_period; /* swap the buffer ID */

I think this would make it better to follow and if later you figure that you
want three or more periods instead of the two, it is going to be easier to add
that.

> +
> +	for (i = 0; i < dma->buf_offset; i += indio_dev->scan_bytes) {
> +		iio_push_to_buffers(indio_dev, data);
> +		data += indio_dev->scan_bytes;
> +	}
> +}
> +
> +static int tiadc_start_dma(struct iio_dev *indio_dev)
> +{
> +	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
> +	struct dma_async_tx_descriptor *desc;
> +
> +	dma->valid_buf_seg = false;
> +	dma->fifo_thresh = FIFO1_THRESHOLD;

FIFO1_THRESHOLD is defined as 19 in the global header file, so
if you have 2 channels enabled the trigger comes when the FIFO have 10
samples/ch, in case of all 8 channels enabled you will round it down the
trigger comes when you have 2 samples/ch.

Would not be better to try to use high threshold for the FIFO to reduce the
number of DMA requests needed runtime?

It is OK as it is at the moment, but I think it would make sense to try to
maximize the FIFO usage.

> +	/*
> +	 * Make the fifo thresh as the multiple of total number of
> +	 * channels enabled, so make sure that that cyclic DMA period
> +	 * length is also a multiple of total number of channels
> +	 * enabled. This ensures that no invalid data is reported
> +	 * to the stack via iio_push_to_buffers().
> +	 */
> +	dma->fifo_thresh -= (dma->fifo_thresh + 1) % adc_dev->total_ch_enabled;
> +	dma->buf_offset = DMA_BUFFER_SIZE / 2;
> +	/* Make sure that period length is multiple of fifo thresh level */
> +	dma->buf_offset -= dma->buf_offset % ((dma->fifo_thresh + 1) *
> +					      sizeof(u16));
> +
> +	dma->conf.src_maxburst = dma->fifo_thresh + 1;
> +	dmaengine_slave_config(dma->chan, &dma->conf);
> +
> +	desc = dmaengine_prep_dma_cyclic(dma->chan, dma->addr,
> +					 dma->buf_offset * 2,
> +					 dma->buf_offset, DMA_DEV_TO_MEM,

I find the buf_offset name and it's use really confusing. It should be called
period_size, really.

> +					 DMA_PREP_INTERRUPT);
> +	if (!desc)
> +		return -EBUSY;
> +
> +	desc->callback = tiadc_dma_rx_complete;
> +	desc->callback_param = indio_dev;
> +
> +	dma->cookie = dmaengine_submit(desc);
> +
> +	dma_async_issue_pending(dma->chan);
> +
> +	tiadc_writel(adc_dev, REG_FIFO1THR, dma->fifo_thresh);
> +	tiadc_writel(adc_dev, REG_DMA1REQ, dma->fifo_thresh);
> +	tiadc_writel(adc_dev, REG_DMAENABLE_SET, DMA_FIFO1);
> +
> +	return 0;
> +}
> +
>  static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> @@ -218,20 +303,30 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
>  static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	unsigned int enb = 0;
>  	u8 bit;
> +	u32 irq_enable;
>  
>  	tiadc_step_config(indio_dev);
> -	for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels)
> +	for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels) {
>  		enb |= (get_adc_step_bit(adc_dev, bit) << 1);
> +		adc_dev->total_ch_enabled++;
> +	}
>  	adc_dev->buffer_en_ch_steps = enb;
>  
> +	if (dma->chan)
> +		tiadc_start_dma(indio_dev);
> +
>  	am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb);
>  
>  	tiadc_writel(adc_dev,  REG_IRQSTATUS, IRQENB_FIFO1THRES
>  				| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
> -	tiadc_writel(adc_dev,  REG_IRQENABLE, IRQENB_FIFO1THRES
> -				| IRQENB_FIFO1OVRRUN);
> +
> +	irq_enable = IRQENB_FIFO1OVRRUN;
> +	if (!dma->chan)
> +		irq_enable |= IRQENB_FIFO1THRES;
> +	tiadc_writel(adc_dev,  REG_IRQENABLE, irq_enable);
>  
>  	return 0;
>  }
> @@ -239,12 +334,18 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
>  static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	int fifo1count, i, read;
>  
>  	tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
>  				IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
>  	am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps);
>  	adc_dev->buffer_en_ch_steps = 0;
> +	adc_dev->total_ch_enabled = 0;
> +	if (dma->chan) {
> +		tiadc_writel(adc_dev, REG_DMAENABLE_CLEAR, 0x2);
> +		dmaengine_terminate_async(dma->chan);
> +	}
>  
>  	/* Flush FIFO of leftover data in the time it takes to disable adc */
>  	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
> @@ -430,6 +531,50 @@ static const struct iio_info tiadc_info = {
>  	.driver_module = THIS_MODULE,
>  };
>  
> +static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
> +{
> +	return false;
> +}
> +
> +static int tiadc_request_dma(struct platform_device *pdev,
> +			     struct tiadc_device *adc_dev)
> +{
> +	struct tiadc_dma	*dma = &adc_dev->dma;
> +	dma_cap_mask_t		mask;
> +
> +	dma->fn = the_no_dma_filter_fn;
> +
> +	/* Default slave configuration parameters */
> +	dma->conf.direction = DMA_DEV_TO_MEM;
> +	dma->conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +	dma->conf.src_addr = adc_dev->mfd_tscadc->tscadc_phys_base + REG_FIFO1;
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_CYCLIC, mask);
> +
> +	/* Get a channel for RX */
> +	dma->chan = dma_request_slave_channel_compat(mask,
> +						     dma->fn, dma->param,
> +						     adc_dev->mfd_tscadc->dev,
> +						     "fifo1");

dma_request_chan()

> +	if (!dma->chan)
> +		return -ENODEV;
> +
> +	/* RX buffer */
> +	dma->buf = dma_alloc_coherent(dma->chan->device->dev, DMA_BUFFER_SIZE,
> +				      &dma->addr, GFP_KERNEL);
> +	if (!dma->buf)
> +		goto err;
> +
> +	dev_dbg_ratelimited(adc_dev->mfd_tscadc->dev, "got dma channel\n");
> +
> +	return 0;
> +err:
> +	dma_release_channel(dma->chan);
> +
> +	return -ENOMEM;
> +}
> +
>  static int tiadc_parse_dt(struct platform_device *pdev,
>  			  struct tiadc_device *adc_dev)
>  {
> @@ -512,8 +657,14 @@ static int tiadc_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, indio_dev);
>  
> +	err = tiadc_request_dma(pdev, adc_dev);
> +	if (err && err != -ENODEV)
> +		goto err_dma;
> +
>  	return 0;
>  
> +err_dma:
> +	iio_device_unregister(indio_dev);
>  err_buffer_unregister:
>  	tiadc_iio_buffered_hardware_remove(indio_dev);
>  err_free_channels:
> @@ -525,8 +676,11 @@ static int tiadc_remove(struct platform_device *pdev)
>  {
>  	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	u32 step_en;
>  
> +	if (dma->chan)
> +		dma_release_channel(dma->chan);
>  	iio_device_unregister(indio_dev);
>  	tiadc_iio_buffered_hardware_remove(indio_dev);
>  	tiadc_channels_remove(indio_dev);
> diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h
> index e45a208..fb9dc99 100644
> --- a/include/linux/mfd/ti_am335x_tscadc.h
> +++ b/include/linux/mfd/ti_am335x_tscadc.h
> @@ -23,6 +23,8 @@
>  #define REG_IRQENABLE		0x02C
>  #define REG_IRQCLR		0x030
>  #define REG_IRQWAKEUP		0x034
> +#define REG_DMAENABLE_SET	0x038
> +#define REG_DMAENABLE_CLEAR	0x038
>  #define REG_CTRL		0x040
>  #define REG_ADCFSM		0x044
>  #define REG_CLKDIV		0x04C
> @@ -36,6 +38,7 @@
>  #define REG_FIFO0THR		0xE8
>  #define REG_FIFO1CNT		0xF0
>  #define REG_FIFO1THR		0xF4
> +#define REG_DMA1REQ		0xF8
>  #define REG_FIFO0		0x100
>  #define REG_FIFO1		0x200
>  
> @@ -126,6 +129,10 @@
>  #define FIFOREAD_DATA_MASK (0xfff << 0)
>  #define FIFOREAD_CHNLID_MASK (0xf << 16)
>  
> +/* DMA ENABLE/CLEAR Register */
> +#define DMA_FIFO0		BIT(0)
> +#define DMA_FIFO1		BIT(1)
> +
>  /* Sequencer Status */
>  #define SEQ_STATUS BIT(5)
>  #define CHARGE_STEP		0x11
> 


-- 
P?ter

^ permalink raw reply

* [GIT PULL] Allwinner sun4i DRM fixes for 4.9
From: Maxime Ripard @ 2016-09-22  7:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi David,

Here is a bunch of fixes for the previous pull request I sent.

Thanks!
Maxime

The following changes since commit 0c3ff44cc23cbede56aa1ca5916b126e681ca69b:

  drm/sun4i: add missing header dependencies (2016-09-08 14:55:48 +0200)

are available in the git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git tags/sunxi-drm-fixes-for-4.9

for you to fetch changes up to f0188ef8301ccbb128bbfd10751a9aeca8c9172e:

  drm/sun4i: Fix the high buffer address mask (2016-09-22 10:13:22 +0300)

----------------------------------------------------------------
Allwinner sun4i DRM fixes for 4.9

A few fixes for the sun4i drm driver that range, including some fixes that
might prevent multiple planes from working depending on the sequence where
they are enabled.

----------------------------------------------------------------
Chen-Yu Tsai (3):
      drm/sun4i: dotclock: Fix clock rate read back calcation
      drm/sun4i: dotclock: Allow divider = 127
      drm/sun4i: dotclock: Round to closest clock rate

Maxime Ripard (3):
      drm/sun4i: Fix formats usable by the primary plane
      drm/sun4i: tv: Check mode pointer
      drm/sun4i: Fix the high buffer address mask

Ville Syrj?l? (1):
      drm/sun4i: Fix sparse warnings

Wei Yongjun (1):
      drm/sun4i: backend: remove redundant dev_err call in sun4i_backend_bind()

 drivers/gpu/drm/sun4i/sun4i_backend.c  | 13 +++++---
 drivers/gpu/drm/sun4i/sun4i_backend.h  |  4 +--
 drivers/gpu/drm/sun4i/sun4i_dotclock.c |  7 +++--
 drivers/gpu/drm/sun4i/sun4i_layer.c    | 56 +++++++++++++++++++++++-----------
 drivers/gpu/drm/sun4i/sun4i_tv.c       | 46 ++++++++++++++++------------
 5 files changed, 79 insertions(+), 47 deletions(-)

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/42771ce4/attachment.sig>

^ permalink raw reply

* [PATCH v5 3/3] ASoC: sun4i-codec: Add custom regmap configs
From: Danny Milosavljevic @ 2016-09-22  7:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-1-dannym@scratchpost.org>

The A20 has a few extra registers that the A10 doesn't have.
Therefore, use different regmaps for A10 as compared to A20.

Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org>
---
 sound/soc/sunxi/sun4i-codec.c | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 3b53b78..e047ec0 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -682,12 +682,37 @@ static const struct regmap_config sun4i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
+	.max_register	= SUN4I_CODEC_ADC_RXCNT,
+};
+
+static const struct regmap_config sun7i_codec_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
 	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL,
 };
 
+struct sun4i_codec_quirks {
+	const struct regmap_config *regmap_config;
+};
+
+static const struct sun4i_codec_quirks sun4i_codec_quirks = {
+	.regmap_config = &sun4i_codec_regmap_config,
+};
+
+static const struct sun4i_codec_quirks sun7i_codec_quirks = {
+	.regmap_config = &sun7i_codec_regmap_config,
+};
+
 static const struct of_device_id sun4i_codec_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-codec" },
-	{ .compatible = "allwinner,sun7i-a20-codec" },
+	{
+		.compatible = "allwinner,sun4i-a10-codec",
+		.data = &sun4i_codec_quirks,
+	},
+	{
+		.compatible = "allwinner,sun7i-a20-codec",
+		.data = &sun7i_codec_quirks,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
@@ -760,6 +785,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card;
 	struct sun4i_codec *scodec;
+	const struct sun4i_codec_quirks *quirks;
 	struct resource *res;
 	void __iomem *base;
 	int ret;
@@ -777,8 +803,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 		return PTR_ERR(base);
 	}
 
+	quirks = of_device_get_match_data(&pdev->dev);
+	if (quirks == NULL) {
+		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+		return -ENODEV;
+	}
+
 	scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-					     &sun4i_codec_regmap_config);
+					       quirks->regmap_config);
 	if (IS_ERR(scodec->regmap)) {
 		dev_err(&pdev->dev, "Failed to create our regmap\n");
 		return PTR_ERR(scodec->regmap);

^ permalink raw reply related

* [PATCH v5 2/3] ASoC: sun4i-codec: Rename some sun7i-only registers
From: Danny Milosavljevic @ 2016-09-22  7:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-1-dannym@scratchpost.org>

Some of the registers defined in the driver are only usable on the
A20. Rename these registers.

Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org>
---
 sound/soc/sunxi/sun4i-codec.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index c2c0583..3b53b78 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -96,8 +96,8 @@
 /* Other various ADC registers */
 #define SUN4I_CODEC_DAC_TXCNT			(0x30)
 #define SUN4I_CODEC_ADC_RXCNT			(0x34)
-#define SUN4I_CODEC_AC_SYS_VERI			(0x38)
-#define SUN4I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
+#define SUN7I_CODEC_AC_DAC_CAL			(0x38)
+#define SUN7I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
 
 struct sun4i_codec {
 	struct device	*dev;
@@ -682,7 +682,7 @@ static const struct regmap_config sun4i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
-	.max_register	= SUN4I_CODEC_AC_MIC_PHONE_CAL,
+	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL,
 };
 
 static const struct of_device_id sun4i_codec_of_match[] = {

^ permalink raw reply related

* [PATCH v5 1/3] ASoC: sun4i-codec: Rename sun4i_codec_widgets for consistency
From: Danny Milosavljevic @ 2016-09-22  7:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071313.12891-1-dannym@scratchpost.org>

ASoC: sun4i-codec: Rename "sun4i_codec_widgets" to "sun4i_codec_controls" for
consistency with the struct field name.

Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org>
---
 sound/soc/sunxi/sun4i-codec.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 0e19c50..c2c0583 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -509,7 +509,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute =
 
 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
 
-static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
+static const struct snd_kcontrol_new sun4i_codec_controls[] = {
 	SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
 		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
 		       sun4i_codec_pa_volume_scale),
@@ -629,8 +629,8 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
 
 static struct snd_soc_codec_driver sun4i_codec_codec = {
 	.component_driver = {
-		.controls		= sun4i_codec_widgets,
-		.num_controls		= ARRAY_SIZE(sun4i_codec_widgets),
+		.controls		= sun4i_codec_controls,
+		.num_controls		= ARRAY_SIZE(sun4i_codec_controls),
 		.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
 		.dapm_routes		= sun4i_codec_codec_dapm_routes,

^ permalink raw reply related

* [PATCH v5 0/3] ASoC: sun4i-codec: Distinguish sun4i from sun7i
From: Danny Milosavljevic @ 2016-09-22  7:13 UTC (permalink / raw)
  To: linux-arm-kernel

ASoC: sun4i-codec: Introduce mechanism to detect sun7i and provide a
different regmap different compared to sun4i Allwinner A10.
 
The controls will be extended in a forthcoming patch - it is necessary
to distinguish between sun4i and sun7i controls because they have different
registers.
 
Renamed SUN4I_CODEC_AC_SYS_VERI to SUN7I_CODEC_AC_DAC_CAL and renamed
SUN4I_CODEC_AC_MIC_PHONE_CAL to SUN7I_CODEC_AC_MIC_PHONE_CAL because these
are actually not present on Allwinner A10.

Handle quirks by regmap config and codec and select the correct quirks
automatically.  

Danny Milosavljevic (3):
  ASoC: sun4i-codec: rename "sun4i_codec_widgets" to
    "sun4i_codec_controls" for consistency with the struct field name.
  ASoC: rename "SUN4I_CODEC_SYS_VERI" to "SUN7I_CODEC_AC_DAC_CAL";
    rename "SUN4I_CODEC_AC_MIC_PHONE_CAL" to
    "SUN7I_CODEC_AC_MIC_PHONE_CAL".
  ASoC: sun4i-codec: Add custom regmap configs for the A10 and A20
    variants.

 sound/soc/sunxi/sun4i-codec.c | 50 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 9 deletions(-)

^ permalink raw reply

* [patch added to 3.12-stable] arm64: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
From: Jiri Slaby @ 2016-09-22  7:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160922071154.1297-1-jslaby@suse.cz>

From: James Hogan <james.hogan@imgtec.com>

This patch has been added to the 3.12 stable tree. If you have any
objections, please let us know.

===============

commit 3146bc64d12377a74dbda12b96ea32da3774ae07 upstream.

AT_VECTOR_SIZE_ARCH should be defined with the maximum number of
NEW_AUX_ENT entries that ARCH_DLINFO can contain, but it wasn't defined
for arm64 at all even though ARCH_DLINFO will contain one NEW_AUX_ENT
for the VDSO address.

This shouldn't be a problem as AT_VECTOR_SIZE_BASE includes space for
AT_BASE_PLATFORM which arm64 doesn't use, but lets define it now and add
the comment above ARCH_DLINFO as found in several other architectures to
remind future modifiers of ARCH_DLINFO to keep AT_VECTOR_SIZE_ARCH up to
date.

Fixes: f668cd1673aa ("arm64: ELF definitions")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 arch/arm64/include/asm/elf.h         | 1 +
 arch/arm64/include/uapi/asm/auxvec.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index e7fa87f9201b..a4e1758c44dc 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -124,6 +124,7 @@ extern unsigned long randomize_et_dyn(unsigned long base);
 
 #define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO							\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
diff --git a/arch/arm64/include/uapi/asm/auxvec.h b/arch/arm64/include/uapi/asm/auxvec.h
index 22d6d8885854..4cf0c17787a8 100644
--- a/arch/arm64/include/uapi/asm/auxvec.h
+++ b/arch/arm64/include/uapi/asm/auxvec.h
@@ -19,4 +19,6 @@
 /* vDSO location */
 #define AT_SYSINFO_EHDR	33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif
-- 
2.10.0

^ permalink raw reply related

* [PATCH] tty/serial: atmel: fix fractional baud rate computation
From: Uwe Kleine-König @ 2016-09-22  7:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921104414.16241-1-nicolas.ferre@atmel.com>

On Wed, Sep 21, 2016 at 12:44:14PM +0200, Nicolas Ferre wrote:
> From: Alexey Starikovskiy <aystarik@gmail.com>
> 
> The problem with previous code was it rounded values in wrong
> place and produced wrong baud rate in some cases.
> 
> Signed-off-by: Alexey Starikovskiy <aystarik@gmail.com>
> [nicolas.ferre at atmel.com: port to newer kernel and add commit log]
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>  drivers/tty/serial/atmel_serial.c | 10 ++++++----
>  include/linux/atmel_serial.h      |  1 +
>  2 files changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 5f550d9feed9..fd8aa1f4ba78 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -2170,13 +2170,15 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
>  	 * accurately. This feature is enabled only when using normal mode.
>  	 * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8))
>  	 * Currently, OVER is always set to 0 so we get
> -	 * baudrate = selected clock (16 * (CD + FP / 8))
> +	 * baudrate = selected clock / (16 * (CD + FP / 8))
> +	 * then
> +	 * 8 CD + FP = selected clock / (2 * baudrate)
>  	 */
>  	if (atmel_port->has_frac_baudrate &&
>  	    (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) {
> -		div = DIV_ROUND_CLOSEST(port->uartclk, baud);
> -		cd = div / 16;
> -		fp = DIV_ROUND_CLOSEST(div % 16, 2);
> +		div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2);
> +		cd = div >> 3;
> +		fp = div & ATMEL_US_FP_MASK;

given baud = 115200 and uartclk = 5414300 this results in:

	div = DIV_ROUND_CLOSEST(5414300, 115200 * 2) = 23
	cd = 2
	fp = 7

which yields a rate of 5414300 / 46 = 117702.17. With cd = 3 and fp = 0
however the resulting rate is 5414300 / 48 = 112797.92.

Which one is better?

>  	} else {
>  		cd = uart_get_divisor(port, baud);
>  	}
> diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h
> index f8e452aa48d7..bd2560502f3c 100644
> --- a/include/linux/atmel_serial.h
> +++ b/include/linux/atmel_serial.h
> @@ -119,6 +119,7 @@
>  #define ATMEL_US_BRGR		0x20	/* Baud Rate Generator Register */
>  #define	ATMEL_US_CD		GENMASK(15, 0)	/* Clock Divider */
>  #define ATMEL_US_FP_OFFSET	16	/* Fractional Part */
> +#define ATMEL_US_FP_MASK	0x7

Is there another user of this header? If not, this can be folded into
the driver.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* [PATCH] clocksource: bcm2835_timer: Unmap region obtained by of_iomap
From: Eric Anholt @ 2016-09-22  6:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474479237-10356-1-git-send-email-arvind.yadav.cs@gmail.com>

Arvind Yadav <arvind.yadav.cs@gmail.com> writes:

> Free memory mapping, if bcm2835_timer_init is not successful.
>
> Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>

Reviewed-by: Eric Anholt <eric@anholt.net>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/72ec6b9b/attachment.sig>

^ permalink raw reply

* [PATCH] dmaengine: edma: Rename set_bits and remove unused clear_bits helper
From: Peter Ujfalusi @ 2016-09-22  6:31 UTC (permalink / raw)
  To: linux-arm-kernel

The clear_bits() helper is not used by the driver so it can be removed.

powerpc architecture defines the set_bits() in
arch/powerpc/include/asm/bitops.h which results failed compile testing on
powerpc architecture:


>> drivers/dma/edma.c:415:20: error: conflicting types for 'set_bits'
    static inline void set_bits(int offset, int len, unsigned long *p)
                       ^~~~~~~~
   In file included from include/linux/bitops.h:36:0,
                    from include/linux/kernel.h:10,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:17,
                    from include/linux/dmaengine.h:20,
                    from drivers/dma/edma.c:16:
   arch/powerpc/include/asm/bitops.h:75:14: note: previous definition of 'set_bits' was here
    DEFINE_BITOP(set_bits, or, "")
                 ^
   arch/powerpc/include/asm/bitops.h:58:24: note: in definition of macro 'DEFINE_BITOP'
    static __inline__ void fn(unsigned long mask, \
                           ^~


>> drivers/dma/edma.c:421:20: error: conflicting types for 'clear_bits'
    static inline void clear_bits(int offset, int len, unsigned long *p)
                       ^~~~~~~~~~
   In file included from include/linux/bitops.h:36:0,
                    from include/linux/kernel.h:10,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:17,
                    from include/linux/dmaengine.h:20,
                    from drivers/dma/edma.c:16:
   arch/powerpc/include/asm/bitops.h:76:14: note: previous definition of 'clear_bits' was here
    DEFINE_BITOP(clear_bits, andc, "")
                 ^
   arch/powerpc/include/asm/bitops.h:58:24: note: in definition of macro 'DEFINE_BITOP'
    static __inline__ void fn(unsigned long mask, \
                           ^~

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
Hi,

the eDMA/sDMA/ti-crossbar COMPILE_TEST series brought up this issue reported by
Intel kbuild test robot.

Vinod: Should I send a v4 of the COMPILE_TEST series, or is it OK if this patch
goes separately? The compile test failure should not break bisect for PPC...

Regards,
Peter

 drivers/dma/edma.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 0241f39ba64c..1f967545fb33 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -412,18 +412,12 @@ static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no,
 	edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or);
 }

-static inline void set_bits(int offset, int len, unsigned long *p)
+static inline void edma_set_bits(int offset, int len, unsigned long *p)
 {
 	for (; len > 0; len--)
 		set_bit(offset + (len - 1), p);
 }

-static inline void clear_bits(int offset, int len, unsigned long *p)
-{
-	for (; len > 0; len--)
-		clear_bit(offset + (len - 1), p);
-}
-
 static void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no,
 					  int priority)
 {
@@ -2266,7 +2260,7 @@ static int edma_probe(struct platform_device *pdev)
 			for (i = 0; rsv_slots[i][0] != -1; i++) {
 				off = rsv_slots[i][0];
 				ln = rsv_slots[i][1];
-				set_bits(off, ln, ecc->slot_inuse);
+				edma_set_bits(off, ln, ecc->slot_inuse);
 			}
 		}
 	}
--
2.10.0

^ permalink raw reply related

* [PATCH 2/4] drivers: iio: ti_am335x_adc: add dma support
From: Vignesh R @ 2016-09-22  6:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921161134.6951-3-mugunthanvnm@ti.com>



On Wednesday 21 September 2016 09:41 PM, Mugunthan V N wrote:
> This patch adds the required pieces to ti_am335x_adc driver for
> DMA support
> 
> Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
> ---
>  drivers/iio/adc/ti_am335x_adc.c      | 160 ++++++++++++++++++++++++++++++++++-
>  include/linux/mfd/ti_am335x_tscadc.h |   7 ++
>  2 files changed, 164 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> index c3cfacca..89d0b07 100644
> --- a/drivers/iio/adc/ti_am335x_adc.c
> +++ b/drivers/iio/adc/ti_am335x_adc.c
> @@ -30,10 +30,32 @@
>  #include <linux/iio/buffer.h>
>  #include <linux/iio/kfifo_buf.h>
>  
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +
> +#define DMA_BUFFER_SIZE		SZ_2K
> +
> +struct tiadc_dma {
> +	/* Filter function */
> +	dma_filter_fn		fn;
> +	/* Parameter to the filter function */
> +	void			*param;

These will not be needed with newer APIs (see below)

> +	struct dma_slave_config	conf;
> +	struct dma_chan		*chan;
> +	dma_addr_t		addr;
> +	dma_cookie_t		cookie;
> +	u8			*buf;
> +	bool			valid_buf_seg;
> +	int			buf_offset;
> +	u8			fifo_thresh;
> +};
> +
>  struct tiadc_device {
>  	struct ti_tscadc_dev *mfd_tscadc;
> +	struct tiadc_dma dma;
>  	struct mutex fifo1_lock; /* to protect fifo access */
>  	int channels;
> +	int total_ch_enabled;
>  	u8 channel_line[8];
>  	u8 channel_step[8];
>  	int buffer_en_ch_steps;
> @@ -184,6 +206,7 @@ static irqreturn_t tiadc_worker_h(int irq, void *private)
>  	u16 *data = adc_dev->data;
>  
>  	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
> +
>  	for (k = 0; k < fifo1count; k = k + i) {
>  		for (i = 0; i < (indio_dev->scan_bytes)/2; i++) {
>  			read = tiadc_readl(adc_dev, REG_FIFO1);
> @@ -198,6 +221,68 @@ static irqreturn_t tiadc_worker_h(int irq, void *private)
>  	return IRQ_HANDLED;
>  }
>  
> +static void tiadc_dma_rx_complete(void *param)
> +{
> +	struct iio_dev *indio_dev = param;
> +	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
> +	u8 *data;
> +	int i;
> +
> +	data = dma->valid_buf_seg ? dma->buf + dma->buf_offset : dma->buf;
> +	dma->valid_buf_seg = !dma->valid_buf_seg;
> +
> +	for (i = 0; i < dma->buf_offset; i += indio_dev->scan_bytes) {
> +		iio_push_to_buffers(indio_dev, data);
> +		data += indio_dev->scan_bytes;
> +	}
> +}
> +
> +static int tiadc_start_dma(struct iio_dev *indio_dev)
> +{
> +	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
> +	struct dma_async_tx_descriptor *desc;
> +
> +	dma->valid_buf_seg = false;
> +	dma->fifo_thresh = FIFO1_THRESHOLD;
> +	/*
> +	 * Make the fifo thresh as the multiple of total number of
> +	 * channels enabled, so make sure that that cyclic DMA period
> +	 * length is also a multiple of total number of channels
> +	 * enabled. This ensures that no invalid data is reported
> +	 * to the stack via iio_push_to_buffers().
> +	 */
> +	dma->fifo_thresh -= (dma->fifo_thresh + 1) % adc_dev->total_ch_enabled;

Can we use rounddown(FIFO1_THRESHOLD + 1, adc_dev->total_ch_enabled)?

> +	dma->buf_offset = DMA_BUFFER_SIZE / 2;
> +	/* Make sure that period length is multiple of fifo thresh level */
> +	dma->buf_offset -= dma->buf_offset % ((dma->fifo_thresh + 1) *
> +					      sizeof(u16));
> +

Can we use rounddown()?

> +	dma->conf.src_maxburst = dma->fifo_thresh + 1;
> +	dmaengine_slave_config(dma->chan, &dma->conf);
> +
> +	desc = dmaengine_prep_dma_cyclic(dma->chan, dma->addr,
> +					 dma->buf_offset * 2,
> +					 dma->buf_offset, DMA_DEV_TO_MEM,
> +					 DMA_PREP_INTERRUPT);
> +	if (!desc)
> +		return -EBUSY;
> +
> +	desc->callback = tiadc_dma_rx_complete;
> +	desc->callback_param = indio_dev;
> +
> +	dma->cookie = dmaengine_submit(desc);
> +
> +	dma_async_issue_pending(dma->chan);
> +
> +	tiadc_writel(adc_dev, REG_FIFO1THR, dma->fifo_thresh);
> +	tiadc_writel(adc_dev, REG_DMA1REQ, dma->fifo_thresh);
> +	tiadc_writel(adc_dev, REG_DMAENABLE_SET, DMA_FIFO1);
> +
> +	return 0;
> +}
> +
>  static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> @@ -218,20 +303,30 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
>  static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	unsigned int enb = 0;
>  	u8 bit;
> +	u32 irq_enable;
>  
>  	tiadc_step_config(indio_dev);
> -	for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels)
> +	for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels) {
>  		enb |= (get_adc_step_bit(adc_dev, bit) << 1);
> +		adc_dev->total_ch_enabled++;
> +	}
>  	adc_dev->buffer_en_ch_steps = enb;
>  
> +	if (dma->chan)
> +		tiadc_start_dma(indio_dev);
> +
>  	am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb);
>  
>  	tiadc_writel(adc_dev,  REG_IRQSTATUS, IRQENB_FIFO1THRES
>  				| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
> -	tiadc_writel(adc_dev,  REG_IRQENABLE, IRQENB_FIFO1THRES
> -				| IRQENB_FIFO1OVRRUN);
> +
> +	irq_enable = IRQENB_FIFO1OVRRUN;
> +	if (!dma->chan)
> +		irq_enable |= IRQENB_FIFO1THRES;
> +	tiadc_writel(adc_dev,  REG_IRQENABLE, irq_enable);
>  
>  	return 0;
>  }
> @@ -239,12 +334,18 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
>  static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
>  {
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	int fifo1count, i, read;
>  
>  	tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
>  				IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
>  	am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps);
>  	adc_dev->buffer_en_ch_steps = 0;
> +	adc_dev->total_ch_enabled = 0;
> +	if (dma->chan) {
> +		tiadc_writel(adc_dev, REG_DMAENABLE_CLEAR, 0x2);
> +		dmaengine_terminate_async(dma->chan);
> +	}
>  
>  	/* Flush FIFO of leftover data in the time it takes to disable adc */
>  	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
> @@ -430,6 +531,50 @@ static const struct iio_info tiadc_info = {
>  	.driver_module = THIS_MODULE,
>  };
>  
> +static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
> +{
> +	return false;
> +}
> +
> +static int tiadc_request_dma(struct platform_device *pdev,
> +			     struct tiadc_device *adc_dev)
> +{
> +	struct tiadc_dma	*dma = &adc_dev->dma;
> +	dma_cap_mask_t		mask;
> +
> +	dma->fn = the_no_dma_filter_fn;
> +
> +	/* Default slave configuration parameters */
> +	dma->conf.direction = DMA_DEV_TO_MEM;
> +	dma->conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +	dma->conf.src_addr = adc_dev->mfd_tscadc->tscadc_phys_base + REG_FIFO1;
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_CYCLIC, mask);
> +
> +	/* Get a channel for RX */
> +	dma->chan = dma_request_slave_channel_compat(mask,
> +						     dma->fn, dma->param,
> +						     adc_dev->mfd_tscadc->dev,
> +						     "fifo1");

Please use dma_request_chan() API instead, this does not need
dma_filter_fn and probe defer can be handled.

> +	if (!dma->chan)
> +		return -ENODEV;
> +
> +	/* RX buffer */
> +	dma->buf = dma_alloc_coherent(dma->chan->device->dev, DMA_BUFFER_SIZE,
> +				      &dma->addr, GFP_KERNEL);
> +	if (!dma->buf)
> +		goto err;
> +
> +	dev_dbg_ratelimited(adc_dev->mfd_tscadc->dev, "got dma channel\n");

Do we need _ratelimited? AFAICS, this print is called only once.

> +
> +	return 0;
> +err:
> +	dma_release_channel(dma->chan);
> +
> +	return -ENOMEM;
> +}
> +
>  static int tiadc_parse_dt(struct platform_device *pdev,
>  			  struct tiadc_device *adc_dev)
>  {
> @@ -512,8 +657,14 @@ static int tiadc_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, indio_dev);
>  
> +	err = tiadc_request_dma(pdev, adc_dev);
> +	if (err && err != -ENODEV)
> +		goto err_dma;
> +
>  	return 0;
>  
> +err_dma:
> +	iio_device_unregister(indio_dev);
>  err_buffer_unregister:
>  	tiadc_iio_buffered_hardware_remove(indio_dev);
>  err_free_channels:
> @@ -525,8 +676,11 @@ static int tiadc_remove(struct platform_device *pdev)
>  {
>  	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>  	struct tiadc_device *adc_dev = iio_priv(indio_dev);
> +	struct tiadc_dma *dma = &adc_dev->dma;
>  	u32 step_en;
>  
> +	if (dma->chan)
> +		dma_release_channel(dma->chan);

dma_free_coherent() for dma->buf?

>  	iio_device_unregister(indio_dev);
>  	tiadc_iio_buffered_hardware_remove(indio_dev);
>  	tiadc_channels_remove(indio_dev);
> diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h
> index e45a208..fb9dc99 100644
> --- a/include/linux/mfd/ti_am335x_tscadc.h
> +++ b/include/linux/mfd/ti_am335x_tscadc.h
> @@ -23,6 +23,8 @@
>  #define REG_IRQENABLE		0x02C
>  #define REG_IRQCLR		0x030
>  #define REG_IRQWAKEUP		0x034
> +#define REG_DMAENABLE_SET	0x038
> +#define REG_DMAENABLE_CLEAR	0x038
>  #define REG_CTRL		0x040
>  #define REG_ADCFSM		0x044
>  #define REG_CLKDIV		0x04C
> @@ -36,6 +38,7 @@
>  #define REG_FIFO0THR		0xE8
>  #define REG_FIFO1CNT		0xF0
>  #define REG_FIFO1THR		0xF4
> +#define REG_DMA1REQ		0xF8
>  #define REG_FIFO0		0x100
>  #define REG_FIFO1		0x200
>  
> @@ -126,6 +129,10 @@
>  #define FIFOREAD_DATA_MASK (0xfff << 0)
>  #define FIFOREAD_CHNLID_MASK (0xf << 16)
>  
> +/* DMA ENABLE/CLEAR Register */
> +#define DMA_FIFO0		BIT(0)
> +#define DMA_FIFO1		BIT(1)
> +
>  /* Sequencer Status */
>  #define SEQ_STATUS BIT(5)
>  #define CHARGE_STEP		0x11
> 

-- 
Regards
Vignesh

^ permalink raw reply

* [PATCH v2 5/6] misc: sram: add Atmel securam support
From: Greg Kroah-Hartman @ 2016-09-22  5:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921220939.27924-6-alexandre.belloni@free-electrons.com>

On Thu, Sep 22, 2016 at 12:09:38AM +0200, Alexandre Belloni wrote:
> The Atmel secure SRAM is connected to a security module and may be erased
> automatically under certain conditions. For that reason, it is necessary to
> wait for the security module to flag that SRAM accesses are allowed before
> accessing it.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
>  drivers/misc/sram.c | 42 +++++++++++++++++++++++++++++++++++-------
>  1 file changed, 35 insertions(+), 7 deletions(-)

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply

* [PATCH] usb: dwc3: host: inherit dma configuration from parent dev
From: Sriram Dash @ 2016-09-22  5:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20042182.GcPMJken6Z@wuerfel>

>From: Arnd Bergmann [mailto:arnd at arndb.de]
>On Wednesday, September 21, 2016 11:43:59 AM CEST Sriram Dash wrote:
>> >From: Arnd Bergmann [mailto:arnd at arndb.de] On Wednesday, September
>> >21, 2016 11:06:47 AM CEST Sriram Dash wrote:
>>
>> ==============================================================
>> From 8b0dea1513e9e73a11dcfa802ddc71cca11d66f8 Mon Sep 17 00:00:00 2001
>> From: Sriram Dash <sriram.dash@nxp.com>
>> Date: Wed, 21 Sep 2016 11:39:30 +0530
>> Subject: [PATCH] usb: xhci: Fix the patch inherit dma configuration
>> from  parent dev
>>
>> Fixes the patch https://patchwork.kernel.org/patch/9319527/
>> ("usb: dwc3: host: inherit dma configuration from parent dev").
>>
>> Signed-off-by: Sriram Dash <sriram.dash@nxp.com>
>> ---
>>  drivers/usb/host/xhci-mem.c | 12 ++++++------
>>  drivers/usb/host/xhci.c     | 20 ++++++++++----------
>>  2 files changed, 16 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
>> index 6afe323..79608df 100644
>> --- a/drivers/usb/host/xhci-mem.c
>> +++ b/drivers/usb/host/xhci-mem.c
>
>All the changes you did to this file seem fine, I completely missed that part.
>
>> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index
>> 01d96c9..9a1ff09 100644
>> --- a/drivers/usb/host/xhci.c
>> +++ b/drivers/usb/host/xhci.c

Yes. Some sanity is required over this patch.

>> @@ -231,7 +231,7 @@ static int xhci_free_msi(struct xhci_hcd *xhci)
>> static int xhci_setup_msi(struct xhci_hcd *xhci)  {
>>  	int ret;
>> -	struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
>> +	struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.sysdev);
>>
>>  	ret = pci_enable_msi(pdev);
>>  	if (ret) {
>
>This one is interesting as I stumbled over some code comment mentioning that for
>dwc3-pci, we don't support MSI. I think with this change, we /can/ actually support
>MSI, but this could be a separate patch and we'd have to test it on dwc3-pci
>hardware. Same for most of this file.
>
>> @@ -745,7 +745,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
>>  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
>>
>>  	if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
>> -		usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
>> +		usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
>>
>>  	spin_lock_irq(&xhci->lock);
>>  	xhci_halt(xhci);
>
>This seems obviously correct, but I don't yet see why it currently works. We
>probably don't call this function on dwc3.
>
>>  #ifdef CONFIG_PM
>> @@ -3605,7 +3605,7 @@ void xhci_free_dev(struct usb_hcd *hcd, struct
>usb_device *udev)
>>  	 * if no devices remain.
>>  	 */
>>  	if (xhci->quirks & XHCI_RESET_ON_RESUME)
>> -		pm_runtime_put_noidle(hcd->self.controller);
>> +		pm_runtime_put_noidle(hcd->self.sysdev);
>>  #endif
>>
>>  	ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
>
>I suspect this one is wrong, based on what Felipe explained earlier:
>the power management should propagate down from the child to the parent
>device.
>
>Someone who understands this better than I do should look at it.
>
>> @@ -3745,7 +3745,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct
>usb_device *udev)
>>  	 * suspend if there is a device attached.
>>  	 */
>>  	if (xhci->quirks & XHCI_RESET_ON_RESUME)
>> -		pm_runtime_get_noresume(hcd->self.controller);
>> +		pm_runtime_get_noresume(hcd->self.sysdev);
>>  #endif
>>
>>
>
>Same here.
>
>> @@ -4834,7 +4834,7 @@ int xhci_get_frame(struct usb_hcd *hcd)  int
>> xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)  {
>>  	struct xhci_hcd		*xhci;
>> -	struct device		*dev = hcd->self.controller;
>> +	struct device		*dev = hcd->self.sysdev;
>>  	int			retval;
>
>
>This one calls
>
>        get_quirks(dev, xhci);
>
>not sure whether this should be called with self.controller or self.sysdev, we should
>audit every one of the callers here to be sure:
>
>drivers/usb/host/xhci-mtk.c:    return xhci_gen_setup(hcd, xhci_mtk_quirks);
>drivers/usb/host/xhci-pci.c:    retval = xhci_gen_setup(hcd, xhci_pci_quirks);
>drivers/usb/host/xhci-plat.c:   return xhci_gen_setup(hcd, xhci_plat_quirks);
>drivers/usb/host/xhci-rcar.c:    * xhci_gen_setup().
>drivers/usb/host/xhci-tegra.c:  return xhci_gen_setup(hcd, tegra_xhci_quirks);
>
>	Arnd

^ permalink raw reply

* [PATCH v3 7/9] dmaengine: edma: enable COMPILE_TEST
From: kbuild test robot @ 2016-09-22  4:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921124135.11849-8-peter.ujfalusi@ti.com>

Hi Peter,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.8-rc7 next-20160921]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Peter-Ujfalusi/dmaengine-ti-drivers-enable-COMPILE_TESTing/20160921-212008
config: powerpc-allyesconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=powerpc 

All errors (new ones prefixed by >>):

>> drivers/dma/edma.c:415:20: error: conflicting types for 'set_bits'
    static inline void set_bits(int offset, int len, unsigned long *p)
                       ^~~~~~~~
   In file included from include/linux/bitops.h:36:0,
                    from include/linux/kernel.h:10,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:17,
                    from include/linux/dmaengine.h:20,
                    from drivers/dma/edma.c:16:
   arch/powerpc/include/asm/bitops.h:75:14: note: previous definition of 'set_bits' was here
    DEFINE_BITOP(set_bits, or, "")
                 ^
   arch/powerpc/include/asm/bitops.h:58:24: note: in definition of macro 'DEFINE_BITOP'
    static __inline__ void fn(unsigned long mask, \
                           ^~
>> drivers/dma/edma.c:421:20: error: conflicting types for 'clear_bits'
    static inline void clear_bits(int offset, int len, unsigned long *p)
                       ^~~~~~~~~~
   In file included from include/linux/bitops.h:36:0,
                    from include/linux/kernel.h:10,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:17,
                    from include/linux/dmaengine.h:20,
                    from drivers/dma/edma.c:16:
   arch/powerpc/include/asm/bitops.h:76:14: note: previous definition of 'clear_bits' was here
    DEFINE_BITOP(clear_bits, andc, "")
                 ^
   arch/powerpc/include/asm/bitops.h:58:24: note: in definition of macro 'DEFINE_BITOP'
    static __inline__ void fn(unsigned long mask, \
                           ^~

vim +/set_bits +415 drivers/dma/edma.c

d9c345d1 Peter Ujfalusi 2015-10-16  409  static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no,
2b6b3b74 Peter Ujfalusi 2015-10-14  410  				 unsigned or)
2b6b3b74 Peter Ujfalusi 2015-10-14  411  {
2b6b3b74 Peter Ujfalusi 2015-10-14  412  	edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or);
2b6b3b74 Peter Ujfalusi 2015-10-14  413  }
2b6b3b74 Peter Ujfalusi 2015-10-14  414  
2b6b3b74 Peter Ujfalusi 2015-10-14 @415  static inline void set_bits(int offset, int len, unsigned long *p)
2b6b3b74 Peter Ujfalusi 2015-10-14  416  {
2b6b3b74 Peter Ujfalusi 2015-10-14  417  	for (; len > 0; len--)
2b6b3b74 Peter Ujfalusi 2015-10-14  418  		set_bit(offset + (len - 1), p);
2b6b3b74 Peter Ujfalusi 2015-10-14  419  }
2b6b3b74 Peter Ujfalusi 2015-10-14  420  
2b6b3b74 Peter Ujfalusi 2015-10-14 @421  static inline void clear_bits(int offset, int len, unsigned long *p)
2b6b3b74 Peter Ujfalusi 2015-10-14  422  {
2b6b3b74 Peter Ujfalusi 2015-10-14  423  	for (; len > 0; len--)
2b6b3b74 Peter Ujfalusi 2015-10-14  424  		clear_bit(offset + (len - 1), p);

:::::: The code at line 415 was first introduced by commit
:::::: 2b6b3b7420190888793c49e97276e1e73bd7eaed ARM/dmaengine: edma: Merge the two drivers under drivers/dma/

:::::: TO: Peter Ujfalusi <peter.ujfalusi@ti.com>
:::::: CC: Vinod Koul <vinod.koul@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 49928 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160922/316e4457/attachment-0001.gz>

^ permalink raw reply

* [PATCH] arm: ubsan: select ARCH_HAS_UBSAN_SANITIZE_ALL
From: Seung-Woo Kim @ 2016-09-22  4:49 UTC (permalink / raw)
  To: linux-arm-kernel

To enable UBSAN on arm, this patch enables ARCH_HAS_UBSAN_SANITIZE_ALL
from arm confiuration. Basic kernel bootup test is passed on arm with
CONFIG_UBSAN_SANITIZE_ALL enabled.

Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
---
This is resend of the patch I already sent, [1], without RFC tag.
[1] https://patchwork.kernel.org/patch/9189533/

I tested kernel build and basic boot up on Exynos5422, Exynos4412 and
Exynos3250 SoC boards.

At previous time on [1], there were some build error on other systems,
but they were caused by driver bug or gcc bug. So I think UBSAN on ARM
can be re-considered.
---
 arch/arm/Kconfig                  |    1 +
 arch/arm/boot/compressed/Makefile |    1 +
 arch/arm/vdso/Makefile            |    1 +
 3 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a9c4e48..a80f9b1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -7,6 +7,7 @@ config ARM
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAVE_CUSTOM_GPIO_H
 	select ARCH_HAS_GCOV_PROFILE_ALL
+	select ARCH_HAS_UBSAN_SANITIZE_ALL
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_SUPPORTS_ATOMIC_RMW
 	select ARCH_USE_BUILTIN_BSWAP
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index d50430c..883374f 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -23,6 +23,7 @@ OBJS		+= hyp-stub.o
 endif
 
 GCOV_PROFILE		:= n
+UBSAN_SANITIZE		:= n
 
 #
 # Architecture dependencies
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
index 59a8fa7..cb90e59 100644
--- a/arch/arm/vdso/Makefile
+++ b/arch/arm/vdso/Makefile
@@ -28,6 +28,7 @@ CFLAGS_vgettimeofday.o = -O2
 
 # Disable gcov profiling for VDSO code
 GCOV_PROFILE := n
+UBSAN_SANITIZE := n
 
 # Force dependency
 $(obj)/vdso.o : $(obj)/vdso.so
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 5/5] arm64: Add uprobe support
From: Pratyush Anand @ 2016-09-22  3:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921170403.GE12180@e104818-lin.cambridge.arm.com>

On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
> On Wed, Sep 21, 2016 at 04:30:47PM +0530, Pratyush Anand wrote:
> > On 20/09/2016:05:59:46 PM, Catalin Marinas wrote:
> > > > +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
> > > > +		unsigned long addr)
> > > > +{
> > > > +	probe_opcode_t insn;
> > > > +
> > > > +	/* TODO: Currently we do not support AARCH32 instruction probing */
> > > 
> > > Is there a way to check (not necessarily in this file) that we don't
> > > probe 32-bit tasks?
> > 
> > - Well, I do not have complete idea about it that, how it can be done. I think
> >   we can not check that just by looking a single bit in an instruction.
> >   My understanding is that, we can only know about it when we are executing the
> >   instruction, by reading pstate, but that would not be useful for uprobe
> >   instruction analysis.
> >   
> >   I hope, instruction encoding for aarch32 and aarch64 are different, and by
> >   analyzing for all types of aarch32 instructions, we will be able to decide
> >   that whether instruction is 32 bit trace-able or not.  Accordingly, we can use
> >   either BRK or BKPT instruction for breakpoint generation.
> 
> We may have some unrelated instruction encoding overlapping but I
> haven't checked. I was more thinking about whether we know which task is
> being probed and check is_compat_task() or maybe using
> compat_user_mode(regs).

I had thought of this, but problem is that we might not have task in existence
when we enable uprobes.  For example: Lets say we are inserting a trace probe at
offset 0x690 in a executable binary.

echo "p test:0x690" > /sys/kernel/debug/tracing/uprobe_events
echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable

In the 'enable' step, it is decided that whether instruction is traceable or
not. 

(1) But at this point 'test' executable might not be running.
(2) Even if it is running, is_compat_task() or compat_user_mode() might not be
usable, as they work with 'current' task.

What I was thinking that, let it go with 'TODO' as of now. 
Later on, we propose some changes in core layer, so that we can read the elf
headers of executable binary. ELFCLASS will be able to tell us, whether its a 32
bit or 64 bit executable. I think, moving "struct uprobe" from
kernel/events/uprobes.c to a include/linux header file will do the job.  "struct
arch_uprobe" is part of "struct uprobe". "struct arch_uprobe" is passed in
arch_uprobe_analyze_insn(). So, we can access struct uprobe's "inode" element
with this change. 

~Pratyush

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox