lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAKrE-KcorYUZOpUOaU7qcBbyJ+FHUFZN_r+paMrL7gq+052RwQ@mail.gmail.com>
Date:	Wed, 19 Mar 2014 09:30:30 +0530
From:	Girish KS <girishks2000@...il.com>
To:	Jassi Brar <jassisinghbrar@...il.com>
Cc:	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
	gregkh@...uxfoundation.org, "Anna, Suman" <s-anna@...com>,
	tony@...mide.com, omar.ramirez@...itl.com, loic.pallardy@...com,
	lftan.linux@...il.com, slapdau@...oo.com.au,
	courtney.cavin@...ymobile.com, rafael.j.wysocki@...el.com,
	robherring2@...il.com, arnd@...db.de, joshc@...eaurora.org,
	linus.walleij@...aro.org, galak@...eaurora.org,
	"ks.giri@...sung.com" <ks.giri@...sung.com>,
	Jassi Brar <jaswinder.singh@...aro.org>
Subject: Re: [PATCHv4 2/5] mailbox: Introduce framework for mailbox

On Wed, Mar 19, 2014 at 12:15 AM, Jassi Brar <jassisinghbrar@...il.com> wrote:
> Introduce common framework for client/protocol drivers and
> controller drivers of Inter-Processor-Communication (IPC).
>
> Client driver developers should have a look at
>  include/linux/mailbox_client.h to understand the part of
> the API exposed to client drivers.
> Similarly controller driver developers should have a look
> at include/linux/mailbox_controller.h
>
> Signed-off-by: Jassi Brar <jaswinder.singh@...aro.org>
> ---
>  drivers/mailbox/Makefile           |   4 +
>  drivers/mailbox/mailbox.c          | 589 +++++++++++++++++++++++++++++++++++++
>  include/linux/mailbox.h            |  18 ++
>  include/linux/mailbox_client.h     |  48 +++
>  include/linux/mailbox_controller.h |  85 ++++++
>  5 files changed, 744 insertions(+)
>  create mode 100644 drivers/mailbox/mailbox.c
>  create mode 100644 include/linux/mailbox.h
>  create mode 100644 include/linux/mailbox_client.h
>  create mode 100644 include/linux/mailbox_controller.h
>
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> index e0facb3..2fa343a 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -1,3 +1,7 @@
> +# Generic MAILBOX API
> +
> +obj-$(CONFIG_MAILBOX)          += mailbox.o
> +
>  obj-$(CONFIG_PL320_MBOX)       += pl320-ipc.o
>
>  obj-$(CONFIG_OMAP_MBOX)                += omap-mailbox.o
> diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> new file mode 100644
> index 0000000..79d576e
> --- /dev/null
> +++ b/drivers/mailbox/mailbox.c
> @@ -0,0 +1,589 @@
> +/*
> + * Mailbox: Common code for Mailbox controllers and users
> + *
> + * Copyright (C) 2014 Linaro Ltd.
> + * Author: Jassi Brar <jassisinghbrar@...il.com>
> + *
> + * 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.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/spinlock.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/mailbox_controller.h>
> +
> +/*
> + * The length of circular buffer for queuing messages from a client.
> + * 'msg_count' tracks the number of buffered messages while 'msg_free'
> + * is the index where the next message would be buffered.
> + * We shouldn't need it too big because every transferr is interrupt
> + * triggered and if we have lots of data to transfer, the interrupt
> + * latencies are going to be the bottleneck, not the buffer length.
> + * Besides, mbox_send_message could be called from atomic context and
> + * the client could also queue another message from the notifier 'tx_done'
> + * of the last transfer done.
> + * REVIST: If too many platforms see the "Try increasing MBOX_TX_QUEUE_LEN"
> + * print, it needs to be taken from config option or somesuch.
> + */
> +#define MBOX_TX_QUEUE_LEN      20
> +
> +#define TXDONE_BY_IRQ  (1 << 0) /* controller has remote RTR irq */
> +#define TXDONE_BY_POLL (1 << 1) /* controller can read status of last TX */
> +#define TXDONE_BY_ACK  (1 << 2) /* S/W ACK recevied by Client ticks the TX */
> +
> +struct mbox_chan {
> +       char name[16]; /* Physical link's name */
> +       struct mbox_con *con; /* Parent Controller */
> +       unsigned txdone_method;
> +
> +       /* Physical links */
> +       struct mbox_link *link;
> +       struct mbox_link_ops *link_ops;
> +
> +       /* client */
> +       struct mbox_client *cl;
> +       struct completion tx_complete;
> +
> +       void *active_req;
> +       unsigned msg_count, msg_free;
> +       void *msg_data[MBOX_TX_QUEUE_LEN];
> +       /* Access to the channel */
> +       spinlock_t lock;
> +       /* Hook to add to the controller's list of channels */
> +       struct list_head node;
> +       /* Notifier to all clients waiting on aquiring this channel */
> +       struct blocking_notifier_head avail;
> +} __aligned(32);
> +
> +/* Internal representation of a controller */
> +struct mbox_con {
> +       struct device *dev;
> +       char name[16]; /* controller_name */
> +       struct list_head channels;
> +       /*
> +        * If the controller supports only TXDONE_BY_POLL,
> +        * this timer polls all the links for txdone.
> +        */
> +       struct timer_list poll;
> +       unsigned period;
> +       /* Hook to add to the global controller list */
> +       struct list_head node;
> +} __aligned(32);
> +
> +static LIST_HEAD(mbox_cons);
> +static DEFINE_MUTEX(con_mutex);
> +
> +static int _add_to_rbuf(struct mbox_chan *chan, void *mssg)
> +{
> +       int idx;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&chan->lock, flags);
> +
> +       /* See if there is any space left */
> +       if (chan->msg_count == MBOX_TX_QUEUE_LEN) {
> +               spin_unlock_irqrestore(&chan->lock, flags);
> +               return -ENOMEM;
> +       }
> +
> +       idx = chan->msg_free;
> +       chan->msg_data[idx] = mssg;
> +       chan->msg_count++;
> +
> +       if (idx == MBOX_TX_QUEUE_LEN - 1)
> +               chan->msg_free = 0;
> +       else
> +               chan->msg_free++;
> +
> +       spin_unlock_irqrestore(&chan->lock, flags);
> +
> +       return idx;
> +}
> +
> +static void _msg_submit(struct mbox_chan *chan)
> +{
> +       struct mbox_link *link = chan->link;
> +       unsigned count, idx;
> +       unsigned long flags;
> +       void *data;
> +       int err;
> +
> +       spin_lock_irqsave(&chan->lock, flags);
> +
> +       if (!chan->msg_count || chan->active_req) {
> +               spin_unlock_irqrestore(&chan->lock, flags);
> +               return;
> +       }
> +
> +       count = chan->msg_count;
> +       idx = chan->msg_free;
> +       if (idx >= count)
> +               idx -= count;
> +       else
> +               idx += MBOX_TX_QUEUE_LEN - count;
> +
> +       data = chan->msg_data[idx];
> +
> +       /* Try to submit a message to the MBOX controller */
> +       err = chan->link_ops->send_data(link, data);
> +       if (!err) {
> +               chan->active_req = data;
> +               chan->msg_count--;
> +       }
> +
> +       spin_unlock_irqrestore(&chan->lock, flags);
> +}
> +
> +static void tx_tick(struct mbox_chan *chan, enum mbox_result r)
> +{
> +       unsigned long flags;
> +       void *mssg;
> +
> +       spin_lock_irqsave(&chan->lock, flags);
> +       mssg = chan->active_req;
> +       chan->active_req = NULL;
> +       spin_unlock_irqrestore(&chan->lock, flags);
> +
> +       /* Submit next message */
> +       _msg_submit(chan);
> +
> +       /* Notify the client */
> +       if (chan->cl->tx_block)
> +               complete(&chan->tx_complete);
> +       else if (mssg && chan->cl->tx_done)
> +               chan->cl->tx_done(chan->cl, mssg, r);
> +}
> +
> +static void poll_txdone(unsigned long data)
> +{
> +       struct mbox_con *con = (struct mbox_con *)data;
> +       bool txdone, resched = false;
> +       struct mbox_chan *chan;
> +
> +       list_for_each_entry(chan, &con->channels, node) {
> +               if (chan->active_req && chan->cl) {
> +                       resched = true;
> +                       txdone = chan->link_ops->last_tx_done(chan->link);
> +                       if (txdone)
> +                               tx_tick(chan, MBOX_OK);
> +               }
> +       }
> +
> +       if (resched)
> +               mod_timer(&con->poll,
> +                       jiffies + msecs_to_jiffies(con->period));
> +}
> +
> +/**
> + * mbox_link_received_data - A way for controller driver to push data
> + *                             received from remote to the upper layer.
> + * @link: Pointer to the mailbox link on which RX happened.
> + * @data: Client specific message typecasted as void *
> + *
> + * After startup and before shutdown any data received on the link
> + * is passed on to the API via atomic mbox_link_received_data().
> + * The controller should ACK the RX only after this call returns.
> + */
> +void mbox_link_received_data(struct mbox_link *link, void *mssg)
> +{
> +       struct mbox_chan *chan = (struct mbox_chan *)link->api_priv;
> +
> +       /* No buffering the received data */
> +       if (chan->cl->rx_callback)
> +               chan->cl->rx_callback(chan->cl, mssg);
> +}
> +EXPORT_SYMBOL_GPL(mbox_link_received_data);
> +
> +/**
> + * mbox_link_txdone - A way for controller driver to notify the
> + *                     framework that the last TX has completed.
> + * @link: Pointer to the mailbox link on which TX happened.
> + * @r: Status of last TX - OK or ERROR
> + *
> + * The controller that has IRQ for TX ACK calls this atomic API
> + * to tick the TX state machine. It works only if txdone_irq
> + * is set by the controller.
> + */
> +void mbox_link_txdone(struct mbox_link *link, enum mbox_result r)
> +{
> +       struct mbox_chan *chan = (struct mbox_chan *)link->api_priv;
> +
> +       if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) {
> +               pr_err("Controller can't run the TX ticker\n");
> +               return;
> +       }
> +
> +       tx_tick(chan, r);
> +}
> +EXPORT_SYMBOL_GPL(mbox_link_txdone);
> +
> +/**
> + * mbox_client_txdone - The way for a client to run the TX state machine.
> + * @chan: Mailbox channel assigned to this client.
> + * @r: Success status of last transmission.
> + *
> + * The client/protocol had received some 'ACK' packet and it notifies
> + * the API that the last packet was sent successfully. This only works
> + * if the controller can't sense TX-Done.
> + */
> +void mbox_client_txdone(struct mbox_chan *chan, enum mbox_result r)
> +{
> +       if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) {
> +               pr_err("Client can't run the TX ticker\n");
> +               return;
> +       }
> +
> +       tx_tick(chan, r);
> +}
> +EXPORT_SYMBOL_GPL(mbox_client_txdone);
> +
> +/**
> + * mbox_send_message - For client to submit a message to be
> + *                             sent to the remote.
> + * @chan: Mailbox channel assigned to this client.
> + * @mssg: Client specific message typecasted.
> + *
> + * For client to submit data to the controller destined for a remote
> + * processor. If the client had set 'tx_block', the call will return
> + * either when the remote receives the data or when 'tx_tout' millisecs
> + * run out.
> + *  In non-blocking mode, the requests are buffered by the API and a
> + * non-negative token is returned for each queued request. If the request
> + * is not queued, a negative token is returned. Upon failure or successful
> + * TX, the API calls 'tx_done' from atomic context, from which the client
> + * could submit yet another request.
> + *  In blocking mode, 'tx_done' is not called, effectively making the
> + * queue length 1.
> + * The pointer to message should be preserved until it is sent
> + * over the link, i.e, tx_done() is made.
> + * This function could be called from atomic context as it simply
> + * queues the data and returns a token against the request.
> + *
> + * Return: Non-negative integer for successful submission (non-blocking mode)
> + *     or transmission over link (blocking mode).
> + *     Negative value denotes failure.
> + */
> +int mbox_send_message(struct mbox_chan *chan, void *mssg)
> +{
> +       int t;
> +
> +       if (!chan || !chan->cl)
> +               return -EINVAL;
> +
> +       t = _add_to_rbuf(chan, mssg);
> +       if (t < 0) {
> +               pr_err("Try increasing MBOX_TX_QUEUE_LEN\n");
> +               return t;
> +       }
> +
> +       _msg_submit(chan);
> +
> +       if (chan->txdone_method == TXDONE_BY_POLL)
> +               poll_txdone((unsigned long)chan->con);

I came across a panic in the complete function. When i traced bact the
call sequence it was
When a client sets chan->cl->tx_block = true, and polling is enabled
for controller.
1.Client sends the message with  mbox_send_message. This function as
seen above will call __msg_submit (this calls the controller specific
send function).
2. Since the tx method is polling the above condition is satisfied and
calls the poll_txdone function.
3. In this poll function, the tx_tick function is invoked.
4. In this tick function since the client has enabled the tx_block it
calls the notify function complete(&chan->tx_complete);
5. Here there is a panic. because the complete is called before
initialization. init_completion needs to be called but not called.

> +
> +       if (chan->cl->tx_block && chan->active_req) {
> +               int ret;
> +               init_completion(&chan->tx_complete);
> +               ret = wait_for_completion_timeout(&chan->tx_complete,
> +                       chan->cl->tx_tout);
> +               if (ret == 0) {
> +                       t = -EIO;
> +                       tx_tick(chan, MBOX_ERR);
> +               }
> +       }
> +
> +       return t;
> +}
> +EXPORT_SYMBOL_GPL(mbox_send_message);
> +
> +/**
> + * mbox_request_channel - Request a mailbox channel.
> + * @cl: Identity of the client requesting the channel.
> + *
> + * The Client specifies its requirements and capabilities while asking for
> + * a mailbox channel by name. It can't be called from atomic context.
> + * The channel is exclusively allocated and can't be used by another
> + * client before the owner calls mbox_free_channel.
> + * After assignment, any packet received on this channel will be
> + * handed over to the client via the 'rx_callback'.
> + *
> + * Return: Pointer to the channel assigned to the client if successful.
> + *             ERR_PTR for request failure.
> + */
> +struct mbox_chan *mbox_request_channel(struct mbox_client *cl)
> +{
> +       struct mbox_chan *chan;
> +       struct mbox_con *con;
> +       unsigned long flags;
> +       char *con_name;
> +       int len, ret;
> +
> +       con_name = cl->chan_name;
> +       len = strcspn(cl->chan_name, ":");
> +
> +       ret = 0;
> +       mutex_lock(&con_mutex);
> +       list_for_each_entry(con, &mbox_cons, node)
> +               if (!strncmp(con->name, con_name, len)) {
> +                       ret = 1;
> +                       break;
> +               }
> +       mutex_unlock(&con_mutex);
> +
> +       if (!ret) {
> +               pr_info("Channel(%s) not found!\n", cl->chan_name);
> +               return ERR_PTR(-ENODEV);
> +       }
> +
> +       ret = 0;
> +       list_for_each_entry(chan, &con->channels, node) {
> +               if (!chan->cl &&
> +                               !strcmp(con_name + len + 1, chan->name) &&
> +                               try_module_get(con->dev->driver->owner)) {
> +                       spin_lock_irqsave(&chan->lock, flags);
> +                       chan->msg_free = 0;
> +                       chan->msg_count = 0;
> +                       chan->active_req = NULL;
> +                       chan->cl = cl;
> +                       if (!cl->tx_tout) /* wait for ever */
> +                               cl->tx_tout = msecs_to_jiffies(3600000);
> +                       else
> +                               cl->tx_tout = msecs_to_jiffies(cl->tx_tout);
> +                       if (chan->txdone_method == TXDONE_BY_POLL
> +                                       && cl->knows_txdone)
> +                               chan->txdone_method |= TXDONE_BY_ACK;
> +                       spin_unlock_irqrestore(&chan->lock, flags);
> +                       ret = 1;
> +                       break;
> +               }
> +       }
> +
> +       if (!ret) {
> +               pr_err("Unable to assign mailbox(%s)\n", cl->chan_name);
> +               return ERR_PTR(-EBUSY);
> +       }
> +
> +       ret = chan->link_ops->startup(chan->link, cl->link_data);
> +       if (ret) {
> +               pr_err("Unable to startup the link\n");
> +               mbox_free_channel(chan);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return chan;
> +}
> +EXPORT_SYMBOL_GPL(mbox_request_channel);
> +
> +/**
> + * mbox_free_channel - The client relinquishes control of a mailbox
> + *                     channel by this call.
> + * @chan: The mailbox channel to be freed.
> + */
> +void mbox_free_channel(struct mbox_chan *chan)
> +{
> +       unsigned long flags;
> +
> +       if (!chan || !chan->cl)
> +               return;
> +
> +       chan->link_ops->shutdown(chan->link);
> +
> +       /* The queued TX requests are simply aborted, no callbacks are made */
> +       spin_lock_irqsave(&chan->lock, flags);
> +       chan->cl = NULL;
> +       chan->active_req = NULL;
> +       if (chan->txdone_method == (TXDONE_BY_POLL | TXDONE_BY_ACK))
> +               chan->txdone_method = TXDONE_BY_POLL;
> +
> +       module_put(chan->con->dev->driver->owner);
> +
> +       spin_unlock_irqrestore(&chan->lock, flags);
> +
> +       blocking_notifier_call_chain(&chan->avail, 0, NULL);
> +}
> +EXPORT_SYMBOL_GPL(mbox_free_channel);
> +
> +static struct mbox_chan *name_to_chan(const char *name)
> +{
> +       struct mbox_chan *chan = NULL;
> +       struct mbox_con *con;
> +       int len, found = 0;
> +
> +       len = strcspn(name, ":");
> +
> +       mutex_lock(&con_mutex);
> +
> +       list_for_each_entry(con, &mbox_cons, node) {
> +               if (!strncmp(con->name, name, len)) {
> +                       list_for_each_entry(chan, &con->channels, node) {
> +                               if (!strcmp(name + len + 1, chan->name)) {
> +                                       found = 1;
> +                                       goto done;
> +                               }
> +                       }
> +               }
> +       }
> +done:
> +       mutex_unlock(&con_mutex);
> +
> +       if (!found)
> +               return NULL;
> +
> +       return chan;
> +}
> +
> +/**
> + * mbox_notify_chan_register - The client may ask the framework to be
> + *              notified when a particular channel becomes available
> + *              to be acquired again.
> + * @name: Name of the mailbox channel the client is interested in.
> + * @nb:        Pointer to the notifier.
> + */
> +int mbox_notify_chan_register(const char *name, struct notifier_block *nb)
> +{
> +       struct mbox_chan *chan = name_to_chan(name);
> +
> +       if (chan && nb)
> +               return blocking_notifier_chain_register(&chan->avail, nb);
> +
> +       return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(mbox_notify_chan_register);
> +
> +/**
> + * mbox_notify_chan_unregister - The client is no more interested in channel.
> + *
> + * @name: Name of the mailbox channel the client was interested in.
> + * @nb: Pointer to the notifier.
> + */
> +void mbox_notify_chan_unregister(const char *name, struct notifier_block *nb)
> +{
> +       struct mbox_chan *chan = name_to_chan(name);
> +
> +       if (chan && nb)
> +               blocking_notifier_chain_unregister(&chan->avail, nb);
> +}
> +EXPORT_SYMBOL_GPL(mbox_notify_chan_unregister);
> +
> +/**
> + * mbox_controller_register - Register the mailbox controller
> + * @mbox_con:  Pointer to the mailbox controller.
> + *
> + * The controller driver registers its communication links to the
> + * global pool managed by the common framework.
> + */
> +int mbox_controller_register(struct mbox_controller *mbox)
> +{
> +       int i, num_links, txdone;
> +       struct mbox_chan *chan;
> +       struct mbox_con *con;
> +
> +       /* Sanity check */
> +       if (!mbox || !mbox->ops)
> +               return -EINVAL;
> +
> +       for (i = 0; mbox->links[i]; i++)
> +               ;
> +       if (!i)
> +               return -EINVAL;
> +       num_links = i;
> +
> +       mutex_lock(&con_mutex);
> +       /* Check if already populated */
> +       list_for_each_entry(con, &mbox_cons, node)
> +               if (!strcmp(mbox->controller_name, con->name)) {
> +                       mutex_unlock(&con_mutex);
> +                       return -EINVAL;
> +               }
> +
> +       con = kzalloc(sizeof(struct mbox_con), GFP_KERNEL);
> +       if (!con)
> +               return -ENOMEM;
> +
> +       chan = kzalloc(sizeof(struct mbox_chan) * num_links, GFP_KERNEL);
> +       if (!chan) {
> +               kfree(con);
> +               return -ENOMEM;
> +       }
> +
> +       con->dev = mbox->dev;
> +       INIT_LIST_HEAD(&con->channels);
> +       snprintf(con->name, 16, "%s", mbox->controller_name);
> +
> +       if (mbox->txdone_irq)
> +               txdone = TXDONE_BY_IRQ;
> +       else if (mbox->txdone_poll)
> +               txdone = TXDONE_BY_POLL;
> +       else /* It has to be ACK then */
> +               txdone = TXDONE_BY_ACK;
> +
> +       if (txdone == TXDONE_BY_POLL) {
> +               con->period = mbox->txpoll_period;
> +               con->poll.function = &poll_txdone;
> +               con->poll.data = (unsigned long)con;
> +               init_timer(&con->poll);
> +       }
> +
> +       for (i = 0; i < num_links; i++) {
> +               chan[i].con = con;
> +               chan[i].cl = NULL;
> +               chan[i].link_ops = mbox->ops;
> +               chan[i].link = mbox->links[i];
> +               chan[i].txdone_method = txdone;
> +               chan[i].link->api_priv = &chan[i];
> +               spin_lock_init(&chan[i].lock);
> +               BLOCKING_INIT_NOTIFIER_HEAD(&chan[i].avail);
> +               list_add_tail(&chan[i].node, &con->channels);
> +               snprintf(chan[i].name, 16, "%s", mbox->links[i]->link_name);
> +       }
> +
> +       list_add_tail(&con->node, &mbox_cons);
> +       mutex_unlock(&con_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(mbox_controller_register);
> +
> +/**
> + * mbox_controller_unregister - UnRegister the mailbox controller
> + * @mbox_con:  Pointer to the mailbox controller.
> + *
> + * Purge the mailbox links from the global pool maintained by the framework.
> + */
> +void mbox_controller_unregister(struct mbox_controller *mbox)
> +{
> +       struct mbox_con *t, *con = NULL;
> +       struct mbox_chan *chan;
> +
> +       mutex_lock(&con_mutex);
> +
> +       list_for_each_entry(t, &mbox_cons, node)
> +               if (!strcmp(mbox->controller_name, t->name)) {
> +                       con = t;
> +                       break;
> +               }
> +
> +       if (con)
> +               list_del(&con->node);
> +
> +       mutex_unlock(&con_mutex);
> +
> +       if (!con)
> +               return;
> +
> +       list_for_each_entry(chan, &con->channels, node)
> +               mbox_free_channel(chan);
> +
> +       del_timer_sync(&con->poll);
> +
> +       kfree(con);
> +}
> +EXPORT_SYMBOL_GPL(mbox_controller_unregister);
> diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
> new file mode 100644
> index 0000000..44bcb2b
> --- /dev/null
> +++ b/include/linux/mailbox.h
> @@ -0,0 +1,18 @@
> +/*
> + * Copyright (C) 2014 Linaro Ltd.
> + * Author: Jassi Brar <jassisinghbrar@...il.com>
> + *
> + * 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.
> + */
> +
> +#ifndef __MAILBOX_H
> +#define __MAILBOX_H
> +
> +enum mbox_result {
> +       MBOX_OK = 0,
> +       MBOX_ERR,
> +};
> +
> +#endif /* __MAILBOX_H */
> diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
> new file mode 100644
> index 0000000..4954378
> --- /dev/null
> +++ b/include/linux/mailbox_client.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2014 Linaro Ltd.
> + * Author: Jassi Brar <jassisinghbrar@...il.com>
> + *
> + * 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.
> + */
> +
> +#ifndef __MAILBOX_CLIENT_H
> +#define __MAILBOX_CLIENT_H
> +
> +#include <linux/mailbox.h>
> +
> +struct mbox_chan;
> +
> +/**
> + * struct mbox_client - User of a mailbox
> + * @chan_name:         The "controller:channel" this client wants
> + * @rx_callback:       Atomic callback to provide client the data received
> + * @tx_done:           Atomic callback to tell client of data transmission
> + * @tx_block:          If the mbox_send_message should block until data is
> + *                     transmitted.
> + * @tx_tout:           Max block period in ms before TX is assumed failure
> + * @knows_txdone:      if the client could run the TX state machine. Usually
> + *                     if the client receives some ACK packet for transmission.
> + *                     Unused if the controller already has TX_Done/RTR IRQ.
> + * @link_data:         Optional controller specific parameters during channel
> + *                     request.
> + */
> +struct mbox_client {
> +       char *chan_name;
> +       void (*rx_callback)(struct mbox_client *cl, void *mssg);
> +       void (*tx_done)(struct mbox_client *cl, void *mssg, enum mbox_result r);
> +       bool tx_block;
> +       unsigned long tx_tout;
> +       bool knows_txdone;
> +       void *link_data;
> +};
> +
> +struct mbox_chan *mbox_request_channel(struct mbox_client *cl);
> +int mbox_send_message(struct mbox_chan *chan, void *mssg);
> +void mbox_client_txdone(struct mbox_chan *chan, enum mbox_result r);
> +void mbox_free_channel(struct mbox_chan *chan);
> +int mbox_notify_chan_register(const char *name, struct notifier_block *nb);
> +void mbox_notify_chan_unregister(const char *name, struct notifier_block *nb);
> +
> +#endif /* __MAILBOX_CLIENT_H */
> diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
> new file mode 100644
> index 0000000..5ff22c6
> --- /dev/null
> +++ b/include/linux/mailbox_controller.h
> @@ -0,0 +1,85 @@
> +/*
> + * 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.
> + */
> +
> +#ifndef __MAILBOX_CONTROLLER_H
> +#define __MAILBOX_CONTROLLER_H
> +
> +#include <linux/mailbox.h>
> +
> +/**
> + * struct mbox_link - s/w representation of a communication link
> + * @link_name: Literal name assigned to the link. Physically
> + *             identical channels may have the same name.
> + * @api_priv:  Hook for the API to map its private data on the link
> + *             Controller driver must not touch it.
> + */
> +struct mbox_link {
> +       char link_name[16];
> +       void *api_priv;
> +};
> +
> +/**
> + * struct mbox_link - s/w representation of a communication link
> + * @send_data: The API asks the MBOX controller driver, in atomic
> + *             context try to transmit a message on the bus. Returns 0 if
> + *             data is accepted for transmission, -EBUSY while rejecting
> + *             if the remote hasn't yet read the last data sent. Actual
> + *             transmission of data is reported by the controller via
> + *             mbox_link_txdone (if it has some TX ACK irq). It must not
> + *             block.
> + * @startup:   Called when a client requests the link. The controller
> + *             could ask clients for additional parameters of communication
> + *             to be provided via client's link_data. This call may
> + *             block. After this call the Controller must forward any
> + *             data received on the link by calling mbox_link_received_data.
> + * @shutdown:  Called when a client relinquishes control of a link.
> + *             This call may block too. The controller must not forwared
> + *             any received data anymore.
> + * @last_tx_done: If the controller sets 'txdone_poll', the API calls
> + *               this to poll status of last TX. The controller must
> + *               give priority to IRQ method over polling and never
> + *               set both txdone_poll and txdone_irq. Only in polling
> + *               mode 'send_data' is expected to return -EBUSY.
> + *               Used only if txdone_poll:=true && txdone_irq:=false
> + */
> +struct mbox_link_ops {
> +       int (*send_data)(struct mbox_link *link, void *data);
> +       int (*startup)(struct mbox_link *link, void *params);
> +       void (*shutdown)(struct mbox_link *link);
> +       bool (*last_tx_done)(struct mbox_link *link);
> +};
> +
> +/**
> + * struct mbox_controller - Controller of a class of communication links
> + * @dev:               Device backing this controller
> + * @controller_name:   Literal name of the controller.
> + * @ops:               Operators that work on each communication link
> + * @links:             Null terminated array of links.
> + * @txdone_irq:                Indicates if the controller can report to API when
> + *                     the last transmitted data was read by the remote.
> + *                     Eg, if it has some TX ACK irq.
> + * @txdone_poll:       If the controller can read but not report the TX
> + *                     done. Ex, some register shows the TX status but
> + *                     no interrupt rises. Ignored if 'txdone_irq' is set.
> + * @txpoll_period:     If 'txdone_poll' is in effect, the API polls for
> + *                     last TX's status after these many millisecs
> + */
> +struct mbox_controller {
> +       struct device *dev;
> +       char controller_name[16];
> +       struct mbox_link_ops *ops;
> +       struct mbox_link **links;
> +       bool txdone_irq;
> +       bool txdone_poll;
> +       unsigned txpoll_period;
> +};
> +
> +int mbox_controller_register(struct mbox_controller *mbox);
> +void mbox_link_received_data(struct mbox_link *link, void *data);
> +void mbox_link_txdone(struct mbox_link *link, enum mbox_result r);
> +void mbox_controller_unregister(struct mbox_controller *mbox);
> +
> +#endif /* __MAILBOX_CONTROLLER_H */
> --
> 1.8.1.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ