Messages in this thread Patch in this message | | | From | Ed Blake <> | Subject | [PATCH 4/4] irqchip: imgpdc: Pass on peripheral mask/unmasks to the parent | Date | Mon, 2 Oct 2017 10:55:59 +0100 |
| |
Pass on peripheral (RTC/IR/WD) irq masks and unmasks to the parent interrupt controller, as well as setting / clearing the relevant bits in the IRQ_ROUTE register.
Clearing bits in the IRQ_ROUTE register will prevent future interrupts from being passed on to the parent, but won't mask an existing interrupt which has already made it to the parent. This is currently causing peipheral interrupts to fire continuously when the system wakes from a suspended state when one of the peripherals is used to wake the system (e.g. RTC, IR). The interrupt occurs early in the wake process (still in the noirq phase) and because the peripheral interrupt is disabled at that point, the core marks it as pending and masks it out. This mask must be passed to the parent controller to be effective.
Signed-off-by: Ed Blake <ed.blake@sondrel.com> --- drivers/irqchip/irq-imgpdc.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index d1bcfef..05c48dd 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -141,21 +141,31 @@ static struct pdc_intc_priv *irqd_to_priv(struct irq_data *data) static void perip_irq_mask(struct irq_data *data) { struct pdc_intc_priv *priv = irqd_to_priv(data); + unsigned int parent_irq = priv->perip_irqs[data->hwirq]; + struct irq_data *parent_irq_data = irq_get_irq_data(parent_irq); raw_spin_lock(&priv->lock); priv->irq_route &= ~data->mask; pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); raw_spin_unlock(&priv->lock); + + /* Pass on the mask to the parent */ + parent_irq_data->chip->irq_mask(parent_irq_data); } static void perip_irq_unmask(struct irq_data *data) { struct pdc_intc_priv *priv = irqd_to_priv(data); + unsigned int parent_irq = priv->perip_irqs[data->hwirq]; + struct irq_data *parent_irq_data = irq_get_irq_data(parent_irq); raw_spin_lock(&priv->lock); priv->irq_route |= data->mask; pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); raw_spin_unlock(&priv->lock); + + /* Pass on the unmask to the parent */ + parent_irq_data->chip->irq_unmask(parent_irq_data); } static int syswake_irq_set_type(struct irq_data *data, unsigned int flow_type) -- 1.9.1
| |