mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
mailbox: updates for v7.2
- core: add debugfs support for used channels, fix resource leak on startup failure, propagate tx error codes, and clarify blocking mode thread support
- exynos: remove unused register definitions
- imx: refactor IRQ handlers, migrate to devm helpers, and other minor improvements
- mpfs: fix syscon presence check in inbox ISR
- mtk-adsp: fix use-after-free during device teardown
- qcom: add dt-bindings for QCOM Maili, Hawi, Shikra APCS, and Nord CPUCP platform support
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE6EwehDt/SOnwFyTyf9lkf8eYP5UFAmo3WjsACgkQf9lkf8eY
P5XMGxAAjEcV+X874iXmPLQ/pVAQBaqVHG2/bhux8RGhB6F27fEDbP46/sMlLuq+
tD6oo61+zMfF+33JC4CD7vGTUIPX4sGoQwQ+5Y60j3AUS0yHHEIADtMkxsbSJaQG
h2XgO9RPJBy4KojPCwFQ+McAwl3Mg72yeEK6Xpim4GG314wGBuO63zlyMQjdSPzc
w04+NUwOdVZwr2t+ar/XqJw4bHiqgV2QIlfvSbuV28NhZGNhnxThxC2NtqPIFDhm
HxbBJvycB+4YszGBPQEfHEFsrVLER0D0yzTcWjTGWHQBGxOjFZ6MYooEuqiwWgzh
MZCmcvW6x1NTrfHGoHY3iQHu9WAhKM2eMDq1ktgJOnDspymWrbirNMB7r9Qo76dM
vxA8HFL/1WxqAJbGfmAtMqr5936nJk2W9cAk3R8R+HLKwYWG2JlGy2ju3xLKDnVT
DpcFYGJF/NVNnHSclcfEHFC84+OUEMgx93NWBkPHugG7+UWJePWxns6Ovrpr4OfP
I28ZktmlpZ1FRpEwepPHuMDfwWPFVVPJpz4aKMSCCO439KaIl+k2pn7KD6MzcR9Y
q1IwaXPXpox6zu2tlEJZBIkPPi0bhrptKwIWWyCfyImSXkNDlE0l6jHIWlgAud21
nFKKqKnBb5mEOtMm+UYjtuG3K9HPrG65JWJV3uVnDd1iTG8DnNs=
=5JeW
-----END PGP SIGNATURE-----
Merge tag 'mailbox-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox
Pull mailbox updates from Jassi Brar:
"Core:
- add debugfs support for used channels
- fix resource leak on startup failure
- propagate tx error codes
- clarify blocking mode thread support
Drivers:
- exynos: remove unused register definitions
- imx: refactor IRQ handlers, migrate to devm helpers, and other
minor improvements
- mpfs: fix syscon presence check in inbox ISR
- mtk-adsp: fix use-after-free during device teardown
- qcom: add dt-bindings for QCOM Maili, Hawi, Shikra APCS, and Nord
CPUCP platform support"
* tag 'mailbox-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox: (23 commits)
mailbox: imx: Don't force-thread the primary handler
mailbox: imx: Move the RXDB part of the mailbox into the threaded handler
mailbox: imx: Move the RX part of the mailbox into the threaded handler
mailbox: imx: Start splitting the IRQ handler in primary and threaded handler
mailbox: imx: Use channel index instead of zero in imx_mu_specific_rx()
mailbox: imx: use devm_of_platform_populate()
mailbox: imx: Use devm_pm_runtime_enable()
mailbox: imx: Add a channel shutdown field
mailbox: imx: Forward the timeout/ error in imx_mu_generic_tx()
dt-bindings: mailbox: qcom: Add IPCC support for Maili Platform
mailbox: add list of used channels to debugfs
mailbox: don't free the channel if the startup callback failed
mailbox: Make mbox_send_message() return error code when tx fails
mailbox: Clarify multi-thread is not supported in blocking mode
mailbox: mtk-adsp: fix UAF during device teardown
mailbox: qcom: Unify user-visible "Qualcomm" name
mailbox: exynos: Drop unused register definitions
dt-bindings: mailbox: qcom: Add IPCC support for Hawi Platform
dt-bindings: mailbox: qcom,cpucp-mbox: Add Hawi compatible
dt-bindings: mailbox: qcom: Add Shikra APCS compatible
...
This commit is contained in:
commit
515db26214
|
|
@ -49,6 +49,7 @@ properties:
|
|||
- qcom,qcs615-apss-shared
|
||||
- qcom,sc7180-apss-shared
|
||||
- qcom,sc8180x-apss-shared
|
||||
- qcom,shikra-apss-shared
|
||||
- qcom,sm7150-apss-shared
|
||||
- qcom,sm8150-apss-shared
|
||||
- const: qcom,sdm845-apss-shared
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,glymur-cpucp-mbox
|
||||
- qcom,hawi-cpucp-mbox
|
||||
- qcom,kaanapali-cpucp-mbox
|
||||
- qcom,nord-cpucp-mbox
|
||||
- qcom,sm8750-cpucp-mbox
|
||||
- const: qcom,x1e80100-cpucp-mbox
|
||||
- enum:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ properties:
|
|||
- enum:
|
||||
- qcom,eliza-ipcc
|
||||
- qcom,glymur-ipcc
|
||||
- qcom,hawi-ipcc
|
||||
- qcom,kaanapali-ipcc
|
||||
- qcom,maili-ipcc
|
||||
- qcom,milos-ipcc
|
||||
- qcom,qcs8300-ipcc
|
||||
- qcom,qdu1000-ipcc
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ config SPRD_MBOX
|
|||
you want to build the Spreatrum mailbox controller driver.
|
||||
|
||||
config QCOM_CPUCP_MBOX
|
||||
tristate "Qualcomm Technologies, Inc. CPUCP mailbox driver"
|
||||
tristate "Qualcomm CPUCP mailbox driver"
|
||||
depends on (ARCH_QCOM || COMPILE_TEST) && 64BIT
|
||||
help
|
||||
Qualcomm Technologies, Inc. CPUSS Control Processor (CPUCP) mailbox
|
||||
|
|
@ -349,7 +349,7 @@ config QCOM_CPUCP_MBOX
|
|||
Y here if you want to build this driver.
|
||||
|
||||
config QCOM_IPCC
|
||||
tristate "Qualcomm Technologies, Inc. IPCC driver"
|
||||
tristate "Qualcomm IPCC driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
help
|
||||
Qualcomm Technologies, Inc. Inter-Processor Communication Controller
|
||||
|
|
|
|||
|
|
@ -16,15 +16,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define EXYNOS_MBOX_MCUCTRL 0x0 /* Mailbox Control Register */
|
||||
#define EXYNOS_MBOX_INTCR0 0x24 /* Interrupt Clear Register 0 */
|
||||
#define EXYNOS_MBOX_INTMR0 0x28 /* Interrupt Mask Register 0 */
|
||||
#define EXYNOS_MBOX_INTSR0 0x2c /* Interrupt Status Register 0 */
|
||||
#define EXYNOS_MBOX_INTMSR0 0x30 /* Interrupt Mask Status Register 0 */
|
||||
#define EXYNOS_MBOX_INTGR1 0x40 /* Interrupt Generation Register 1 */
|
||||
#define EXYNOS_MBOX_INTMR1 0x48 /* Interrupt Mask Register 1 */
|
||||
#define EXYNOS_MBOX_INTSR1 0x4c /* Interrupt Status Register 1 */
|
||||
#define EXYNOS_MBOX_INTMSR1 0x50 /* Interrupt Mask Status Register 1 */
|
||||
|
||||
#define EXYNOS_MBOX_INTMR0_MASK GENMASK(15, 0)
|
||||
#define EXYNOS_MBOX_INTGR1_MASK GENMASK(15, 0)
|
||||
|
|
|
|||
|
|
@ -80,13 +80,14 @@ struct imx_mu_con_priv {
|
|||
enum imx_mu_chan_type type;
|
||||
struct mbox_chan *chan;
|
||||
struct work_struct txdb_work;
|
||||
bool shutdown;
|
||||
};
|
||||
|
||||
struct imx_mu_priv {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
void *msg;
|
||||
spinlock_t xcr_lock; /* control register lock */
|
||||
raw_spinlock_t xcr_lock; /* control register lock */
|
||||
|
||||
struct mbox_controller mbox;
|
||||
struct mbox_chan mbox_chans[IMX_MU_CHANS];
|
||||
|
|
@ -206,19 +207,44 @@ static int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx)
|
|||
|
||||
static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&priv->xcr_lock, flags);
|
||||
guard(raw_spinlock_irqsave)(&priv->xcr_lock);
|
||||
|
||||
val = imx_mu_read(priv, priv->dcfg->xCR[type]);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
imx_mu_write(priv, val, priv->dcfg->xCR[type]);
|
||||
spin_unlock_irqrestore(&priv->xcr_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void imx_mu_xcr_clr_shut(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp,
|
||||
enum imx_mu_xcr type, u32 clr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->xcr_lock);
|
||||
cp->shutdown = true;
|
||||
|
||||
val = imx_mu_read(priv, priv->dcfg->xCR[type]);
|
||||
val &= ~clr;
|
||||
imx_mu_write(priv, val, priv->dcfg->xCR[type]);
|
||||
}
|
||||
|
||||
static void imx_mu_xcr_set_act(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp,
|
||||
enum imx_mu_xcr type, u32 set)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->xcr_lock);
|
||||
if (!cp->shutdown) {
|
||||
val = imx_mu_read(priv, priv->dcfg->xCR[type]);
|
||||
val |= set;
|
||||
imx_mu_write(priv, val, priv->dcfg->xCR[type]);
|
||||
}
|
||||
}
|
||||
|
||||
static int imx_mu_generic_tx(struct imx_mu_priv *priv,
|
||||
struct imx_mu_con_priv *cp,
|
||||
void *data)
|
||||
|
|
@ -227,6 +253,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
|
|||
u32 val;
|
||||
int ret, count;
|
||||
|
||||
ret = 0;
|
||||
switch (cp->type) {
|
||||
case IMX_MU_TYPE_TX:
|
||||
imx_mu_write(priv, *arg, priv->dcfg->xTR + cp->idx * 4);
|
||||
|
|
@ -259,7 +286,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_mu_generic_rx(struct imx_mu_priv *priv,
|
||||
|
|
@ -349,7 +376,6 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *
|
|||
|
||||
data = (u32 *)priv->msg;
|
||||
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0));
|
||||
*data++ = imx_mu_read(priv, priv->dcfg->xRR);
|
||||
|
||||
if (priv->dcfg->type & IMX_MU_V2_S4) {
|
||||
|
|
@ -376,7 +402,6 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *
|
|||
*data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % num_rr) * 4);
|
||||
}
|
||||
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0);
|
||||
mbox_chan_received_data(cp->chan, (void *)priv->msg);
|
||||
|
||||
return 0;
|
||||
|
|
@ -508,11 +533,41 @@ static void imx_mu_txdb_work(struct work_struct *t)
|
|||
mbox_chan_txdone(cp->chan, 0);
|
||||
}
|
||||
|
||||
static irqreturn_t imx_mu_isr_th(int irq, void *p)
|
||||
{
|
||||
struct mbox_chan *chan = p;
|
||||
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
|
||||
struct imx_mu_con_priv *cp = chan->con_priv;
|
||||
|
||||
switch (cp->type) {
|
||||
case IMX_MU_TYPE_TX:
|
||||
mbox_chan_txdone(chan, 0);
|
||||
break;
|
||||
|
||||
case IMX_MU_TYPE_RX:
|
||||
if (!priv->dcfg->rx(priv, cp))
|
||||
imx_mu_xcr_set_act(priv, cp, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
|
||||
break;
|
||||
|
||||
case IMX_MU_TYPE_RXDB:
|
||||
if (!priv->dcfg->rxdb(priv, cp))
|
||||
imx_mu_xcr_set_act(priv, cp, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n",
|
||||
cp->type);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t imx_mu_isr(int irq, void *p)
|
||||
{
|
||||
struct mbox_chan *chan = p;
|
||||
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
|
||||
struct imx_mu_con_priv *cp = chan->con_priv;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
u32 val, ctrl;
|
||||
|
||||
switch (cp->type) {
|
||||
|
|
@ -548,13 +603,15 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
|
|||
if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) &&
|
||||
(cp->type == IMX_MU_TYPE_TX)) {
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
|
||||
mbox_chan_txdone(chan, 0);
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) &&
|
||||
(cp->type == IMX_MU_TYPE_RX)) {
|
||||
priv->dcfg->rx(priv, cp);
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) &&
|
||||
(cp->type == IMX_MU_TYPE_RXDB)) {
|
||||
priv->dcfg->rxdb(priv, cp);
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else {
|
||||
dev_warn_ratelimited(priv->dev, "Not handled interrupt\n");
|
||||
return IRQ_NONE;
|
||||
|
|
@ -563,7 +620,7 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
|
|||
if (priv->suspend)
|
||||
pm_system_wakeup();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_mu_send_data(struct mbox_chan *chan, void *data)
|
||||
|
|
@ -578,7 +635,7 @@ static int imx_mu_startup(struct mbox_chan *chan)
|
|||
{
|
||||
struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
|
||||
struct imx_mu_con_priv *cp = chan->con_priv;
|
||||
unsigned long irq_flag = 0;
|
||||
unsigned long irq_flag = IRQF_NO_THREAD;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(priv->dev);
|
||||
|
|
@ -598,12 +655,14 @@ static int imx_mu_startup(struct mbox_chan *chan)
|
|||
if (!(priv->dcfg->type & IMX_MU_V2_IRQ))
|
||||
irq_flag |= IRQF_SHARED;
|
||||
|
||||
ret = request_irq(priv->irq[cp->type], imx_mu_isr, irq_flag, cp->irq_desc, chan);
|
||||
ret = request_threaded_irq(priv->irq[cp->type], imx_mu_isr, imx_mu_isr_th,
|
||||
irq_flag, cp->irq_desc, chan);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq[cp->type]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cp->shutdown = false;
|
||||
switch (cp->type) {
|
||||
case IMX_MU_TYPE_RX:
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx), 0);
|
||||
|
|
@ -638,13 +697,13 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
|
|||
|
||||
switch (cp->type) {
|
||||
case IMX_MU_TYPE_TX:
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
|
||||
imx_mu_xcr_clr_shut(priv, cp, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
|
||||
break;
|
||||
case IMX_MU_TYPE_RX:
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
|
||||
imx_mu_xcr_clr_shut(priv, cp, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
|
||||
break;
|
||||
case IMX_MU_TYPE_RXDB:
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
|
||||
imx_mu_xcr_clr_shut(priv, cp, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
|
||||
break;
|
||||
case IMX_MU_TYPE_RST:
|
||||
imx_mu_xcr_rmw(priv, IMX_MU_CR, IMX_MU_xCR_RST(priv->dcfg->type), 0);
|
||||
|
|
@ -924,7 +983,7 @@ static int imx_mu_probe(struct platform_device *pdev)
|
|||
goto disable_clk;
|
||||
}
|
||||
|
||||
spin_lock_init(&priv->xcr_lock);
|
||||
raw_spin_lock_init(&priv->xcr_lock);
|
||||
|
||||
priv->mbox.dev = dev;
|
||||
priv->mbox.ops = &imx_mu_ops;
|
||||
|
|
@ -933,38 +992,36 @@ static int imx_mu_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = devm_mbox_controller_register(dev, &priv->mbox);
|
||||
if (ret)
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret < 0)
|
||||
goto disable_clk;
|
||||
|
||||
of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret < 0)
|
||||
goto disable_runtime_pm;
|
||||
goto disable_clk;
|
||||
|
||||
ret = pm_runtime_put_sync(dev);
|
||||
if (ret < 0)
|
||||
goto disable_runtime_pm;
|
||||
goto disable_clk;
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
ret = devm_mbox_controller_register(dev, &priv->mbox);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
devm_of_platform_populate(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_runtime_pm:
|
||||
pm_runtime_disable(dev);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(priv->clk);
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx_mu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_mu_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(priv->dev);
|
||||
}
|
||||
|
||||
static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
|
|||
struct mbox_chan *chan = data;
|
||||
struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
|
||||
|
||||
if (mbox->control_scb)
|
||||
if (mbox->sysreg_scb)
|
||||
regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0);
|
||||
else
|
||||
writel_relaxed(0, mbox->int_reg);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
static LIST_HEAD(mbox_cons);
|
||||
|
|
@ -98,8 +100,10 @@ static void tx_tick(struct mbox_chan *chan, int r)
|
|||
if (chan->cl->tx_done)
|
||||
chan->cl->tx_done(chan->cl, mssg, r);
|
||||
|
||||
if (r != -ETIME && chan->cl->tx_block)
|
||||
if (r != -ETIME && chan->cl->tx_block) {
|
||||
chan->tx_status = r;
|
||||
complete(&chan->tx_complete);
|
||||
}
|
||||
}
|
||||
|
||||
static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
|
|
@ -258,6 +262,10 @@ EXPORT_SYMBOL_GPL(mbox_chan_tx_slots_available);
|
|||
* over the chan, 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.
|
||||
* In blocking mode, it is caller's responsibility to serialize threads'
|
||||
* access to a channel if multi-threads are to send messages through the
|
||||
* same channel, i.e. caller should not call this function until any
|
||||
* previous call returns.
|
||||
*
|
||||
* Return: Non-negative integer for successful submission (non-blocking mode)
|
||||
* or transmission over chan (blocking mode).
|
||||
|
|
@ -291,6 +299,8 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
|
|||
if (ret == 0) {
|
||||
t = -ETIME;
|
||||
tx_tick(chan, t);
|
||||
} else if (chan->tx_status < 0) {
|
||||
t = chan->tx_status;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,6 +337,19 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mbox_flush);
|
||||
|
||||
static void mbox_clean_and_put_channel(struct mbox_chan *chan)
|
||||
{
|
||||
/* The queued TX requests are simply aborted, no callbacks are made */
|
||||
scoped_guard(spinlock_irqsave, &chan->lock) {
|
||||
chan->cl = NULL;
|
||||
chan->active_req = MBOX_NO_MSG;
|
||||
if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
|
||||
chan->txdone_method = MBOX_TXDONE_BY_POLL;
|
||||
}
|
||||
|
||||
module_put(chan->mbox->dev->driver->owner);
|
||||
}
|
||||
|
||||
static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
|
||||
{
|
||||
struct device *dev = cl->dev;
|
||||
|
|
@ -350,10 +373,9 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
|
|||
|
||||
if (chan->mbox->ops->startup) {
|
||||
ret = chan->mbox->ops->startup(chan);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to startup the chan (%d)\n", ret);
|
||||
mbox_free_channel(chan);
|
||||
mbox_clean_and_put_channel(chan);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -495,15 +517,7 @@ void mbox_free_channel(struct mbox_chan *chan)
|
|||
if (chan->mbox->ops->shutdown)
|
||||
chan->mbox->ops->shutdown(chan);
|
||||
|
||||
/* The queued TX requests are simply aborted, no callbacks are made */
|
||||
scoped_guard(spinlock_irqsave, &chan->lock) {
|
||||
chan->cl = NULL;
|
||||
chan->active_req = MBOX_NO_MSG;
|
||||
if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
|
||||
chan->txdone_method = MBOX_TXDONE_BY_POLL;
|
||||
}
|
||||
|
||||
module_put(chan->mbox->dev->driver->owner);
|
||||
mbox_clean_and_put_channel(chan);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mbox_free_channel);
|
||||
|
||||
|
|
@ -632,3 +646,66 @@ int devm_mbox_controller_register(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_mbox_controller_register);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static void *mbox_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
mutex_lock(&con_mutex);
|
||||
return seq_list_start(&mbox_cons, *pos);
|
||||
}
|
||||
|
||||
static void *mbox_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(v, &mbox_cons, pos);
|
||||
}
|
||||
|
||||
static void mbox_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
mutex_unlock(&con_mutex);
|
||||
}
|
||||
|
||||
static int mbox_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
const struct mbox_controller *mbox = list_entry(v, struct mbox_controller, node);
|
||||
|
||||
seq_printf(seq, "%s:\n", dev_name(mbox->dev));
|
||||
|
||||
for (unsigned int i = 0; i < mbox->num_chans; i++) {
|
||||
struct mbox_chan *chan = &mbox->chans[i];
|
||||
|
||||
scoped_guard(spinlock_irqsave, &chan->lock) {
|
||||
if (chan->cl) {
|
||||
struct device *cl_dev = chan->cl->dev;
|
||||
|
||||
seq_printf(seq, " %3u: %s\n", i,
|
||||
cl_dev ? dev_name(cl_dev) : "NULL device");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations mbox_sops = {
|
||||
.start = mbox_seq_start,
|
||||
.next = mbox_seq_next,
|
||||
.stop = mbox_seq_stop,
|
||||
.show = mbox_seq_show,
|
||||
};
|
||||
DEFINE_SEQ_ATTRIBUTE(mbox);
|
||||
|
||||
/*
|
||||
* subsys_initcall() is used here but controllers may already have been
|
||||
* registered earlier or will be later. The rationale is that debugfs is
|
||||
* accessed only late, i.e. from userspace. So, files created here must make no
|
||||
* assumptions about initcall ordering.
|
||||
*/
|
||||
static int __init mbox_init(void)
|
||||
{
|
||||
struct dentry *mbox_debugfs = debugfs_create_dir("mailbox", NULL);
|
||||
|
||||
debugfs_create_file("mailbox_summary", 0444, mbox_debugfs, NULL, &mbox_fops);
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(mbox_init);
|
||||
#endif /* DEBUG_FS */
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ struct mtk_adsp_mbox_priv {
|
|||
struct mbox_controller mbox;
|
||||
void __iomem *va_mboxreg;
|
||||
const struct mtk_adsp_mbox_cfg *cfg;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct mtk_adsp_mbox_cfg {
|
||||
|
|
@ -67,6 +68,8 @@ static int mtk_adsp_mbox_startup(struct mbox_chan *chan)
|
|||
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
|
||||
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
|
||||
|
||||
enable_irq(priv->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +77,8 @@ static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan)
|
|||
{
|
||||
struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox);
|
||||
|
||||
disable_irq(priv->irq);
|
||||
|
||||
/* Clear ADSP mbox command */
|
||||
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
|
||||
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
|
||||
|
|
@ -139,8 +144,10 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev)
|
|||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
priv->irq = irq;
|
||||
ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq,
|
||||
mtk_adsp_mbox_isr, IRQF_TRIGGER_NONE,
|
||||
mtk_adsp_mbox_isr,
|
||||
IRQF_TRIGGER_NONE | IRQF_NO_AUTOEN,
|
||||
dev_name(dev), mbox->chans);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define APSS_CPUCP_IPC_CHAN_SUPPORTED 3
|
||||
#define APSS_CPUCP_MBOX_CMD_OFF 0x4
|
||||
|
||||
/* Tx Registers */
|
||||
|
|
@ -26,6 +25,14 @@
|
|||
#define APSS_CPUCP_RX_MBOX_EN 0x4c00
|
||||
#define APSS_CPUCP_RX_MBOX_CMD_MASK GENMASK_ULL(63, 0)
|
||||
|
||||
/**
|
||||
* struct qcom_cpucp_mbox_data - Per-hardware mailbox configuration data
|
||||
* @num_chans: Number of IPC channels supported by this hardware
|
||||
*/
|
||||
struct qcom_cpucp_mbox_data {
|
||||
int num_chans;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qcom_cpucp_mbox - Holder for the mailbox driver
|
||||
* @chans: The mailbox channel
|
||||
|
|
@ -34,7 +41,7 @@
|
|||
* @rx_base: Base address of the CPUCP rx registers
|
||||
*/
|
||||
struct qcom_cpucp_mbox {
|
||||
struct mbox_chan chans[APSS_CPUCP_IPC_CHAN_SUPPORTED];
|
||||
struct mbox_chan *chans;
|
||||
struct mbox_controller mbox;
|
||||
void __iomem *tx_base;
|
||||
void __iomem *rx_base;
|
||||
|
|
@ -53,7 +60,7 @@ static irqreturn_t qcom_cpucp_mbox_irq_fn(int irq, void *data)
|
|||
|
||||
status = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_STAT);
|
||||
|
||||
for_each_set_bit(i, (unsigned long *)&status, APSS_CPUCP_IPC_CHAN_SUPPORTED) {
|
||||
for_each_set_bit(i, (unsigned long *)&status, cpucp->mbox.num_chans) {
|
||||
u32 val = readl(cpucp->rx_base + APSS_CPUCP_RX_MBOX_CMD(i) + APSS_CPUCP_MBOX_CMD_OFF);
|
||||
struct mbox_chan *chan = &cpucp->chans[i];
|
||||
unsigned long flags;
|
||||
|
|
@ -112,15 +119,24 @@ static const struct mbox_chan_ops qcom_cpucp_mbox_chan_ops = {
|
|||
|
||||
static int qcom_cpucp_mbox_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct qcom_cpucp_mbox_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qcom_cpucp_mbox *cpucp;
|
||||
struct mbox_controller *mbox;
|
||||
int irq, ret;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (!data)
|
||||
return dev_err_probe(dev, -EINVAL, "No match data found\n");
|
||||
|
||||
cpucp = devm_kzalloc(dev, sizeof(*cpucp), GFP_KERNEL);
|
||||
if (!cpucp)
|
||||
return -ENOMEM;
|
||||
|
||||
cpucp->chans = devm_kcalloc(dev, data->num_chans, sizeof(*cpucp->chans), GFP_KERNEL);
|
||||
if (!cpucp->chans)
|
||||
return -ENOMEM;
|
||||
|
||||
cpucp->rx_base = devm_of_iomap(dev, dev->of_node, 0, NULL);
|
||||
if (IS_ERR(cpucp->rx_base))
|
||||
return PTR_ERR(cpucp->rx_base);
|
||||
|
|
@ -146,7 +162,7 @@ static int qcom_cpucp_mbox_probe(struct platform_device *pdev)
|
|||
|
||||
mbox = &cpucp->mbox;
|
||||
mbox->dev = dev;
|
||||
mbox->num_chans = APSS_CPUCP_IPC_CHAN_SUPPORTED;
|
||||
mbox->num_chans = data->num_chans;
|
||||
mbox->chans = cpucp->chans;
|
||||
mbox->ops = &qcom_cpucp_mbox_chan_ops;
|
||||
|
||||
|
|
@ -157,8 +173,17 @@ static int qcom_cpucp_mbox_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct qcom_cpucp_mbox_data qcom_x1e80100_mbox_data = {
|
||||
.num_chans = 3,
|
||||
};
|
||||
|
||||
static const struct qcom_cpucp_mbox_data qcom_nord_mbox_data = {
|
||||
.num_chans = 16,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_cpucp_mbox_of_match[] = {
|
||||
{ .compatible = "qcom,x1e80100-cpucp-mbox" },
|
||||
{ .compatible = "qcom,nord-cpucp-mbox", .data = &qcom_nord_mbox_data },
|
||||
{ .compatible = "qcom,x1e80100-cpucp-mbox", .data = &qcom_x1e80100_mbox_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_cpucp_mbox_of_match);
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ struct mbox_controller {
|
|||
* @txdone_method: Way to detect TXDone chosen by the API
|
||||
* @cl: Pointer to the current owner of this channel
|
||||
* @tx_complete: Transmission completion
|
||||
* @tx_status: Transmission status
|
||||
* @active_req: Currently active request hook
|
||||
* @msg_count: No. of mssg currently queued
|
||||
* @msg_free: Index of next available mssg slot
|
||||
|
|
@ -132,6 +133,7 @@ struct mbox_chan {
|
|||
unsigned txdone_method;
|
||||
struct mbox_client *cl;
|
||||
struct completion tx_complete;
|
||||
int tx_status;
|
||||
void *active_req;
|
||||
unsigned msg_count, msg_free;
|
||||
void *msg_data[MBOX_TX_QUEUE_LEN];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user