From b5452838c661726880652f14e20ab58efed54fa5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 2 Nov 2018 16:11:55 +0100 Subject: [PATCH 01/30] mailbox: hi3660: constify mbox_chan_ops structure The mbox_chan_ops structure can be const as it is only stored in the ops field of an mbox_controller structure and this field is const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Jassi Brar --- drivers/mailbox/hi3660-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c index 3eea6b642484..c3fd1f2b797f 100644 --- a/drivers/mailbox/hi3660-mailbox.c +++ b/drivers/mailbox/hi3660-mailbox.c @@ -206,7 +206,7 @@ static int hi3660_mbox_send_data(struct mbox_chan *chan, void *msg) return 0; } -static struct mbox_chan_ops hi3660_mbox_ops = { +static const struct mbox_chan_ops hi3660_mbox_ops = { .startup = hi3660_mbox_startup, .send_data = hi3660_mbox_send_data, }; From 2e4ac7cc493f36e45facb921a992a145351d280c Mon Sep 17 00:00:00 2001 From: Kevin Wangtao Date: Mon, 3 Dec 2018 11:55:09 +0800 Subject: [PATCH 02/30] mailbox: Hi3660: Fixup mailbox state machine malfunction issue Current mailbox driver of Hi3660 release the mailbox directly before sending a new message which may cause last message lost and next message sending doesn't take effect actually. This patch fixs this issue by following the right progress below, each time before sending a message, mailbox driver will check whether the mailbox is in ready state, if last message has been acknowledged, the mailbox driver will clear the ack state to turn the mailbox to ready state again. Signed-off-by: Kevin Wangtao Reviewed-and-tested-by: Leo Yan Tested-by: Valentin Schneider Signed-off-by: Jassi Brar --- drivers/mailbox/hi3660-mailbox.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c index c3fd1f2b797f..f9aed5d8f9f1 100644 --- a/drivers/mailbox/hi3660-mailbox.c +++ b/drivers/mailbox/hi3660-mailbox.c @@ -38,6 +38,7 @@ #define MBOX_AUTOMATIC_ACK 1 #define MBOX_STATE_IDLE BIT(4) +#define MBOX_STATE_READY BIT(5) #define MBOX_STATE_ACK BIT(7) #define MBOX_MSG_LEN 8 @@ -91,8 +92,8 @@ static int hi3660_mbox_check_state(struct mbox_chan *chan) unsigned long val; unsigned int ret; - /* Mailbox is idle so directly bail out */ - if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE) + /* Mailbox is ready to use */ + if (readl(base + MBOX_MODE_REG) & MBOX_STATE_READY) return 0; /* Wait for acknowledge from remote */ @@ -103,9 +104,9 @@ static int hi3660_mbox_check_state(struct mbox_chan *chan) return ret; } - /* Ensure channel is released */ - writel(0xffffffff, base + MBOX_IMASK_REG); - writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG); + /* clear ack state, mailbox will get back to ready state */ + writel(BIT(mchan->ack_irq), base + MBOX_ICLR_REG); + return 0; } @@ -160,10 +161,6 @@ static int hi3660_mbox_startup(struct mbox_chan *chan) { int ret; - ret = hi3660_mbox_check_state(chan); - if (ret) - return ret; - ret = hi3660_mbox_unlock(chan); if (ret) return ret; @@ -183,10 +180,11 @@ static int hi3660_mbox_send_data(struct mbox_chan *chan, void *msg) void __iomem *base = MBOX_BASE(mbox, ch); u32 *buf = msg; unsigned int i; + int ret; - /* Ensure channel is released */ - writel_relaxed(0xffffffff, base + MBOX_IMASK_REG); - writel_relaxed(BIT(mchan->ack_irq), base + MBOX_SRC_REG); + ret = hi3660_mbox_check_state(chan); + if (ret) + return ret; /* Clear mask for destination interrupt */ writel_relaxed(~BIT(mchan->dst_irq), base + MBOX_IMASK_REG); From 78f3ff524fca63e7d2a57149a34ade23d2c12798 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 3 Dec 2018 17:50:11 +0300 Subject: [PATCH 03/30] mailbox: ti-msgmgr: Off by one in ti_msgmgr_of_xlate() The > comparison should be >= or we access one element beyond the end of the array. (The inst->qinsts[] array is allocated in the ti_msgmgr_probe() function and it has ->num_valid_queues elements.) Fixes: a2b79838b891 ("mailbox: ti-msgmgr: Add support for Secure Proxy") Signed-off-by: Dan Carpenter Acked-by: Nishanth Menon Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index 713d701b6568..6f6addd51d14 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -547,7 +547,7 @@ static struct mbox_chan *ti_msgmgr_of_xlate(struct mbox_controller *mbox, } if (d->is_sproxy) { - if (req_pid > d->num_valid_queues) + if (req_pid >= d->num_valid_queues) goto err; qinst = &inst->qinsts[req_pid]; return qinst->chan; From e2affdbef2aca880f4b9e758779c72540db5f168 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 10 Nov 2018 16:59:15 +0100 Subject: [PATCH 04/30] mailbox: bcm2835: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Cc: Lubomir Rintel Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt Acked-by: Lubomir Rintel Signed-off-by: Jassi Brar --- drivers/mailbox/bcm2835-mailbox.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c index e92bbc533821..bb3ee728169d 100644 --- a/drivers/mailbox/bcm2835-mailbox.c +++ b/drivers/mailbox/bcm2835-mailbox.c @@ -1,15 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2010,2015 Broadcom * Copyright (C) 2013-2014 Lubomir Rintel * Copyright (C) 2013 Craig McGeachie * - * 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 device provides a mechanism for writing to the mailboxes, - * that are shared between the ARM and the VideoCore processor - * * Parts of the driver are based on: * - arch/arm/mach-bcm2708/vcio.c file written by Gray Girling that was * obtained from branch "rpi-3.6.y" of git://github.com/raspberrypi/ From e898d9cdd3a9f105863d63dd3b46443742a4757c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:44 +0100 Subject: [PATCH 05/30] mailbox: Add device-managed registration functions Add device-managed equivalents of the mbox_controller_register() and mbox_controller_unregister() functions that can be used to have the devres infrastructure automatically unregister mailbox controllers on driver probe failure or driver removal. This can help remove a lot of boiler plate code from drivers. Reviewed-by: Bjorn Andersson Reviewed-by: Sudeep Holla Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 70 ++++++++++++++++++++++++++++++ include/linux/mailbox_controller.h | 5 +++ 2 files changed, 75 insertions(+) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 674b35f402f5..08ce9a1ab53a 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -515,3 +515,73 @@ void mbox_controller_unregister(struct mbox_controller *mbox) mutex_unlock(&con_mutex); } EXPORT_SYMBOL_GPL(mbox_controller_unregister); + +static void __devm_mbox_controller_unregister(struct device *dev, void *res) +{ + struct mbox_controller **mbox = res; + + mbox_controller_unregister(*mbox); +} + +static int devm_mbox_controller_match(struct device *dev, void *res, void *data) +{ + struct mbox_controller **mbox = res; + + if (WARN_ON(!mbox || !*mbox)) + return 0; + + return *mbox == data; +} + +/** + * devm_mbox_controller_register() - managed mbox_controller_register() + * @dev: device owning the mailbox controller being registered + * @mbox: mailbox controller being registered + * + * This function adds a device-managed resource that will make sure that the + * mailbox controller, which is registered using mbox_controller_register() + * as part of this function, will be unregistered along with the rest of + * device-managed resources upon driver probe failure or driver removal. + * + * Returns 0 on success or a negative error code on failure. + */ +int devm_mbox_controller_register(struct device *dev, + struct mbox_controller *mbox) +{ + struct mbox_controller **ptr; + int err; + + ptr = devres_alloc(__devm_mbox_controller_unregister, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + err = mbox_controller_register(mbox); + if (err < 0) { + devres_free(ptr); + return err; + } + + devres_add(dev, ptr); + *ptr = mbox; + + return 0; +} +EXPORT_SYMBOL_GPL(devm_mbox_controller_register); + +/** + * devm_mbox_controller_unregister() - managed mbox_controller_unregister() + * @dev: device owning the mailbox controller being unregistered + * @mbox: mailbox controller being unregistered + * + * This function unregisters the mailbox controller and removes the device- + * managed resource that was set up to automatically unregister the mailbox + * controller on driver probe failure or driver removal. It's typically not + * necessary to call this function. + */ +void devm_mbox_controller_unregister(struct device *dev, struct mbox_controller *mbox) +{ + WARN_ON(devres_release(dev, __devm_mbox_controller_unregister, + devm_mbox_controller_match, mbox)); +} +EXPORT_SYMBOL_GPL(devm_mbox_controller_unregister); diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 74deadb42d76..9b0b21207345 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -131,4 +131,9 @@ void mbox_controller_unregister(struct mbox_controller *mbox); /* can sleep */ void mbox_chan_received_data(struct mbox_chan *chan, void *data); /* atomic */ void mbox_chan_txdone(struct mbox_chan *chan, int r); /* atomic */ +int devm_mbox_controller_register(struct device *dev, + struct mbox_controller *mbox); +void devm_mbox_controller_unregister(struct device *dev, + struct mbox_controller *mbox); + #endif /* __MAILBOX_CONTROLLER_H */ From 6aba2f4aac1ac030edacc76a10043e4d1b885e3d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:45 +0100 Subject: [PATCH 06/30] mailbox: arm-mhu: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Sudeep Holla Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/arm_mhu.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index 99befa76e37c..64d85c6a2bdf 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -152,7 +152,7 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) amba_set_drvdata(adev, mhu); - err = mbox_controller_register(&mhu->mbox); + err = devm_mbox_controller_register(dev, &mhu->mbox); if (err) { dev_err(dev, "Failed to register mailboxes %d\n", err); return err; @@ -162,15 +162,6 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) return 0; } -static int mhu_remove(struct amba_device *adev) -{ - struct arm_mhu *mhu = amba_get_drvdata(adev); - - mbox_controller_unregister(&mhu->mbox); - - return 0; -} - static struct amba_id mhu_ids[] = { { .id = 0x1bb098, @@ -186,7 +177,6 @@ static struct amba_driver arm_mhu_driver = { }, .id_table = mhu_ids, .probe = mhu_probe, - .remove = mhu_remove, }; module_amba_driver(arm_mhu_driver); From 709cbeea1b34f92619140b20bf15602a7f1240d8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:46 +0100 Subject: [PATCH 07/30] mailbox: bcm2835: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Eric Anholt Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/bcm2835-mailbox.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c index bb3ee728169d..39761d190545 100644 --- a/drivers/mailbox/bcm2835-mailbox.c +++ b/drivers/mailbox/bcm2835-mailbox.c @@ -172,7 +172,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev) if (!mbox->controller.chans) return -ENOMEM; - ret = mbox_controller_register(&mbox->controller); + ret = devm_mbox_controller_register(dev, &mbox->controller); if (ret) return ret; @@ -182,13 +182,6 @@ static int bcm2835_mbox_probe(struct platform_device *pdev) return ret; } -static int bcm2835_mbox_remove(struct platform_device *pdev) -{ - struct bcm2835_mbox *mbox = platform_get_drvdata(pdev); - mbox_controller_unregister(&mbox->controller); - return 0; -} - static const struct of_device_id bcm2835_mbox_of_match[] = { { .compatible = "brcm,bcm2835-mbox", }, {}, @@ -201,7 +194,6 @@ static struct platform_driver bcm2835_mbox_driver = { .of_match_table = bcm2835_mbox_of_match, }, .probe = bcm2835_mbox_probe, - .remove = bcm2835_mbox_remove, }; module_platform_driver(bcm2835_mbox_driver); From 0cafc12ab9cc163e6078db8ec978c200a632e88e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:47 +0100 Subject: [PATCH 08/30] mailbox: bcm-flexrm: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Acked-by: Scott Branden Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-flexrm-mailbox.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index d7a8ed7d8097..d713271ebf7c 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -1665,7 +1665,7 @@ skip_debugfs: mbox->controller.chans[index].con_priv = &mbox->rings[index]; /* Register mailbox controller */ - ret = mbox_controller_register(&mbox->controller); + ret = devm_mbox_controller_register(dev, &mbox->controller); if (ret) goto fail_free_debugfs_root; @@ -1691,8 +1691,6 @@ static int flexrm_mbox_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct flexrm_mbox *mbox = platform_get_drvdata(pdev); - mbox_controller_unregister(&mbox->controller); - debugfs_remove_recursive(mbox->root); platform_msi_domain_free_irqs(dev); From 6267ee6afae0a3c130dc585118dd60e090c6448b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:48 +0100 Subject: [PATCH 09/30] mailbox: bcm-pdc: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 4fe7be0bdd11..ccf3d62af7e7 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -1471,7 +1471,7 @@ static int pdc_mb_init(struct pdc_state *pdcs) mbc->chans[chan_index].con_priv = pdcs; /* Register mailbox controller */ - err = mbox_controller_register(mbc); + err = devm_mbox_controller_register(dev, mbc); if (err) { dev_crit(dev, "Failed to register PDC mailbox controller. Error %d.", @@ -1641,8 +1641,6 @@ static int pdc_remove(struct platform_device *pdev) pdc_hw_disable(pdcs); - mbox_controller_unregister(&pdcs->mbc); - dma_pool_destroy(pdcs->rx_buf_pool); dma_pool_destroy(pdcs->ring_pool); return 0; From e73cb83c807b3a1c3c430b646668ce358b13ee74 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:49 +0100 Subject: [PATCH 10/30] mailbox: hi3660: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Tested-by: Leo Yan Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/hi3660-mailbox.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c index f9aed5d8f9f1..53f4bc2488c5 100644 --- a/drivers/mailbox/hi3660-mailbox.c +++ b/drivers/mailbox/hi3660-mailbox.c @@ -265,7 +265,7 @@ static int hi3660_mbox_probe(struct platform_device *pdev) for (ch = 0; ch < MBOX_CHAN_MAX; ch++) chan[ch].con_priv = (void *)ch; - err = mbox_controller_register(&mbox->controller); + err = devm_mbox_controller_register(dev, &mbox->controller); if (err) { dev_err(dev, "Failed to register mailbox %d\n", err); return err; @@ -276,17 +276,8 @@ static int hi3660_mbox_probe(struct platform_device *pdev) return 0; } -static int hi3660_mbox_remove(struct platform_device *pdev) -{ - struct hi3660_mbox *mbox = platform_get_drvdata(pdev); - - mbox_controller_unregister(&mbox->controller); - return 0; -} - static struct platform_driver hi3660_mbox_driver = { .probe = hi3660_mbox_probe, - .remove = hi3660_mbox_remove, .driver = { .name = "hi3660-mbox", .of_match_table = hi3660_mbox_of_match, From ad3e7f9651ca344fc14b1709c7f91d9e570c389c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:50 +0100 Subject: [PATCH 11/30] mailbox: hi6220: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Leo Yan Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/hi6220-mailbox.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mailbox/hi6220-mailbox.c b/drivers/mailbox/hi6220-mailbox.c index 4fa9803cd204..c32cbfaf223a 100644 --- a/drivers/mailbox/hi6220-mailbox.c +++ b/drivers/mailbox/hi6220-mailbox.c @@ -349,7 +349,7 @@ static int hi6220_mbox_probe(struct platform_device *pdev) mbox->controller.txpoll_period = 5; } - err = mbox_controller_register(&mbox->controller); + err = devm_mbox_controller_register(dev, &mbox->controller); if (err) { dev_err(dev, "Failed to register mailbox %d\n", err); return err; @@ -360,14 +360,6 @@ static int hi6220_mbox_probe(struct platform_device *pdev) return 0; } -static int hi6220_mbox_remove(struct platform_device *pdev) -{ - struct hi6220_mbox *mbox = platform_get_drvdata(pdev); - - mbox_controller_unregister(&mbox->controller); - return 0; -} - static struct platform_driver hi6220_mbox_driver = { .driver = { .name = "hi6220-mbox", @@ -375,7 +367,6 @@ static struct platform_driver hi6220_mbox_driver = { .of_match_table = hi6220_mbox_of_match, }, .probe = hi6220_mbox_probe, - .remove = hi6220_mbox_remove, }; static int __init hi6220_mbox_init(void) From 4013286c7231e05780c6e73b91d357678f819b4b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:51 +0100 Subject: [PATCH 12/30] mailbox: imx: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Oleksij Rempel Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 363d35d5e49d..774362a05159 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -324,14 +324,13 @@ static int imx_mu_probe(struct platform_device *pdev) imx_mu_init_generic(priv); - return mbox_controller_register(&priv->mbox); + return devm_mbox_controller_register(dev, &priv->mbox); } static int imx_mu_remove(struct platform_device *pdev) { struct imx_mu_priv *priv = platform_get_drvdata(pdev); - mbox_controller_unregister(&priv->mbox); clk_disable_unprepare(priv->clk); return 0; From 87f63f578b734ca45cb8ebe251bd65560b89de26 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:52 +0100 Subject: [PATCH 13/30] mailbox: altera: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-altera.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c index bcb29df9549e..397e25ddae29 100644 --- a/drivers/mailbox/mailbox-altera.c +++ b/drivers/mailbox/mailbox-altera.c @@ -341,7 +341,7 @@ static int altera_mbox_probe(struct platform_device *pdev) } } - ret = mbox_controller_register(&mbox->controller); + ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller); if (ret) { dev_err(&pdev->dev, "Register mailbox failed\n"); goto err; @@ -352,18 +352,6 @@ err: return ret; } -static int altera_mbox_remove(struct platform_device *pdev) -{ - struct altera_mbox *mbox = platform_get_drvdata(pdev); - - if (!mbox) - return -EINVAL; - - mbox_controller_unregister(&mbox->controller); - - return 0; -} - static const struct of_device_id altera_mbox_match[] = { { .compatible = "altr,mailbox-1.0" }, { /* Sentinel */ } @@ -373,7 +361,6 @@ MODULE_DEVICE_TABLE(of, altera_mbox_match); static struct platform_driver altera_mbox_driver = { .probe = altera_mbox_probe, - .remove = altera_mbox_remove, .driver = { .name = DRIVER_NAME, .of_match_table = altera_mbox_match, From d0c196dbee7957ea446c4047c501537aeccf5fa0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:53 +0100 Subject: [PATCH 14/30] mailbox: sti: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Acked-by: Lee Jones Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-sti.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c index 779d41262ef0..adf82b85dbb2 100644 --- a/drivers/mailbox/mailbox-sti.c +++ b/drivers/mailbox/mailbox-sti.c @@ -462,7 +462,7 @@ static int sti_mbox_probe(struct platform_device *pdev) mbox->chans = chans; mbox->num_chans = STI_MBOX_CHAN_MAX; - ret = mbox_controller_register(mbox); + ret = devm_mbox_controller_register(&pdev->dev, mbox); if (ret) return ret; @@ -480,7 +480,6 @@ static int sti_mbox_probe(struct platform_device *pdev) IRQF_ONESHOT, mdev->name, mdev); if (ret) { dev_err(&pdev->dev, "Can't claim IRQ %d\n", irq); - mbox_controller_unregister(mbox); return -EINVAL; } @@ -489,18 +488,8 @@ static int sti_mbox_probe(struct platform_device *pdev) return 0; } -static int sti_mbox_remove(struct platform_device *pdev) -{ - struct sti_mbox_device *mdev = platform_get_drvdata(pdev); - - mbox_controller_unregister(mdev->mbox); - - return 0; -} - static struct platform_driver sti_mbox_driver = { .probe = sti_mbox_probe, - .remove = sti_mbox_remove, .driver = { .name = "sti-mailbox", .of_match_table = sti_mailbox_match, From 0b7f5fe837f682dbb9f751afb513a4b28c7ceb56 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:54 +0100 Subject: [PATCH 15/30] mailbox: xgene-slimpro: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-xgene-slimpro.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mailbox/mailbox-xgene-slimpro.c b/drivers/mailbox/mailbox-xgene-slimpro.c index b8b2b3533f46..8f397da1150b 100644 --- a/drivers/mailbox/mailbox-xgene-slimpro.c +++ b/drivers/mailbox/mailbox-xgene-slimpro.c @@ -224,7 +224,7 @@ static int slimpro_mbox_probe(struct platform_device *pdev) ctx->mb_ctrl.ops = &slimpro_mbox_ops; ctx->mb_ctrl.num_chans = i; - rc = mbox_controller_register(&ctx->mb_ctrl); + rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl); if (rc) { dev_err(&pdev->dev, "APM X-Gene SLIMpro MailBox register failed:%d\n", rc); @@ -235,14 +235,6 @@ static int slimpro_mbox_probe(struct platform_device *pdev) return 0; } -static int slimpro_mbox_remove(struct platform_device *pdev) -{ - struct slimpro_mbox *smb = platform_get_drvdata(pdev); - - mbox_controller_unregister(&smb->mb_ctrl); - return 0; -} - static const struct of_device_id slimpro_of_match[] = { {.compatible = "apm,xgene-slimpro-mbox" }, { }, @@ -259,7 +251,6 @@ MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids); static struct platform_driver slimpro_mbox_driver = { .probe = slimpro_mbox_probe, - .remove = slimpro_mbox_remove, .driver = { .name = "xgene-slimpro-mbox", .of_match_table = of_match_ptr(slimpro_of_match), From 8aed5719557269807447b8bb936067b36a54b787 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:55 +0100 Subject: [PATCH 16/30] mailbox: mtk-cmdq: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mtk-cmdq-mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index f7cc29c00302..d9c3ec3667a8 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -337,7 +337,6 @@ static int cmdq_remove(struct platform_device *pdev) { struct cmdq *cmdq = platform_get_drvdata(pdev); - mbox_controller_unregister(&cmdq->mbox); clk_unprepare(cmdq->clock); if (cmdq->mbox.chans) @@ -524,7 +523,7 @@ static int cmdq_probe(struct platform_device *pdev) cmdq->mbox.chans[i].con_priv = (void *)&cmdq->thread[i]; } - err = mbox_controller_register(&cmdq->mbox); + err = devm_mbox_controller_register(dev, &cmdq->mbox); if (err < 0) { dev_err(dev, "failed to register mailbox: %d\n", err); return err; From ec1c674f0ae3905cd540ab2f30d9c4265981d7b4 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:56 +0100 Subject: [PATCH 17/30] mailbox: mtk-cmdq: Remove needless devm_kfree() calls Memory allocated through device-managed functions doesn't need to be explicitly freed, so these calls can be removed. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mtk-cmdq-mailbox.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index d9c3ec3667a8..22811784dc7d 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -339,14 +339,6 @@ static int cmdq_remove(struct platform_device *pdev) clk_unprepare(cmdq->clock); - if (cmdq->mbox.chans) - devm_kfree(&pdev->dev, cmdq->mbox.chans); - - if (cmdq->thread) - devm_kfree(&pdev->dev, cmdq->thread); - - devm_kfree(&pdev->dev, cmdq); - return 0; } From a3abf4363c7ec8f980a0ac1c880e2627349d8626 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:57 +0100 Subject: [PATCH 18/30] mailbox: omap: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/omap-mailbox.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index db66e952a871..ca50177a33f2 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -486,7 +486,7 @@ static int omap_mbox_register(struct omap_mbox_device *mdev) list_add(&mdev->elem, &omap_mbox_devices); mutex_unlock(&omap_mbox_devices_lock); - ret = mbox_controller_register(&mdev->controller); + ret = devm_mbox_controller_register(mdev->dev, &mdev->controller); err_out: if (ret) { @@ -508,8 +508,6 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev) list_del(&mdev->elem); mutex_unlock(&omap_mbox_devices_lock); - mbox_controller_unregister(&mdev->controller); - mboxes = mdev->mboxes; for (i = 0; mboxes[i]; i++) device_unregister(mboxes[i]->dev); From 85a555246e6db7b4e9803704e1e0c694dfe658a0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:58 +0100 Subject: [PATCH 19/30] mailbox: platform-mhu: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Acked-by: Neil Armstrong Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/platform_mhu.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/mailbox/platform_mhu.c b/drivers/mailbox/platform_mhu.c index e13201a5cec6..d2502c5be130 100644 --- a/drivers/mailbox/platform_mhu.c +++ b/drivers/mailbox/platform_mhu.c @@ -163,7 +163,7 @@ static int platform_mhu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mhu); - err = mbox_controller_register(&mhu->mbox); + err = devm_mbox_controller_register(dev, &mhu->mbox); if (err) { dev_err(dev, "Failed to register mailboxes %d\n", err); return err; @@ -173,15 +173,6 @@ static int platform_mhu_probe(struct platform_device *pdev) return 0; } -static int platform_mhu_remove(struct platform_device *pdev) -{ - struct platform_mhu *mhu = platform_get_drvdata(pdev); - - mbox_controller_unregister(&mhu->mbox); - - return 0; -} - static const struct of_device_id platform_mhu_dt_ids[] = { { .compatible = "amlogic,meson-gxbb-mhu", }, { /* sentinel */ }, @@ -190,7 +181,6 @@ MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids); static struct platform_driver platform_mhu_driver = { .probe = platform_mhu_probe, - .remove = platform_mhu_remove, .driver = { .name = "platform-mhu", .of_match_table = platform_mhu_dt_ids, From 83dd44a17d40ab258aede6f560d27444e7dcfba7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:19:59 +0100 Subject: [PATCH 20/30] mailbox: qcom-apcs: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Bjorn Andersson Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index aed23ac9550d..3cf2937be149 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -91,7 +91,7 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) apcs->mbox.chans = apcs->mbox_chans; apcs->mbox.num_chans = ARRAY_SIZE(apcs->mbox_chans); - ret = mbox_controller_register(&apcs->mbox); + ret = devm_mbox_controller_register(&pdev->dev, &apcs->mbox); if (ret) { dev_err(&pdev->dev, "failed to register APCS IPC controller\n"); return ret; @@ -115,7 +115,6 @@ static int qcom_apcs_ipc_remove(struct platform_device *pdev) struct qcom_apcs_ipc *apcs = platform_get_drvdata(pdev); struct platform_device *clk = apcs->clk; - mbox_controller_unregister(&apcs->mbox); platform_device_unregister(clk); return 0; From 08f2f88a3bbf3cdfdf3b890159d45519e2d5bbeb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:20:00 +0100 Subject: [PATCH 21/30] mailbox: rockchip: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Caesar Wang Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/rockchip-mailbox.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index d702a204f5c1..f24a77b1a0ff 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -247,28 +247,15 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->chans[i].msg = NULL; } - ret = mbox_controller_register(&mb->mbox); + ret = devm_mbox_controller_register(&pdev->dev, &mb->mbox); if (ret < 0) dev_err(&pdev->dev, "Failed to register mailbox: %d\n", ret); return ret; } -static int rockchip_mbox_remove(struct platform_device *pdev) -{ - struct rockchip_mbox *mb = platform_get_drvdata(pdev); - - if (!mb) - return -EINVAL; - - mbox_controller_unregister(&mb->mbox); - - return 0; -} - static struct platform_driver rockchip_mbox_driver = { .probe = rockchip_mbox_probe, - .remove = rockchip_mbox_remove, .driver = { .name = "rockchip-mailbox", .of_match_table = of_match_ptr(rockchip_mbox_of_match), From 368d7767b50154eb052938a13494879b00135ed3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:20:01 +0100 Subject: [PATCH 22/30] mailbox: stm32-ipcc: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Reviewed-by: Ludovic Barre Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/stm32-ipcc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index 533b0da5235d..a338bd4cd7db 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -299,7 +299,7 @@ static int stm32_ipcc_probe(struct platform_device *pdev) for (i = 0; i < ipcc->controller.num_chans; i++) ipcc->controller.chans[i].con_priv = (void *)i; - ret = mbox_controller_register(&ipcc->controller); + ret = devm_mbox_controller_register(dev, &ipcc->controller); if (ret) goto err_irq_wkp; @@ -329,8 +329,6 @@ static int stm32_ipcc_remove(struct platform_device *pdev) { struct stm32_ipcc *ipcc = platform_get_drvdata(pdev); - mbox_controller_unregister(&ipcc->controller); - if (ipcc->wkp) dev_pm_clear_wake_irq(&pdev->dev); From 2298a6f09f455f64bf253e6fb5c1ff72f38a6249 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Dec 2018 18:20:02 +0100 Subject: [PATCH 23/30] mailbox: ti-msgmgr: Use device-managed registration API Get rid of some boilerplate driver removal code by using the newly added device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index 6f6addd51d14..88047d835211 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -817,26 +817,15 @@ static int ti_msgmgr_probe(struct platform_device *pdev) mbox->of_xlate = ti_msgmgr_of_xlate; platform_set_drvdata(pdev, inst); - ret = mbox_controller_register(mbox); + ret = devm_mbox_controller_register(dev, mbox); if (ret) dev_err(dev, "Failed to register mbox_controller(%d)\n", ret); return ret; } -static int ti_msgmgr_remove(struct platform_device *pdev) -{ - struct ti_msgmgr_inst *inst; - - inst = platform_get_drvdata(pdev); - mbox_controller_unregister(&inst->mbox); - - return 0; -} - static struct platform_driver ti_msgmgr_driver = { .probe = ti_msgmgr_probe, - .remove = ti_msgmgr_remove, .driver = { .name = "ti-msgmgr", .of_match_table = of_match_ptr(ti_msgmgr_of_match), From a8803d7421cc2be2ac12a8155e5d824f04259eff Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Nov 2018 10:54:10 +0100 Subject: [PATCH 24/30] mailbox: Support blocking transfers in atomic context The mailbox framework supports blocking transfers via completions for clients that can sleep. In order to support blocking transfers in cases where the transmission is not permitted to sleep, add a new ->flush() callback that controller drivers can implement to busy loop until the transmission has been completed. A new mbox_flush() function can be called by mailbox consumers in atomic context to make sure a transfer has completed. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 28 ++++++++++++++++++++++++++++ include/linux/mailbox_client.h | 1 + include/linux/mailbox_controller.h | 4 ++++ 3 files changed, 33 insertions(+) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 08ce9a1ab53a..6abb35ff49fa 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -283,6 +283,34 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg) } EXPORT_SYMBOL_GPL(mbox_send_message); +/** + * mbox_flush - flush a mailbox channel + * @chan: mailbox channel to flush + * @timeout: time, in milliseconds, to allow the flush operation to succeed + * + * Mailbox controllers that need to work in atomic context can implement the + * ->flush() callback to busy loop until a transmission has been completed. + * The implementation must call mbox_chan_txdone() upon success. Clients can + * call the mbox_flush() function at any time after mbox_send_message() to + * flush the transmission. After the function returns success, the mailbox + * transmission is guaranteed to have completed. + * + * Returns: 0 on success or a negative error code on failure. + */ +int mbox_flush(struct mbox_chan *chan, unsigned long timeout) +{ + int ret; + + if (!chan->mbox->ops->flush) + return -ENOTSUPP; + + ret = chan->mbox->ops->flush(chan, timeout); + if (ret < 0) + tx_tick(chan, ret); + + return ret; +} + /** * mbox_request_channel - Request a mailbox channel. * @cl: Identity of the client requesting the channel. diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h index 44348710953f..faa7da3c9c8b 100644 --- a/include/linux/mailbox_client.h +++ b/include/linux/mailbox_client.h @@ -44,6 +44,7 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl, const char *name); struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index); int mbox_send_message(struct mbox_chan *chan, void *mssg); +int mbox_flush(struct mbox_chan *chan, unsigned long timeout); void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */ void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 9b0b21207345..4994a438444c 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -24,6 +24,9 @@ struct mbox_chan; * transmission of data is reported by the controller via * mbox_chan_txdone (if it has some TX ACK irq). It must not * sleep. + * @flush: Called when a client requests transmissions to be blocking but + * the context doesn't allow sleeping. Typically the controller + * will implement a busy loop waiting for the data to flush out. * @startup: Called when a client requests the chan. The controller * could ask clients for additional parameters of communication * to be provided via client's chan_data. This call may @@ -46,6 +49,7 @@ struct mbox_chan; */ struct mbox_chan_ops { int (*send_data)(struct mbox_chan *chan, void *data); + int (*flush)(struct mbox_chan *chan, unsigned long timeout); int (*startup)(struct mbox_chan *chan); void (*shutdown)(struct mbox_chan *chan); bool (*last_tx_done)(struct mbox_chan *chan); From 8ed82e23875e6014d9aa8e03bf4301b27d614050 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 28 Nov 2018 10:54:11 +0100 Subject: [PATCH 25/30] mailbox: Allow multiple controllers per device Look through the whole controller list when mapping device tree phandles to controllers instead of stopping at the first one. Each controller is intended to only contain one kind of mailbox, but some devices (like Tegra HSP) implement multiple kinds and use the same device tree node for all of them. As such, we need to allow multiple mbox_controllers per device tree node. Signed-off-by: Mikko Perttunen Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 6abb35ff49fa..c6a7d4582dc6 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -355,7 +355,8 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) list_for_each_entry(mbox, &mbox_cons, node) if (mbox->dev->of_node == spec.np) { chan = mbox->of_xlate(mbox, &spec); - break; + if (!IS_ERR(chan)) + break; } of_node_put(spec.np); From fed8b7e366e7c8f81e957ef91aa8f0a38e038c66 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 28 Nov 2018 10:54:12 +0100 Subject: [PATCH 26/30] dt-bindings: tegra186-hsp: Add shared mailboxes Shared mailboxes are a mechanism to transport data from one processor in the system to another. They are bidirectional links with both a producer and a consumer. Interrupts are used to let the consumer know when data was written to the mailbox by the producer, and to let the producer know when the consumer has read the data from the mailbox. These interrupts are mapped to one or more "shared interrupts". Typically each processor in the system owns one of these shared interrupts. Add documentation to the device tree bindings about how clients can use mailbox specifiers to request a specific shared mailbox and select which direction they drive. Also document how to specify the shared interrupts in addition to the existing doorbell interrupt. Signed-off-by: Mikko Perttunen Acked-by: Jon Hunter Reviewed-by: Rob Herring Acked-by: Thierry Reding Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- .../bindings/mailbox/nvidia,tegra186-hsp.txt | 30 +++++++++++++++---- include/dt-bindings/mailbox/tegra186-hsp.h | 11 +++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt index b99d25fc2f26..ff3eafc5a882 100644 --- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt @@ -15,12 +15,15 @@ Required properties: Array of strings. one of: - "nvidia,tegra186-hsp" + - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp" - reg : Offset and length of the register set for the device. - interrupt-names Array of strings. Contains a list of names for the interrupts described by the interrupt property. May contain the following entries, in any order: - "doorbell" + - "sharedN", where 'N' is a number from zero up to the number of + external interrupts supported by the HSP instance minus one. Users of this binding MUST look up entries in the interrupt property by name, using this interrupt-names property to do so. - interrupts @@ -29,12 +32,29 @@ Required properties: in a matching order. - #mbox-cells : Should be 2. -The mbox specifier of the "mboxes" property in the client node should -contain two data. The first one should be the HSP type and the second -one should be the ID that the client is going to use. Those information -can be found in the following file. +The mbox specifier of the "mboxes" property in the client node should contain +two cells. The first cell determines the HSP type and the second cell is used +to identify the mailbox that the client is going to use. -- . +For doorbells, the second cell specifies the index of the doorbell to use. + +For shared mailboxes, the second cell is composed of two fields: +- bits 31..24: + A bit mask of flags that further specify how the shared mailbox will be + used. Valid flags are: + - bit 31: + Defines the direction of the mailbox. If set, the mailbox will be used + as a producer (i.e. used to send data). If cleared, the mailbox is the + consumer of data sent by a producer. + +- bits 23.. 0: + The index of the shared mailbox to use. The number of available mailboxes + may vary by instance of the HSP block and SoC generation. + +The following file contains definitions that can be used to construct mailbox +specifiers: + + Example: diff --git a/include/dt-bindings/mailbox/tegra186-hsp.h b/include/dt-bindings/mailbox/tegra186-hsp.h index bcab5b7ca785..3bdec7a84d35 100644 --- a/include/dt-bindings/mailbox/tegra186-hsp.h +++ b/include/dt-bindings/mailbox/tegra186-hsp.h @@ -22,4 +22,15 @@ #define TEGRA_HSP_DB_MASTER_CCPLEX 17 #define TEGRA_HSP_DB_MASTER_BPMP 19 +/* + * Shared mailboxes are unidirectional, so the direction needs to be specified + * in the device tree. + */ +#define TEGRA_HSP_SM_MASK 0x00ffffff +#define TEGRA_HSP_SM_FLAG_RX (0 << 31) +#define TEGRA_HSP_SM_FLAG_TX (1 << 31) + +#define TEGRA_HSP_SM_RX(x) (TEGRA_HSP_SM_FLAG_RX | ((x) & TEGRA_HSP_SM_MASK)) +#define TEGRA_HSP_SM_TX(x) (TEGRA_HSP_SM_FLAG_TX | ((x) & TEGRA_HSP_SM_MASK)) + #endif From 91b1b1c3da8a8fd9ee4538e00dd5e5fb5be1cdb4 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Nov 2018 10:54:13 +0100 Subject: [PATCH 27/30] mailbox: tegra-hsp: Add support for shared mailboxes The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit registers consisting of a FULL bit in MSB position and 31 bits of data. The hardware can be configured to trigger interrupts when a mailbox is empty or full. Add support for these shared mailboxes to the HSP driver. The initial use for the mailboxes is the Tegra Combined UART. For this purpose, we use interrupts to receive data, and spinning to wait for the transmit mailbox to be emptied to minimize unnecessary overhead. Based on work by Mikko Perttunen . Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/tegra-hsp.c | 506 +++++++++++++++++++++++++++++++----- 1 file changed, 444 insertions(+), 62 deletions(-) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 0cde356c11ab..a4ec18d76cba 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -11,6 +11,7 @@ * more details. */ +#include #include #include #include @@ -21,6 +22,17 @@ #include +#include "mailbox.h" + +#define HSP_INT_IE(x) (0x100 + ((x) * 4)) +#define HSP_INT_IV 0x300 +#define HSP_INT_IR 0x304 + +#define HSP_INT_EMPTY_SHIFT 0 +#define HSP_INT_EMPTY_MASK 0xff +#define HSP_INT_FULL_SHIFT 8 +#define HSP_INT_FULL_MASK 0xff + #define HSP_INT_DIMENSIONING 0x380 #define HSP_nSM_SHIFT 0 #define HSP_nSS_SHIFT 4 @@ -34,6 +46,11 @@ #define HSP_DB_RAW 0x8 #define HSP_DB_PENDING 0xc +#define HSP_SM_SHRD_MBOX 0x0 +#define HSP_SM_SHRD_MBOX_FULL BIT(31) +#define HSP_SM_SHRD_MBOX_FULL_INT_IE 0x04 +#define HSP_SM_SHRD_MBOX_EMPTY_INT_IE 0x08 + #define HSP_DB_CCPLEX 1 #define HSP_DB_BPMP 3 #define HSP_DB_MAX 7 @@ -55,6 +72,12 @@ struct tegra_hsp_doorbell { unsigned int index; }; +struct tegra_hsp_mailbox { + struct tegra_hsp_channel channel; + unsigned int index; + bool producer; +}; + struct tegra_hsp_db_map { const char *name; unsigned int master; @@ -63,13 +86,18 @@ struct tegra_hsp_db_map { struct tegra_hsp_soc { const struct tegra_hsp_db_map *map; + bool has_per_mb_ie; }; struct tegra_hsp { + struct device *dev; const struct tegra_hsp_soc *soc; - struct mbox_controller mbox; + struct mbox_controller mbox_db; + struct mbox_controller mbox_sm; void __iomem *regs; - unsigned int irq; + unsigned int doorbell_irq; + unsigned int *shared_irqs; + unsigned int shared_irq; unsigned int num_sm; unsigned int num_as; unsigned int num_ss; @@ -78,13 +106,10 @@ struct tegra_hsp { spinlock_t lock; struct list_head doorbells; -}; + struct tegra_hsp_mailbox *mailboxes; -static inline struct tegra_hsp * -to_tegra_hsp(struct mbox_controller *mbox) -{ - return container_of(mbox, struct tegra_hsp, mbox); -} + unsigned long mask; +}; static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset) { @@ -158,7 +183,7 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data) spin_lock(&hsp->lock); - for_each_set_bit(master, &value, hsp->mbox.num_chans) { + for_each_set_bit(master, &value, hsp->mbox_db.num_chans) { struct tegra_hsp_doorbell *db; db = __tegra_hsp_doorbell_get(hsp, master); @@ -182,6 +207,71 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t tegra_hsp_shared_irq(int irq, void *data) +{ + struct tegra_hsp *hsp = data; + unsigned long bit, mask; + u32 status, value; + void *msg; + + status = tegra_hsp_readl(hsp, HSP_INT_IR) & hsp->mask; + + /* process EMPTY interrupts first */ + mask = (status >> HSP_INT_EMPTY_SHIFT) & HSP_INT_EMPTY_MASK; + + for_each_set_bit(bit, &mask, hsp->num_sm) { + struct tegra_hsp_mailbox *mb = &hsp->mailboxes[bit]; + + if (mb->producer) { + /* + * Disable EMPTY interrupts until data is sent with + * the next message. These interrupts are level- + * triggered, so if we kept them enabled they would + * constantly trigger until we next write data into + * the message. + */ + spin_lock(&hsp->lock); + + hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index); + tegra_hsp_writel(hsp, hsp->mask, + HSP_INT_IE(hsp->shared_irq)); + + spin_unlock(&hsp->lock); + + mbox_chan_txdone(mb->channel.chan, 0); + } + } + + /* process FULL interrupts */ + mask = (status >> HSP_INT_FULL_SHIFT) & HSP_INT_FULL_MASK; + + for_each_set_bit(bit, &mask, hsp->num_sm) { + struct tegra_hsp_mailbox *mb = &hsp->mailboxes[bit]; + + if (!mb->producer) { + value = tegra_hsp_channel_readl(&mb->channel, + HSP_SM_SHRD_MBOX); + value &= ~HSP_SM_SHRD_MBOX_FULL; + msg = (void *)(unsigned long)value; + mbox_chan_received_data(mb->channel.chan, msg); + + /* + * Need to clear all bits here since some producers, + * such as TCU, depend on fields in the register + * getting cleared by the consumer. + * + * The mailbox API doesn't give the consumers a way + * of doing that explicitly, so we have to make sure + * we cover all possible cases. + */ + tegra_hsp_channel_writel(&mb->channel, 0x0, + HSP_SM_SHRD_MBOX); + } + } + + return IRQ_HANDLED; +} + static struct tegra_hsp_channel * tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, unsigned int master, unsigned int index) @@ -194,7 +284,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, if (!db) return ERR_PTR(-ENOMEM); - offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16; + offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K; offset += index * 0x100; db->channel.regs = hsp->regs + offset; @@ -235,8 +325,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan) unsigned long flags; u32 value; - if (db->master >= hsp->mbox.num_chans) { - dev_err(hsp->mbox.dev, + if (db->master >= chan->mbox->num_chans) { + dev_err(chan->mbox->dev, "invalid master ID %u for HSP channel\n", db->master); return -EINVAL; @@ -281,46 +371,167 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan) spin_unlock_irqrestore(&hsp->lock, flags); } -static const struct mbox_chan_ops tegra_hsp_doorbell_ops = { +static const struct mbox_chan_ops tegra_hsp_db_ops = { .send_data = tegra_hsp_doorbell_send_data, .startup = tegra_hsp_doorbell_startup, .shutdown = tegra_hsp_doorbell_shutdown, }; -static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox, +static int tegra_hsp_mailbox_send_data(struct mbox_chan *chan, void *data) +{ + struct tegra_hsp_mailbox *mb = chan->con_priv; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned long flags; + u32 value; + + if (WARN_ON(!mb->producer)) + return -EPERM; + + /* copy data and mark mailbox full */ + value = (u32)(unsigned long)data; + value |= HSP_SM_SHRD_MBOX_FULL; + + tegra_hsp_channel_writel(&mb->channel, value, HSP_SM_SHRD_MBOX); + + /* enable EMPTY interrupt for the shared mailbox */ + spin_lock_irqsave(&hsp->lock, flags); + + hsp->mask |= BIT(HSP_INT_EMPTY_SHIFT + mb->index); + tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq)); + + spin_unlock_irqrestore(&hsp->lock, flags); + + return 0; +} + +static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, + unsigned long timeout) +{ + struct tegra_hsp_mailbox *mb = chan->con_priv; + struct tegra_hsp_channel *ch = &mb->channel; + u32 value; + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_before(jiffies, timeout)) { + value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX); + if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) { + mbox_chan_txdone(chan, 0); + return 0; + } + + udelay(1); + } + + return -ETIME; +} + +static int tegra_hsp_mailbox_startup(struct mbox_chan *chan) +{ + struct tegra_hsp_mailbox *mb = chan->con_priv; + struct tegra_hsp_channel *ch = &mb->channel; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned long flags; + + chan->txdone_method = TXDONE_BY_IRQ; + + /* + * Shared mailboxes start out as consumers by default. FULL and EMPTY + * interrupts are coalesced at the same shared interrupt. + * + * Keep EMPTY interrupts disabled at startup and only enable them when + * the mailbox is actually full. This is required because the FULL and + * EMPTY interrupts are level-triggered, so keeping EMPTY interrupts + * enabled all the time would cause an interrupt storm while mailboxes + * are idle. + */ + + spin_lock_irqsave(&hsp->lock, flags); + + if (mb->producer) + hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index); + else + hsp->mask |= BIT(HSP_INT_FULL_SHIFT + mb->index); + + tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq)); + + spin_unlock_irqrestore(&hsp->lock, flags); + + if (hsp->soc->has_per_mb_ie) { + if (mb->producer) + tegra_hsp_channel_writel(ch, 0x0, + HSP_SM_SHRD_MBOX_EMPTY_INT_IE); + else + tegra_hsp_channel_writel(ch, 0x1, + HSP_SM_SHRD_MBOX_FULL_INT_IE); + } + + return 0; +} + +static void tegra_hsp_mailbox_shutdown(struct mbox_chan *chan) +{ + struct tegra_hsp_mailbox *mb = chan->con_priv; + struct tegra_hsp_channel *ch = &mb->channel; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned long flags; + + if (hsp->soc->has_per_mb_ie) { + if (mb->producer) + tegra_hsp_channel_writel(ch, 0x0, + HSP_SM_SHRD_MBOX_EMPTY_INT_IE); + else + tegra_hsp_channel_writel(ch, 0x0, + HSP_SM_SHRD_MBOX_FULL_INT_IE); + } + + spin_lock_irqsave(&hsp->lock, flags); + + if (mb->producer) + hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index); + else + hsp->mask &= ~BIT(HSP_INT_FULL_SHIFT + mb->index); + + tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq)); + + spin_unlock_irqrestore(&hsp->lock, flags); +} + +static const struct mbox_chan_ops tegra_hsp_sm_ops = { + .send_data = tegra_hsp_mailbox_send_data, + .flush = tegra_hsp_mailbox_flush, + .startup = tegra_hsp_mailbox_startup, + .shutdown = tegra_hsp_mailbox_shutdown, +}; + +static struct mbox_chan *tegra_hsp_db_xlate(struct mbox_controller *mbox, const struct of_phandle_args *args) { + struct tegra_hsp *hsp = container_of(mbox, struct tegra_hsp, mbox_db); + unsigned int type = args->args[0], master = args->args[1]; struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV); - struct tegra_hsp *hsp = to_tegra_hsp(mbox); - unsigned int type = args->args[0]; - unsigned int master = args->args[1]; struct tegra_hsp_doorbell *db; struct mbox_chan *chan; unsigned long flags; unsigned int i; - switch (type) { - case TEGRA_HSP_MBOX_TYPE_DB: - db = tegra_hsp_doorbell_get(hsp, master); - if (db) - channel = &db->channel; + if (type != TEGRA_HSP_MBOX_TYPE_DB || !hsp->doorbell_irq) + return ERR_PTR(-ENODEV); - break; - - default: - break; - } + db = tegra_hsp_doorbell_get(hsp, master); + if (db) + channel = &db->channel; if (IS_ERR(channel)) return ERR_CAST(channel); spin_lock_irqsave(&hsp->lock, flags); - for (i = 0; i < hsp->mbox.num_chans; i++) { - chan = &hsp->mbox.chans[i]; + for (i = 0; i < mbox->num_chans; i++) { + chan = &mbox->chans[i]; if (!chan->con_priv) { - chan->con_priv = channel; channel->chan = chan; + chan->con_priv = db; break; } @@ -332,6 +543,29 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox, return chan ?: ERR_PTR(-EBUSY); } +static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *args) +{ + struct tegra_hsp *hsp = container_of(mbox, struct tegra_hsp, mbox_sm); + unsigned int type = args->args[0], index; + struct tegra_hsp_mailbox *mb; + + index = args->args[1] & TEGRA_HSP_SM_MASK; + + if (type != TEGRA_HSP_MBOX_TYPE_SM || !hsp->shared_irqs || + index >= hsp->num_sm) + return ERR_PTR(-ENODEV); + + mb = &hsp->mailboxes[index]; + + if ((args->args[1] & TEGRA_HSP_SM_FLAG_TX) == 0) + mb->producer = false; + else + mb->producer = true; + + return mb->channel.chan; +} + static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp) { struct tegra_hsp_doorbell *db, *tmp; @@ -364,10 +598,70 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp) return 0; } +static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev) +{ + int i; + + hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes), + GFP_KERNEL); + if (!hsp->mailboxes) + return -ENOMEM; + + for (i = 0; i < hsp->num_sm; i++) { + struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i]; + + mb->index = i; + + mb->channel.hsp = hsp; + mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K; + mb->channel.chan = &hsp->mbox_sm.chans[i]; + mb->channel.chan->con_priv = mb; + } + + return 0; +} + +static int tegra_hsp_request_shared_irq(struct tegra_hsp *hsp) +{ + unsigned int i, irq = 0; + int err; + + for (i = 0; i < hsp->num_si; i++) { + irq = hsp->shared_irqs[i]; + if (irq <= 0) + continue; + + err = devm_request_irq(hsp->dev, irq, tegra_hsp_shared_irq, 0, + dev_name(hsp->dev), hsp); + if (err < 0) { + dev_err(hsp->dev, "failed to request interrupt: %d\n", + err); + continue; + } + + hsp->shared_irq = i; + + /* disable all interrupts */ + tegra_hsp_writel(hsp, 0, HSP_INT_IE(hsp->shared_irq)); + + dev_dbg(hsp->dev, "interrupt requested: %u\n", irq); + + break; + } + + if (i == hsp->num_si) { + dev_err(hsp->dev, "failed to find available interrupt\n"); + return -ENOENT; + } + + return 0; +} + static int tegra_hsp_probe(struct platform_device *pdev) { struct tegra_hsp *hsp; struct resource *res; + unsigned int i; u32 value; int err; @@ -375,6 +669,7 @@ static int tegra_hsp_probe(struct platform_device *pdev) if (!hsp) return -ENOMEM; + hsp->dev = &pdev->dev; hsp->soc = of_device_get_match_data(&pdev->dev); INIT_LIST_HEAD(&hsp->doorbells); spin_lock_init(&hsp->lock); @@ -392,58 +687,138 @@ static int tegra_hsp_probe(struct platform_device *pdev) hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK; err = platform_get_irq_byname(pdev, "doorbell"); - if (err < 0) { - dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err); - return err; + if (err >= 0) + hsp->doorbell_irq = err; + + if (hsp->num_si > 0) { + unsigned int count = 0; + + hsp->shared_irqs = devm_kcalloc(&pdev->dev, hsp->num_si, + sizeof(*hsp->shared_irqs), + GFP_KERNEL); + if (!hsp->shared_irqs) + return -ENOMEM; + + for (i = 0; i < hsp->num_si; i++) { + char *name; + + name = kasprintf(GFP_KERNEL, "shared%u", i); + if (!name) + return -ENOMEM; + + err = platform_get_irq_byname(pdev, name); + if (err >= 0) { + hsp->shared_irqs[i] = err; + count++; + } + + kfree(name); + } + + if (count == 0) { + devm_kfree(&pdev->dev, hsp->shared_irqs); + hsp->shared_irqs = NULL; + } } - hsp->irq = err; + /* setup the doorbell controller */ + hsp->mbox_db.of_xlate = tegra_hsp_db_xlate; + hsp->mbox_db.num_chans = 32; + hsp->mbox_db.dev = &pdev->dev; + hsp->mbox_db.ops = &tegra_hsp_db_ops; - hsp->mbox.of_xlate = of_tegra_hsp_xlate; - hsp->mbox.num_chans = 32; - hsp->mbox.dev = &pdev->dev; - hsp->mbox.txdone_irq = false; - hsp->mbox.txdone_poll = false; - hsp->mbox.ops = &tegra_hsp_doorbell_ops; - - hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans, - sizeof(*hsp->mbox.chans), - GFP_KERNEL); - if (!hsp->mbox.chans) + hsp->mbox_db.chans = devm_kcalloc(&pdev->dev, hsp->mbox_db.num_chans, + sizeof(*hsp->mbox_db.chans), + GFP_KERNEL); + if (!hsp->mbox_db.chans) return -ENOMEM; - err = tegra_hsp_add_doorbells(hsp); + if (hsp->doorbell_irq) { + err = tegra_hsp_add_doorbells(hsp); + if (err < 0) { + dev_err(&pdev->dev, "failed to add doorbells: %d\n", + err); + return err; + } + } + + err = mbox_controller_register(&hsp->mbox_db); if (err < 0) { - dev_err(&pdev->dev, "failed to add doorbells: %d\n", err); - return err; + dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n", + err); + goto remove_doorbells; + } + + /* setup the shared mailbox controller */ + hsp->mbox_sm.of_xlate = tegra_hsp_sm_xlate; + hsp->mbox_sm.num_chans = hsp->num_sm; + hsp->mbox_sm.dev = &pdev->dev; + hsp->mbox_sm.ops = &tegra_hsp_sm_ops; + + hsp->mbox_sm.chans = devm_kcalloc(&pdev->dev, hsp->mbox_sm.num_chans, + sizeof(*hsp->mbox_sm.chans), + GFP_KERNEL); + if (!hsp->mbox_sm.chans) + return -ENOMEM; + + if (hsp->shared_irqs) { + err = tegra_hsp_add_mailboxes(hsp, &pdev->dev); + if (err < 0) { + dev_err(&pdev->dev, "failed to add mailboxes: %d\n", + err); + goto unregister_mbox_db; + } + } + + err = mbox_controller_register(&hsp->mbox_sm); + if (err < 0) { + dev_err(&pdev->dev, "failed to register shared mailbox: %d\n", + err); + goto unregister_mbox_db; } platform_set_drvdata(pdev, hsp); - err = mbox_controller_register(&hsp->mbox); - if (err) { - dev_err(&pdev->dev, "failed to register mailbox: %d\n", err); - tegra_hsp_remove_doorbells(hsp); - return err; + if (hsp->doorbell_irq) { + err = devm_request_irq(&pdev->dev, hsp->doorbell_irq, + tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND, + dev_name(&pdev->dev), hsp); + if (err < 0) { + dev_err(&pdev->dev, + "failed to request doorbell IRQ#%u: %d\n", + hsp->doorbell_irq, err); + goto unregister_mbox_sm; + } } - err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq, - IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp); - if (err < 0) { - dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", - hsp->irq, err); - return err; + if (hsp->shared_irqs) { + err = tegra_hsp_request_shared_irq(hsp); + if (err < 0) + goto unregister_mbox_sm; } return 0; + +unregister_mbox_sm: + mbox_controller_unregister(&hsp->mbox_sm); +unregister_mbox_db: + mbox_controller_unregister(&hsp->mbox_db); +remove_doorbells: + if (hsp->doorbell_irq) + tegra_hsp_remove_doorbells(hsp); + + return err; } static int tegra_hsp_remove(struct platform_device *pdev) { struct tegra_hsp *hsp = platform_get_drvdata(pdev); - mbox_controller_unregister(&hsp->mbox); - tegra_hsp_remove_doorbells(hsp); + mbox_controller_unregister(&hsp->mbox_sm); + mbox_controller_unregister(&hsp->mbox_db); + + if (hsp->doorbell_irq) + tegra_hsp_remove_doorbells(hsp); return 0; } @@ -456,10 +831,17 @@ static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = { static const struct tegra_hsp_soc tegra186_hsp_soc = { .map = tegra186_hsp_db_map, + .has_per_mb_ie = false, +}; + +static const struct tegra_hsp_soc tegra194_hsp_soc = { + .map = tegra186_hsp_db_map, + .has_per_mb_ie = true, }; static const struct of_device_id tegra_hsp_match[] = { { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc }, + { .compatible = "nvidia,tegra194-hsp", .data = &tegra194_hsp_soc }, { } }; From 9a63f0f4059955210ae74c745513332a568e9738 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Nov 2018 10:54:14 +0100 Subject: [PATCH 28/30] mailbox: tegra-hsp: Add suspend/resume support Upon resuming from a system sleep state, the interrupts for all active shared mailboxes need to be reenabled, otherwise they will not work. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/tegra-hsp.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index a4ec18d76cba..07d1fbff3642 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -823,6 +824,23 @@ static int tegra_hsp_remove(struct platform_device *pdev) return 0; } +static int tegra_hsp_resume(struct device *dev) +{ + struct tegra_hsp *hsp = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < hsp->num_sm; i++) { + struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i]; + + if (mb->channel.chan->cl) + tegra_hsp_mailbox_startup(mb->channel.chan); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tegra_hsp_pm_ops, NULL, tegra_hsp_resume); + static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = { { "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, }, { "bpmp", TEGRA_HSP_DB_MASTER_BPMP, HSP_DB_BPMP, }, @@ -849,6 +867,7 @@ static struct platform_driver tegra_hsp_driver = { .driver = { .name = "tegra-hsp", .of_match_table = tegra_hsp_match, + .pm = &tegra_hsp_pm_ops, }, .probe = tegra_hsp_probe, .remove = tegra_hsp_remove, From a54d03ed01b4ed64c22d2b53d61d4049ec49a51f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 28 Nov 2018 10:54:15 +0100 Subject: [PATCH 29/30] mailbox: tegra-hsp: use devm_kstrdup_const() Use devm_kstrdup_const() in the tegra-hsp driver. This mostly serves as an example of how to use this new routine to shrink driver code. Also use devm_kzalloc() instead of regular kzalloc() to shrink the driver even more. Doorbell objects are only removed in the driver's remove callback so it's safe to convert all memory allocations to devres. Signed-off-by: Bartosz Golaszewski Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/tegra-hsp.c | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 07d1fbff3642..9628e52e2371 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -281,7 +281,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, unsigned int offset; unsigned long flags; - db = kzalloc(sizeof(*db), GFP_KERNEL); + db = devm_kzalloc(hsp->dev, sizeof(*db), GFP_KERNEL); if (!db) return ERR_PTR(-ENOMEM); @@ -291,7 +291,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, db->channel.regs = hsp->regs + offset; db->channel.hsp = hsp; - db->name = kstrdup_const(name, GFP_KERNEL); + db->name = devm_kstrdup_const(hsp->dev, name, GFP_KERNEL); db->master = master; db->index = index; @@ -302,13 +302,6 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, return &db->channel; } -static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db) -{ - list_del(&db->list); - kfree_const(db->name); - kfree(db); -} - static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data) { struct tegra_hsp_doorbell *db = chan->con_priv; @@ -567,19 +560,6 @@ static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox, return mb->channel.chan; } -static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp) -{ - struct tegra_hsp_doorbell *db, *tmp; - unsigned long flags; - - spin_lock_irqsave(&hsp->lock, flags); - - list_for_each_entry_safe(db, tmp, &hsp->doorbells, list) - __tegra_hsp_doorbell_destroy(db); - - spin_unlock_irqrestore(&hsp->lock, flags); -} - static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp) { const struct tegra_hsp_db_map *map = hsp->soc->map; @@ -588,10 +568,8 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp) while (map->name) { channel = tegra_hsp_doorbell_create(hsp, map->name, map->master, map->index); - if (IS_ERR(channel)) { - tegra_hsp_remove_doorbells(hsp); + if (IS_ERR(channel)) return PTR_ERR(channel); - } map++; } @@ -747,7 +725,7 @@ static int tegra_hsp_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n", err); - goto remove_doorbells; + return err; } /* setup the shared mailbox controller */ @@ -804,9 +782,6 @@ unregister_mbox_sm: mbox_controller_unregister(&hsp->mbox_sm); unregister_mbox_db: mbox_controller_unregister(&hsp->mbox_db); -remove_doorbells: - if (hsp->doorbell_irq) - tegra_hsp_remove_doorbells(hsp); return err; } @@ -818,9 +793,6 @@ static int tegra_hsp_remove(struct platform_device *pdev) mbox_controller_unregister(&hsp->mbox_sm); mbox_controller_unregister(&hsp->mbox_db); - if (hsp->doorbell_irq) - tegra_hsp_remove_doorbells(hsp); - return 0; } From d69e11648e486ee0f21cb246f687b083f0d4e124 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Nov 2018 10:54:16 +0100 Subject: [PATCH 30/30] mailbox: tegra-hsp: Use device-managed registration API In order to get rid of a lot of cleanup boilerplate code, use the device-managed registration API. Signed-off-by: Thierry Reding Signed-off-by: Jassi Brar --- drivers/mailbox/tegra-hsp.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 9628e52e2371..e443f6a2ec4b 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -721,7 +721,7 @@ static int tegra_hsp_probe(struct platform_device *pdev) } } - err = mbox_controller_register(&hsp->mbox_db); + err = devm_mbox_controller_register(&pdev->dev, &hsp->mbox_db); if (err < 0) { dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n", err); @@ -745,15 +745,15 @@ static int tegra_hsp_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to add mailboxes: %d\n", err); - goto unregister_mbox_db; + return err; } } - err = mbox_controller_register(&hsp->mbox_sm); + err = devm_mbox_controller_register(&pdev->dev, &hsp->mbox_sm); if (err < 0) { dev_err(&pdev->dev, "failed to register shared mailbox: %d\n", err); - goto unregister_mbox_db; + return err; } platform_set_drvdata(pdev, hsp); @@ -766,33 +766,16 @@ static int tegra_hsp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n", hsp->doorbell_irq, err); - goto unregister_mbox_sm; + return err; } } if (hsp->shared_irqs) { err = tegra_hsp_request_shared_irq(hsp); if (err < 0) - goto unregister_mbox_sm; + return err; } - return 0; - -unregister_mbox_sm: - mbox_controller_unregister(&hsp->mbox_sm); -unregister_mbox_db: - mbox_controller_unregister(&hsp->mbox_db); - - return err; -} - -static int tegra_hsp_remove(struct platform_device *pdev) -{ - struct tegra_hsp *hsp = platform_get_drvdata(pdev); - - mbox_controller_unregister(&hsp->mbox_sm); - mbox_controller_unregister(&hsp->mbox_db); - return 0; } @@ -842,7 +825,6 @@ static struct platform_driver tegra_hsp_driver = { .pm = &tegra_hsp_pm_ops, }, .probe = tegra_hsp_probe, - .remove = tegra_hsp_remove, }; static int __init tegra_hsp_init(void)