We don't remove the legacy methods here, but we mark them as deprecated
in the hopes that people with the ability to properly test modifications
can adapt its users.

Signed-off-by: Courtney Cavin <courtney.ca...@sonymobile.com>
---
 drivers/mailbox/pl320-ipc.c | 258 ++++++++++++++++++++++++++++++++++----------
 include/linux/mailbox.h     |  29 ++++-
 2 files changed, 225 insertions(+), 62 deletions(-)

diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
index d873cba..b8da247 100644
--- a/drivers/mailbox/pl320-ipc.c
+++ b/drivers/mailbox/pl320-ipc.c
@@ -15,7 +15,6 @@
  */
 #include <linux/types.h>
 #include <linux/err.h>
-#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
@@ -27,6 +26,7 @@
 #include <linux/amba/bus.h>
 
 #include <linux/mailbox.h>
+#include <linux/mbox.h>
 
 #define IPCMxSOURCE(m)         ((m) * 0x40)
 #define IPCMxDSET(m)           (((m) * 0x40) + 0x004)
@@ -50,131 +50,162 @@
 #define A9_SOURCE              1
 #define M3_SOURCE              0
 
-static void __iomem *ipc_base;
-static int ipc_irq;
-static DEFINE_MUTEX(ipc_m1_lock);
-static DECLARE_COMPLETION(ipc_completion);
-static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+struct pl320 {
+       struct mbox_adapter adapter;
+       void __iomem *base;
+       int irq;
+       struct completion completion;
+};
 
-static inline void set_destination(int source, int mbox)
+static inline void set_destination(struct pl320 *pl, int source, int mbox)
 {
-       __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
-       __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+       __raw_writel(CHAN_MASK(source), pl->base + IPCMxDSET(mbox));
+       __raw_writel(CHAN_MASK(source), pl->base + IPCMxMSET(mbox));
 }
 
-static inline void clear_destination(int source, int mbox)
+static inline void clear_destination(struct pl320 *pl, int source, int mbox)
 {
-       __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
-       __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+       __raw_writel(CHAN_MASK(source), pl->base + IPCMxDCLEAR(mbox));
+       __raw_writel(CHAN_MASK(source), pl->base + IPCMxMCLEAR(mbox));
 }
 
-static void __ipc_send(int mbox, u32 *data)
+static void __ipc_send(struct pl320 *pl, int mbox, const u32 *data)
 {
        int i;
        for (i = 0; i < 7; i++)
-               __raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
-       __raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+               __raw_writel(data[i], pl->base + IPCMxDR(mbox, i));
+       __raw_writel(0x1, pl->base + IPCMxSEND(mbox));
 }
 
-static u32 __ipc_rcv(int mbox, u32 *data)
+static u32 __ipc_rcv(struct pl320 *pl, int mbox, u32 *data)
 {
        int i;
        for (i = 0; i < 7; i++)
-               data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+               data[i] = __raw_readl(pl->base + IPCMxDR(mbox, i));
        return data[1];
 }
 
 /* blocking implmentation from the A9 side, not usuable in interrupts! */
-int pl320_ipc_transmit(u32 *data)
+static int pl320_ipc_put_message(struct mbox_adapter *adap,
+               struct mbox_channel *chan, const void *data, unsigned int len)
 {
+       struct pl320 *pl;
+       u32 repl[7];
        int ret;
 
-       mutex_lock(&ipc_m1_lock);
+       if (len != 28 || chan->id != 0)
+               return -EINVAL;
 
-       init_completion(&ipc_completion);
-       __ipc_send(IPC_TX_MBOX, data);
-       ret = wait_for_completion_timeout(&ipc_completion,
+       pl = container_of(adap, struct pl320, adapter);
+       reinit_completion(&pl->completion);
+       __ipc_send(pl, IPC_TX_MBOX, data);
+       ret = wait_for_completion_timeout(&pl->completion,
                                          msecs_to_jiffies(1000));
-       if (ret == 0) {
-               ret = -ETIMEDOUT;
-               goto out;
-       }
+       if (ret == 0)
+               return -ETIMEDOUT;
+
+       ret = __ipc_rcv(pl, IPC_TX_MBOX, repl);
 
-       ret = __ipc_rcv(IPC_TX_MBOX, data);
-out:
-       mutex_unlock(&ipc_m1_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(pl320_ipc_transmit);
 
 static irqreturn_t ipc_handler(int irq, void *dev)
 {
+       struct pl320 *pl = dev;
        u32 irq_stat;
        u32 data[7];
 
-       irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+       irq_stat = __raw_readl(pl->base + IPCMMIS(1));
        if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
-               __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
-               complete(&ipc_completion);
+               __raw_writel(0, pl->base + IPCMxSEND(IPC_TX_MBOX));
+               complete(&pl->completion);
        }
        if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
-               __ipc_rcv(IPC_RX_MBOX, data);
-               atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
-               __raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+               __ipc_rcv(pl, IPC_RX_MBOX, data);
+               mbox_channel_notify(&pl->adapter.channels[0], data, 28);
+               __raw_writel(2, pl->base + IPCMxSEND(IPC_RX_MBOX));
        }
 
        return IRQ_HANDLED;
 }
 
-int pl320_ipc_register_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&ipc_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(pl320_ipc_register_notifier);
-
-int pl320_ipc_unregister_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&ipc_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(pl320_ipc_unregister_notifier);
+static const struct mbox_adapter_ops pl320_mbox_ops = {
+       .owner = THIS_MODULE,
+       .put_message = pl320_ipc_put_message,
+};
 
 static int pl320_probe(struct amba_device *adev, const struct amba_id *id)
 {
+       struct pl320 *pl;
        int ret;
 
-       ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
-       if (ipc_base == NULL)
+       pl = devm_kzalloc(&adev->dev, sizeof(*pl), GFP_KERNEL);
+       if (pl == NULL)
+               return -ENOMEM;
+       pl->base = ioremap(adev->res.start, resource_size(&adev->res));
+       if (pl->base == NULL)
                return -ENOMEM;
 
-       __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+       init_completion(&pl->completion);
 
-       ipc_irq = adev->irq[0];
-       ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+       pl->adapter.dev = &adev->dev;
+       pl->adapter.ops = &pl320_mbox_ops;
+       pl->adapter.nchannels = 1;
+
+       ret = mbox_adapter_add(&pl->adapter);
+       if (ret)
+               goto err;
+
+       __raw_writel(0, pl->base + IPCMxSEND(IPC_TX_MBOX));
+
+       pl->irq = adev->irq[0];
+       ret = request_irq(pl->irq, ipc_handler, 0, dev_name(&adev->dev), pl);
        if (ret < 0)
                goto err;
 
        /* Init slow mailbox */
        __raw_writel(CHAN_MASK(A9_SOURCE),
-                       ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+                       pl->base + IPCMxSOURCE(IPC_TX_MBOX));
        __raw_writel(CHAN_MASK(M3_SOURCE),
-                       ipc_base + IPCMxDSET(IPC_TX_MBOX));
+                       pl->base + IPCMxDSET(IPC_TX_MBOX));
        __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
-                    ipc_base + IPCMxMSET(IPC_TX_MBOX));
+                    pl->base + IPCMxMSET(IPC_TX_MBOX));
 
        /* Init receive mailbox */
        __raw_writel(CHAN_MASK(M3_SOURCE),
-                       ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+                       pl->base + IPCMxSOURCE(IPC_RX_MBOX));
        __raw_writel(CHAN_MASK(A9_SOURCE),
-                       ipc_base + IPCMxDSET(IPC_RX_MBOX));
+                       pl->base + IPCMxDSET(IPC_RX_MBOX));
        __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
-                    ipc_base + IPCMxMSET(IPC_RX_MBOX));
+                    pl->base + IPCMxMSET(IPC_RX_MBOX));
 
+       amba_set_drvdata(adev, pl);
        return 0;
 err:
-       iounmap(ipc_base);
+       iounmap(pl->base);
        return ret;
 }
 
+static int pl320_remove(struct amba_device *adev)
+{
+       struct pl320 *pl;
+       int ret;
+
+       pl = amba_get_drvdata(adev);
+
+       disable_irq(pl->irq);
+
+       ret = mbox_adapter_remove(&pl->adapter);
+       if (ret) {
+               enable_irq(pl->irq);
+               return ret;
+       }
+
+       free_irq(pl->irq, pl);
+       iounmap(pl->base);
+       return 0;
+}
+
 static struct amba_id pl320_ids[] = {
        {
                .id     = 0x00041320,
@@ -189,6 +220,7 @@ static struct amba_driver pl320_driver = {
        },
        .id_table       = pl320_ids,
        .probe          = pl320_probe,
+       .remove         = pl320_remove,
 };
 
 static int __init ipc_init(void)
@@ -196,3 +228,111 @@ static int __init ipc_init(void)
        return amba_driver_register(&pl320_driver);
 }
 module_init(ipc_init);
+
+/* Legacy API */
+static struct mbox *pl320_mbox;
+static struct notifier_block *pl320_notifier;
+static DEFINE_SPINLOCK(pl320_legacy_lock);
+static DEFINE_MUTEX(pl320_mutex);
+
+static int __pl320_notify(struct notifier_block *nb,
+               unsigned long len, void *data)
+{
+       unsigned long flags;
+       u32 *mdata = data;
+       int rc;
+
+       spin_lock_irqsave(&pl320_legacy_lock, flags);
+       if (!pl320_notifier) {
+               spin_unlock_irqrestore(&pl320_legacy_lock, flags);
+               return NOTIFY_DONE;
+       }
+
+       rc = pl320_notifier->notifier_call(pl320_notifier,
+                       mdata[0], mdata + 1);
+       spin_unlock_irqrestore(&pl320_legacy_lock, flags);
+       return rc;
+}
+
+static void __pl320_set_notifier(struct notifier_block *nb)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pl320_legacy_lock, flags);
+       pl320_notifier = nb;
+       spin_unlock_irqrestore(&pl320_legacy_lock, flags);
+}
+
+static struct notifier_block pl320_nb = {
+       .notifier_call = __pl320_notify,
+};
+
+static int __pl320_legacy_setup(struct notifier_block *nb, bool exist_ok)
+{
+       int rc = 0;
+
+       if (WARN_ON(!exist_ok && pl320_mbox))
+               return -EBUSY;
+
+       if (pl320_mbox)
+               return 0;
+
+       __pl320_set_notifier(nb);
+
+       pl320_mbox = mbox_request(NULL, "pl320", &pl320_nb);
+       if (IS_ERR(pl320_mbox)) {
+               rc = PTR_ERR(pl320_mbox);
+               pl320_mbox = NULL;
+               __pl320_set_notifier(NULL);
+       }
+
+       return rc;
+}
+
+int __pl320_legacy_ipc_transmit(u32 *data)
+{
+       int rc;
+
+       mutex_lock(&pl320_mutex);
+       rc = __pl320_legacy_setup(NULL, true);
+       if (rc)
+               goto out;
+
+       rc = mbox_put_message(pl320_mbox, data, 7 * sizeof(*data));
+out:
+       mutex_unlock(&pl320_mutex);
+
+       return rc;
+}
+EXPORT_SYMBOL(__pl320_legacy_ipc_transmit);
+
+int __pl320_legacy_ipc_register_notifier(struct notifier_block *nb)
+{
+       int rc;
+
+       mutex_lock(&pl320_mutex);
+       rc = __pl320_legacy_setup(nb, false);
+       mutex_unlock(&pl320_mutex);
+
+       return rc;
+}
+EXPORT_SYMBOL(__pl320_legacy_ipc_register_notifier);
+
+int __pl320_legacy_ipc_unregister_notifier(struct notifier_block *nb)
+{
+       mutex_lock(&pl320_mutex);
+
+       if (WARN_ON(!pl320_mbox)) {
+               mutex_unlock(&pl320_mutex);
+               return -EINVAL;
+       }
+
+       mbox_release(pl320_mbox);
+       __pl320_set_notifier(NULL);
+       pl320_mbox = NULL;
+
+       mutex_unlock(&pl320_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(__pl320_legacy_ipc_unregister_notifier);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index 5161f63..2330954 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -12,6 +12,29 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-int pl320_ipc_transmit(u32 *data);
-int pl320_ipc_register_notifier(struct notifier_block *nb);
-int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+#ifndef PL320_MAILBOX_H
+#define PL320_MAILBOX_H
+
+#include <linux/compiler.h>
+#include <linux/mbox.h>
+
+int __pl320_legacy_ipc_transmit(u32 *data);
+int __pl320_legacy_ipc_register_notifier(struct notifier_block *nb);
+int __pl320_legacy_ipc_unregister_notifier(struct notifier_block *nb);
+
+static inline int __deprecated pl320_ipc_transmit(u32 *data)
+{
+       return __pl320_legacy_ipc_transmit(data);
+}
+static inline int __deprecated
+pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+       return __pl320_legacy_ipc_register_notifier(nb);
+}
+static inline int __deprecated
+pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+       return __pl320_legacy_ipc_unregister_notifier(nb);
+}
+
+#endif
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to