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-next>] [day] [month] [year] [list]
Date:   Mon, 4 Dec 2017 16:11:06 +0100
From:   Rasmus Villemoes <rasmus.villemoes@...vas.dk>
To:     LKML <linux-kernel@...r.kernel.org>
CC:     Thomas Gleixner <tglx@...utronix.de>,
        Marc Zyngier <marc.zyngier@....com>,
        Shawn Guo <shawnguo@...nel.org>
Subject: polarity inversion on LS1021a

The LS1021A has a standard GIC-400, but allows inverting the polarity of
six external interrupt lines via a certain register, effectively
supporting IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_EDGE_FALLING for those.

I'm trying to figure out how one would add support for this. The patch
below works but is obviously just meant to help show what I mean, so
please don't comment on all the things that are wrong with it.

It feels wrong to create a whole new irqchip driver copy-pasting the
entire irg-gic.c, but I can't figure out how and where one could hook
into the existing one. Any pointers on how to do this properly will be
greatly appreciated.

Thanks,
Rasmus


diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 651d726e8b12..299710b7dd09 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -290,6 +290,48 @@ static int gic_irq_get_irqchip_state(struct
irq_data *d,
 	return 0;
 }

+static int gic_set_type_ls1_ext_irq_polarity(unsigned int gicirq,
+					     unsigned int *type)
+{
+	struct device_node *np;
+	void __iomem *scfg = NULL;
+	u32 polarity_mask = 0;
+	u32 intpcr;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg");
+	if (!np)
+		return 0;
+
+	scfg = of_iomap(np, 0);
+	if (!scfg)
+		return -EINVAL;
+
+	switch (gicirq) {
+	case 195: polarity_mask = 0x80000000; break;
+	case 196: polarity_mask = 0x40000000; break;
+	case 197: polarity_mask = 0x20000000; break;
+	case 199: polarity_mask = 0x10000000; break;
+	case 200: polarity_mask = 0x08000000; break;
+	case 201: polarity_mask = 0x04000000; break;
+	}
+	if (!polarity_mask)
+		return 0;
+
+	intpcr = ioread32be(scfg + 0x1ac);
+
+	if (*type == IRQ_TYPE_LEVEL_LOW || *type == IRQ_TYPE_EDGE_FALLING)
+		iowrite32be(intpcr | polarity_mask, scfg + 0x1ac);
+	else
+		iowrite32be(intpcr & ~polarity_mask, scfg + 0x1ac);
+
+	if (*type == IRQ_TYPE_LEVEL_LOW)
+		*type = IRQ_TYPE_LEVEL_HIGH;
+	else if (*type == IRQ_TYPE_EDGE_FALLING)
+		*type = IRQ_TYPE_EDGE_RISING;
+
+	return 0;
+}
+
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
 	void __iomem *base = gic_dist_base(d);
@@ -299,6 +341,8 @@ static int gic_set_type(struct irq_data *d, unsigned
int type)
 	if (gicirq < 16)
 		return -EINVAL;

+	gic_set_type_ls1_ext_irq_polarity(gicirq, &type);
+
 	/* SPIs have restrictions on the supported types */
 	if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
 			    type != IRQ_TYPE_EDGE_RISING)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ