FROMGIT: irqchip/qcom-pdc: Trim unused levels of the interrupt hierarchy

The QCOM PDC driver creates a bunch of unnecessary levels in
the interrupt hierarchy when dealing with non-wakeup-capable
interrupts. By definition, these lines are terminated at the
PDC level, and everything below this is completely fake.

This also results in additional complexity as most of the
callbacks have to check for the validity of the parent level.
Needless to say, this doesn't look very good.

Solve this by disconnecting the interrupt hierarchy below
the last valid level, and considerably simplify the handling
of all the other interrupts by avoiding now unnecessary cheks.
In most cases, the standard irq_*_parent() handlers are directly
used.

This also cures an issue reporting by Maulik where gpio_to_irq()
returns an error after having observed a set of invalid levels.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Maulik Shah <mkshah@codeaurora.org>
Tested-by: Maulik Shah <mkshah@codeaurora.org>
Link: https://lore.kernel.org/r/1629705880-27877-3-git-send-email-mkshah@codeaurora.org

Bug: 196928089
(cherry picked from commit 9d4f24bfe043274d9274bcfe223b901bd8fb7182
https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git irq/irqchip-next)

Change-Id: Idec7d3b80e0d170be425f1e24efd41ad451bff4e
Signed-off-by: Maulik Shah <mkshah@codeaurora.org>
This commit is contained in:
Marc Zyngier
2021-08-23 13:34:40 +05:30
committed by Todd Kjos
parent 4c9aa4c6f0
commit 34f60eead2

View File

@@ -65,26 +65,6 @@ static u32 pdc_reg_read(int reg, u32 i)
return readl_relaxed(pdc_base + reg + i * sizeof(u32));
}
static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which,
bool *state)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return 0;
return irq_chip_get_parent_state(d, which, state);
}
static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which,
bool value)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return 0;
return irq_chip_set_parent_state(d, which, value);
}
static void pdc_enable_intr(struct irq_data *d, bool on)
{
int pin_out = d->hwirq;
@@ -103,38 +83,16 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
static void qcom_pdc_gic_disable(struct irq_data *d)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return;
pdc_enable_intr(d, false);
irq_chip_disable_parent(d);
}
static void qcom_pdc_gic_enable(struct irq_data *d)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return;
pdc_enable_intr(d, true);
irq_chip_enable_parent(d);
}
static void qcom_pdc_gic_mask(struct irq_data *d)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return;
irq_chip_mask_parent(d);
}
static void qcom_pdc_gic_unmask(struct irq_data *d)
{
if (d->hwirq == GPIO_NO_WAKE_IRQ)
return;
irq_chip_unmask_parent(d);
}
static u32 __spi_pin_read(unsigned int pin)
{
void __iomem *cfg_reg = spi_cfg->base + pin * 4;
@@ -222,15 +180,11 @@ enum pdc_irq_config_bits {
*/
static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
{
int pin_out = d->hwirq;
int parent_hwirq = d->parent_data->hwirq;
enum pdc_irq_config_bits pdc_type;
enum pdc_irq_config_bits old_pdc_type;
int ret;
if (pin_out == GPIO_NO_WAKE_IRQ)
return 0;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
pdc_type = PDC_EDGE_RISING;
@@ -255,8 +209,8 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out);
pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
old_pdc_type = pdc_reg_read(IRQ_i_CFG, d->hwirq);
pdc_reg_write(IRQ_i_CFG, d->hwirq, pdc_type);
/* Additionally, configure (only) the GPIO in the f/w */
ret = spi_configure_type(parent_hwirq, type);
@@ -285,12 +239,12 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
static struct irq_chip qcom_pdc_gic_chip = {
.name = "PDC",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = qcom_pdc_gic_mask,
.irq_unmask = qcom_pdc_gic_unmask,
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_disable = qcom_pdc_gic_disable,
.irq_enable = qcom_pdc_gic_enable,
.irq_get_irqchip_state = qcom_pdc_gic_get_irqchip_state,
.irq_set_irqchip_state = qcom_pdc_gic_set_irqchip_state,
.irq_get_irqchip_state = irq_chip_get_parent_state,
.irq_set_irqchip_state = irq_chip_set_parent_state,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_type = qcom_pdc_gic_set_type,
.flags = IRQCHIP_MASK_ON_SUSPEND |
@@ -351,7 +305,7 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,
parent_hwirq = get_parent_hwirq(hwirq);
if (parent_hwirq == PDC_NO_PARENT_IRQ)
return 0;
return irq_domain_disconnect_hierarchy(domain->parent, virq);
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;
@@ -388,17 +342,17 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
if (ret)
return ret;
if (hwirq == GPIO_NO_WAKE_IRQ)
return irq_domain_disconnect_hierarchy(domain, virq);
ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
&qcom_pdc_gic_chip, NULL);
if (ret)
return ret;
if (hwirq == GPIO_NO_WAKE_IRQ)
return 0;
parent_hwirq = get_parent_hwirq(hwirq);
if (parent_hwirq == PDC_NO_PARENT_IRQ)
return 0;
return irq_domain_disconnect_hierarchy(domain->parent, virq);
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;