[PATCH v4] mailbox/omap: adapt to the new mailbox framework

Jassi Brar jaswinder.singh at linaro.org
Mon Nov 24 01:54:42 PST 2014


On 4 November 2014 at 04:35, Suman Anna <s-anna at ti.com> wrote:
> The OMAP mailbox driver and its existing clients (remoteproc
> for OMAP4+) are adapted to use the generic mailbox framework.
>
> The main changes for the adaptation are:
>   - The tasklet used for Tx is replaced with the state machine from
>     the generic mailbox framework. The workqueue used for processing
>     the received messages stays intact for minimizing the effects on
>     the OMAP mailbox clients.
>   - The existing exported client API, omap_mbox_get, omap_mbox_put and
>     omap_mbox_send_msg are deleted, as the framework provides equivalent
>     functionality. A OMAP-specific omap_mbox_request_channel is added
>     though to support non-DT way of requesting mailboxes.
>   - The OMAP mailbox driver is integrated with the mailbox framework
>     through the proper implementations of mbox_chan_ops, except for
>     .last_tx_done and .peek_data. The OMAP mailbox driver does not need
>     these ops, as it is completely interrupt driven.
>   - The OMAP mailbox driver uses a custom of_xlate controller ops that
>     allows phandles for the pargs specifier instead of indexing to avoid
>     any channel registration order dependencies.
>   - The new framework does not support multiple clients operating on a
>     single channel, so the reference counting logic is simplified.
>   - The remoteproc driver (current client) is adapted to use the new API.
>     The notifier callbacks used within this client is replaced with the
>     regular callbacks from the newer framework.
>   - The exported OMAP mailbox API are limited to omap_mbox_save_ctx,
>     omap_mbox_restore_ctx, omap_mbox_enable_irq & omap_mbox_disable_irq,
>     with the signature modified to take in the new mbox_chan handle instead
>     of the OMAP specific omap_mbox handle. The first 2 will be removed when
>     the OMAP mailbox driver is adapted to runtime_pm. The other exported
>     API omap_mbox_request_channel will be removed once existing legacy
>     users are converted to DT.
>
> Cc: Jassi Brar <jassisinghbrar at gmail.com>
> Cc: Ohad Ben-Cohen <ohad at wizery.com>
> Signed-off-by: Suman Anna <s-anna at ti.com>
> ---
> v3->v4: No code changes, switched the example to use the DSP node instead of
> WkupM3 in the bindings document & minor commit description changes. Other than
> that, this is a repost of the driver adaptation patch [1] from the OMAP Mailbox
> framework adaptation series [2]. This patch is intended for the 3.19 merge window,
> all the dependent patches in [2] are merged as of 3.18-rc2. The DTS patch in [2]
> will be posted separately.
>
> [1] http://marc.info/?l=linux-omap&m=141038453917790&w=2
> [2] http://marc.info/?l=linux-omap&m=141038447817775&w=2
>
>  .../devicetree/bindings/mailbox/omap-mailbox.txt   |  23 ++
>  drivers/mailbox/omap-mailbox.c                     | 346 ++++++++++++---------
>  drivers/remoteproc/omap_remoteproc.c               |  51 +--
>  include/linux/omap-mailbox.h                       |  16 +-
>  4 files changed, 256 insertions(+), 180 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
> index 48edc4b..d1a0433 100644
> --- a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
> +++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
> @@ -43,6 +43,9 @@ Required properties:
>                         device. The format is dependent on which interrupt
>                         controller the OMAP device uses
>  - ti,hwmods:           Name of the hwmod associated with the mailbox
> +- #mbox-cells:         Common mailbox binding property to identify the number
> +                       of cells required for the mailbox specifier. Should be
> +                       1
>  - ti,mbox-num-users:   Number of targets (processor devices) that the mailbox
>                         device can interrupt
>  - ti,mbox-num-fifos:   Number of h/w fifo queues within the mailbox IP block
> @@ -72,6 +75,18 @@ data that represent the following:
>      Cell #3 (usr_id)  - mailbox user id for identifying the interrupt line
>                          associated with generating a tx/rx fifo interrupt.
>
> +Mailbox Users:
> +==============
> +A device needing to communicate with a target processor device should specify
> +them using the common mailbox binding properties, "mboxes" and the optional
> +"mbox-names" (please see Documentation/devicetree/bindings/mailbox/mailbox.txt
> +for details). Each value of the mboxes property should contain a phandle to the
> +mailbox controller device node and an args specifier that will be the phandle to
> +the intended sub-mailbox child node to be used for communication. The equivalent
> +"mbox-names" property value can be used to give a name to the communication channel
> +to be used by the client user.
> +
> +
>  Example:
>  --------
>
> @@ -81,6 +96,7 @@ mailbox: mailbox at 4a0f4000 {
>         reg = <0x4a0f4000 0x200>;
>         interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>         ti,hwmods = "mailbox";
> +       #mbox-cells = <1>;
>         ti,mbox-num-users = <3>;
>         ti,mbox-num-fifos = <8>;
>         mbox_ipu: mbox_ipu {
> @@ -93,12 +109,19 @@ mailbox: mailbox at 4a0f4000 {
>         };
>  };
>
> +dsp {
> +       ...
> +       mboxes = <&mailbox &mbox_dsp>;
> +       ...
> +};
> +
>  /* AM33xx */
>  mailbox: mailbox at 480C8000 {
>         compatible = "ti,omap4-mailbox";
>         reg = <0x480C8000 0x200>;
>         interrupts = <77>;
>         ti,hwmods = "mailbox";
> +       #mbox-cells = <1>;
>         ti,mbox-num-users = <4>;
>         ti,mbox-num-fifos = <8>;
>         mbox_wkupm3: wkup_m3 {
> diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
> index bcc7ee1..66b83ca 100644
> --- a/drivers/mailbox/omap-mailbox.c
> +++ b/drivers/mailbox/omap-mailbox.c
> @@ -29,13 +29,14 @@
>  #include <linux/slab.h>
>  #include <linux/kfifo.h>
>  #include <linux/err.h>
> -#include <linux/notifier.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/platform_data/mailbox-omap.h>
>  #include <linux/omap-mailbox.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/mailbox_client.h>
>
>  #define MAILBOX_REVISION               0x000
>  #define MAILBOX_MESSAGE(m)             (0x040 + 4 * (m))
> @@ -80,7 +81,6 @@ struct omap_mbox_queue {
>         spinlock_t              lock;
>         struct kfifo            fifo;
>         struct work_struct      work;
> -       struct tasklet_struct   tasklet;
>         struct omap_mbox        *mbox;
>         bool full;
>  };
> @@ -92,6 +92,7 @@ struct omap_mbox_device {
>         u32 num_users;
>         u32 num_fifos;
>         struct omap_mbox **mboxes;
> +       struct mbox_controller controller;
>         struct list_head elem;
>  };
>
> @@ -110,15 +111,14 @@ struct omap_mbox_fifo_info {
>  struct omap_mbox {
>         const char              *name;
>         int                     irq;
> -       struct omap_mbox_queue  *txq, *rxq;
> +       struct omap_mbox_queue  *rxq;
>         struct device           *dev;
>         struct omap_mbox_device *parent;
>         struct omap_mbox_fifo   tx_fifo;
>         struct omap_mbox_fifo   rx_fifo;
>         u32                     ctx[OMAP4_MBOX_NR_REGS];
>         u32                     intr_type;
> -       int                     use_count;
> -       struct blocking_notifier_head   notifier;
> +       struct mbox_chan        *chan;
>  };
>
>  /* global variables for the mailbox devices */
> @@ -129,6 +129,14 @@ static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
>  module_param(mbox_kfifo_size, uint, S_IRUGO);
>  MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
>
> +static struct omap_mbox *mbox_chan_to_omap_mbox(struct mbox_chan *chan)
> +{
> +       if (!chan || !chan->con_priv)
> +               return NULL;
> +
> +       return (struct omap_mbox *)chan->con_priv;
> +}
> +
>  static inline
>  unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs)
>  {
> @@ -194,41 +202,14 @@ static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
>         return (int)(enable & status & bit);
>  }
>
> -/*
> - * message sender
> - */
> -int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
> -{
> -       struct omap_mbox_queue *mq = mbox->txq;
> -       int ret = 0, len;
> -
> -       spin_lock_bh(&mq->lock);
> -
> -       if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
> -               ret = -ENOMEM;
> -               goto out;
> -       }
> -
> -       if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) {
> -               mbox_fifo_write(mbox, msg);
> -               goto out;
> -       }
> -
> -       len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
> -       WARN_ON(len != sizeof(msg));
> -
> -       tasklet_schedule(&mbox->txq->tasklet);
> -
> -out:
> -       spin_unlock_bh(&mq->lock);
> -       return ret;
> -}
> -EXPORT_SYMBOL(omap_mbox_msg_send);
> -
> -void omap_mbox_save_ctx(struct omap_mbox *mbox)
> +void omap_mbox_save_ctx(struct mbox_chan *chan)
>  {
>         int i;
>         int nr_regs;
> +       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
> +
> +       if (WARN_ON(!mbox))
> +               return;
>
>         if (mbox->intr_type)
>                 nr_regs = OMAP4_MBOX_NR_REGS;
> @@ -243,10 +224,14 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox)
>  }
>  EXPORT_SYMBOL(omap_mbox_save_ctx);
>
> -void omap_mbox_restore_ctx(struct omap_mbox *mbox)
> +void omap_mbox_restore_ctx(struct mbox_chan *chan)
>  {
>         int i;
>         int nr_regs;
> +       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
> +
> +       if (WARN_ON(!mbox))
> +               return;
>
>         if (mbox->intr_type)
>                 nr_regs = OMAP4_MBOX_NR_REGS;
> @@ -254,14 +239,13 @@ void omap_mbox_restore_ctx(struct omap_mbox *mbox)
>                 nr_regs = MBOX_NR_REGS;
>         for (i = 0; i < nr_regs; i++) {
>                 mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32));
> -
>                 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
>                         i, mbox->ctx[i]);
>         }
>  }
>  EXPORT_SYMBOL(omap_mbox_restore_ctx);
>
> -void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
> +static void _omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
>  {
>         u32 l;
>         struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
> @@ -273,9 +257,8 @@ void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
>         l |= bit;
>         mbox_write_reg(mbox->parent, l, irqenable);
>  }
> -EXPORT_SYMBOL(omap_mbox_enable_irq);
>
> -void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
> +static void _omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
>  {
>         struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
>                                 &mbox->tx_fifo : &mbox->rx_fifo;
> @@ -291,28 +274,28 @@ void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
>
>         mbox_write_reg(mbox->parent, bit, irqdisable);
>  }
> -EXPORT_SYMBOL(omap_mbox_disable_irq);
>
> -static void mbox_tx_tasklet(unsigned long tx_data)
> +void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
>  {
> -       struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
> -       struct omap_mbox_queue *mq = mbox->txq;
> -       mbox_msg_t msg;
> -       int ret;
> +       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
>
> -       while (kfifo_len(&mq->fifo)) {
> -               if (mbox_fifo_full(mbox)) {
> -                       omap_mbox_enable_irq(mbox, IRQ_TX);
> -                       break;
> -               }
> +       if (WARN_ON(!mbox))
> +               return;
>
> -               ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
> -                                                               sizeof(msg));
> -               WARN_ON(ret != sizeof(msg));
> +       _omap_mbox_enable_irq(mbox, irq);
> +}
> +EXPORT_SYMBOL(omap_mbox_enable_irq);
>
> -               mbox_fifo_write(mbox, msg);
> -       }
> +void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
> +{
> +       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
> +
> +       if (WARN_ON(!mbox))
> +               return;
> +
> +       _omap_mbox_disable_irq(mbox, irq);
>  }
> +EXPORT_SYMBOL(omap_mbox_disable_irq);
>
>  /*
>   * Message receiver(workqueue)
> @@ -328,12 +311,11 @@ static void mbox_rx_work(struct work_struct *work)
>                 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
>                 WARN_ON(len != sizeof(msg));
>
> -               blocking_notifier_call_chain(&mq->mbox->notifier, len,
> -                                                               (void *)msg);
> +               mbox_chan_received_data(mq->mbox->chan, (void *)msg);
>                 spin_lock_irq(&mq->lock);
>                 if (mq->full) {
>                         mq->full = false;
> -                       omap_mbox_enable_irq(mq->mbox, IRQ_RX);
> +                       _omap_mbox_enable_irq(mq->mbox, IRQ_RX);
>                 }
>                 spin_unlock_irq(&mq->lock);
>         }
> @@ -344,9 +326,9 @@ static void mbox_rx_work(struct work_struct *work)
>   */
>  static void __mbox_tx_interrupt(struct omap_mbox *mbox)
>  {
> -       omap_mbox_disable_irq(mbox, IRQ_TX);
> +       _omap_mbox_disable_irq(mbox, IRQ_TX);
>         ack_mbox_irq(mbox, IRQ_TX);
> -       tasklet_schedule(&mbox->txq->tasklet);
> +       mbox_chan_txdone(mbox->chan, 0);
>  }
>
>  static void __mbox_rx_interrupt(struct omap_mbox *mbox)
> @@ -357,7 +339,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
>
>         while (!mbox_fifo_empty(mbox)) {
>                 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
> -                       omap_mbox_disable_irq(mbox, IRQ_RX);
> +                       _omap_mbox_disable_irq(mbox, IRQ_RX);
>                         mq->full = true;
>                         goto nomem;
>                 }
> @@ -388,11 +370,13 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
>  }
>
>  static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
> -                                       void (*work) (struct work_struct *),
> -                                       void (*tasklet)(unsigned long))
> +                                       void (*work)(struct work_struct *))
>  {
>         struct omap_mbox_queue *mq;
>
> +       if (!work)
> +               return NULL;
> +
>         mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
>         if (!mq)
>                 return NULL;
> @@ -402,12 +386,9 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
>         if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
>                 goto error;
>
> -       if (work)
> -               INIT_WORK(&mq->work, work);
> -
> -       if (tasklet)
> -               tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
> +       INIT_WORK(&mq->work, work);
>         return mq;
> +
>  error:
>         kfree(mq);
>         return NULL;
> @@ -423,71 +404,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
>  {
>         int ret = 0;
>         struct omap_mbox_queue *mq;
> -       struct omap_mbox_device *mdev = mbox->parent;
>
> -       mutex_lock(&mdev->cfg_lock);
> -       ret = pm_runtime_get_sync(mdev->dev);
> -       if (unlikely(ret < 0))
> -               goto fail_startup;
> -
> -       if (!mbox->use_count++) {
> -               mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
> -               if (!mq) {
> -                       ret = -ENOMEM;
> -                       goto fail_alloc_txq;
> -               }
> -               mbox->txq = mq;
> +       mq = mbox_queue_alloc(mbox, mbox_rx_work);
> +       if (!mq)
> +               return -ENOMEM;
> +       mbox->rxq = mq;
> +       mq->mbox = mbox;
> +
> +       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
> +                         mbox->name, mbox);
> +       if (unlikely(ret)) {
> +               pr_err("failed to register mailbox interrupt:%d\n", ret);
> +               goto fail_request_irq;
> +       }
>
> -               mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
> -               if (!mq) {
> -                       ret = -ENOMEM;
> -                       goto fail_alloc_rxq;
> -               }
> -               mbox->rxq = mq;
> -               mq->mbox = mbox;
> -               ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
> -                                                       mbox->name, mbox);
> -               if (unlikely(ret)) {
> -                       pr_err("failed to register mailbox interrupt:%d\n",
> -                                                                       ret);
> -                       goto fail_request_irq;
> -               }
> +       _omap_mbox_enable_irq(mbox, IRQ_RX);
>
> -               omap_mbox_enable_irq(mbox, IRQ_RX);
> -       }
> -       mutex_unlock(&mdev->cfg_lock);
>         return 0;
>
>  fail_request_irq:
>         mbox_queue_free(mbox->rxq);
> -fail_alloc_rxq:
> -       mbox_queue_free(mbox->txq);
> -fail_alloc_txq:
> -       pm_runtime_put_sync(mdev->dev);
> -       mbox->use_count--;
> -fail_startup:
> -       mutex_unlock(&mdev->cfg_lock);
>         return ret;
>  }
>
>  static void omap_mbox_fini(struct omap_mbox *mbox)
>  {
> -       struct omap_mbox_device *mdev = mbox->parent;
> -
> -       mutex_lock(&mdev->cfg_lock);
> -
> -       if (!--mbox->use_count) {
> -               omap_mbox_disable_irq(mbox, IRQ_RX);
> -               free_irq(mbox->irq, mbox);
> -               tasklet_kill(&mbox->txq->tasklet);
> -               flush_work(&mbox->rxq->work);
> -               mbox_queue_free(mbox->txq);
> -               mbox_queue_free(mbox->rxq);
> -       }
> -
> -       pm_runtime_put_sync(mdev->dev);
> -
> -       mutex_unlock(&mdev->cfg_lock);
> +       _omap_mbox_disable_irq(mbox, IRQ_RX);
> +       free_irq(mbox->irq, mbox);
> +       flush_work(&mbox->rxq->work);
> +       mbox_queue_free(mbox->rxq);
>  }
>
>  static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
> @@ -509,42 +454,55 @@ static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
>         return mbox;
>  }
>
> -struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
> +struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl,
> +                                           const char *chan_name)
>  {
> +       struct device *dev = cl->dev;
>         struct omap_mbox *mbox = NULL;
>         struct omap_mbox_device *mdev;
> +       struct mbox_chan *chan;
> +       unsigned long flags;
>         int ret;
>
> +       if (!dev)
> +               return ERR_PTR(-ENODEV);
> +
> +       if (dev->of_node) {
> +               pr_err("%s: please use mbox_request_channel(), this API is supported only for OMAP non-DT usage\n",
> +                      __func__);
> +               return ERR_PTR(-ENODEV);
> +       }
> +
>         mutex_lock(&omap_mbox_devices_lock);
>         list_for_each_entry(mdev, &omap_mbox_devices, elem) {
> -               mbox = omap_mbox_device_find(mdev, name);
> +               mbox = omap_mbox_device_find(mdev, chan_name);
>                 if (mbox)
>                         break;
>         }
>         mutex_unlock(&omap_mbox_devices_lock);
>
> -       if (!mbox)
> +       if (!mbox || !mbox->chan)
>                 return ERR_PTR(-ENOENT);
>
> -       if (nb)
> -               blocking_notifier_chain_register(&mbox->notifier, nb);
> +       chan = mbox->chan;
> +       spin_lock_irqsave(&chan->lock, flags);
> +       chan->msg_free = 0;
> +       chan->msg_count = 0;
> +       chan->active_req = NULL;
> +       chan->cl = cl;
> +       init_completion(&chan->tx_complete);
> +       spin_unlock_irqrestore(&chan->lock, flags);
>
> -       ret = omap_mbox_startup(mbox);
> +       ret = chan->mbox->ops->startup(chan);
>         if (ret) {
> -               blocking_notifier_chain_unregister(&mbox->notifier, nb);
> -               return ERR_PTR(-ENODEV);
> +               pr_err("Unable to startup the chan (%d)\n", ret);
> +               mbox_free_channel(chan);
> +               chan = ERR_PTR(ret);
>         }
>
> -       return mbox;
> -}
> -EXPORT_SYMBOL(omap_mbox_get);
> -
> -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
> -{
> -       blocking_notifier_chain_unregister(&mbox->notifier, nb);
> -       omap_mbox_fini(mbox);
> +       return chan;
>  }
> -EXPORT_SYMBOL(omap_mbox_put);
> +EXPORT_SYMBOL(omap_mbox_request_channel);
>
Why not mbox_request_channel()?
And what about other 4 exports - omap_mbox_{save_ctx, restore_ctx,
enable_irq & disable_irq} ?

-Jassi



More information about the linux-arm-kernel mailing list