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 <kkartik@nvidia.com>
Reviewed-by: Akhil R <akhilrajeev@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Akhil R <akhilrajeev@nvidia.com>
Tested-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Kartik
2023-02-22 08:54:00 +00:00
committed by Noah Wager
parent 01469c29f0
commit 72da190925
+98 -57
View File
@@ -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,
};