lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1506938159-466-5-git-send-email-ed.blake@sondrel.com>
Date:   Mon,  2 Oct 2017 10:55:59 +0100
From:   Ed Blake <ed.blake@...drel.com>
To:     tglx@...utronix.de, jason@...edaemon.net, marc.zyngier@....com
Cc:     linux-kernel@...r.kernel.org, Ed Blake <ed.blake@...drel.com>
Subject: [PATCH 4/4] irqchip: imgpdc: Pass on peripheral mask/unmasks to the parent

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@...drel.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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ