From 72da1909256f6dac10f687d2942ba266158428ef Mon Sep 17 00:00:00 2001 From: Kartik Date: Wed, 22 Feb 2023 08:54:00 +0000 Subject: [PATCH] NVIDIA: SAUCE: mailbox: tegra-hsp: Add sm ops route_irq & set_irq BugLink: https://bugs.launchpad.net/bugs/2072591 Tegra194 onwards supports per mailbox IE registers to enable or disable interrupts for a mailbox. Whereas, the common IE registers i.e., HSP_INT_IE(X) are used to allow interrupt routing for a mailbox via shared interrupt 'X'. Currently, the mailbox interrupts are managed by setting the per mailbox IE registers at mailbox_startup/shutdown and routing is controlled with HSP_INT_IE(X) registers during the send/receive operation. In a virtualized environment, writing into HSP_INT_IE registers adds additional overhead, as these registers are trapped by hypervisor to protect configuration made by other firmwares. Since the send and receive operations are called more frequently, this way of managing interrupts increases the overall turnaround time. Instead, we should route the interrupts using HSP_INT_IE(X) registers during mailbox startup/shutdown and enable/disable the full/empty interrupts using per mailbox IE registers during send/receive operations. Add route_irq and set_irq ops for shared mailboxes. Where route_irq uses HSP_INT_IE(X) registers to allow interrupt routing and set_irq uses per mailbox to enable/disable interrupts for a shared mailbox. Note that Tegra186 does not support per mailbox interrupt enable and disable registers. Hence HSP_INT_IE(X) is used to enable/disable interrupts for mailboxes. http://nvbugs/4191232 Signed-off-by: Kartik Reviewed-by: Akhil R Reviewed-by: Laxman Dewangan Tested-by: Akhil R Tested-by: Laxman Dewangan Signed-off-by: Laxman Dewangan Acked-by: Jacob Martin Acked-by: Noah Wager Signed-off-by: Noah Wager --- drivers/mailbox/tegra-hsp.c | 155 +++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 57 deletions(-) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 716b34872a1f..7fb77616f183 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -57,6 +57,7 @@ #define HSP_MBOX_TYPE_MASK 0xff +struct tegra_hsp_mailbox; struct tegra_hsp_channel; struct tegra_hsp; @@ -77,6 +78,8 @@ struct tegra_hsp_doorbell { struct tegra_hsp_sm_ops { void (*send)(struct tegra_hsp_channel *channel, void *data); void (*recv)(struct tegra_hsp_channel *channel); + void (*route_irq)(struct tegra_hsp_mailbox *mb, bool enable); + void (*set_irq)(struct tegra_hsp_mailbox *mb, bool enable); }; struct tegra_hsp_shared_interrupt { @@ -186,41 +189,6 @@ tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master) return db; } -/* - * Enables or disables interrupt for a mailbox. Should be called with - * hsp->lock held. - */ -static void tegra_hsp_sm_set_irq(struct tegra_hsp_mailbox *mb, bool enable) -{ - struct tegra_hsp_shared_interrupt *si = mb->si; - struct tegra_hsp_channel *ch = &mb->channel; - struct tegra_hsp *hsp = mb->channel.hsp; - unsigned int shift; - unsigned int mask; - - shift = mb->producer ? HSP_INT_EMPTY_SHIFT : HSP_INT_FULL_SHIFT; - mask = tegra_hsp_readl(hsp, HSP_INT_IE(si->index)); - - if (enable) { - mask |= BIT(shift + mb->index); - hsp->mask |= BIT(shift + mb->index); - } else { - mask &= ~BIT(shift + mb->index); - hsp->mask &= ~BIT(shift + mb->index); - } - - tegra_hsp_writel(hsp, mask, HSP_INT_IE(si->index)); - - if (hsp->soc->has_per_mb_ie) { - unsigned int reg_ie; - - reg_ie = mb->producer ? HSP_SM_SHRD_MBOX_EMPTY_INT_IE : - HSP_SM_SHRD_MBOX_FULL_INT_IE; - - tegra_hsp_channel_writel(ch, enable ? 0x1 : 0x0, reg_ie); - } -} - static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data) { struct tegra_hsp *hsp = data; @@ -283,9 +251,7 @@ static irqreturn_t tegra_hsp_shared_irq(int irq, void *data) * the message. */ spin_lock(&hsp->lock); - - tegra_hsp_sm_set_irq(mb, false); - + mb->ops->set_irq(mb, false); spin_unlock(&hsp->lock); mbox_chan_txdone(mb->channel.chan, 0); @@ -440,9 +406,86 @@ static void tegra_hsp_sm_recv32(struct tegra_hsp_channel *channel) mbox_chan_received_data(channel->chan, msg); } -static const struct tegra_hsp_sm_ops tegra_hsp_sm_32bit_ops = { +static void tegra186_hsp_sm_route_irq(struct tegra_hsp_mailbox *mb, + bool enable) +{ + /* + * On Tegra186 IE register is used only for enabling/disabling shared + * interrupts. + */ +} + +static void tegra186_hsp_sm_set_irq(struct tegra_hsp_mailbox *mb, bool enable) +{ + struct tegra_hsp_shared_interrupt *si = mb->si; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned int shift; + unsigned int mask; + + shift = mb->producer ? HSP_INT_EMPTY_SHIFT : HSP_INT_FULL_SHIFT; + mask = tegra_hsp_readl(hsp, HSP_INT_IE(si->index)); + + if (enable) { + mask |= BIT(shift + mb->index); + hsp->mask |= BIT(shift + mb->index); + } else { + mask &= ~BIT(shift + mb->index); + hsp->mask &= ~BIT(shift + mb->index); + } + + tegra_hsp_writel(hsp, mask, HSP_INT_IE(si->index)); +} + +static const struct tegra_hsp_sm_ops tegra186_hsp_sm_32bit_ops = { .send = tegra_hsp_sm_send32, .recv = tegra_hsp_sm_recv32, + .route_irq = tegra186_hsp_sm_route_irq, + .set_irq = tegra186_hsp_sm_set_irq, +}; + +static void tegra194_hsp_sm_route_irq(struct tegra_hsp_mailbox *mb, + bool enable) +{ + struct tegra_hsp_shared_interrupt *si = mb->si; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned int shift; + unsigned int mask; + + shift = mb->producer ? HSP_INT_EMPTY_SHIFT : HSP_INT_FULL_SHIFT; + mask = tegra_hsp_readl(hsp, HSP_INT_IE(si->index)); + + if (enable) + mask |= BIT(shift + mb->index); + else + mask &= ~BIT(shift + mb->index); + + tegra_hsp_writel(hsp, mask, HSP_INT_IE(si->index)); +} + +static void tegra194_hsp_sm_set_irq(struct tegra_hsp_mailbox *mb, bool enable) +{ + struct tegra_hsp_channel *ch = &mb->channel; + struct tegra_hsp *hsp = mb->channel.hsp; + unsigned int reg_ie; + unsigned int shift; + + shift = mb->producer ? HSP_INT_EMPTY_SHIFT : HSP_INT_FULL_SHIFT; + reg_ie = mb->producer ? HSP_SM_SHRD_MBOX_EMPTY_INT_IE : + HSP_SM_SHRD_MBOX_FULL_INT_IE; + + if (enable) + hsp->mask |= BIT(shift + mb->index); + else + hsp->mask &= ~BIT(shift + mb->index); + + tegra_hsp_channel_writel(ch, enable ? 0x1 : 0x0, reg_ie); +} + +static const struct tegra_hsp_sm_ops tegra194_hsp_sm_32bit_ops = { + .send = tegra_hsp_sm_send32, + .recv = tegra_hsp_sm_recv32, + .route_irq = tegra194_hsp_sm_route_irq, + .set_irq = tegra194_hsp_sm_set_irq, }; static void tegra_hsp_sm_send128(struct tegra_hsp_channel *channel, void *data) @@ -486,9 +529,11 @@ static void tegra_hsp_sm_recv128(struct tegra_hsp_channel *channel) mbox_chan_received_data(channel->chan, msg); } -static const struct tegra_hsp_sm_ops tegra_hsp_sm_128bit_ops = { +static const struct tegra_hsp_sm_ops tegra234_hsp_sm_128bit_ops = { .send = tegra_hsp_sm_send128, .recv = tegra_hsp_sm_recv128, + .route_irq = tegra194_hsp_sm_route_irq, + .set_irq = tegra194_hsp_sm_set_irq, }; static int tegra_hsp_mailbox_send_data(struct mbox_chan *chan, void *data) @@ -504,7 +549,7 @@ static int tegra_hsp_mailbox_send_data(struct mbox_chan *chan, void *data) /* enable EMPTY interrupt for the shared mailbox */ spin_lock_irqsave(&hsp->lock, flags); - tegra_hsp_sm_set_irq(mb, true); + mb->ops->set_irq(mb, true); spin_unlock_irqrestore(&hsp->lock, flags); return 0; @@ -559,9 +604,11 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan) spin_lock_irqsave(&hsp->lock, flags); if (mb->producer) - tegra_hsp_sm_set_irq(mb, false); + mb->ops->set_irq(mb, false); else - tegra_hsp_sm_set_irq(mb, true); + mb->ops->set_irq(mb, true); + + mb->ops->route_irq(mb, true); spin_unlock_irqrestore(&hsp->lock, flags); @@ -571,21 +618,12 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan) 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); - tegra_hsp_sm_set_irq(mb, false); + mb->ops->route_irq(mb, false); + mb->ops->set_irq(mb, false); spin_unlock_irqrestore(&hsp->lock, flags); } @@ -654,9 +692,12 @@ static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox, if (!hsp->soc->has_128_bit_mb) return ERR_PTR(-ENODEV); - mb->ops = &tegra_hsp_sm_128bit_ops; + mb->ops = &tegra234_hsp_sm_128bit_ops; } else { - mb->ops = &tegra_hsp_sm_32bit_ops; + if (hsp->soc->has_per_mb_ie) + mb->ops = &tegra194_hsp_sm_32bit_ops; + else + mb->ops = &tegra186_hsp_sm_32bit_ops; } if ((args->args[1] & TEGRA_HSP_SM_FLAG_TX) == 0) @@ -1007,7 +1048,7 @@ static const struct tegra_hsp_soc tegra194_hsp_soc = { static const struct tegra_hsp_soc tegra234_hsp_soc = { .map = tegra186_hsp_db_map, - .has_per_mb_ie = false, + .has_per_mb_ie = true, .has_128_bit_mb = true, .reg_stride = 0x100, };