Skip to content

Commit c351ab7

Browse files
author
Marc Zyngier
committed
soc/tegra: pmc: Don't create fake interrupt hierarchy levels
The Tegra PMC driver does ungodly things with the interrupt hierarchy, repeatedly corrupting it by pulling hwirq numbers out of thin air, overriding existing IRQ mappings and changing the handling flow of unsuspecting users. All of this is done in the name of preserving the interrupt hierarchy even when these levels do not exist in the HW. Together with the use of proper IRQs for IPIs, this leads to an unbootable system as the rescheduling IPI gets repeatedly repurposed for random drivers... Instead, let's simply mark the level from which the hierarchy does not make sense for the HW, and let the core code trim the usused levels from the hierarchy. Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 8681cc3 commit c351ab7

1 file changed

Lines changed: 7 additions & 48 deletions

File tree

drivers/soc/tegra/pmc.c

Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,44 +1990,17 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
19901990
event->id,
19911991
&pmc->irq, pmc);
19921992

1993-
/*
1994-
* GPIOs don't have an equivalent interrupt in the
1995-
* parent controller (GIC). However some code, such
1996-
* as the one in irq_get_irqchip_state(), require a
1997-
* valid IRQ chip to be set. Make sure that's the
1998-
* case by passing NULL here, which will install a
1999-
* dummy IRQ chip for the interrupt in the parent
2000-
* domain.
2001-
*/
2002-
if (domain->parent)
2003-
irq_domain_set_hwirq_and_chip(domain->parent,
2004-
virq, 0, NULL,
2005-
NULL);
2006-
1993+
/* GPIO hierarchies stop at the PMC level */
1994+
if (!err && domain->parent)
1995+
err = irq_domain_disconnect_hierarchy(domain->parent,
1996+
virq);
20071997
break;
20081998
}
20091999
}
20102000

2011-
/*
2012-
* For interrupts that don't have associated wake events, assign a
2013-
* dummy hardware IRQ number. This is used in the ->irq_set_type()
2014-
* and ->irq_set_wake() callbacks to return early for these IRQs.
2015-
*/
2016-
if (i == soc->num_wake_events) {
2017-
err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX,
2018-
&pmc->irq, pmc);
2019-
2020-
/*
2021-
* Interrupts without a wake event don't have a corresponding
2022-
* interrupt in the parent controller (GIC). Pass NULL for the
2023-
* chip here, which causes a dummy IRQ chip to be installed
2024-
* for the interrupt in the parent domain, to make this
2025-
* explicit.
2026-
*/
2027-
if (domain->parent)
2028-
irq_domain_set_hwirq_and_chip(domain->parent, virq, 0,
2029-
NULL, NULL);
2030-
}
2001+
/* If there is no wake-up event, there is no PMC mapping */
2002+
if (i == soc->num_wake_events)
2003+
err = irq_domain_disconnect_hierarchy(domain, virq);
20312004

20322005
return err;
20332006
}
@@ -2043,9 +2016,6 @@ static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
20432016
unsigned int offset, bit;
20442017
u32 value;
20452018

2046-
if (data->hwirq == ULONG_MAX)
2047-
return 0;
2048-
20492019
offset = data->hwirq / 32;
20502020
bit = data->hwirq % 32;
20512021

@@ -2080,9 +2050,6 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
20802050
unsigned int offset, bit;
20812051
u32 value;
20822052

2083-
if (data->hwirq == ULONG_MAX)
2084-
return 0;
2085-
20862053
offset = data->hwirq / 32;
20872054
bit = data->hwirq % 32;
20882055

@@ -2123,10 +2090,6 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
21232090
unsigned int offset, bit;
21242091
u32 value;
21252092

2126-
/* nothing to do if there's no associated wake event */
2127-
if (WARN_ON(data->hwirq == ULONG_MAX))
2128-
return 0;
2129-
21302093
offset = data->hwirq / 32;
21312094
bit = data->hwirq % 32;
21322095

@@ -2154,10 +2117,6 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
21542117
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
21552118
u32 value;
21562119

2157-
/* nothing to do if there's no associated wake event */
2158-
if (data->hwirq == ULONG_MAX)
2159-
return 0;
2160-
21612120
value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
21622121

21632122
switch (type) {

0 commit comments

Comments
 (0)