linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/24] MIPS GIC cleanup, part 1
@ 2014-09-15 23:51 Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 01/24] MIPS: Always use IRQ domains for CPU IRQs Andrew Bresticker
                   ` (25 more replies)
  0 siblings, 26 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The current MIPS GIC driver and the platform code using it are rather
ugly and could use a good cleanup before adding device-tree support [0].
This major issues addressed in this series are converting the GIC (and
platforms using it) to use IRQ domains and properly mapping interrupts
through the GIC instead of using it transparently.  For part 2 I plan
on: updating the driver to use proper iomem accessors, cleaning up and
moving the GIC clocksource driver to drivers/clocksource/, adding DT
support, and possibly converting the GIC driver to use generic irqchip.

Patches 1-16 are cleanups for the existing GIC driver and prepare platforms
using it for the switch to IRQ domains and using the GIC in a non-transparent
way.

Patches 17-24 convert the GIC driver to use IRQ domains and updates the
platforms using it to properly map GIC interrupts instead of using the static
routing tables to make the GIC appear transparent.

I've tested this series on Malta and, with additional patches, on the
DT-enabled Danube platform.  Unfortunately I do not have SEAD-3 hardware,
so that has only been compile tested.  Compile tested on all other affected
architectures (ath79, ralink, lantiq).

[0] https://lkml.org/lkml/2014/9/5/542

Andrew Bresticker (24):
  MIPS: Always use IRQ domains for CPU IRQs
  MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init()
  MIPS: Provide a generic plat_irq_dispatch
  MIPS: Set vint handler when mapping CPU interrupts
  MIPS: i8259: Use IRQ domains
  MIPS: Add hook to get C0 performance counter interrupt
  MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs
  MIPS: Remove gic_{enable,disable}_interrupt()
  MIPS: sead3: Remove sead3-serial.c
  MIPS: sead3: Do not overlap CPU/GIC IRQ ranges
  MIPS: Malta: Move MSC01 interrupt base
  MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h
  MIPS: Move GIC to drivers/irqchip/
  irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
  irqchip: mips-gic: Implement irq_set_type callback
  irqchip: mips-gic: Fix gic_set_affinity() return value
  irqchip: mips-gic: Use IRQ domains
  irqchip: mips-gic: Stop using per-platform mapping tables
  irqchip: mips-gic: Probe for number of external interrupts
  irqchip: mips-gic: Use separate edge/level irq_chips
  irqchip: mips-gic: Support local interrupts
  irqchip: mips-gic: Remove unnecessary globals
  MIPS: Malta: Use generic plat_irq_dispatch
  MIPS: sead3: Use generic plat_irq_dispatch

 Documentation/devicetree/bindings/mips/cpu_irq.txt |   4 +-
 arch/mips/Kconfig                                  |  12 +-
 arch/mips/ath79/irq.c                              |   1 -
 arch/mips/ath79/setup.c                            |   5 +
 arch/mips/include/asm/gic.h                        |  82 ++-
 arch/mips/include/asm/irq_cpu.h                    |   4 +-
 arch/mips/include/asm/mach-generic/irq.h           |   6 +
 arch/mips/include/asm/mach-malta/irq.h             |   1 -
 arch/mips/include/asm/mach-sead3/irq.h             |   1 -
 arch/mips/include/asm/mips-boards/maltaint.h       |  24 +-
 arch/mips/include/asm/mips-boards/sead3int.h       |  15 +-
 arch/mips/include/asm/time.h                       |   1 +
 arch/mips/kernel/Makefile                          |   1 -
 arch/mips/kernel/cevt-gic.c                        |  14 +-
 arch/mips/kernel/cevt-r4k.c                        |   4 +-
 arch/mips/kernel/i8259.c                           |  24 +-
 arch/mips/kernel/irq-gic.c                         | 402 --------------
 arch/mips/kernel/irq_cpu.c                         |  45 +-
 arch/mips/kernel/perf_event_mipsxx.c               |  23 +-
 arch/mips/kernel/smp-cps.c                         |   4 +-
 arch/mips/kernel/smp-mt.c                          |   4 +-
 arch/mips/lantiq/irq.c                             |   8 +-
 arch/mips/mti-malta/malta-int.c                    | 307 ++---------
 arch/mips/mti-malta/malta-time.c                   |  39 +-
 arch/mips/mti-sead3/sead3-ehci.c                   |   8 +-
 arch/mips/mti-sead3/sead3-int.c                    | 121 +----
 arch/mips/mti-sead3/sead3-net.c                    |  14 +-
 arch/mips/mti-sead3/sead3-platform.c               |  18 +-
 arch/mips/mti-sead3/sead3-serial.c                 |  45 --
 arch/mips/mti-sead3/sead3-time.c                   |  35 +-
 arch/mips/oprofile/op_model_mipsxx.c               |  18 +-
 arch/mips/ralink/irq.c                             |  10 +-
 drivers/irqchip/Kconfig                            |   4 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-mips-gic.c                     | 597 +++++++++++++++++++++
 35 files changed, 867 insertions(+), 1035 deletions(-)
 delete mode 100644 arch/mips/kernel/irq-gic.c
 delete mode 100644 arch/mips/mti-sead3/sead3-serial.c
 create mode 100644 drivers/irqchip/irq-mips-gic.c

-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/24] MIPS: Always use IRQ domains for CPU IRQs
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 02/24] MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init() Andrew Bresticker
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Use an IRQ domain for the 8 CPU IRQs in both the DT and non-DT cases.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/Kconfig          |  1 +
 arch/mips/kernel/irq_cpu.c | 36 +++++++++++-------------------------
 2 files changed, 12 insertions(+), 25 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 900c7e5..9fc335c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1051,6 +1051,7 @@ config MIPS_HUGE_TLB_SUPPORT
 
 config IRQ_CPU
 	bool
+	select IRQ_DOMAIN
 
 config IRQ_CPU_RM7K
 	bool
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index e498f2b..b097f7d 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -94,28 +94,6 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
 	.irq_eoi	= unmask_mips_irq,
 };
 
-void __init mips_cpu_irq_init(void)
-{
-	int irq_base = MIPS_CPU_IRQ_BASE;
-	int i;
-
-	/* Mask interrupts. */
-	clear_c0_status(ST0_IM);
-	clear_c0_cause(CAUSEF_IP);
-
-	/* Software interrupts are used for MT/CMT IPI */
-	for (i = irq_base; i < irq_base + 2; i++)
-		irq_set_chip_and_handler(i, cpu_has_mipsmt ?
-					 &mips_mt_cpu_irq_controller :
-					 &mips_cpu_irq_controller,
-					 handle_percpu_irq);
-
-	for (i = irq_base + 2; i < irq_base + 8; i++)
-		irq_set_chip_and_handler(i, &mips_cpu_irq_controller,
-					 handle_percpu_irq);
-}
-
-#ifdef CONFIG_IRQ_DOMAIN
 static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
 			     irq_hw_number_t hw)
 {
@@ -138,8 +116,7 @@ static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = {
 	.xlate = irq_domain_xlate_onecell,
 };
 
-int __init mips_cpu_intc_init(struct device_node *of_node,
-			      struct device_node *parent)
+static void __init __mips_cpu_irq_init(struct device_node *of_node)
 {
 	struct irq_domain *domain;
 
@@ -151,7 +128,16 @@ int __init mips_cpu_intc_init(struct device_node *of_node,
 				       &mips_cpu_intc_irq_domain_ops, NULL);
 	if (!domain)
 		panic("Failed to add irqdomain for MIPS CPU");
+}
+
+void __init mips_cpu_irq_init(void)
+{
+	__mips_cpu_irq_init(NULL);
+}
 
+int __init mips_cpu_intc_init(struct device_node *of_node,
+			      struct device_node *parent)
+{
+	__mips_cpu_irq_init(of_node);
 	return 0;
 }
-#endif /* CONFIG_IRQ_DOMAIN */
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/24] MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init()
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 01/24] MIPS: Always use IRQ domains for CPU IRQs Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch Andrew Bresticker
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

mips_cpu_intc_init() is used for DT-based initialization of the CPU
IRQ domain.  Give it a more appropriate name.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 Documentation/devicetree/bindings/mips/cpu_irq.txt | 4 ++--
 arch/mips/include/asm/irq_cpu.h                    | 4 ++--
 arch/mips/kernel/irq_cpu.c                         | 4 ++--
 arch/mips/ralink/irq.c                             | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/mips/cpu_irq.txt b/Documentation/devicetree/bindings/mips/cpu_irq.txt
index 13aa4b6..fc149f3 100644
--- a/Documentation/devicetree/bindings/mips/cpu_irq.txt
+++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt
@@ -1,6 +1,6 @@
 MIPS CPU interrupt controller
 
-On MIPS the mips_cpu_intc_init() helper can be used to initialize the 8 CPU
+On MIPS the mips_cpu_irq_of_init() helper can be used to initialize the 8 CPU
 IRQs from a devicetree file and create a irq_domain for IRQ controller.
 
 With the irq_domain in place we can describe how the 8 IRQs are wired to the
@@ -36,7 +36,7 @@ Example devicetree:
 
 Example platform irq.c:
 static struct of_device_id __initdata of_irq_ids[] = {
-	{ .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init },
+	{ .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
 	{ .compatible = "ralink,rt2880-intc", .data = intc_of_init },
 	{},
 };
diff --git a/arch/mips/include/asm/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h
index 3f11fdb..39a160b 100644
--- a/arch/mips/include/asm/irq_cpu.h
+++ b/arch/mips/include/asm/irq_cpu.h
@@ -19,8 +19,8 @@ extern void rm9k_cpu_irq_init(void);
 
 #ifdef CONFIG_IRQ_DOMAIN
 struct device_node;
-extern int mips_cpu_intc_init(struct device_node *of_node,
-			      struct device_node *parent);
+extern int mips_cpu_irq_of_init(struct device_node *of_node,
+				struct device_node *parent);
 #endif
 
 #endif /* _ASM_IRQ_CPU_H */
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index b097f7d..ca98a9f 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -135,8 +135,8 @@ void __init mips_cpu_irq_init(void)
 	__mips_cpu_irq_init(NULL);
 }
 
-int __init mips_cpu_intc_init(struct device_node *of_node,
-			      struct device_node *parent)
+int __init mips_cpu_irq_of_init(struct device_node *of_node,
+				struct device_node *parent)
 {
 	__mips_cpu_irq_init(of_node);
 	return 0;
diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c
index 781b3d1..0495011 100644
--- a/arch/mips/ralink/irq.c
+++ b/arch/mips/ralink/irq.c
@@ -173,7 +173,7 @@ static int __init intc_of_init(struct device_node *node,
 }
 
 static struct of_device_id __initdata of_irq_ids[] = {
-	{ .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init },
+	{ .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
 	{ .compatible = "ralink,rt2880-intc", .data = intc_of_init },
 	{},
 };
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 01/24] MIPS: Always use IRQ domains for CPU IRQs Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 02/24] MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init() Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17  8:56   ` Qais Yousef
  2014-09-15 23:51 ` [PATCH 04/24] MIPS: Set vint handler when mapping CPU interrupts Andrew Bresticker
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

For platforms which boot with device-tree or have correctly chained
all external interrupt controllers, a generic plat_irq_dispatch() can
be used.  Implement a plat_irq_dispatch() which simply handles all the
pending interrupts as reported by C0_Cause.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/kernel/irq_cpu.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index ca98a9f..f17bd08 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -94,6 +94,21 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
 	.irq_eoi	= unmask_mips_irq,
 };
 
+asmlinkage void __weak plat_irq_dispatch(void)
+{
+	unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM;
+	int irq;
+
+	if (!pending) {
+		spurious_interrupt();
+		return;
+	}
+
+	pending >>= CAUSEB_IP;
+	for_each_set_bit(irq, &pending, 8)
+		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+}
+
 static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
 			     irq_hw_number_t hw)
 {
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/24] MIPS: Set vint handler when mapping CPU interrupts
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (2 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 05/24] MIPS: i8259: Use IRQ domains Andrew Bresticker
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

When mapping an interrupt in the CPU IRQ domain, set the vint handler
for that interrupt if the CPU uses vectored interrupt handling.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/kernel/irq_cpu.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index f17bd08..5069acb 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -36,6 +36,7 @@
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
+#include <asm/setup.h>
 
 static inline void unmask_mips_irq(struct irq_data *d)
 {
@@ -121,6 +122,9 @@ static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
 		chip = &mips_cpu_irq_controller;
 	}
 
+	if (cpu_has_vint)
+		set_vi_handler(hw, plat_irq_dispatch);
+
 	irq_set_chip_and_handler(irq, chip, handle_percpu_irq);
 
 	return 0;
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/24] MIPS: i8259: Use IRQ domains
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (3 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 04/24] MIPS: Set vint handler when mapping CPU interrupts Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 06/24] MIPS: Add hook to get C0 performance counter interrupt Andrew Bresticker
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Create a legacy IRQ domain for the 16 i8259 interrupts.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/Kconfig        |  1 +
 arch/mips/kernel/i8259.c | 24 +++++++++++++++++++-----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 9fc335c..de72c92 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -971,6 +971,7 @@ config SYS_SUPPORTS_HOTPLUG_CPU
 
 config I8259
 	bool
+	select IRQ_DOMAIN
 
 config MIPS_BONITO64
 	bool
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index 50b3648..a74ec3a 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
@@ -308,6 +309,19 @@ static struct resource pic2_io_resource = {
 	.flags = IORESOURCE_BUSY
 };
 
+static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq,
+				 irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq);
+	irq_set_probe(virq);
+	return 0;
+}
+
+static struct irq_domain_ops i8259A_ops = {
+	.map = i8259A_irq_domain_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
 /*
  * On systems with i8259-style interrupt controllers we assume for
  * driver compatibility reasons interrupts 0 - 15 to be the i8259
@@ -315,17 +329,17 @@ static struct resource pic2_io_resource = {
  */
 void __init init_i8259_irqs(void)
 {
-	int i;
+	struct irq_domain *domain;
 
 	insert_resource(&ioport_resource, &pic1_io_resource);
 	insert_resource(&ioport_resource, &pic2_io_resource);
 
 	init_8259A(0);
 
-	for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) {
-		irq_set_chip_and_handler(i, &i8259A_chip, handle_level_irq);
-		irq_set_probe(i);
-	}
+	domain = irq_domain_add_legacy(NULL, 16, I8259A_IRQ_BASE, 0,
+				       &i8259A_ops, NULL);
+	if (!domain)
+		panic("Failed to add i8259 IRQ domain");
 
 	setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/24] MIPS: Add hook to get C0 performance counter interrupt
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (4 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 05/24] MIPS: i8259: Use IRQ domains Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 07/24] MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs Andrew Bresticker
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The hardware perf event driver and oprofile interpret the global
cp0_perfcount_irq differently: in the hardware perf event driver
it is an offset from MIPS_CPU_IRQ_BASE and in oprofile it is the
actual IRQ number.  This still works most of the time since
MIPS_CPU_IRQ_BASE is usually 0, but is clearly wrong.  Since the
performance counter interrupt may vary from platform to platform
like the C0 timer interrupt, add the optional get_c0_perfcount_int
hook which returns the IRQ number of the performance counter.
The hook should return < 0 if the performance counter interrupt is
shared with the timer.  If the hook is not present, the CPU vector
reported in C0_IntCtl (cp0_perfcount_irq) is used.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/ath79/irq.c                |  1 -
 arch/mips/ath79/setup.c              |  5 +++++
 arch/mips/include/asm/time.h         |  1 +
 arch/mips/kernel/perf_event_mipsxx.c | 23 +++++++----------------
 arch/mips/lantiq/irq.c               |  8 +++++++-
 arch/mips/mti-malta/malta-time.c     | 16 ++++++----------
 arch/mips/mti-sead3/sead3-time.c     |  7 ++++---
 arch/mips/oprofile/op_model_mipsxx.c | 18 ++++++++++++++----
 arch/mips/ralink/irq.c               |  8 +++++++-
 9 files changed, 51 insertions(+), 36 deletions(-)

diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c
index 9c0e176..6adae36 100644
--- a/arch/mips/ath79/irq.c
+++ b/arch/mips/ath79/irq.c
@@ -359,7 +359,6 @@ void __init arch_init_irq(void)
 		BUG();
 	}
 
-	cp0_perfcount_irq = ATH79_MISC_IRQ(5);
 	mips_cpu_irq_init();
 	ath79_misc_irq_init();
 
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
index 64807a4..a73c93c 100644
--- a/arch/mips/ath79/setup.c
+++ b/arch/mips/ath79/setup.c
@@ -182,6 +182,11 @@ const char *get_system_type(void)
 	return ath79_sys_type;
 }
 
+int get_c0_perfcount_int(void)
+{
+	return ATH79_MISC_IRQ(5);
+}
+
 unsigned int get_c0_compare_int(void)
 {
 	return CP0_LEGACY_COMPARE_IRQ;
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
index 8f3047d..7969933 100644
--- a/arch/mips/include/asm/time.h
+++ b/arch/mips/include/asm/time.h
@@ -46,6 +46,7 @@ extern unsigned int mips_hpt_frequency;
  * so it lives here.
  */
 extern int (*perf_irq)(void);
+extern int __weak get_c0_perfcount_int(void);
 
 /*
  * Initialize the calling CPU's compare interrupt as clockevent device
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index b63f248..3a25096 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -1614,22 +1614,13 @@ init_hw_perf_events(void)
 		counters = counters_total_to_per_cpu(counters);
 #endif
 
-#ifdef MSC01E_INT_BASE
-	if (cpu_has_veic) {
-		/*
-		 * Using platform specific interrupt controller defines.
-		 */
-		irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
-	} else {
-#endif
-		if ((cp0_perfcount_irq >= 0) &&
-				(cp0_compare_irq != cp0_perfcount_irq))
-			irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
-		else
-			irq = -1;
-#ifdef MSC01E_INT_BASE
-	}
-#endif
+	if (get_c0_perfcount_int)
+		irq = get_c0_perfcount_int();
+	else if ((cp0_perfcount_irq >= 0) &&
+		 (cp0_compare_irq != cp0_perfcount_irq))
+		irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+	else
+		irq = -1;
 
 	mipspmu.map_raw_event = mipsxx_pmu_map_raw_event;
 
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index 030568a..21c38ee 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -70,6 +70,7 @@ static struct resource ltq_eiu_irq[MAX_EIU];
 static void __iomem *ltq_icu_membase[MAX_IM];
 static void __iomem *ltq_eiu_membase;
 static struct irq_domain *ltq_domain;
+static int ltq_perfcount_irq;
 
 int ltq_eiu_get_irq(int exin)
 {
@@ -449,7 +450,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
 #endif
 
 	/* tell oprofile which irq to use */
-	cp0_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
+	ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
 
 	/*
 	 * if the timer irq is not one of the mips irqs we need to
@@ -461,6 +462,11 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
 	return 0;
 }
 
+int get_c0_perfcount_int(void)
+{
+	return ltq_perfcount_irq;
+}
+
 unsigned int get_c0_compare_int(void)
 {
 	return MIPS_CPU_TIMER_IRQ;
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index 3778a35..a4e035c 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -121,22 +121,20 @@ void read_persistent_clock(struct timespec *ts)
 	ts->tv_nsec = 0;
 }
 
-static void __init plat_perf_setup(void)
+int get_c0_perfcount_int(void)
 {
-#ifdef MSC01E_INT_BASE
 	if (cpu_has_veic) {
 		set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
 		mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
-	} else
-#endif
-	if (cp0_perfcount_irq >= 0) {
+	} else if (cp0_perfcount_irq >= 0) {
 		if (cpu_has_vint)
 			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
 		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
-#ifdef CONFIG_SMP
-		irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq);
-#endif
+	} else {
+		mips_cpu_perf_irq = -1;
 	}
+
+	return mips_cpu_perf_irq;
 }
 
 unsigned int get_c0_compare_int(void)
@@ -201,6 +199,4 @@ void __init plat_time_init(void)
 #endif
 	}
 #endif
-
-	plat_perf_setup();
 }
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c
index 678d03d..f090c51 100644
--- a/arch/mips/mti-sead3/sead3-time.c
+++ b/arch/mips/mti-sead3/sead3-time.c
@@ -81,13 +81,16 @@ void read_persistent_clock(struct timespec *ts)
 	ts->tv_nsec = 0;
 }
 
-static void __init plat_perf_setup(void)
+int get_c0_perfcount_int(void)
 {
 	if (cp0_perfcount_irq >= 0) {
 		if (cpu_has_vint)
 			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
 		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+	} else {
+		mips_cpu_perf_irq = -1;
 	}
+	return mips_cpu_perf_irq;
 }
 
 unsigned int get_c0_compare_int(void)
@@ -108,6 +111,4 @@ void __init plat_time_init(void)
 		(est_freq % 1000000) * 100 / 1000000);
 
 	mips_scroll_message();
-
-	plat_perf_setup();
 }
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index 42821ae..01f721a 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <asm/irq_regs.h>
+#include <asm/time.h>
 
 #include "op_impl.h"
 
@@ -35,6 +36,7 @@
 #define M_PERFCTL_COUNT_ALL_THREADS	(1UL	  << 13)
 
 static int (*save_perf_irq)(void);
+static int perfcount_irq;
 
 /*
  * XLR has only one set of counters per core. Designate the
@@ -431,8 +433,16 @@ static int __init mipsxx_init(void)
 	save_perf_irq = perf_irq;
 	perf_irq = mipsxx_perfcount_handler;
 
-	if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
-		return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int,
+	if (get_c0_perfcount_int)
+		perfcount_irq = get_c0_perfcount_int();
+	else if ((cp0_perfcount_irq >= 0) &&
+		 (cp0_compare_irq != cp0_perfcount_irq))
+		perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+	else
+		perfcount_irq = -1;
+
+	if (perfcount_irq >= 0)
+		return request_irq(perfcount_irq, mipsxx_perfcount_int,
 			0, "Perfcounter", save_perf_irq);
 
 	return 0;
@@ -442,8 +452,8 @@ static void mipsxx_exit(void)
 {
 	int counters = op_model_mipsxx_ops.num_counters;
 
-	if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
-		free_irq(cp0_perfcount_irq, save_perf_irq);
+	if (perfcount_irq >= 0)
+		free_irq(perfcount_irq, save_perf_irq);
 
 	counters = counters_per_cpu_to_total(counters);
 	on_each_cpu(reset_counters, (void *)(long)counters, 1);
diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c
index 0495011..7634dcd 100644
--- a/arch/mips/ralink/irq.c
+++ b/arch/mips/ralink/irq.c
@@ -45,6 +45,7 @@
 #define RALINK_INTC_IRQ_PERFC   (RALINK_INTC_IRQ_BASE + 9)
 
 static void __iomem *rt_intc_membase;
+static int rt_perfcount_irq;
 
 static inline void rt_intc_w32(u32 val, unsigned reg)
 {
@@ -73,6 +74,11 @@ static struct irq_chip ralink_intc_irq_chip = {
 	.irq_mask_ack	= ralink_intc_irq_mask,
 };
 
+int get_c0_perfcount_int(void)
+{
+	return rt_perfcount_irq;
+}
+
 unsigned int get_c0_compare_int(void)
 {
 	return CP0_LEGACY_COMPARE_IRQ;
@@ -167,7 +173,7 @@ static int __init intc_of_init(struct device_node *node,
 	irq_set_handler_data(irq, domain);
 
 	/* tell the kernel which irq is used for performance monitoring */
-	cp0_perfcount_irq = irq_create_mapping(domain, 9);
+	rt_perfcount_irq = irq_create_mapping(domain, 9);
 
 	return 0;
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/24] MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (5 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 06/24] MIPS: Add hook to get C0 performance counter interrupt Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 08/24] MIPS: Remove gic_{enable,disable}_interrupt() Andrew Bresticker
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Currently interrupt vectors 2 and 5 are left disabled on secondary CPUs.
Since systems using CPS must also have a GIC, which is responsible for
routing all external interrupts and can map them to any hardware interrupt
vector, enable the remaining vectors.  The two software interrupt vectors
are left disabled since they are not used with CPS.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/kernel/smp-cps.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
index e6e16a1..cd20aca 100644
--- a/arch/mips/kernel/smp-cps.c
+++ b/arch/mips/kernel/smp-cps.c
@@ -273,8 +273,8 @@ static void cps_init_secondary(void)
 	if (cpu_has_mipsmt)
 		dmt();
 
-	change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
-				 STATUSF_IP6 | STATUSF_IP7);
+	change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 |
+				 STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7);
 }
 
 static void cps_smp_finish(void)
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/24] MIPS: Remove gic_{enable,disable}_interrupt()
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (6 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 07/24] MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 09/24] MIPS: sead3: Remove sead3-serial.c Andrew Bresticker
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Nothing calls gic_{enable,disable}_interrupt() any more.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h     |  2 --
 arch/mips/mti-malta/malta-int.c | 10 ----------
 arch/mips/mti-sead3/sead3-int.c | 34 ----------------------------------
 3 files changed, 46 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index d7699cf..022d831 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -376,8 +376,6 @@ extern void gic_bind_eic_interrupt(int irq, int set);
 extern unsigned int gic_get_timer_pending(void);
 extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
 extern unsigned int gic_get_int(void);
-extern void gic_enable_interrupt(int irq_vec);
-extern void gic_disable_interrupt(int irq_vec);
 extern void gic_irq_ack(struct irq_data *d);
 extern void gic_finish_irq(struct irq_data *d);
 extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index e4f43ba..5c31208 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -715,16 +715,6 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
 	return retval;
 }
 
-void gic_enable_interrupt(int irq_vec)
-{
-	GIC_SET_INTR_MASK(irq_vec);
-}
-
-void gic_disable_interrupt(int irq_vec)
-{
-	GIC_CLR_INTR_MASK(irq_vec);
-}
-
 void gic_irq_ack(struct irq_data *d)
 {
 	int irq = (d->irq - gic_irq_base);
diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
index 6a560ac..9d5b5bd 100644
--- a/arch/mips/mti-sead3/sead3-int.c
+++ b/arch/mips/mti-sead3/sead3-int.c
@@ -85,40 +85,6 @@ void __init arch_init_irq(void)
 			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
 }
 
-void gic_enable_interrupt(int irq_vec)
-{
-	unsigned int i, irq_source;
-
-	/* enable all the interrupts associated with this vector */
-	for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) {
-		irq_source = gic_shared_intr_map[irq_vec].intr_list[i];
-		GIC_SET_INTR_MASK(irq_source);
-	}
-	/* enable all local interrupts associated with this vector */
-	if (gic_shared_intr_map[irq_vec].local_intr_mask) {
-		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
-		GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK),
-			gic_shared_intr_map[irq_vec].local_intr_mask);
-	}
-}
-
-void gic_disable_interrupt(int irq_vec)
-{
-	unsigned int i, irq_source;
-
-	/* disable all the interrupts associated with this vector */
-	for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) {
-		irq_source = gic_shared_intr_map[irq_vec].intr_list[i];
-		GIC_CLR_INTR_MASK(irq_source);
-	}
-	/* disable all local interrupts associated with this vector */
-	if (gic_shared_intr_map[irq_vec].local_intr_mask) {
-		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
-		GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK),
-			gic_shared_intr_map[irq_vec].local_intr_mask);
-	}
-}
-
 void gic_irq_ack(struct irq_data *d)
 {
 	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/24] MIPS: sead3: Remove sead3-serial.c
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (7 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 08/24] MIPS: Remove gic_{enable,disable}_interrupt() Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 10/24] MIPS: sead3: Do not overlap CPU/GIC IRQ ranges Andrew Bresticker
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

It's a duplicate of sead3-platform.c and is not even compiled.
Remove it before we start fixing up IRQ assignments.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/mti-sead3/sead3-serial.c | 45 --------------------------------------
 1 file changed, 45 deletions(-)
 delete mode 100644 arch/mips/mti-sead3/sead3-serial.c

diff --git a/arch/mips/mti-sead3/sead3-serial.c b/arch/mips/mti-sead3/sead3-serial.c
deleted file mode 100644
index bc52705..0000000
--- a/arch/mips/mti-sead3/sead3-serial.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define UART(base, int)							\
-{									\
-	.mapbase	= base,						\
-	.irq		= int,						\
-	.uartclk	= 14745600,					\
-	.iotype		= UPIO_MEM32,					\
-	.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \
-	.regshift	= 2,						\
-}
-
-static struct plat_serial8250_port uart8250_data[] = {
-	UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4),   /* ttyS0 = USB   */
-	UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4),   /* ttyS1 = RS232 */
-	{ },
-};
-
-static struct platform_device uart8250_device = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_PLATFORM,
-	.dev			= {
-		.platform_data	= uart8250_data,
-	},
-};
-
-static int __init uart8250_init(void)
-{
-	return platform_device_register(&uart8250_device);
-}
-
-module_init(uart8250_init);
-
-MODULE_AUTHOR("Chris Dearman <chris@mips.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("8250 UART probe driver for the SEAD-3 platform");
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/24] MIPS: sead3: Do not overlap CPU/GIC IRQ ranges
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (8 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 09/24] MIPS: sead3: Remove sead3-serial.c Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 11/24] MIPS: Malta: Move MSC01 interrupt base Andrew Bresticker
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

In preparation for GIC IRQ domain support, assign a GIC IRQ base
that does not overlap with the CPU IRQs.

Note that this breaks SEAD-3 when the GIC is in EIC mode, though
I'm not convinced it was working before either.  It will be fixed
in the following patches.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/mips-boards/sead3int.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index 6b17aaf..2320331 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -14,6 +14,6 @@
 #define GIC_BASE_ADDR		0x1b1c0000
 #define GIC_ADDRSPACE_SZ	(128 * 1024)
 
-#define MIPS_GIC_IRQ_BASE	(MIPS_CPU_IRQ_BASE + 0)
+#define MIPS_GIC_IRQ_BASE	(MIPS_CPU_IRQ_BASE + 8)
 
 #endif /* !(_MIPS_SEAD3INT_H) */
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/24] MIPS: Malta: Move MSC01 interrupt base
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (9 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 10/24] MIPS: sead3: Do not overlap CPU/GIC IRQ ranges Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 12/24] MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h Andrew Bresticker
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The GIC on Malta boards supports a total of 47 interrupts (40 shared
and 7 local) and is assigned a base of 24.  This overlaps with the
MSC01 interrupt assignments which have a base of 64, so move the MSC01
interrupt base back a bit to give the GIC some room.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/mips-boards/maltaint.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index e330732..4186606 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -33,18 +33,18 @@
 #define MIPSCPU_INT_CORELO	MIPSCPU_INT_MB4
 
 /*
- * Interrupts 64..127 are used for Soc-it Classic interrupts
+ * Interrupts 96..127 are used for Soc-it Classic interrupts
  */
-#define MSC01C_INT_BASE		64
+#define MSC01C_INT_BASE		96
 
 /* SOC-it Classic interrupt offsets */
 #define MSC01C_INT_TMR		0
 #define MSC01C_INT_PCI		1
 
 /*
- * Interrupts 64..127 are used for Soc-it EIC interrupts
+ * Interrupts 96..127 are used for Soc-it EIC interrupts
  */
-#define MSC01E_INT_BASE		64
+#define MSC01E_INT_BASE		96
 
 /* SOC-it EIC interrupt offsets */
 #define MSC01E_INT_SW0		1
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 12/24] MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (10 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 11/24] MIPS: Malta: Move MSC01 interrupt base Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 13/24] MIPS: Move GIC to drivers/irqchip/ Andrew Bresticker
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Define a generic MIPS_GIC_IRQ_BASE which should be suitable for all
current boards in <mach-generic/irq.h>.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/mach-generic/irq.h     | 6 ++++++
 arch/mips/include/asm/mips-boards/maltaint.h | 2 --
 arch/mips/include/asm/mips-boards/sead3int.h | 2 --
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/mips/include/asm/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h
index 139cd20..050e18b 100644
--- a/arch/mips/include/asm/mach-generic/irq.h
+++ b/arch/mips/include/asm/mach-generic/irq.h
@@ -36,4 +36,10 @@
 
 #endif /* CONFIG_IRQ_CPU */
 
+#ifdef CONFIG_MIPS_GIC
+#ifndef MIPS_GIC_IRQ_BASE
+#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
+#endif
+#endif /* CONFIG_MIPS_GIC */
+
 #endif /* __ASM_MACH_GENERIC_IRQ_H */
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index 4186606..d741628 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -10,8 +10,6 @@
 #ifndef _MIPS_MALTAINT_H
 #define _MIPS_MALTAINT_H
 
-#define MIPS_GIC_IRQ_BASE	(MIPS_CPU_IRQ_BASE + 8)
-
 /*
  * Interrupts 0..15 are used for Malta ISA compatible interrupts
  */
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index 2320331..11ebec9 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -14,6 +14,4 @@
 #define GIC_BASE_ADDR		0x1b1c0000
 #define GIC_ADDRSPACE_SZ	(128 * 1024)
 
-#define MIPS_GIC_IRQ_BASE	(MIPS_CPU_IRQ_BASE + 8)
-
 #endif /* !(_MIPS_SEAD3INT_H) */
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 13/24] MIPS: Move GIC to drivers/irqchip/
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (11 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 12/24] MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks Andrew Bresticker
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Move GIC irqchip support to drivers/irqchip/ and rename the Kconfig
option from IRQ_GIC to MIPS_GIC to avoid confusion with the ARM GIC.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/Kconfig                                            | 10 +++-------
 arch/mips/kernel/Makefile                                    |  1 -
 arch/mips/kernel/cevt-r4k.c                                  |  2 +-
 arch/mips/kernel/smp-mt.c                                    |  4 ++--
 arch/mips/mti-malta/malta-time.c                             | 10 +++++-----
 drivers/irqchip/Kconfig                                      |  4 ++++
 drivers/irqchip/Makefile                                     |  1 +
 arch/mips/kernel/irq-gic.c => drivers/irqchip/irq-mips-gic.c |  0
 8 files changed, 16 insertions(+), 16 deletions(-)
 rename arch/mips/kernel/irq-gic.c => drivers/irqchip/irq-mips-gic.c (100%)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index de72c92..a0720d0 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -319,7 +319,7 @@ config MIPS_MALTA
 	select GENERIC_ISA_DMA
 	select HAVE_PCSPKR_PLATFORM
 	select IRQ_CPU
-	select IRQ_GIC
+	select MIPS_GIC
 	select HW_HAS_PCI
 	select I8253
 	select I8259
@@ -360,7 +360,7 @@ config MIPS_SEAD3
 	select CPU_MIPSR2_IRQ_EI
 	select DMA_NONCOHERENT
 	select IRQ_CPU
-	select IRQ_GIC
+	select MIPS_GIC
 	select LIBFDT
 	select MIPS_MSC
 	select SYS_HAS_CPU_MIPS32_R1
@@ -1069,10 +1069,6 @@ config IRQ_TXX9
 config IRQ_GT641XX
 	bool
 
-config IRQ_GIC
-	select MIPS_CM
-	bool
-
 config PCI_GT64XXX_PCI0
 	bool
 
@@ -1886,7 +1882,7 @@ config FORCE_MAX_ZONEORDER
 
 config CEVT_GIC
 	bool "Use GIC global counter for clock events"
-	depends on IRQ_GIC && !MIPS_SEAD3
+	depends on MIPS_GIC && !MIPS_SEAD3
 	help
 	  Use the GIC global counter for the clock events. The R4K clock
 	  event driver is always present, so if the platform ends up not
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 008a2fe..3982e51 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -68,7 +68,6 @@ obj-$(CONFIG_IRQ_CPU_RM7K)	+= irq-rm7000.o
 obj-$(CONFIG_MIPS_MSC)		+= irq-msc01.o
 obj-$(CONFIG_IRQ_TXX9)		+= irq_txx9.o
 obj-$(CONFIG_IRQ_GT641XX)	+= irq-gt641xx.o
-obj-$(CONFIG_IRQ_GIC)		+= irq-gic.o
 
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_32BIT)		+= scall32-o32.o
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index bc127e2..5b8f8e3 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -85,7 +85,7 @@ void mips_event_handler(struct clock_event_device *dev)
  */
 static int c0_compare_int_pending(void)
 {
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (cpu_has_veic)
 		return gic_get_timer_pending();
 #endif
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 21f23ad..d60475f 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -119,7 +119,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action)
 	unsigned long flags;
 	int vpflags;
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (gic_present) {
 		gic_send_ipi_single(cpu, action);
 		return;
@@ -158,7 +158,7 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
 
 static void vsmp_init_secondary(void)
 {
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	/* This is Malta specific: IPI,performance and timer interrupts */
 	if (gic_present)
 		change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index a4e035c..17cfc8a 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -70,7 +70,7 @@ static void __init estimate_frequencies(void)
 {
 	unsigned long flags;
 	unsigned int count, start;
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	unsigned int giccount = 0, gicstart = 0;
 #endif
 
@@ -87,7 +87,7 @@ static void __init estimate_frequencies(void)
 
 	/* Initialize counters. */
 	start = read_c0_count();
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (gic_present)
 		GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart);
 #endif
@@ -97,7 +97,7 @@ static void __init estimate_frequencies(void)
 	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
 
 	count = read_c0_count();
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (gic_present)
 		GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount);
 #endif
@@ -107,7 +107,7 @@ static void __init estimate_frequencies(void)
 	count -= start;
 	mips_hpt_frequency = count;
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (gic_present) {
 		giccount -= gicstart;
 		gic_frequency = giccount;
@@ -189,7 +189,7 @@ void __init plat_time_init(void)
 	setup_pit_timer();
 #endif
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
 	if (gic_present) {
 		freq = freqround(gic_frequency, 5000);
 		printk("GIC frequency %d.%02d MHz\n", freq/1000000,
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index b8632bf..ddacccf 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -113,3 +113,7 @@ config IRQ_CROSSBAR
 	  The primary irqchip invokes the crossbar's callback which inturn allocates
 	  a free irq and configures the IP. Thus the peripheral interrupts are
 	  routed to one of the free irqchip interrupt lines.
+
+config MIPS_GIC
+	bool
+	select MIPS_CM
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 73052ba..fd47e0d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
 obj-$(CONFIG_XTENSA_MX)			+= irq-xtensa-mx.o
 obj-$(CONFIG_IRQ_CROSSBAR)		+= irq-crossbar.o
 obj-$(CONFIG_BRCMSTB_L2_IRQ)		+= irq-brcmstb-l2.o
+obj-$(CONFIG_MIPS_GIC)			+= irq-mips-gic.o
diff --git a/arch/mips/kernel/irq-gic.c b/drivers/irqchip/irq-mips-gic.c
similarity index 100%
rename from arch/mips/kernel/irq-gic.c
rename to drivers/irqchip/irq-mips-gic.c
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (12 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 13/24] MIPS: Move GIC to drivers/irqchip/ Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17  9:14   ` Qais Yousef
  2014-09-15 23:51 ` [PATCH 15/24] irqchip: mips-gic: Implement irq_set_type callback Andrew Bresticker
                   ` (11 subsequent siblings)
  25 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

There's no need for platforms to have their own GIC irq_ack/irq_eoi
callbacks.  Move them to the GIC irqchip driver.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h     |  2 --
 arch/mips/mti-malta/malta-int.c | 16 ----------------
 arch/mips/mti-sead3/sead3-int.c | 21 ---------------------
 drivers/irqchip/irq-mips-gic.c  | 15 ++++++++++++---
 4 files changed, 12 insertions(+), 42 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 022d831..1bf7985 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -376,7 +376,5 @@ extern void gic_bind_eic_interrupt(int irq, int set);
 extern unsigned int gic_get_timer_pending(void);
 extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
 extern unsigned int gic_get_int(void);
-extern void gic_irq_ack(struct irq_data *d);
-extern void gic_finish_irq(struct irq_data *d);
 extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
 #endif /* _ASM_GICREGS_H */
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 5c31208..b60adfd 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -715,22 +715,6 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
 	return retval;
 }
 
-void gic_irq_ack(struct irq_data *d)
-{
-	int irq = (d->irq - gic_irq_base);
-
-	GIC_CLR_INTR_MASK(irq);
-
-	if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
-		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
-}
-
-void gic_finish_irq(struct irq_data *d)
-{
-	/* Enable interrupts. */
-	GIC_SET_INTR_MASK(d->irq - gic_irq_base);
-}
-
 void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
 {
 	int i;
diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
index 9d5b5bd..03f9865 100644
--- a/arch/mips/mti-sead3/sead3-int.c
+++ b/arch/mips/mti-sead3/sead3-int.c
@@ -85,27 +85,6 @@ void __init arch_init_irq(void)
 			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
 }
 
-void gic_irq_ack(struct irq_data *d)
-{
-	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
-}
-
-void gic_finish_irq(struct irq_data *d)
-{
-	unsigned int irq = (d->irq - gic_irq_base);
-	unsigned int i, irq_source;
-
-	/* Clear edge detectors. */
-	for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) {
-		irq_source = gic_shared_intr_map[irq].intr_list[i];
-		if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE)
-			GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq_source);
-	}
-
-	/* Enable interrupts. */
-	GIC_SET_INTR_MASK(irq);
-}
-
 void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
 {
 	int i;
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 9e9d8b9..0dc2972 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -237,6 +237,15 @@ static void gic_unmask_irq(struct irq_data *d)
 	GIC_SET_INTR_MASK(d->irq - gic_irq_base);
 }
 
+static void gic_ack_irq(struct irq_data *d)
+{
+	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
+
+	/* Clear edge detector */
+	if (gic_irq_flags[d->irq - gic_irq_base] & GIC_TRIG_EDGE)
+		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq - gic_irq_base);
+}
+
 #ifdef CONFIG_SMP
 static DEFINE_SPINLOCK(gic_lock);
 
@@ -272,11 +281,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 
 static struct irq_chip gic_irq_controller = {
 	.name			=	"MIPS GIC",
-	.irq_ack		=	gic_irq_ack,
+	.irq_ack		=	gic_ack_irq,
 	.irq_mask		=	gic_mask_irq,
-	.irq_mask_ack		=	gic_mask_irq,
+	.irq_mask_ack		=	gic_ack_irq,
 	.irq_unmask		=	gic_unmask_irq,
-	.irq_eoi		=	gic_finish_irq,
+	.irq_eoi		=	gic_unmask_irq,
 #ifdef CONFIG_SMP
 	.irq_set_affinity	=	gic_set_affinity,
 #endif
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 15/24] irqchip: mips-gic: Implement irq_set_type callback
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (13 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 16/24] irqchip: mips-gic: Fix gic_set_affinity() return value Andrew Bresticker
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Implement an irq_set_type callback for the GIC which is used to set
the polarity and trigger type of GIC interrupts.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h    |  9 ++++++++
 drivers/irqchip/irq-mips-gic.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 1bf7985..662b567 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -23,6 +23,8 @@
 #define GIC_POL_NEG			0
 #define GIC_TRIG_EDGE			1
 #define GIC_TRIG_LEVEL			0
+#define GIC_TRIG_DUAL_ENABLE		1
+#define GIC_TRIG_DUAL_DISABLE		0
 
 #define MSK(n) ((1 << (n)) - 1)
 #define REG32(addr)		(*(volatile unsigned int *) (addr))
@@ -179,6 +181,13 @@
 		GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \
 		(trig) << GIC_INTR_BIT(intr))
 
+/* Dual edge triggering : Reset Value is always 0 */
+#define GIC_SH_SET_DUAL_OFS		0x0200
+#define GIC_SET_DUAL(intr, dual) \
+	GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_DUAL_OFS + \
+		GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \
+		(dual) << GIC_INTR_BIT(intr))
+
 /* Mask manipulation */
 #define GIC_SH_SMASK_OFS		0x0380
 #define GIC_SET_INTR_MASK(intr) \
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 0dc2972..cde743c 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -246,6 +246,56 @@ static void gic_ack_irq(struct irq_data *d)
 		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq - gic_irq_base);
 }
 
+static int gic_set_type(struct irq_data *d, unsigned int type)
+{
+	unsigned int irq = d->irq - gic_irq_base;
+	bool is_edge;
+
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_FALLING:
+		GIC_SET_POLARITY(irq, GIC_POL_NEG);
+		GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE);
+		GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE);
+		is_edge = true;
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		GIC_SET_POLARITY(irq, GIC_POL_POS);
+		GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE);
+		GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE);
+		is_edge = true;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		/* polarity is irrelevant in this case */
+		GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE);
+		GIC_SET_DUAL(irq, GIC_TRIG_DUAL_ENABLE);
+		is_edge = true;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		GIC_SET_POLARITY(irq, GIC_POL_NEG);
+		GIC_SET_TRIGGER(irq, GIC_TRIG_LEVEL);
+		GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE);
+		is_edge = false;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	default:
+		GIC_SET_POLARITY(irq, GIC_POL_POS);
+		GIC_SET_TRIGGER(irq, GIC_TRIG_LEVEL);
+		GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE);
+		is_edge = false;
+		break;
+	}
+
+	if (is_edge) {
+		gic_irq_flags[irq] |= GIC_TRIG_EDGE;
+		__irq_set_handler_locked(d->irq, handle_edge_irq);
+	} else {
+		gic_irq_flags[irq] &= ~GIC_TRIG_EDGE;
+		__irq_set_handler_locked(d->irq, handle_level_irq);
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_SMP
 static DEFINE_SPINLOCK(gic_lock);
 
@@ -286,6 +336,7 @@ static struct irq_chip gic_irq_controller = {
 	.irq_mask_ack		=	gic_ack_irq,
 	.irq_unmask		=	gic_unmask_irq,
 	.irq_eoi		=	gic_unmask_irq,
+	.irq_set_type		=	gic_set_type,
 #ifdef CONFIG_SMP
 	.irq_set_affinity	=	gic_set_affinity,
 #endif
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 16/24] irqchip: mips-gic: Fix gic_set_affinity() return value
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (14 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 15/24] irqchip: mips-gic: Implement irq_set_type callback Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 17/24] irqchip: mips-gic: Use IRQ domains Andrew Bresticker
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

If the online CPU check in gic_set_affinity() fails, return a proper
errno value instead of -1.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/irqchip/irq-mips-gic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index cde743c..fd00318 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -309,7 +309,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 
 	cpumask_and(&tmp, cpumask, cpu_online_mask);
 	if (cpus_empty(tmp))
-		return -1;
+		return -EINVAL;
 
 	/* Assumption : cpumask refers to a single CPU */
 	spin_lock_irqsave(&gic_lock, flags);
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 17/24] irqchip: mips-gic: Use IRQ domains
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (15 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 16/24] irqchip: mips-gic: Fix gic_set_affinity() return value Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables Andrew Bresticker
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Use a simple IRQ domain for the MIPS GIC.  Remove the gic_platform_init
callback as it's no longer necessary for it to set the irqchip.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h     |  1 -
 arch/mips/mti-malta/malta-int.c |  8 -------
 arch/mips/mti-sead3/sead3-int.c | 15 --------------
 drivers/irqchip/irq-mips-gic.c  | 46 +++++++++++++++++++++++++++++++++--------
 4 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 662b567..efcf4de 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -385,5 +385,4 @@ extern void gic_bind_eic_interrupt(int irq, int set);
 extern unsigned int gic_get_timer_pending(void);
 extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
 extern unsigned int gic_get_int(void);
-extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
 #endif /* _ASM_GICREGS_H */
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index b60adfd..e56563c 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -714,11 +714,3 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
 
 	return retval;
 }
-
-void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
-{
-	int i;
-
-	for (i = gic_irq_base; i < (gic_irq_base + irqs); i++)
-		irq_set_chip(i, irq_controller);
-}
diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
index 03f9865..8f36342 100644
--- a/arch/mips/mti-sead3/sead3-int.c
+++ b/arch/mips/mti-sead3/sead3-int.c
@@ -85,18 +85,3 @@ void __init arch_init_irq(void)
 			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
 }
 
-void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
-{
-	int i;
-
-	/*
-	 * For non-EIC mode, we want to setup the GIC in pass-through
-	 * mode, as if the GIC didn't exist. Do not map any interrupts
-	 * for an external interrupt controller.
-	 */
-	if (!cpu_has_veic)
-		return;
-
-	for (i = gic_irq_base; i < (gic_irq_base + irqs); i++)
-		irq_set_chip_and_handler(i, irq_controller, handle_percpu_irq);
-}
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index fd00318..b4d87c4 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -43,6 +43,7 @@ struct gic_intrmask_regs {
 static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
 static struct gic_pending_regs pending_regs[NR_CPUS];
 static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
+static struct irq_domain *gic_irq_domain;
 
 #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
 cycle_t gic_read_count(void)
@@ -229,26 +230,28 @@ unsigned int gic_get_int(void)
 
 static void gic_mask_irq(struct irq_data *d)
 {
-	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
+	GIC_CLR_INTR_MASK(d->hwirq);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-	GIC_SET_INTR_MASK(d->irq - gic_irq_base);
+	GIC_SET_INTR_MASK(d->hwirq);
 }
 
 static void gic_ack_irq(struct irq_data *d)
 {
-	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
+	unsigned int irq = d->hwirq;
+
+	GIC_CLR_INTR_MASK(irq);
 
 	/* Clear edge detector */
-	if (gic_irq_flags[d->irq - gic_irq_base] & GIC_TRIG_EDGE)
-		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq - gic_irq_base);
+	if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
+		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
-	unsigned int irq = d->irq - gic_irq_base;
+	unsigned int irq = d->hwirq;
 	bool is_edge;
 
 	switch (type & IRQ_TYPE_SENSE_MASK) {
@@ -302,7 +305,7 @@ static DEFINE_SPINLOCK(gic_lock);
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 			    bool force)
 {
-	unsigned int irq = (d->irq - gic_irq_base);
+	unsigned int irq = d->hwirq;
 	cpumask_t	tmp = CPU_MASK_NONE;
 	unsigned long	flags;
 	int		i;
@@ -347,6 +350,7 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
 	unsigned int flags)
 {
 	struct gic_shared_intr_map *map_ptr;
+	int i;
 
 	/* Setup Intr to Pin mapping */
 	if (pin & GIC_MAP_TO_NMI_MSK) {
@@ -384,6 +388,8 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
 	GIC_CLR_INTR_MASK(intr);
 
 	/* Initialise per-cpu Interrupt software masks */
+	for (i = 0; i < NR_CPUS; i++)
+		clear_bit(intr, pcpu_masks[i].pcpu_mask);
 	set_bit(intr, pcpu_masks[cpu].pcpu_mask);
 
 	if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
@@ -435,6 +441,25 @@ static void __init gic_basic_init(int numintrs, int numvpes,
 	vpe_local_setup(numvpes);
 }
 
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
+			      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &gic_irq_controller, handle_level_irq);
+
+	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
+		 GIC_MAP_TO_PIN_MSK | 0);
+	/* Map to VPE 0 by default */
+	GIC_SH_MAP_TO_VPE_SMASK(hw, 0);
+	set_bit(hw, pcpu_masks[0].pcpu_mask);
+
+	return 0;
+}
+
+static struct irq_domain_ops gic_irq_domain_ops = {
+	.map = gic_irq_domain_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
 void __init gic_init(unsigned long gic_base_addr,
 		     unsigned long gic_addrspace_size,
 		     struct gic_intr_map *intr_map, unsigned int intr_map_size,
@@ -456,7 +481,10 @@ void __init gic_init(unsigned long gic_base_addr,
 		  GIC_SH_CONFIG_NUMVPES_SHF;
 	numvpes = numvpes + 1;
 
-	gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
+	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase,
+					       &gic_irq_domain_ops, NULL);
+	if (!gic_irq_domain)
+		panic("Failed to add GIC IRQ domain");
 
-	gic_platform_init(numintrs, &gic_irq_controller);
+	gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (16 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 17/24] irqchip: mips-gic: Use IRQ domains Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17  9:21   ` Qais Yousef
  2014-09-15 23:51 ` [PATCH 19/24] irqchip: mips-gic: Probe for number of external interrupts Andrew Bresticker
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Now that the GIC properly uses IRQ domains, kill off the per-platform
routing tables that were used to make the GIC appear transparent.

This includes:
 - removing the mapping tables and the support for applying them,
 - moving GIC IPI support to the GIC driver,
 - properly routing the i8259 through the GIC on Malta, and
 - updating IRQ assignments on SEAD-3 when the GIC is present.

Platforms no longer will pass an interrupt mapping table to gic_init.
Instead, they will pass the CPU interrupt vector (2 - 7) that they
expect the GIC to route interrupts to.  Note that in EIC mode this
value is ignored and all GIC interrupts are routed to EIC vector 1.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
I'm not sure what other external interrupts (if any) are also routed
through the GIC on Malta boards.  In particular I'm concerned about
the MSC01 IRQ chip and the CoreHi interrupt.  Neither of these matter
a whole lot since we don't use any MSC01 interrupts and the CoreHI
interrupt is fatal.
---
 arch/mips/include/asm/gic.h                  |  35 +----
 arch/mips/include/asm/mips-boards/maltaint.h |  14 +-
 arch/mips/include/asm/mips-boards/sead3int.h |  13 ++
 arch/mips/kernel/cevt-gic.c                  |   3 +-
 arch/mips/mti-malta/malta-int.c              | 189 +++++--------------------
 arch/mips/mti-sead3/sead3-ehci.c             |   8 +-
 arch/mips/mti-sead3/sead3-int.c              |  28 +---
 arch/mips/mti-sead3/sead3-net.c              |  14 +-
 arch/mips/mti-sead3/sead3-platform.c         |  18 ++-
 drivers/irqchip/irq-mips-gic.c               | 201 ++++++++++++++-------------
 10 files changed, 198 insertions(+), 325 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index efcf4de..cfbf907 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -316,31 +316,6 @@
 	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \
 		 GIC_SH_MAP_TO_VPE_REG_BIT(vpe))
 
-/*
- * Interrupt Meta-data specification. The ipiflag helps
- * in building ipi_map.
- */
-struct gic_intr_map {
-	unsigned int cpunum;	/* Directed to this CPU */
-#define GIC_UNUSED		0xdead			/* Dummy data */
-	unsigned int pin;	/* Directed to this Pin */
-	unsigned int polarity;	/* Polarity : +/-	*/
-	unsigned int trigtype;	/* Trigger  : Edge/Levl */
-	unsigned int flags;	/* Misc flags	*/
-#define GIC_FLAG_TRANSPARENT   0x01
-};
-
-/*
- * This is only used in EIC mode. This helps to figure out which
- * shared interrupts we need to process when we get a vector interrupt.
- */
-#define GIC_MAX_SHARED_INTR  0x5
-struct gic_shared_intr_map {
-	unsigned int num_shared_intr;
-	unsigned int intr_list[GIC_MAX_SHARED_INTR];
-	unsigned int local_intr_mask;
-};
-
 /* GIC nomenclature for Core Interrupt Pins. */
 #define GIC_CPU_INT0		0 /* Core Interrupt 2 */
 #define GIC_CPU_INT1		1 /* .		      */
@@ -349,6 +324,9 @@ struct gic_shared_intr_map {
 #define GIC_CPU_INT4		4 /* .		      */
 #define GIC_CPU_INT5		5 /* Core Interrupt 7 */
 
+/* Add 2 to convert GIC CPU pin to core interrupt */
+#define GIC_CPU_PIN_OFFSET	2
+
 /* Local GIC interrupts. */
 #define GIC_INT_TMR		(GIC_CPU_INT5)
 #define GIC_INT_PERFCTR		(GIC_CPU_INT5)
@@ -365,13 +343,12 @@ struct gic_shared_intr_map {
 extern unsigned int gic_present;
 extern unsigned int gic_frequency;
 extern unsigned long _gic_base;
-extern unsigned int gic_irq_base;
 extern unsigned int gic_irq_flags[];
-extern struct gic_shared_intr_map gic_shared_intr_map[];
+extern unsigned int gic_cpu_pin;
 
 extern void gic_init(unsigned long gic_base_addr,
-	unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
-	unsigned int intrmap_size, unsigned int irqbase);
+	unsigned long gic_addrspace_size, unsigned int cpu_vec,
+	unsigned int irqbase);
 extern void gic_clocksource_init(unsigned int);
 extern unsigned int gic_compare_int (void);
 extern cycle_t gic_read_count(void);
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index d741628..bdd6f39 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -20,11 +20,10 @@
 #define MIPSCPU_INT_SW1		1
 #define MIPSCPU_INT_MB0		2
 #define MIPSCPU_INT_I8259A	MIPSCPU_INT_MB0
+#define MIPSCPU_INT_GIC		MIPSCPU_INT_MB0 /* GIC chained interrupt */
 #define MIPSCPU_INT_MB1		3
 #define MIPSCPU_INT_SMI		MIPSCPU_INT_MB1
-#define MIPSCPU_INT_IPI0	MIPSCPU_INT_MB1 /* GIC IPI */
 #define MIPSCPU_INT_MB2		4
-#define MIPSCPU_INT_IPI1	MIPSCPU_INT_MB2 /* GIC IPI */
 #define MIPSCPU_INT_MB3		5
 #define MIPSCPU_INT_COREHI	MIPSCPU_INT_MB3
 #define MIPSCPU_INT_MB4		6
@@ -61,14 +60,7 @@
 #define MSC01E_INT_PERFCTR	10
 #define MSC01E_INT_CPUCTR	11
 
-/* External Interrupts used for IPI */
-#define GIC_IPI_EXT_INTR_RESCHED_VPE0	16
-#define GIC_IPI_EXT_INTR_CALLFNC_VPE0	17
-#define GIC_IPI_EXT_INTR_RESCHED_VPE1	18
-#define GIC_IPI_EXT_INTR_CALLFNC_VPE1	19
-#define GIC_IPI_EXT_INTR_RESCHED_VPE2	20
-#define GIC_IPI_EXT_INTR_CALLFNC_VPE2	21
-#define GIC_IPI_EXT_INTR_RESCHED_VPE3	22
-#define GIC_IPI_EXT_INTR_CALLFNC_VPE3	23
+/* GIC external interrupts */
+#define GIC_INT_I8259A		3
 
 #endif /* !(_MIPS_MALTAINT_H) */
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index 11ebec9..a2e0095 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -14,4 +14,17 @@
 #define GIC_BASE_ADDR		0x1b1c0000
 #define GIC_ADDRSPACE_SZ	(128 * 1024)
 
+/* CPU interrupt offsets */
+#define CPU_INT_GIC		2
+#define CPU_INT_EHCI		2
+#define CPU_INT_UART0		4
+#define CPU_INT_UART1		4
+#define CPU_INT_NET		6
+
+/* GIC interrupt offsets */
+#define GIC_INT_NET		0
+#define GIC_INT_UART1		2
+#define GIC_INT_UART0		3
+#define GIC_INT_EHCI		5
+
 #endif /* !(_MIPS_SEAD3INT_H) */
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
index 6093716..a90bd4c 100644
--- a/arch/mips/kernel/cevt-gic.c
+++ b/arch/mips/kernel/cevt-gic.c
@@ -91,7 +91,8 @@ int gic_clockevent_init(void)
 
 	clockevents_register_device(cd);
 
-	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
+	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP),
+		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
 	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
 
 	if (gic_timer_irq_installed)
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index e56563c..3b3bc1d 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -38,14 +38,9 @@
 #include <asm/rtlx.h>
 
 static unsigned long _msc01_biu_base;
-static unsigned int ipi_map[NR_CPUS];
 
 static DEFINE_RAW_SPINLOCK(mips_irq_lock);
 
-#ifdef CONFIG_MIPS_GIC_IPI
-DECLARE_BITMAP(ipi_ints, GIC_NUM_INTRS);
-#endif
-
 static inline int mips_pcibios_iack(void)
 {
 	int irq;
@@ -127,24 +122,10 @@ static void malta_hw0_irqdispatch(void)
 #endif
 }
 
-static void malta_ipi_irqdispatch(void)
+static irqreturn_t i8259_handler(int irq, void *dev_id)
 {
-#ifdef CONFIG_MIPS_GIC_IPI
-	unsigned long irq;
-	DECLARE_BITMAP(pending, GIC_NUM_INTRS);
-
-	gic_get_int_mask(pending, ipi_ints);
-
-	irq = find_first_bit(pending, GIC_NUM_INTRS);
-
-	while (irq < GIC_NUM_INTRS) {
-		do_IRQ(MIPS_GIC_IRQ_BASE + irq);
-
-		irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1);
-	}
-#endif
-	if (gic_compare_int())
-		do_IRQ(MIPS_GIC_IRQ_BASE);
+	malta_hw0_irqdispatch();
+	return IRQ_HANDLED;
 }
 
 static void corehi_irqdispatch(void)
@@ -203,6 +184,12 @@ static void corehi_irqdispatch(void)
 	die("CoreHi interrupt", regs);
 }
 
+static irqreturn_t corehi_handler(int irq, void *dev_id)
+{
+	corehi_irqdispatch();
+	return IRQ_HANDLED;
+}
+
 static inline int clz(unsigned long x)
 {
 	__asm__(
@@ -286,10 +273,9 @@ asmlinkage void plat_irq_dispatch(void)
 
 	irq = irq_ffs(pending);
 
-	if (irq == MIPSCPU_INT_I8259A)
-		malta_hw0_irqdispatch();
-	else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
-		malta_ipi_irqdispatch();
+	/* HACK: GIC doesn't properly dispatch local interrupts yet */
+	if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int())
+		do_IRQ(MIPS_GIC_IRQ_BASE);
 	else
 		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
 }
@@ -312,13 +298,6 @@ static void ipi_call_dispatch(void)
 	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
 }
 
-#endif /* CONFIG_MIPS_MT_SMP */
-
-#ifdef CONFIG_MIPS_GIC_IPI
-
-#define GIC_MIPS_CPU_IPI_RESCHED_IRQ	3
-#define GIC_MIPS_CPU_IPI_CALL_IRQ	4
-
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
 #ifdef CONFIG_MIPS_VPE_APSP_API_CMP
@@ -349,31 +328,16 @@ static struct irqaction irq_call = {
 	.flags		= IRQF_PERCPU,
 	.name		= "IPI_call"
 };
-#endif /* CONFIG_MIPS_GIC_IPI */
-
-static int gic_resched_int_base;
-static int gic_call_int_base;
-#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu))
-#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu))
-
-unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
-{
-	return GIC_CALL_INT(cpu);
-}
-
-unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
-{
-	return GIC_RESCHED_INT(cpu);
-}
+#endif /* CONFIG_MIPS_MT_SMP */
 
 static struct irqaction i8259irq = {
-	.handler = no_action,
+	.handler = i8259_handler,
 	.name = "XT-PIC cascade",
 	.flags = IRQF_NO_THREAD,
 };
 
 static struct irqaction corehi_irqaction = {
-	.handler = no_action,
+	.handler = corehi_handler,
 	.name = "CoreHi",
 	.flags = IRQF_NO_THREAD,
 };
@@ -399,60 +363,6 @@ static msc_irqmap_t msc_eicirqmap[] __initdata = {
 
 static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
 
-/*
- * This GIC specific tabular array defines the association between External
- * Interrupts and CPUs/Core Interrupts. The nature of the External
- * Interrupts is also defined here - polarity/trigger.
- */
-
-#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
-#define X GIC_UNUSED
-
-static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
-	{ X, X,		   X,		X,		0 },
-	{ X, X,		   X,		X,		0 },
-	{ X, X,		   X,		X,		0 },
-	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ X, X,		   X,		X,		0 },
-	{ X, X,		   X,		X,		0 },
-	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_NMI,  GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_NMI,  GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ X, X,		   X,		X,		0 },
-	/* The remainder of this table is initialised by fill_ipi_map */
-};
-#undef X
-
-#ifdef CONFIG_MIPS_GIC_IPI
-static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
-{
-	int intr = baseintr + cpu;
-	gic_intr_map[intr].cpunum = cpu;
-	gic_intr_map[intr].pin = cpupin;
-	gic_intr_map[intr].polarity = GIC_POL_POS;
-	gic_intr_map[intr].trigtype = GIC_TRIG_EDGE;
-	gic_intr_map[intr].flags = 0;
-	ipi_map[cpu] |= (1 << (cpupin + 2));
-	bitmap_set(ipi_ints, intr, 1);
-}
-
-static void __init fill_ipi_map(void)
-{
-	int cpu;
-
-	for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
-		fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
-		fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
-	}
-}
-#endif
-
 void __init arch_init_ipiirq(int irq, struct irqaction *action)
 {
 	setup_irq(irq, action);
@@ -461,6 +371,8 @@ void __init arch_init_ipiirq(int irq, struct irqaction *action)
 
 void __init arch_init_irq(void)
 {
+	int corehi_irq, i8259_irq;
+
 	init_i8259_irqs();
 
 	if (!cpu_has_veic)
@@ -507,34 +419,11 @@ void __init arch_init_irq(void)
 					msc_nr_irqs);
 	}
 
-	if (cpu_has_veic) {
-		set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch);
-		set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
-		setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq);
-		setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction);
-	} else if (cpu_has_vint) {
-		set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
-		set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch);
-		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
-		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
-						&corehi_irqaction);
-	} else {
-		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
-		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
-						&corehi_irqaction);
-	}
-
 	if (gic_present) {
-		/* FIXME */
 		int i;
-#if defined(CONFIG_MIPS_GIC_IPI)
-		gic_call_int_base = GIC_NUM_INTRS -
-			(NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
-		gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
-		fill_ipi_map();
-#endif
-		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
-				ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
+
+		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC,
+			 MIPS_GIC_IRQ_BASE);
 		if (!mips_cm_present()) {
 			/* Enable the GIC */
 			i = REG(_msc01_biu_base, MSC01_SC_CFG);
@@ -542,28 +431,8 @@ void __init arch_init_irq(void)
 				(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
 			pr_debug("GIC Enabled\n");
 		}
-#if defined(CONFIG_MIPS_GIC_IPI)
-		/* set up ipi interrupts */
-		if (cpu_has_vint) {
-			set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
-			set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
-		}
-		/* Argh.. this really needs sorting out.. */
-		pr_info("CPU%d: status register was %08x\n",
-			smp_processor_id(), read_c0_status());
-		write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
-		pr_info("CPU%d: status register now %08x\n",
-			smp_processor_id(), read_c0_status());
-		write_c0_status(0x1100dc00);
-		pr_info("CPU%d: status register frc %08x\n",
-			smp_processor_id(), read_c0_status());
-		for (i = 0; i < nr_cpu_ids; i++) {
-			arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
-					 GIC_RESCHED_INT(i), &irq_resched);
-			arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
-					 GIC_CALL_INT(i), &irq_call);
-		}
-#endif
+		i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A;
+		corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
 	} else {
 #if defined(CONFIG_MIPS_MT_SMP)
 		/* set up ipi interrupts */
@@ -587,7 +456,21 @@ void __init arch_init_irq(void)
 		arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched);
 		arch_init_ipiirq(cpu_ipi_call_irq, &irq_call);
 #endif
+		if (cpu_has_veic) {
+			set_vi_handler(MSC01E_INT_I8259A,
+				       malta_hw0_irqdispatch);
+			set_vi_handler(MSC01E_INT_COREHI,
+				       corehi_irqdispatch);
+			i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A;
+			corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
+		} else {
+			i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A;
+			corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
+		}
 	}
+
+	setup_irq(i8259_irq, &i8259irq);
+	setup_irq(corehi_irq, &corehi_irqaction);
 }
 
 void malta_be_init(void)
diff --git a/arch/mips/mti-sead3/sead3-ehci.c b/arch/mips/mti-sead3/sead3-ehci.c
index 772fc05..4ddaa0f 100644
--- a/arch/mips/mti-sead3/sead3-ehci.c
+++ b/arch/mips/mti-sead3/sead3-ehci.c
@@ -10,6 +10,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 
+#include <asm/gic.h>
+#include <asm/mips-boards/sead3int.h>
+
 struct resource ehci_resources[] = {
 	{
 		.start			= 0x1b200000,
@@ -17,7 +20,6 @@ struct resource ehci_resources[] = {
 		.flags			= IORESOURCE_MEM
 	},
 	{
-		.start			= MIPS_CPU_IRQ_BASE + 2,
 		.flags			= IORESOURCE_IRQ
 	}
 };
@@ -37,6 +39,10 @@ static struct platform_device ehci_device = {
 
 static int __init ehci_init(void)
 {
+	if (gic_present)
+		ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI;
+	else
+		ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI;
 	return platform_device_register(&ehci_device);
 }
 
diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
index 8f36342..cb06cd9 100644
--- a/arch/mips/mti-sead3/sead3-int.c
+++ b/arch/mips/mti-sead3/sead3-int.c
@@ -22,30 +22,6 @@
 
 static unsigned long sead3_config_reg;
 
-/*
- * This table defines the setup for each external GIC interrupt. It is
- * indexed by interrupt number.
- */
-#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
-static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
-	{ 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
-};
-
 asmlinkage void plat_irq_dispatch(void)
 {
 	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
@@ -81,7 +57,7 @@ void __init arch_init_irq(void)
 		(current_cpu_data.options & MIPS_CPU_VEIC) ?  "on" : "off");
 
 	if (gic_present)
-		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
-			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
+		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC,
+			 MIPS_GIC_IRQ_BASE);
 }
 
diff --git a/arch/mips/mti-sead3/sead3-net.c b/arch/mips/mti-sead3/sead3-net.c
index dd11e7e..c9f728a 100644
--- a/arch/mips/mti-sead3/sead3-net.c
+++ b/arch/mips/mti-sead3/sead3-net.c
@@ -10,6 +10,9 @@
 #include <linux/platform_device.h>
 #include <linux/smsc911x.h>
 
+#include <asm/gic.h>
+#include <asm/mips-boards/sead3int.h>
+
 static struct smsc911x_platform_config sead3_smsc911x_data = {
 	.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
 	.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
@@ -17,14 +20,13 @@ static struct smsc911x_platform_config sead3_smsc911x_data = {
 	.phy_interface = PHY_INTERFACE_MODE_MII,
 };
 
-struct resource sead3_net_resourcess[] = {
+struct resource sead3_net_resources[] = {
 	{
 		.start			= 0x1f010000,
 		.end			= 0x1f01ffff,
 		.flags			= IORESOURCE_MEM
 	},
 	{
-		.start			= MIPS_CPU_IRQ_BASE + 6,
 		.flags			= IORESOURCE_IRQ
 	}
 };
@@ -35,12 +37,16 @@ static struct platform_device sead3_net_device = {
 	.dev			= {
 		.platform_data	= &sead3_smsc911x_data,
 	},
-	.num_resources		= ARRAY_SIZE(sead3_net_resourcess),
-	.resource		= sead3_net_resourcess
+	.num_resources		= ARRAY_SIZE(sead3_net_resources),
+	.resource		= sead3_net_resources
 };
 
 static int __init sead3_net_init(void)
 {
+	if (gic_present)
+		sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET;
+	else
+		sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET;
 	return platform_device_register(&sead3_net_device);
 }
 
diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c
index 6c3b33d..d9661eb 100644
--- a/arch/mips/mti-sead3/sead3-platform.c
+++ b/arch/mips/mti-sead3/sead3-platform.c
@@ -9,10 +9,13 @@
 #include <linux/init.h>
 #include <linux/serial_8250.h>
 
-#define UART(base, int)							\
+#include <asm/gic.h>
+#include <asm/mips-boards/sead3int.h>
+
+#define UART(base)							\
 {									\
 	.mapbase	= base,						\
-	.irq		= int,						\
+	.irq		= -1,						\
 	.uartclk	= 14745600,					\
 	.iotype		= UPIO_MEM32,					\
 	.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \
@@ -20,8 +23,8 @@
 }
 
 static struct plat_serial8250_port uart8250_data[] = {
-	UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4),   /* ttyS0 = USB   */
-	UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4),   /* ttyS1 = RS232 */
+	UART(0x1f000900),   /* ttyS0 = USB   */
+	UART(0x1f000800),   /* ttyS1 = RS232 */
 	{ },
 };
 
@@ -35,6 +38,13 @@ static struct platform_device uart8250_device = {
 
 static int __init uart8250_init(void)
 {
+	if (gic_present) {
+		uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0;
+		uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1;
+	} else {
+		uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0;
+		uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1;
+	}
 	return platform_device_register(&uart8250_device);
 }
 
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index b4d87c4..094be83 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -8,6 +8,8 @@
  */
 #include <linux/bitmap.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/irq.h>
 #include <linux/clocksource.h>
@@ -22,11 +24,8 @@
 unsigned int gic_frequency;
 unsigned int gic_present;
 unsigned long _gic_base;
-unsigned int gic_irq_base;
 unsigned int gic_irq_flags[GIC_NUM_INTRS];
-
-/* The index into this array is the vector # of the interrupt. */
-struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
+unsigned int gic_cpu_pin;
 
 struct gic_pcpu_mask {
 	DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
@@ -45,6 +44,8 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
 static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static struct irq_domain *gic_irq_domain;
 
+static void __gic_irq_dispatch(void);
+
 #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
 cycle_t gic_read_count(void)
 {
@@ -116,21 +117,6 @@ void gic_send_ipi(unsigned int intr)
 	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
 }
 
-static void gic_eic_irq_dispatch(void)
-{
-	unsigned int cause = read_c0_cause();
-	int irq;
-
-	irq = (cause & ST0_IM) >> STATUSB_IP2;
-	if (irq == 0)
-		irq = -1;
-
-	if (irq >= 0)
-		do_IRQ(gic_irq_base + irq);
-	else
-		spurious_interrupt();
-}
-
 static void __init vpe_local_setup(unsigned int numvpes)
 {
 	unsigned long timer_intr = GIC_INT_TMR;
@@ -165,16 +151,15 @@ static void __init vpe_local_setup(unsigned int numvpes)
 				 GIC_MAP_TO_PIN_MSK | timer_intr);
 		if (cpu_has_veic) {
 			set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
-				gic_eic_irq_dispatch);
-			gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
+				       __gic_irq_dispatch);
 		}
 
 		if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
 			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
 				 GIC_MAP_TO_PIN_MSK | perf_intr);
 		if (cpu_has_veic) {
-			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
-			gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
+			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET,
+				       __gic_irq_dispatch);
 		}
 	}
 }
@@ -345,64 +330,100 @@ static struct irq_chip gic_irq_controller = {
 #endif
 };
 
-static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
-	unsigned int pin, unsigned int polarity, unsigned int trigtype,
-	unsigned int flags)
+static void __gic_irq_dispatch(void)
 {
-	struct gic_shared_intr_map *map_ptr;
-	int i;
-
-	/* Setup Intr to Pin mapping */
-	if (pin & GIC_MAP_TO_NMI_MSK) {
-		int i;
+	unsigned int intr, virq;
 
-		GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
-		/* FIXME: hack to route NMI to all cpu's */
-		for (i = 0; i < NR_CPUS; i += 32) {
-			GICWRITE(GIC_REG_ADDR(SHARED,
-					  GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)),
-				 0xffffffff);
-		}
-	} else {
-		GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
-			 GIC_MAP_TO_PIN_MSK | pin);
-		/* Setup Intr to CPU mapping */
-		GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
-		if (cpu_has_veic) {
-			set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
-				gic_eic_irq_dispatch);
-			map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
-			if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
-				BUG();
-			map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
-		}
+	while ((intr = gic_get_int()) != GIC_NUM_INTRS) {
+		virq = irq_linear_revmap(gic_irq_domain, intr);
+		do_IRQ(virq);
 	}
+}
 
-	/* Setup Intr Polarity */
-	GIC_SET_POLARITY(intr, polarity);
+static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)
+{
+	__gic_irq_dispatch();
+}
+
+#ifdef CONFIG_MIPS_GIC_IPI
+static int gic_resched_int_base;
+static int gic_call_int_base;
+
+unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
+{
+	return gic_resched_int_base + cpu;
+}
 
-	/* Setup Intr Trigger Type */
-	GIC_SET_TRIGGER(intr, trigtype);
+unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
+{
+	return gic_call_int_base + cpu;
+}
 
-	/* Init Intr Masks */
-	GIC_CLR_INTR_MASK(intr);
+static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
+{
+	scheduler_ipi();
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
+{
+	smp_call_function_interrupt();
+
+	return IRQ_HANDLED;
+}
 
-	/* Initialise per-cpu Interrupt software masks */
+static struct irqaction irq_resched = {
+	.handler	= ipi_resched_interrupt,
+	.flags		= IRQF_PERCPU,
+	.name		= "IPI resched"
+};
+
+static struct irqaction irq_call = {
+	.handler	= ipi_call_interrupt,
+	.flags		= IRQF_PERCPU,
+	.name		= "IPI call"
+};
+
+static __init void gic_ipi_init_one(unsigned int intr, int cpu,
+				    struct irqaction *action)
+{
+	int virq = irq_create_mapping(gic_irq_domain, intr);
+	int i;
+
+	GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
 	for (i = 0; i < NR_CPUS; i++)
 		clear_bit(intr, pcpu_masks[i].pcpu_mask);
 	set_bit(intr, pcpu_masks[cpu].pcpu_mask);
 
-	if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
-		GIC_SET_INTR_MASK(intr);
-	if (trigtype == GIC_TRIG_EDGE)
-		gic_irq_flags[intr] |= GIC_TRIG_EDGE;
+	irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+
+	irq_set_handler(virq, handle_percpu_irq);
+	setup_irq(virq, action);
 }
 
-static void __init gic_basic_init(int numintrs, int numvpes,
-			struct gic_intr_map *intrmap, int mapsize)
+static __init void gic_ipi_init(void)
 {
-	unsigned int i, cpu;
-	unsigned int pin_offset = 0;
+	int i;
+
+	/* Use last 2 * NR_CPUS interrupts as IPIs */
+	gic_resched_int_base = GIC_NUM_INTRS - nr_cpu_ids;
+	gic_call_int_base = gic_resched_int_base - nr_cpu_ids;
+
+	for (i = 0; i < nr_cpu_ids; i++) {
+		gic_ipi_init_one(gic_call_int_base + i, i, &irq_call);
+		gic_ipi_init_one(gic_resched_int_base + i, i, &irq_resched);
+	}
+}
+#else
+static inline void gic_ipi_init(void)
+{
+}
+#endif
+
+static void __init gic_basic_init(int numintrs, int numvpes)
+{
+	unsigned int i;
 
 	board_bind_eic_interrupt = &gic_bind_eic_interrupt;
 
@@ -411,31 +432,8 @@ static void __init gic_basic_init(int numintrs, int numvpes,
 		GIC_SET_POLARITY(i, GIC_POL_POS);
 		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
 		GIC_CLR_INTR_MASK(i);
-		if (i < GIC_NUM_INTRS) {
+		if (i < GIC_NUM_INTRS)
 			gic_irq_flags[i] = 0;
-			gic_shared_intr_map[i].num_shared_intr = 0;
-			gic_shared_intr_map[i].local_intr_mask = 0;
-		}
-	}
-
-	/*
-	 * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
-	 * one because the GIC will add one (since 0=no intr).
-	 */
-	if (cpu_has_veic)
-		pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-
-	/* Setup specifics */
-	for (i = 0; i < mapsize; i++) {
-		cpu = intrmap[i].cpunum;
-		if (cpu == GIC_UNUSED)
-			continue;
-		gic_setup_intr(i,
-			intrmap[i].cpunum,
-			intrmap[i].pin + pin_offset,
-			intrmap[i].polarity,
-			intrmap[i].trigtype,
-			intrmap[i].flags);
 	}
 
 	vpe_local_setup(numvpes);
@@ -447,7 +445,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
 	irq_set_chip_and_handler(virq, &gic_irq_controller, handle_level_irq);
 
 	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
-		 GIC_MAP_TO_PIN_MSK | 0);
+		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
 	/* Map to VPE 0 by default */
 	GIC_SH_MAP_TO_VPE_SMASK(hw, 0);
 	set_bit(hw, pcpu_masks[0].pcpu_mask);
@@ -461,8 +459,7 @@ static struct irq_domain_ops gic_irq_domain_ops = {
 };
 
 void __init gic_init(unsigned long gic_base_addr,
-		     unsigned long gic_addrspace_size,
-		     struct gic_intr_map *intr_map, unsigned int intr_map_size,
+		     unsigned long gic_addrspace_size, unsigned int cpu_vec,
 		     unsigned int irqbase)
 {
 	unsigned int gicconfig;
@@ -470,7 +467,6 @@ void __init gic_init(unsigned long gic_base_addr,
 
 	_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
 						    gic_addrspace_size);
-	gic_irq_base = irqbase;
 
 	GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
 	numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
@@ -481,10 +477,23 @@ void __init gic_init(unsigned long gic_base_addr,
 		  GIC_SH_CONFIG_NUMVPES_SHF;
 	numvpes = numvpes + 1;
 
+	if (cpu_has_veic) {
+		/* Always use vector 1 in EIC mode */
+		gic_cpu_pin = 0;
+		set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
+			       __gic_irq_dispatch);
+	} else {
+		gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
+		irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
+					gic_irq_dispatch);
+	}
+
 	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase,
 					       &gic_irq_domain_ops, NULL);
 	if (!gic_irq_domain)
 		panic("Failed to add GIC IRQ domain");
 
-	gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
+	gic_basic_init(numintrs, numvpes);
+
+	gic_ipi_init();
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 19/24] irqchip: mips-gic: Probe for number of external interrupts
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (17 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips Andrew Bresticker
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Instead of requiring platforms to define the correct GIC_NUM_INTRS,
use the value reported in GIC_SH_CONFIG.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h            |  2 ++
 arch/mips/include/asm/mach-malta/irq.h |  1 -
 arch/mips/include/asm/mach-sead3/irq.h |  1 -
 drivers/irqchip/irq-mips-gic.c         | 40 +++++++++++++++++-----------------
 4 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index cfbf907..8d1e457 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -18,6 +18,8 @@
 
 #undef	GICISBYTELITTLEENDIAN
 
+#define GIC_MAX_INTRS			256
+
 /* Constants */
 #define GIC_POL_POS			1
 #define GIC_POL_NEG			0
diff --git a/arch/mips/include/asm/mach-malta/irq.h b/arch/mips/include/asm/mach-malta/irq.h
index f2c13d2..47cfe64 100644
--- a/arch/mips/include/asm/mach-malta/irq.h
+++ b/arch/mips/include/asm/mach-malta/irq.h
@@ -2,7 +2,6 @@
 #define __ASM_MACH_MIPS_IRQ_H
 
 
-#define GIC_NUM_INTRS (24 + NR_CPUS * 2)
 #define NR_IRQS 256
 
 #include_next <irq.h>
diff --git a/arch/mips/include/asm/mach-sead3/irq.h b/arch/mips/include/asm/mach-sead3/irq.h
index d8106f7..5d154cf 100644
--- a/arch/mips/include/asm/mach-sead3/irq.h
+++ b/arch/mips/include/asm/mach-sead3/irq.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_MACH_MIPS_IRQ_H
 #define __ASM_MACH_MIPS_IRQ_H
 
-#define GIC_NUM_INTRS (24 + NR_CPUS * 2)
 #define NR_IRQS 256
 
 
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 094be83..c9ba102 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -28,21 +28,22 @@ unsigned int gic_irq_flags[GIC_NUM_INTRS];
 unsigned int gic_cpu_pin;
 
 struct gic_pcpu_mask {
-	DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
+	DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
 };
 
 struct gic_pending_regs {
-	DECLARE_BITMAP(pending, GIC_NUM_INTRS);
+	DECLARE_BITMAP(pending, GIC_MAX_INTRS);
 };
 
 struct gic_intrmask_regs {
-	DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
+	DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
 };
 
 static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
 static struct gic_pending_regs pending_regs[NR_CPUS];
 static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static struct irq_domain *gic_irq_domain;
+static int gic_shared_intrs;
 
 static void __gic_irq_dispatch(void);
 
@@ -191,26 +192,26 @@ void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
 	intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
 							  GIC_SH_MASK_31_0_OFS);
 
-	for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
+	for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) {
 		GICREAD(*pending_abs, pending[i]);
 		GICREAD(*intrmask_abs, intrmask[i]);
 		pending_abs++;
 		intrmask_abs++;
 	}
 
-	bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
-	bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
-	bitmap_and(dst, src, pending, GIC_NUM_INTRS);
+	bitmap_and(pending, pending, intrmask, gic_shared_intrs);
+	bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
+	bitmap_and(dst, src, pending, gic_shared_intrs);
 }
 
 unsigned int gic_get_int(void)
 {
-	DECLARE_BITMAP(interrupts, GIC_NUM_INTRS);
+	DECLARE_BITMAP(interrupts, GIC_MAX_INTRS);
 
-	bitmap_fill(interrupts, GIC_NUM_INTRS);
+	bitmap_fill(interrupts, gic_shared_intrs);
 	gic_get_int_mask(interrupts, interrupts);
 
-	return find_first_bit(interrupts, GIC_NUM_INTRS);
+	return find_first_bit(interrupts, gic_shared_intrs);
 }
 
 static void gic_mask_irq(struct irq_data *d)
@@ -334,7 +335,7 @@ static void __gic_irq_dispatch(void)
 {
 	unsigned int intr, virq;
 
-	while ((intr = gic_get_int()) != GIC_NUM_INTRS) {
+	while ((intr = gic_get_int()) != gic_shared_intrs) {
 		virq = irq_linear_revmap(gic_irq_domain, intr);
 		do_IRQ(virq);
 	}
@@ -407,7 +408,7 @@ static __init void gic_ipi_init(void)
 	int i;
 
 	/* Use last 2 * NR_CPUS interrupts as IPIs */
-	gic_resched_int_base = GIC_NUM_INTRS - nr_cpu_ids;
+	gic_resched_int_base = gic_shared_intrs - nr_cpu_ids;
 	gic_call_int_base = gic_resched_int_base - nr_cpu_ids;
 
 	for (i = 0; i < nr_cpu_ids; i++) {
@@ -421,19 +422,18 @@ static inline void gic_ipi_init(void)
 }
 #endif
 
-static void __init gic_basic_init(int numintrs, int numvpes)
+static void __init gic_basic_init(int numvpes)
 {
 	unsigned int i;
 
 	board_bind_eic_interrupt = &gic_bind_eic_interrupt;
 
 	/* Setup defaults */
-	for (i = 0; i < numintrs; i++) {
+	for (i = 0; i < gic_shared_intrs; i++) {
 		GIC_SET_POLARITY(i, GIC_POL_POS);
 		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
 		GIC_CLR_INTR_MASK(i);
-		if (i < GIC_NUM_INTRS)
-			gic_irq_flags[i] = 0;
+		gic_irq_flags[i] = 0;
 	}
 
 	vpe_local_setup(numvpes);
@@ -469,9 +469,9 @@ void __init gic_init(unsigned long gic_base_addr,
 						    gic_addrspace_size);
 
 	GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-	numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
+	gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
 		   GIC_SH_CONFIG_NUMINTRS_SHF;
-	numintrs = ((numintrs + 1) * 8);
+	gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
 
 	numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
 		  GIC_SH_CONFIG_NUMVPES_SHF;
@@ -488,12 +488,12 @@ void __init gic_init(unsigned long gic_base_addr,
 					gic_irq_dispatch);
 	}
 
-	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase,
+	gic_irq_domain = irq_domain_add_simple(NULL, gic_shared_intrs, irqbase,
 					       &gic_irq_domain_ops, NULL);
 	if (!gic_irq_domain)
 		panic("Failed to add GIC IRQ domain");
 
-	gic_basic_init(numintrs, numvpes);
+	gic_basic_init(numvpes);
 
 	gic_ipi_init();
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (18 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 19/24] irqchip: mips-gic: Probe for number of external interrupts Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17  9:24   ` Qais Yousef
  2014-09-15 23:51 ` [PATCH 21/24] irqchip: mips-gic: Support local interrupts Andrew Bresticker
                   ` (5 subsequent siblings)
  25 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

GIC edge-triggered interrupts must be acknowledged by clearing the edge
detector via a write to GIC_SH_WEDGE.  Create a separate edge-triggered
irq_chip with the appropriate irq_ack() callback.  This also allows us
to get rid of gic_irq_flags.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h    |  1 -
 drivers/irqchip/irq-mips-gic.c | 38 ++++++++++++++++++++++++--------------
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 8d1e457..f245395 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -345,7 +345,6 @@
 extern unsigned int gic_present;
 extern unsigned int gic_frequency;
 extern unsigned long _gic_base;
-extern unsigned int gic_irq_flags[];
 extern unsigned int gic_cpu_pin;
 
 extern void gic_init(unsigned long gic_base_addr,
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index c9ba102..6682a4e 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -24,7 +24,6 @@
 unsigned int gic_frequency;
 unsigned int gic_present;
 unsigned long _gic_base;
-unsigned int gic_irq_flags[GIC_NUM_INTRS];
 unsigned int gic_cpu_pin;
 
 struct gic_pcpu_mask {
@@ -44,6 +43,7 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
 static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static struct irq_domain *gic_irq_domain;
 static int gic_shared_intrs;
+static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
 
 static void __gic_irq_dispatch(void);
 
@@ -228,11 +228,7 @@ static void gic_ack_irq(struct irq_data *d)
 {
 	unsigned int irq = d->hwirq;
 
-	GIC_CLR_INTR_MASK(irq);
-
-	/* Clear edge detector */
-	if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
-		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
+	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -275,11 +271,13 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 	}
 
 	if (is_edge) {
-		gic_irq_flags[irq] |= GIC_TRIG_EDGE;
-		__irq_set_handler_locked(d->irq, handle_edge_irq);
+		__irq_set_chip_handler_name_locked(d->irq,
+						   &gic_edge_irq_controller,
+						   handle_edge_irq, NULL);
 	} else {
-		gic_irq_flags[irq] &= ~GIC_TRIG_EDGE;
-		__irq_set_handler_locked(d->irq, handle_level_irq);
+		__irq_set_chip_handler_name_locked(d->irq,
+						   &gic_level_irq_controller,
+						   handle_level_irq, NULL);
 	}
 
 	return 0;
@@ -318,11 +316,23 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 }
 #endif
 
-static struct irq_chip gic_irq_controller = {
+static struct irq_chip gic_level_irq_controller = {
+	.name			=	"MIPS GIC",
+	.irq_ack		=	gic_mask_irq,
+	.irq_mask		=	gic_mask_irq,
+	.irq_mask_ack		=	gic_mask_irq,
+	.irq_unmask		=	gic_unmask_irq,
+	.irq_eoi		=	gic_unmask_irq,
+	.irq_set_type		=	gic_set_type,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	=	gic_set_affinity,
+#endif
+};
+
+static struct irq_chip gic_edge_irq_controller = {
 	.name			=	"MIPS GIC",
 	.irq_ack		=	gic_ack_irq,
 	.irq_mask		=	gic_mask_irq,
-	.irq_mask_ack		=	gic_ack_irq,
 	.irq_unmask		=	gic_unmask_irq,
 	.irq_eoi		=	gic_unmask_irq,
 	.irq_set_type		=	gic_set_type,
@@ -433,7 +443,6 @@ static void __init gic_basic_init(int numvpes)
 		GIC_SET_POLARITY(i, GIC_POL_POS);
 		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
 		GIC_CLR_INTR_MASK(i);
-		gic_irq_flags[i] = 0;
 	}
 
 	vpe_local_setup(numvpes);
@@ -442,7 +451,8 @@ static void __init gic_basic_init(int numvpes)
 static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
 			      irq_hw_number_t hw)
 {
-	irq_set_chip_and_handler(virq, &gic_irq_controller, handle_level_irq);
+	irq_set_chip_and_handler(virq, &gic_level_irq_controller,
+				 handle_level_irq);
 
 	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
 		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 21/24] irqchip: mips-gic: Support local interrupts
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (19 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17  9:50   ` Qais Yousef
  2014-09-15 23:51 ` [PATCH 22/24] irqchip: mips-gic: Remove unnecessary globals Andrew Bresticker
                   ` (4 subsequent siblings)
  25 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The MIPS GIC supports 7 local interrupts, 2 of which are the GIC
local watchdog and count/compare timer.  The remainder are CPU
interrupts which may optionally be re-routed through the GIC.
GIC hardware IRQs 0-6 are now used for local interrupts while
hardware IRQs 7+ are used for external (shared) interrupts.

Note that the 5 CPU interrupts may not be re-routable through
the GIC.  In that case mapping will fail and the vectors reported
in C0_IntCtl should be used instead.  gic_get_c0_compare_int() and
gic_get_c0_perfcount_int() will return the correct IRQ number to
use for the C0 timer and perfcounter interrupts based on the
routability of those interrupts through the GIC.

Malta, SEAD-3, and the GIC clockevent driver have been updated
to use local interrupts and the R4K clockevent driver has been
updated to poll for C0 timer interrupts through the GIC when
the GIC is present.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h                  |  29 +++-
 arch/mips/include/asm/mips-boards/maltaint.h |   4 +-
 arch/mips/include/asm/mips-boards/sead3int.h |  10 +-
 arch/mips/kernel/cevt-gic.c                  |  15 +-
 arch/mips/kernel/cevt-r4k.c                  |   2 +-
 arch/mips/mti-malta/malta-int.c              |   6 +-
 arch/mips/mti-malta/malta-time.c             |  13 +-
 arch/mips/mti-sead3/sead3-time.c             |  34 +---
 drivers/irqchip/irq-mips-gic.c               | 244 +++++++++++++++++++--------
 9 files changed, 232 insertions(+), 125 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index f245395..6b99610 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -209,6 +209,7 @@
 #define GIC_VPE_WD_MAP_OFS		0x0040
 #define GIC_VPE_COMPARE_MAP_OFS		0x0044
 #define GIC_VPE_TIMER_MAP_OFS		0x0048
+#define GIC_VPE_FDC_MAP_OFS		0x004c
 #define GIC_VPE_PERFCTR_MAP_OFS		0x0050
 #define GIC_VPE_SWINT0_MAP_OFS		0x0054
 #define GIC_VPE_SWINT1_MAP_OFS		0x0058
@@ -262,6 +263,10 @@
 #define GIC_MAP_MSK			(MSK(6) << GIC_MAP_SHF)
 
 /* GIC_VPE_CTL Masks */
+#define GIC_VPE_CTL_FDC_RTBL_SHF	4
+#define GIC_VPE_CTL_FDC_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_FDC_RTBL_SHF)
+#define GIC_VPE_CTL_SWINT_RTBL_SHF	3
+#define GIC_VPE_CTL_SWINT_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_SWINT_RTBL_SHF)
 #define GIC_VPE_CTL_PERFCNT_RTBL_SHF	2
 #define GIC_VPE_CTL_PERFCNT_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF)
 #define GIC_VPE_CTL_TIMER_RTBL_SHF	1
@@ -329,16 +334,30 @@
 /* Add 2 to convert GIC CPU pin to core interrupt */
 #define GIC_CPU_PIN_OFFSET	2
 
-/* Local GIC interrupts. */
-#define GIC_INT_TMR		(GIC_CPU_INT5)
-#define GIC_INT_PERFCTR		(GIC_CPU_INT5)
-
 /* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */
 #define GIC_CPU_TO_VEC_OFFSET	(2)
 
 /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
 #define GIC_PIN_TO_VEC_OFFSET	(1)
 
+/* Local GIC interrupts. */
+#define GIC_LOCAL_INT_WD	0 /* GIC watchdog */
+#define GIC_LOCAL_INT_COMPARE	1 /* GIC count and compare timer */
+#define GIC_LOCAL_INT_TIMER	2 /* CPU timer interrupt */
+#define GIC_LOCAL_INT_PERFCTR	3 /* CPU performance counter */
+#define GIC_LOCAL_INT_SWINT0	4 /* CPU software interrupt 0 */
+#define GIC_LOCAL_INT_SWINT1	5 /* CPU software interrupt 1 */
+#define GIC_LOCAL_INT_FDC	6 /* CPU fast debug channel */
+#define GIC_NUM_LOCAL_INTRS	7
+
+/* Convert between local/shared IRQ number and GIC HW IRQ number. */
+#define GIC_LOCAL_HWIRQ_BASE	0
+#define GIC_LOCAL_TO_HWIRQ(x)	(GIC_LOCAL_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_LOCAL(x)	((x) - GIC_LOCAL_HWIRQ_BASE)
+#define GIC_SHARED_HWIRQ_BASE	GIC_NUM_LOCAL_INTRS
+#define GIC_SHARED_TO_HWIRQ(x)	(GIC_SHARED_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_SHARED(x)	((x) - GIC_SHARED_HWIRQ_BASE)
+
 #include <linux/clocksource.h>
 #include <linux/irq.h>
 
@@ -363,4 +382,6 @@ extern void gic_bind_eic_interrupt(int irq, int set);
 extern unsigned int gic_get_timer_pending(void);
 extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
 extern unsigned int gic_get_int(void);
+extern int gic_get_c0_compare_int(void);
+extern int gic_get_c0_perfcount_int(void);
 #endif /* _ASM_GICREGS_H */
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index bdd6f39..38b06a0 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -10,6 +10,8 @@
 #ifndef _MIPS_MALTAINT_H
 #define _MIPS_MALTAINT_H
 
+#include <asm/gic.h>
+
 /*
  * Interrupts 0..15 are used for Malta ISA compatible interrupts
  */
@@ -61,6 +63,6 @@
 #define MSC01E_INT_CPUCTR	11
 
 /* GIC external interrupts */
-#define GIC_INT_I8259A		3
+#define GIC_INT_I8259A		GIC_SHARED_TO_HWIRQ(3)
 
 #endif /* !(_MIPS_MALTAINT_H) */
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index a2e0095..59d6c32 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -10,6 +10,8 @@
 #ifndef _MIPS_SEAD3INT_H
 #define _MIPS_SEAD3INT_H
 
+#include <asm/gic.h>
+
 /* SEAD-3 GIC address space definitions. */
 #define GIC_BASE_ADDR		0x1b1c0000
 #define GIC_ADDRSPACE_SZ	(128 * 1024)
@@ -22,9 +24,9 @@
 #define CPU_INT_NET		6
 
 /* GIC interrupt offsets */
-#define GIC_INT_NET		0
-#define GIC_INT_UART1		2
-#define GIC_INT_UART0		3
-#define GIC_INT_EHCI		5
+#define GIC_INT_NET		GIC_SHARED_TO_HWIRQ(0)
+#define GIC_INT_UART1		GIC_SHARED_TO_HWIRQ(2)
+#define GIC_INT_UART0		GIC_SHARED_TO_HWIRQ(3)
+#define GIC_INT_EHCI		GIC_SHARED_TO_HWIRQ(5)
 
 #endif /* !(_MIPS_SEAD3INT_H) */
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
index a90bd4c..4f9262a 100644
--- a/arch/mips/kernel/cevt-gic.c
+++ b/arch/mips/kernel/cevt-gic.c
@@ -68,7 +68,7 @@ int gic_clockevent_init(void)
 	if (!cpu_has_counter || !gic_frequency)
 		return -ENXIO;
 
-	irq = MIPS_GIC_IRQ_BASE;
+	irq = MIPS_GIC_IRQ_BASE + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE);
 
 	cd = &per_cpu(gic_clockevent_device, cpu);
 
@@ -91,16 +91,13 @@ int gic_clockevent_init(void)
 
 	clockevents_register_device(cd);
 
-	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP),
-		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
-	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
+	if (!gic_timer_irq_installed) {
+		setup_percpu_irq(irq, &gic_compare_irqaction);
+		gic_timer_irq_installed = 1;
+	}
 
-	if (gic_timer_irq_installed)
-		return 0;
+	enable_percpu_irq(irq, IRQ_TYPE_NONE);
 
-	gic_timer_irq_installed = 1;
 
-	setup_irq(irq, &gic_compare_irqaction);
-	irq_set_handler(irq, handle_percpu_irq);
 	return 0;
 }
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 5b8f8e3..fd0ef8d 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -86,7 +86,7 @@ void mips_event_handler(struct clock_event_device *dev)
 static int c0_compare_int_pending(void)
 {
 #ifdef CONFIG_MIPS_GIC
-	if (cpu_has_veic)
+	if (gic_present)
 		return gic_get_timer_pending();
 #endif
 	return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 3b3bc1d..c6b3548 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -273,11 +273,7 @@ asmlinkage void plat_irq_dispatch(void)
 
 	irq = irq_ffs(pending);
 
-	/* HACK: GIC doesn't properly dispatch local interrupts yet */
-	if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int())
-		do_IRQ(MIPS_GIC_IRQ_BASE);
-	else
-		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+	do_IRQ(MIPS_CPU_IRQ_BASE + irq);
 }
 
 #ifdef CONFIG_MIPS_MT_SMP
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index 17cfc8a..f6ca8ea 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -126,9 +126,9 @@ int get_c0_perfcount_int(void)
 	if (cpu_has_veic) {
 		set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
 		mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
+	} else if (gic_present) {
+		mips_cpu_perf_irq = gic_get_c0_perfcount_int();
 	} else if (cp0_perfcount_irq >= 0) {
-		if (cpu_has_vint)
-			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
 		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
 	} else {
 		mips_cpu_perf_irq = -1;
@@ -139,15 +139,12 @@ int get_c0_perfcount_int(void)
 
 unsigned int get_c0_compare_int(void)
 {
-#ifdef MSC01E_INT_BASE
 	if (cpu_has_veic) {
 		set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
 		mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
-	} else
-#endif
-	{
-		if (cpu_has_vint)
-			set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
+	} else if (gic_present) {
+		mips_cpu_timer_irq = gic_get_c0_compare_int();
+	} else {
 		mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
 	}
 
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c
index f090c51..fd40de3 100644
--- a/arch/mips/mti-sead3/sead3-time.c
+++ b/arch/mips/mti-sead3/sead3-time.c
@@ -8,24 +8,12 @@
 #include <linux/init.h>
 
 #include <asm/cpu.h>
+#include <asm/gic.h>
 #include <asm/setup.h>
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/mips-boards/generic.h>
 
-static int mips_cpu_timer_irq;
-static int mips_cpu_perf_irq;
-
-static void mips_timer_dispatch(void)
-{
-	do_IRQ(mips_cpu_timer_irq);
-}
-
-static void mips_perf_dispatch(void)
-{
-	do_IRQ(mips_cpu_perf_irq);
-}
-
 static void __iomem *status_reg = (void __iomem *)0xbf000410;
 
 /*
@@ -83,22 +71,18 @@ void read_persistent_clock(struct timespec *ts)
 
 int get_c0_perfcount_int(void)
 {
-	if (cp0_perfcount_irq >= 0) {
-		if (cpu_has_vint)
-			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
-		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
-	} else {
-		mips_cpu_perf_irq = -1;
-	}
-	return mips_cpu_perf_irq;
+	if (gic_present)
+		return gic_get_c0_compare_int();
+	if (cp0_perfcount_irq >= 0)
+		return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+	return -1;
 }
 
 unsigned int get_c0_compare_int(void)
 {
-	if (cpu_has_vint)
-		set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
-	mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
-	return mips_cpu_timer_irq;
+	if (gic_present)
+		return gic_get_c0_compare_int();
+	return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
 }
 
 void __init plat_time_init(void)
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 6682a4e..3abe310 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -43,6 +43,7 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
 static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static struct irq_domain *gic_irq_domain;
 static int gic_shared_intrs;
+static int gic_vpes;
 static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
 
 static void __gic_irq_dispatch(void);
@@ -95,12 +96,39 @@ cycle_t gic_read_compare(void)
 }
 #endif
 
+static bool gic_local_irq_is_routable(int intr)
+{
+	u32 vpe_ctl;
+
+	/* All local interrupts are routable in EIC mode. */
+	if (cpu_has_veic)
+		return true;
+
+	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
+	switch (intr) {
+	case GIC_LOCAL_INT_TIMER:
+		return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
+	case GIC_LOCAL_INT_PERFCTR:
+		return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
+	case GIC_LOCAL_INT_FDC:
+		return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
+	case GIC_LOCAL_INT_SWINT0:
+	case GIC_LOCAL_INT_SWINT1:
+		/*
+		 * SWINT{0,1} are not routable in non-EIC mode, regardless
+		 * of the setting of SWINT_ROUTABLE.
+		 */
+		return false;
+	default:
+		return true;
+	}
+}
+
 unsigned int gic_get_timer_pending(void)
 {
 	unsigned int vpe_pending;
 
-	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
-	GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
+	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), vpe_pending);
 	return (vpe_pending & GIC_VPE_PEND_TIMER_MSK);
 }
 
@@ -118,53 +146,6 @@ void gic_send_ipi(unsigned int intr)
 	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
 }
 
-static void __init vpe_local_setup(unsigned int numvpes)
-{
-	unsigned long timer_intr = GIC_INT_TMR;
-	unsigned long perf_intr = GIC_INT_PERFCTR;
-	unsigned int vpe_ctl;
-	int i;
-
-	if (cpu_has_veic) {
-		/*
-		 * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
-		 * map to pin X+2-1 (since GIC adds 1)
-		 */
-		timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-		/*
-		 * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
-		 * map to pin X+2-1 (since GIC adds 1)
-		 */
-		perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-	}
-
-	/*
-	 * Setup the default performance counter timer interrupts
-	 * for all VPEs
-	 */
-	for (i = 0; i < numvpes; i++) {
-		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
-
-		/* Are Interrupts locally routable? */
-		GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
-		if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
-			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
-				 GIC_MAP_TO_PIN_MSK | timer_intr);
-		if (cpu_has_veic) {
-			set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
-				       __gic_irq_dispatch);
-		}
-
-		if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
-			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
-				 GIC_MAP_TO_PIN_MSK | perf_intr);
-		if (cpu_has_veic) {
-			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET,
-				       __gic_irq_dispatch);
-		}
-	}
-}
-
 unsigned int gic_compare_int(void)
 {
 	unsigned int pending;
@@ -176,6 +157,26 @@ unsigned int gic_compare_int(void)
 		return 0;
 }
 
+int gic_get_c0_compare_int(void)
+{
+	if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
+		return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
+	return irq_create_mapping(gic_irq_domain,
+				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER));
+}
+
+int gic_get_c0_perfcount_int(void)
+{
+	if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) {
+		/* Is the erformance counter shared with the timer? */
+		if (cp0_perfcount_irq < 0)
+			return -1;
+		return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+	}
+	return irq_create_mapping(gic_irq_domain,
+				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
+}
+
 void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
 {
 	unsigned int i;
@@ -216,24 +217,24 @@ unsigned int gic_get_int(void)
 
 static void gic_mask_irq(struct irq_data *d)
 {
-	GIC_CLR_INTR_MASK(d->hwirq);
+	GIC_CLR_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-	GIC_SET_INTR_MASK(d->hwirq);
+	GIC_SET_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
 }
 
 static void gic_ack_irq(struct irq_data *d)
 {
-	unsigned int irq = d->hwirq;
+	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 
 	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
-	unsigned int irq = d->hwirq;
+	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 	bool is_edge;
 
 	switch (type & IRQ_TYPE_SENSE_MASK) {
@@ -289,7 +290,7 @@ static DEFINE_SPINLOCK(gic_lock);
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 			    bool force)
 {
-	unsigned int irq = d->hwirq;
+	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 	cpumask_t	tmp = CPU_MASK_NONE;
 	unsigned long	flags;
 	int		i;
@@ -341,12 +342,54 @@ static struct irq_chip gic_edge_irq_controller = {
 #endif
 };
 
+static unsigned int gic_get_local_int(void)
+{
+	unsigned long pending, masked;
+
+	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
+	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked);
+
+	bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
+
+	return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+}
+
+static void gic_mask_local_irq(struct irq_data *d)
+{
+	int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+
+	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
+}
+
+static void gic_unmask_local_irq(struct irq_data *d)
+{
+	int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+
+	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
+}
+
+static struct irq_chip gic_local_irq_controller = {
+	.name			=	"MIPS GIC Local",
+	.irq_ack		=	gic_mask_local_irq,
+	.irq_mask		=	gic_mask_local_irq,
+	.irq_mask_ack		=	gic_mask_local_irq,
+	.irq_unmask		=	gic_unmask_local_irq,
+	.irq_eoi		=	gic_unmask_local_irq,
+};
+
 static void __gic_irq_dispatch(void)
 {
 	unsigned int intr, virq;
 
+	while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
+		virq = irq_linear_revmap(gic_irq_domain,
+					 GIC_LOCAL_TO_HWIRQ(intr));
+		do_IRQ(virq);
+	}
+
 	while ((intr = gic_get_int()) != gic_shared_intrs) {
-		virq = irq_linear_revmap(gic_irq_domain, intr);
+		virq = irq_linear_revmap(gic_irq_domain,
+					 GIC_SHARED_TO_HWIRQ(intr));
 		do_IRQ(virq);
 	}
 }
@@ -399,7 +442,8 @@ static struct irqaction irq_call = {
 static __init void gic_ipi_init_one(unsigned int intr, int cpu,
 				    struct irqaction *action)
 {
-	int virq = irq_create_mapping(gic_irq_domain, intr);
+	int virq = irq_create_mapping(gic_irq_domain,
+				      GIC_SHARED_TO_HWIRQ(intr));
 	int i;
 
 	GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
@@ -432,7 +476,7 @@ static inline void gic_ipi_init(void)
 }
 #endif
 
-static void __init gic_basic_init(int numvpes)
+static void __init gic_basic_init(void)
 {
 	unsigned int i;
 
@@ -444,25 +488,89 @@ static void __init gic_basic_init(int numvpes)
 		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
 		GIC_CLR_INTR_MASK(i);
 	}
+}
+
+static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
+				    irq_hw_number_t hw)
+{
+	int intr = GIC_HWIRQ_TO_LOCAL(hw);
+	int i;
+
+	if (!gic_local_irq_is_routable(intr))
+		return -EPERM;
 
-	vpe_local_setup(numvpes);
+	irq_set_chip_and_handler(virq, &gic_local_irq_controller,
+				 handle_percpu_irq);
+
+	/*
+	 * HACK: These are all really percpu interrupts, but the rest
+	 * of the MIPS kernel code does not use the percpu IRQ API for
+	 * the CP0 timer and performance counter interrupts.
+	 */
+	if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR)
+		irq_set_percpu_devid(virq);
+
+	for (i = 0; i < gic_vpes; i++) {
+		u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
+
+		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+
+		switch (intr) {
+		case GIC_LOCAL_INT_WD:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
+			break;
+		case GIC_LOCAL_INT_COMPARE:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
+			break;
+		case GIC_LOCAL_INT_TIMER:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
+			break;
+		case GIC_LOCAL_INT_PERFCTR:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val);
+			break;
+		case GIC_LOCAL_INT_SWINT0:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val);
+			break;
+		case GIC_LOCAL_INT_SWINT1:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val);
+			break;
+		case GIC_LOCAL_INT_FDC:
+			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
+			break;
+		default:
+			pr_err("Invalid local IRQ %d\n", intr);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
 }
 
-static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
-			      irq_hw_number_t hw)
+static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
+				     irq_hw_number_t hw)
 {
+	int intr = GIC_HWIRQ_TO_SHARED(hw);
+
 	irq_set_chip_and_handler(virq, &gic_level_irq_controller,
 				 handle_level_irq);
 
-	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
+	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
 		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
 	/* Map to VPE 0 by default */
-	GIC_SH_MAP_TO_VPE_SMASK(hw, 0);
-	set_bit(hw, pcpu_masks[0].pcpu_mask);
+	GIC_SH_MAP_TO_VPE_SMASK(intr, 0);
+	set_bit(intr, pcpu_masks[0].pcpu_mask);
 
 	return 0;
 }
 
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
+			      irq_hw_number_t hw)
+{
+	if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS)
+		return gic_local_irq_domain_map(d, virq, hw);
+	return gic_shared_irq_domain_map(d, virq, hw);
+}
+
 static struct irq_domain_ops gic_irq_domain_ops = {
 	.map = gic_irq_domain_map,
 	.xlate = irq_domain_xlate_twocell,
@@ -473,7 +581,6 @@ void __init gic_init(unsigned long gic_base_addr,
 		     unsigned int irqbase)
 {
 	unsigned int gicconfig;
-	int numvpes, numintrs;
 
 	_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
 						    gic_addrspace_size);
@@ -483,9 +590,9 @@ void __init gic_init(unsigned long gic_base_addr,
 		   GIC_SH_CONFIG_NUMINTRS_SHF;
 	gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
 
-	numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
+	gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
 		  GIC_SH_CONFIG_NUMVPES_SHF;
-	numvpes = numvpes + 1;
+	gic_vpes = gic_vpes + 1;
 
 	if (cpu_has_veic) {
 		/* Always use vector 1 in EIC mode */
@@ -498,12 +605,13 @@ void __init gic_init(unsigned long gic_base_addr,
 					gic_irq_dispatch);
 	}
 
-	gic_irq_domain = irq_domain_add_simple(NULL, gic_shared_intrs, irqbase,
+	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS +
+					       gic_shared_intrs, irqbase,
 					       &gic_irq_domain_ops, NULL);
 	if (!gic_irq_domain)
 		panic("Failed to add GIC IRQ domain");
 
-	gic_basic_init(numvpes);
+	gic_basic_init();
 
 	gic_ipi_init();
 }
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 22/24] irqchip: mips-gic: Remove unnecessary globals
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (20 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 21/24] irqchip: mips-gic: Support local interrupts Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 23/24] MIPS: Malta: Use generic plat_irq_dispatch Andrew Bresticker
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Now that all GIC interrupt routing and handling logic is in the GIC
driver itself, un-export variables/functions which are no longer used
outside the GIC driver.  This also allows us to remove gic_compare_int
and combine gic_get_int_mask with gic_get_int since these interfaces
are no longer used.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/include/asm/gic.h    |  5 -----
 drivers/irqchip/irq-mips-gic.c | 28 ++++------------------------
 2 files changed, 4 insertions(+), 29 deletions(-)

diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 6b99610..727b7bf 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -364,13 +364,11 @@
 extern unsigned int gic_present;
 extern unsigned int gic_frequency;
 extern unsigned long _gic_base;
-extern unsigned int gic_cpu_pin;
 
 extern void gic_init(unsigned long gic_base_addr,
 	unsigned long gic_addrspace_size, unsigned int cpu_vec,
 	unsigned int irqbase);
 extern void gic_clocksource_init(unsigned int);
-extern unsigned int gic_compare_int (void);
 extern cycle_t gic_read_count(void);
 extern cycle_t gic_read_compare(void);
 extern void gic_write_compare(cycle_t cnt);
@@ -378,10 +376,7 @@ extern void gic_write_cpu_compare(cycle_t cnt, int cpu);
 extern void gic_send_ipi(unsigned int intr);
 extern unsigned int plat_ipi_call_int_xlate(unsigned int);
 extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
-extern void gic_bind_eic_interrupt(int irq, int set);
 extern unsigned int gic_get_timer_pending(void);
-extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
-extern unsigned int gic_get_int(void);
 extern int gic_get_c0_compare_int(void);
 extern int gic_get_c0_perfcount_int(void);
 #endif /* _ASM_GICREGS_H */
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 3abe310..845affb 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -24,7 +24,6 @@
 unsigned int gic_frequency;
 unsigned int gic_present;
 unsigned long _gic_base;
-unsigned int gic_cpu_pin;
 
 struct gic_pcpu_mask {
 	DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
@@ -44,6 +43,7 @@ static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static struct irq_domain *gic_irq_domain;
 static int gic_shared_intrs;
 static int gic_vpes;
+static unsigned int gic_cpu_pin;
 static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
 
 static void __gic_irq_dispatch(void);
@@ -132,7 +132,7 @@ unsigned int gic_get_timer_pending(void)
 	return (vpe_pending & GIC_VPE_PEND_TIMER_MSK);
 }
 
-void gic_bind_eic_interrupt(int irq, int set)
+static void gic_bind_eic_interrupt(int irq, int set)
 {
 	/* Convert irq vector # to hw int # */
 	irq -= GIC_PIN_TO_VEC_OFFSET;
@@ -146,17 +146,6 @@ void gic_send_ipi(unsigned int intr)
 	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
 }
 
-unsigned int gic_compare_int(void)
-{
-	unsigned int pending;
-
-	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
-	if (pending & GIC_VPE_PEND_CMP_MSK)
-		return 1;
-	else
-		return 0;
-}
-
 int gic_get_c0_compare_int(void)
 {
 	if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
@@ -177,7 +166,7 @@ int gic_get_c0_perfcount_int(void)
 				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
 }
 
-void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
+static unsigned int gic_get_int(void)
 {
 	unsigned int i;
 	unsigned long *pending, *intrmask, *pcpu_mask;
@@ -202,17 +191,8 @@ void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
 
 	bitmap_and(pending, pending, intrmask, gic_shared_intrs);
 	bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
-	bitmap_and(dst, src, pending, gic_shared_intrs);
-}
-
-unsigned int gic_get_int(void)
-{
-	DECLARE_BITMAP(interrupts, GIC_MAX_INTRS);
-
-	bitmap_fill(interrupts, gic_shared_intrs);
-	gic_get_int_mask(interrupts, interrupts);
 
-	return find_first_bit(interrupts, gic_shared_intrs);
+	return find_first_bit(pending, gic_shared_intrs);
 }
 
 static void gic_mask_irq(struct irq_data *d)
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 23/24] MIPS: Malta: Use generic plat_irq_dispatch
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (21 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 22/24] irqchip: mips-gic: Remove unnecessary globals Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-15 23:51 ` [PATCH 24/24] MIPS: sead3: " Andrew Bresticker
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The generic plat_irq_dispatch provided in irq_cpu.c is sufficient for
dispatching interrupts on Malta in legacy and vectored interrupt modes.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/mti-malta/malta-int.c | 92 -----------------------------------------
 1 file changed, 92 deletions(-)

diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index c6b3548..bcab0b1 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -190,92 +190,6 @@ static irqreturn_t corehi_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static inline int clz(unsigned long x)
-{
-	__asm__(
-	"	.set	push					\n"
-	"	.set	mips32					\n"
-	"	clz	%0, %1					\n"
-	"	.set	pop					\n"
-	: "=r" (x)
-	: "r" (x));
-
-	return x;
-}
-
-/*
- * Version of ffs that only looks at bits 12..15.
- */
-static inline unsigned int irq_ffs(unsigned int pending)
-{
-#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
-	return -clz(pending) + 31 - CAUSEB_IP;
-#else
-	unsigned int a0 = 7;
-	unsigned int t0;
-
-	t0 = pending & 0xf000;
-	t0 = t0 < 1;
-	t0 = t0 << 2;
-	a0 = a0 - t0;
-	pending = pending << t0;
-
-	t0 = pending & 0xc000;
-	t0 = t0 < 1;
-	t0 = t0 << 1;
-	a0 = a0 - t0;
-	pending = pending << t0;
-
-	t0 = pending & 0x8000;
-	t0 = t0 < 1;
-	/* t0 = t0 << 2; */
-	a0 = a0 - t0;
-	/* pending = pending << t0; */
-
-	return a0;
-#endif
-}
-
-/*
- * IRQs on the Malta board look basically (barring software IRQs which we
- * don't use at all and all external interrupt sources are combined together
- * on hardware interrupt 0 (MIPS IRQ 2)) like:
- *
- *	MIPS IRQ	Source
- *	--------	------
- *	       0	Software (ignored)
- *	       1	Software (ignored)
- *	       2	Combined hardware interrupt (hw0)
- *	       3	Hardware (ignored)
- *	       4	Hardware (ignored)
- *	       5	Hardware (ignored)
- *	       6	Hardware (ignored)
- *	       7	R4k timer (what we use)
- *
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ----	    R4k Timer
- * Lowest  ----	    Combined hardware interrupt
- *
- * then we just return, if multiple IRQs are pending then we will just take
- * another exception, big deal.
- */
-
-asmlinkage void plat_irq_dispatch(void)
-{
-	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
-	int irq;
-
-	if (unlikely(!pending)) {
-		spurious_interrupt();
-		return;
-	}
-
-	irq = irq_ffs(pending);
-
-	do_IRQ(MIPS_CPU_IRQ_BASE + irq);
-}
-
 #ifdef CONFIG_MIPS_MT_SMP
 
 #define MIPS_CPU_IPI_RESCHED_IRQ 0	/* SW int 0 for resched */
@@ -438,12 +352,6 @@ void __init arch_init_irq(void)
 			cpu_ipi_resched_irq = MSC01E_INT_SW0;
 			cpu_ipi_call_irq = MSC01E_INT_SW1;
 		} else {
-			if (cpu_has_vint) {
-				set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ,
-					ipi_resched_dispatch);
-				set_vi_handler (MIPS_CPU_IPI_CALL_IRQ,
-					ipi_call_dispatch);
-			}
 			cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE +
 				MIPS_CPU_IPI_RESCHED_IRQ;
 			cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE +
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 24/24] MIPS: sead3: Use generic plat_irq_dispatch
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (22 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 23/24] MIPS: Malta: Use generic plat_irq_dispatch Andrew Bresticker
@ 2014-09-15 23:51 ` Andrew Bresticker
  2014-09-17 10:20 ` [PATCH 00/24] MIPS GIC cleanup, part 1 Qais Yousef
  2014-09-17 14:07 ` Jason Cooper
  25 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-15 23:51 UTC (permalink / raw)
  To: Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Andrew Bresticker, Jeffrey Deans, Markos Chandras, Paul Burton,
	Qais Yousef, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

The generic plat_irq_dispatch provided in irq_cpu.c is sufficient for
dispatching interrupts on SEAD-3 in legacy and vectored interrupt modes.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/mips/mti-sead3/sead3-int.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
index cb06cd9..69ae185 100644
--- a/arch/mips/mti-sead3/sead3-int.c
+++ b/arch/mips/mti-sead3/sead3-int.c
@@ -22,32 +22,11 @@
 
 static unsigned long sead3_config_reg;
 
-asmlinkage void plat_irq_dispatch(void)
-{
-	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
-	int irq;
-
-	irq = (fls(pending) - CAUSEB_IP - 1);
-	if (irq >= 0)
-		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
-	else
-		spurious_interrupt();
-}
-
 void __init arch_init_irq(void)
 {
-	int i;
-
-	if (!cpu_has_veic) {
+	if (!cpu_has_veic)
 		mips_cpu_irq_init();
 
-		if (cpu_has_vint) {
-			/* install generic handler */
-			for (i = 0; i < 8; i++)
-				set_vi_handler(i, plat_irq_dispatch);
-		}
-	}
-
 	sead3_config_reg = (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE,
 		SEAD_CONFIG_SIZE);
 	gic_present = (REG32(sead3_config_reg) & SEAD_CONFIG_GIC_PRESENT_MSK) >>
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch
  2014-09-15 23:51 ` [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch Andrew Bresticker
@ 2014-09-17  8:56   ` Qais Yousef
  2014-09-17 16:36     ` Andrew Bresticker
  0 siblings, 1 reply; 40+ messages in thread
From: Qais Yousef @ 2014-09-17  8:56 UTC (permalink / raw)
  To: Andrew Bresticker, Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Jeffrey Deans, Markos Chandras, Paul Burton, Jonas Gorski,
	John Crispin, David Daney, linux-mips, linux-kernel

Hi Andrew,

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> For platforms which boot with device-tree or have correctly chained
> all external interrupt controllers, a generic plat_irq_dispatch() can
> be used.  Implement a plat_irq_dispatch() which simply handles all the
> pending interrupts as reported by C0_Cause.
>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> ---
>   arch/mips/kernel/irq_cpu.c | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
>
> diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
> index ca98a9f..f17bd08 100644
> --- a/arch/mips/kernel/irq_cpu.c
> +++ b/arch/mips/kernel/irq_cpu.c
> @@ -94,6 +94,21 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
>   	.irq_eoi	= unmask_mips_irq,
>   };
>   
> +asmlinkage void __weak plat_irq_dispatch(void)
> +{
> +	unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM;
> +	int irq;
> +
> +	if (!pending) {
> +		spurious_interrupt();
> +		return;
> +	}
> +
> +	pending >>= CAUSEB_IP;
> +	for_each_set_bit(irq, &pending, 8)
> +		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
> +}
> +

If I read the for_each_set_bit() macro correctly it'll iterate through 
the bits from least to most significant ones which is the reversed 
priority expected. Some platforms set timer interrupt to bit 7 which is 
should be the highest priority interrupt. Also when cpu_has_vint is set 
the hardware prioritirise from most significant to least significant 
bits so if plat_irq_dispatch() is used with set_vi_handler() it'll cause 
interrupts to be serviced in the wrong order.

Qais

>   static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
>   			     irq_hw_number_t hw)
>   {


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
  2014-09-15 23:51 ` [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks Andrew Bresticker
@ 2014-09-17  9:14   ` Qais Yousef
  2014-09-17 17:14     ` Andrew Bresticker
  0 siblings, 1 reply; 40+ messages in thread
From: Qais Yousef @ 2014-09-17  9:14 UTC (permalink / raw)
  To: Andrew Bresticker, Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Jeffrey Deans, Markos Chandras, Paul Burton, Jonas Gorski,
	John Crispin, David Daney, linux-mips, linux-kernel

Hi Andrew,

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> There's no need for platforms to have their own GIC irq_ack/irq_eoi
> callbacks.  Move them to the GIC irqchip driver.
>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> ---
>   arch/mips/include/asm/gic.h     |  2 --
>   arch/mips/mti-malta/malta-int.c | 16 ----------------
>   arch/mips/mti-sead3/sead3-int.c | 21 ---------------------
>   drivers/irqchip/irq-mips-gic.c  | 15 ++++++++++++---
>   4 files changed, 12 insertions(+), 42 deletions(-)
>
> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
> index 022d831..1bf7985 100644
> --- a/arch/mips/include/asm/gic.h
> +++ b/arch/mips/include/asm/gic.h
> @@ -376,7 +376,5 @@ extern void gic_bind_eic_interrupt(int irq, int set);
>   extern unsigned int gic_get_timer_pending(void);
>   extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
>   extern unsigned int gic_get_int(void);
> -extern void gic_irq_ack(struct irq_data *d);
> -extern void gic_finish_irq(struct irq_data *d);
>   extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
>   #endif /* _ASM_GICREGS_H */
> diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
> index 5c31208..b60adfd 100644
> --- a/arch/mips/mti-malta/malta-int.c
> +++ b/arch/mips/mti-malta/malta-int.c
> @@ -715,22 +715,6 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
>   	return retval;
>   }
>   
> -void gic_irq_ack(struct irq_data *d)
> -{
> -	int irq = (d->irq - gic_irq_base);
> -
> -	GIC_CLR_INTR_MASK(irq);
> -
> -	if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
> -		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
> -}
> -
> -void gic_finish_irq(struct irq_data *d)
> -{
> -	/* Enable interrupts. */
> -	GIC_SET_INTR_MASK(d->irq - gic_irq_base);
> -}
> -
>   void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
>   {
>   	int i;
> diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
> index 9d5b5bd..03f9865 100644
> --- a/arch/mips/mti-sead3/sead3-int.c
> +++ b/arch/mips/mti-sead3/sead3-int.c
> @@ -85,27 +85,6 @@ void __init arch_init_irq(void)
>   			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
>   }
>   
> -void gic_irq_ack(struct irq_data *d)
> -{
> -	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
> -}
> -
> -void gic_finish_irq(struct irq_data *d)
> -{
> -	unsigned int irq = (d->irq - gic_irq_base);
> -	unsigned int i, irq_source;
> -
> -	/* Clear edge detectors. */
> -	for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) {
> -		irq_source = gic_shared_intr_map[irq].intr_list[i];
> -		if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE)
> -			GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq_source);
> -	}
> -
> -	/* Enable interrupts. */
> -	GIC_SET_INTR_MASK(irq);
> -}
> -
>   void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
>   {
>   	int i;
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index 9e9d8b9..0dc2972 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -237,6 +237,15 @@ static void gic_unmask_irq(struct irq_data *d)
>   	GIC_SET_INTR_MASK(d->irq - gic_irq_base);
>   }
>   
> +static void gic_ack_irq(struct irq_data *d)
> +{
> +	GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
> +
> +	/* Clear edge detector */
> +	if (gic_irq_flags[d->irq - gic_irq_base] & GIC_TRIG_EDGE)
> +		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq - gic_irq_base);
> +}
> +
>   #ifdef CONFIG_SMP
>   static DEFINE_SPINLOCK(gic_lock);
>   
> @@ -272,11 +281,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
>   
>   static struct irq_chip gic_irq_controller = {
>   	.name			=	"MIPS GIC",
> -	.irq_ack		=	gic_irq_ack,
> +	.irq_ack		=	gic_ack_irq,
>   	.irq_mask		=	gic_mask_irq,
> -	.irq_mask_ack		=	gic_mask_irq,
> +	.irq_mask_ack		=	gic_ack_irq,
>   	.irq_unmask		=	gic_unmask_irq,
> -	.irq_eoi		=	gic_finish_irq,
> +	.irq_eoi		=	gic_unmask_irq,
>   #ifdef CONFIG_SMP
>   	.irq_set_affinity	=	gic_set_affinity,
>   #endif

I'm no expert in irq_chip api but I think providing irq_mask_ack and 
irq_eoi makes no sense to GIC and can be removed.

Qais

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables
  2014-09-15 23:51 ` [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables Andrew Bresticker
@ 2014-09-17  9:21   ` Qais Yousef
  0 siblings, 0 replies; 40+ messages in thread
From: Qais Yousef @ 2014-09-17  9:21 UTC (permalink / raw)
  To: Andrew Bresticker, Jason Cooper
  Cc: Ralf Baechle, Thomas Gleixner, Jeffrey Deans, Markos Chandras,
	Paul Burton, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

Ah how beautiful to see all this code disappearing, nice work! :)

Qais

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> Now that the GIC properly uses IRQ domains, kill off the per-platform
> routing tables that were used to make the GIC appear transparent.
>
> This includes:
>   - removing the mapping tables and the support for applying them,
>   - moving GIC IPI support to the GIC driver,
>   - properly routing the i8259 through the GIC on Malta, and
>   - updating IRQ assignments on SEAD-3 when the GIC is present.
>
> Platforms no longer will pass an interrupt mapping table to gic_init.
> Instead, they will pass the CPU interrupt vector (2 - 7) that they
> expect the GIC to route interrupts to.  Note that in EIC mode this
> value is ignored and all GIC interrupts are routed to EIC vector 1.
>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> ---
> I'm not sure what other external interrupts (if any) are also routed
> through the GIC on Malta boards.  In particular I'm concerned about
> the MSC01 IRQ chip and the CoreHi interrupt.  Neither of these matter
> a whole lot since we don't use any MSC01 interrupts and the CoreHI
> interrupt is fatal.
> ---
>   arch/mips/include/asm/gic.h                  |  35 +----
>   arch/mips/include/asm/mips-boards/maltaint.h |  14 +-
>   arch/mips/include/asm/mips-boards/sead3int.h |  13 ++
>   arch/mips/kernel/cevt-gic.c                  |   3 +-
>   arch/mips/mti-malta/malta-int.c              | 189 +++++--------------------
>   arch/mips/mti-sead3/sead3-ehci.c             |   8 +-
>   arch/mips/mti-sead3/sead3-int.c              |  28 +---
>   arch/mips/mti-sead3/sead3-net.c              |  14 +-
>   arch/mips/mti-sead3/sead3-platform.c         |  18 ++-
>   drivers/irqchip/irq-mips-gic.c               | 201 ++++++++++++++-------------
>   10 files changed, 198 insertions(+), 325 deletions(-)
>
> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
> index efcf4de..cfbf907 100644
> --- a/arch/mips/include/asm/gic.h
> +++ b/arch/mips/include/asm/gic.h
> @@ -316,31 +316,6 @@
>   	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \
>   		 GIC_SH_MAP_TO_VPE_REG_BIT(vpe))
>   
> -/*
> - * Interrupt Meta-data specification. The ipiflag helps
> - * in building ipi_map.
> - */
> -struct gic_intr_map {
> -	unsigned int cpunum;	/* Directed to this CPU */
> -#define GIC_UNUSED		0xdead			/* Dummy data */
> -	unsigned int pin;	/* Directed to this Pin */
> -	unsigned int polarity;	/* Polarity : +/-	*/
> -	unsigned int trigtype;	/* Trigger  : Edge/Levl */
> -	unsigned int flags;	/* Misc flags	*/
> -#define GIC_FLAG_TRANSPARENT   0x01
> -};
> -
> -/*
> - * This is only used in EIC mode. This helps to figure out which
> - * shared interrupts we need to process when we get a vector interrupt.
> - */
> -#define GIC_MAX_SHARED_INTR  0x5
> -struct gic_shared_intr_map {
> -	unsigned int num_shared_intr;
> -	unsigned int intr_list[GIC_MAX_SHARED_INTR];
> -	unsigned int local_intr_mask;
> -};
> -
>   /* GIC nomenclature for Core Interrupt Pins. */
>   #define GIC_CPU_INT0		0 /* Core Interrupt 2 */
>   #define GIC_CPU_INT1		1 /* .		      */
> @@ -349,6 +324,9 @@ struct gic_shared_intr_map {
>   #define GIC_CPU_INT4		4 /* .		      */
>   #define GIC_CPU_INT5		5 /* Core Interrupt 7 */
>   
> +/* Add 2 to convert GIC CPU pin to core interrupt */
> +#define GIC_CPU_PIN_OFFSET	2
> +
>   /* Local GIC interrupts. */
>   #define GIC_INT_TMR		(GIC_CPU_INT5)
>   #define GIC_INT_PERFCTR		(GIC_CPU_INT5)
> @@ -365,13 +343,12 @@ struct gic_shared_intr_map {
>   extern unsigned int gic_present;
>   extern unsigned int gic_frequency;
>   extern unsigned long _gic_base;
> -extern unsigned int gic_irq_base;
>   extern unsigned int gic_irq_flags[];
> -extern struct gic_shared_intr_map gic_shared_intr_map[];
> +extern unsigned int gic_cpu_pin;
>   
>   extern void gic_init(unsigned long gic_base_addr,
> -	unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
> -	unsigned int intrmap_size, unsigned int irqbase);
> +	unsigned long gic_addrspace_size, unsigned int cpu_vec,
> +	unsigned int irqbase);
>   extern void gic_clocksource_init(unsigned int);
>   extern unsigned int gic_compare_int (void);
>   extern cycle_t gic_read_count(void);
> diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
> index d741628..bdd6f39 100644
> --- a/arch/mips/include/asm/mips-boards/maltaint.h
> +++ b/arch/mips/include/asm/mips-boards/maltaint.h
> @@ -20,11 +20,10 @@
>   #define MIPSCPU_INT_SW1		1
>   #define MIPSCPU_INT_MB0		2
>   #define MIPSCPU_INT_I8259A	MIPSCPU_INT_MB0
> +#define MIPSCPU_INT_GIC		MIPSCPU_INT_MB0 /* GIC chained interrupt */
>   #define MIPSCPU_INT_MB1		3
>   #define MIPSCPU_INT_SMI		MIPSCPU_INT_MB1
> -#define MIPSCPU_INT_IPI0	MIPSCPU_INT_MB1 /* GIC IPI */
>   #define MIPSCPU_INT_MB2		4
> -#define MIPSCPU_INT_IPI1	MIPSCPU_INT_MB2 /* GIC IPI */
>   #define MIPSCPU_INT_MB3		5
>   #define MIPSCPU_INT_COREHI	MIPSCPU_INT_MB3
>   #define MIPSCPU_INT_MB4		6
> @@ -61,14 +60,7 @@
>   #define MSC01E_INT_PERFCTR	10
>   #define MSC01E_INT_CPUCTR	11
>   
> -/* External Interrupts used for IPI */
> -#define GIC_IPI_EXT_INTR_RESCHED_VPE0	16
> -#define GIC_IPI_EXT_INTR_CALLFNC_VPE0	17
> -#define GIC_IPI_EXT_INTR_RESCHED_VPE1	18
> -#define GIC_IPI_EXT_INTR_CALLFNC_VPE1	19
> -#define GIC_IPI_EXT_INTR_RESCHED_VPE2	20
> -#define GIC_IPI_EXT_INTR_CALLFNC_VPE2	21
> -#define GIC_IPI_EXT_INTR_RESCHED_VPE3	22
> -#define GIC_IPI_EXT_INTR_CALLFNC_VPE3	23
> +/* GIC external interrupts */
> +#define GIC_INT_I8259A		3
>   
>   #endif /* !(_MIPS_MALTAINT_H) */
> diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
> index 11ebec9..a2e0095 100644
> --- a/arch/mips/include/asm/mips-boards/sead3int.h
> +++ b/arch/mips/include/asm/mips-boards/sead3int.h
> @@ -14,4 +14,17 @@
>   #define GIC_BASE_ADDR		0x1b1c0000
>   #define GIC_ADDRSPACE_SZ	(128 * 1024)
>   
> +/* CPU interrupt offsets */
> +#define CPU_INT_GIC		2
> +#define CPU_INT_EHCI		2
> +#define CPU_INT_UART0		4
> +#define CPU_INT_UART1		4
> +#define CPU_INT_NET		6
> +
> +/* GIC interrupt offsets */
> +#define GIC_INT_NET		0
> +#define GIC_INT_UART1		2
> +#define GIC_INT_UART0		3
> +#define GIC_INT_EHCI		5
> +
>   #endif /* !(_MIPS_SEAD3INT_H) */
> diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
> index 6093716..a90bd4c 100644
> --- a/arch/mips/kernel/cevt-gic.c
> +++ b/arch/mips/kernel/cevt-gic.c
> @@ -91,7 +91,8 @@ int gic_clockevent_init(void)
>   
>   	clockevents_register_device(cd);
>   
> -	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
> +	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP),
> +		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
>   	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
>   
>   	if (gic_timer_irq_installed)
> diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
> index e56563c..3b3bc1d 100644
> --- a/arch/mips/mti-malta/malta-int.c
> +++ b/arch/mips/mti-malta/malta-int.c
> @@ -38,14 +38,9 @@
>   #include <asm/rtlx.h>
>   
>   static unsigned long _msc01_biu_base;
> -static unsigned int ipi_map[NR_CPUS];
>   
>   static DEFINE_RAW_SPINLOCK(mips_irq_lock);
>   
> -#ifdef CONFIG_MIPS_GIC_IPI
> -DECLARE_BITMAP(ipi_ints, GIC_NUM_INTRS);
> -#endif
> -
>   static inline int mips_pcibios_iack(void)
>   {
>   	int irq;
> @@ -127,24 +122,10 @@ static void malta_hw0_irqdispatch(void)
>   #endif
>   }
>   
> -static void malta_ipi_irqdispatch(void)
> +static irqreturn_t i8259_handler(int irq, void *dev_id)
>   {
> -#ifdef CONFIG_MIPS_GIC_IPI
> -	unsigned long irq;
> -	DECLARE_BITMAP(pending, GIC_NUM_INTRS);
> -
> -	gic_get_int_mask(pending, ipi_ints);
> -
> -	irq = find_first_bit(pending, GIC_NUM_INTRS);
> -
> -	while (irq < GIC_NUM_INTRS) {
> -		do_IRQ(MIPS_GIC_IRQ_BASE + irq);
> -
> -		irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1);
> -	}
> -#endif
> -	if (gic_compare_int())
> -		do_IRQ(MIPS_GIC_IRQ_BASE);
> +	malta_hw0_irqdispatch();
> +	return IRQ_HANDLED;
>   }
>   
>   static void corehi_irqdispatch(void)
> @@ -203,6 +184,12 @@ static void corehi_irqdispatch(void)
>   	die("CoreHi interrupt", regs);
>   }
>   
> +static irqreturn_t corehi_handler(int irq, void *dev_id)
> +{
> +	corehi_irqdispatch();
> +	return IRQ_HANDLED;
> +}
> +
>   static inline int clz(unsigned long x)
>   {
>   	__asm__(
> @@ -286,10 +273,9 @@ asmlinkage void plat_irq_dispatch(void)
>   
>   	irq = irq_ffs(pending);
>   
> -	if (irq == MIPSCPU_INT_I8259A)
> -		malta_hw0_irqdispatch();
> -	else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
> -		malta_ipi_irqdispatch();
> +	/* HACK: GIC doesn't properly dispatch local interrupts yet */
> +	if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int())
> +		do_IRQ(MIPS_GIC_IRQ_BASE);
>   	else
>   		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
>   }
> @@ -312,13 +298,6 @@ static void ipi_call_dispatch(void)
>   	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
>   }
>   
> -#endif /* CONFIG_MIPS_MT_SMP */
> -
> -#ifdef CONFIG_MIPS_GIC_IPI
> -
> -#define GIC_MIPS_CPU_IPI_RESCHED_IRQ	3
> -#define GIC_MIPS_CPU_IPI_CALL_IRQ	4
> -
>   static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
>   {
>   #ifdef CONFIG_MIPS_VPE_APSP_API_CMP
> @@ -349,31 +328,16 @@ static struct irqaction irq_call = {
>   	.flags		= IRQF_PERCPU,
>   	.name		= "IPI_call"
>   };
> -#endif /* CONFIG_MIPS_GIC_IPI */
> -
> -static int gic_resched_int_base;
> -static int gic_call_int_base;
> -#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu))
> -#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu))
> -
> -unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
> -{
> -	return GIC_CALL_INT(cpu);
> -}
> -
> -unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
> -{
> -	return GIC_RESCHED_INT(cpu);
> -}
> +#endif /* CONFIG_MIPS_MT_SMP */
>   
>   static struct irqaction i8259irq = {
> -	.handler = no_action,
> +	.handler = i8259_handler,
>   	.name = "XT-PIC cascade",
>   	.flags = IRQF_NO_THREAD,
>   };
>   
>   static struct irqaction corehi_irqaction = {
> -	.handler = no_action,
> +	.handler = corehi_handler,
>   	.name = "CoreHi",
>   	.flags = IRQF_NO_THREAD,
>   };
> @@ -399,60 +363,6 @@ static msc_irqmap_t msc_eicirqmap[] __initdata = {
>   
>   static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
>   
> -/*
> - * This GIC specific tabular array defines the association between External
> - * Interrupts and CPUs/Core Interrupts. The nature of the External
> - * Interrupts is also defined here - polarity/trigger.
> - */
> -
> -#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
> -#define X GIC_UNUSED
> -
> -static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
> -	{ X, X,		   X,		X,		0 },
> -	{ X, X,		   X,		X,		0 },
> -	{ X, X,		   X,		X,		0 },
> -	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ X, X,		   X,		X,		0 },
> -	{ X, X,		   X,		X,		0 },
> -	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_NMI,  GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_NMI,  GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ X, X,		   X,		X,		0 },
> -	/* The remainder of this table is initialised by fill_ipi_map */
> -};
> -#undef X
> -
> -#ifdef CONFIG_MIPS_GIC_IPI
> -static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
> -{
> -	int intr = baseintr + cpu;
> -	gic_intr_map[intr].cpunum = cpu;
> -	gic_intr_map[intr].pin = cpupin;
> -	gic_intr_map[intr].polarity = GIC_POL_POS;
> -	gic_intr_map[intr].trigtype = GIC_TRIG_EDGE;
> -	gic_intr_map[intr].flags = 0;
> -	ipi_map[cpu] |= (1 << (cpupin + 2));
> -	bitmap_set(ipi_ints, intr, 1);
> -}
> -
> -static void __init fill_ipi_map(void)
> -{
> -	int cpu;
> -
> -	for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
> -		fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
> -		fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
> -	}
> -}
> -#endif
> -
>   void __init arch_init_ipiirq(int irq, struct irqaction *action)
>   {
>   	setup_irq(irq, action);
> @@ -461,6 +371,8 @@ void __init arch_init_ipiirq(int irq, struct irqaction *action)
>   
>   void __init arch_init_irq(void)
>   {
> +	int corehi_irq, i8259_irq;
> +
>   	init_i8259_irqs();
>   
>   	if (!cpu_has_veic)
> @@ -507,34 +419,11 @@ void __init arch_init_irq(void)
>   					msc_nr_irqs);
>   	}
>   
> -	if (cpu_has_veic) {
> -		set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch);
> -		set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
> -		setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq);
> -		setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction);
> -	} else if (cpu_has_vint) {
> -		set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
> -		set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch);
> -		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
> -		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
> -						&corehi_irqaction);
> -	} else {
> -		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
> -		setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
> -						&corehi_irqaction);
> -	}
> -
>   	if (gic_present) {
> -		/* FIXME */
>   		int i;
> -#if defined(CONFIG_MIPS_GIC_IPI)
> -		gic_call_int_base = GIC_NUM_INTRS -
> -			(NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
> -		gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
> -		fill_ipi_map();
> -#endif
> -		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
> -				ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
> +
> +		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC,
> +			 MIPS_GIC_IRQ_BASE);
>   		if (!mips_cm_present()) {
>   			/* Enable the GIC */
>   			i = REG(_msc01_biu_base, MSC01_SC_CFG);
> @@ -542,28 +431,8 @@ void __init arch_init_irq(void)
>   				(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
>   			pr_debug("GIC Enabled\n");
>   		}
> -#if defined(CONFIG_MIPS_GIC_IPI)
> -		/* set up ipi interrupts */
> -		if (cpu_has_vint) {
> -			set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
> -			set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
> -		}
> -		/* Argh.. this really needs sorting out.. */
> -		pr_info("CPU%d: status register was %08x\n",
> -			smp_processor_id(), read_c0_status());
> -		write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
> -		pr_info("CPU%d: status register now %08x\n",
> -			smp_processor_id(), read_c0_status());
> -		write_c0_status(0x1100dc00);
> -		pr_info("CPU%d: status register frc %08x\n",
> -			smp_processor_id(), read_c0_status());
> -		for (i = 0; i < nr_cpu_ids; i++) {
> -			arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
> -					 GIC_RESCHED_INT(i), &irq_resched);
> -			arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
> -					 GIC_CALL_INT(i), &irq_call);
> -		}
> -#endif
> +		i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A;
> +		corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
>   	} else {
>   #if defined(CONFIG_MIPS_MT_SMP)
>   		/* set up ipi interrupts */
> @@ -587,7 +456,21 @@ void __init arch_init_irq(void)
>   		arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched);
>   		arch_init_ipiirq(cpu_ipi_call_irq, &irq_call);
>   #endif
> +		if (cpu_has_veic) {
> +			set_vi_handler(MSC01E_INT_I8259A,
> +				       malta_hw0_irqdispatch);
> +			set_vi_handler(MSC01E_INT_COREHI,
> +				       corehi_irqdispatch);
> +			i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A;
> +			corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
> +		} else {
> +			i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A;
> +			corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
> +		}
>   	}
> +
> +	setup_irq(i8259_irq, &i8259irq);
> +	setup_irq(corehi_irq, &corehi_irqaction);
>   }
>   
>   void malta_be_init(void)
> diff --git a/arch/mips/mti-sead3/sead3-ehci.c b/arch/mips/mti-sead3/sead3-ehci.c
> index 772fc05..4ddaa0f 100644
> --- a/arch/mips/mti-sead3/sead3-ehci.c
> +++ b/arch/mips/mti-sead3/sead3-ehci.c
> @@ -10,6 +10,9 @@
>   #include <linux/dma-mapping.h>
>   #include <linux/platform_device.h>
>   
> +#include <asm/gic.h>
> +#include <asm/mips-boards/sead3int.h>
> +
>   struct resource ehci_resources[] = {
>   	{
>   		.start			= 0x1b200000,
> @@ -17,7 +20,6 @@ struct resource ehci_resources[] = {
>   		.flags			= IORESOURCE_MEM
>   	},
>   	{
> -		.start			= MIPS_CPU_IRQ_BASE + 2,
>   		.flags			= IORESOURCE_IRQ
>   	}
>   };
> @@ -37,6 +39,10 @@ static struct platform_device ehci_device = {
>   
>   static int __init ehci_init(void)
>   {
> +	if (gic_present)
> +		ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI;
> +	else
> +		ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI;
>   	return platform_device_register(&ehci_device);
>   }
>   
> diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c
> index 8f36342..cb06cd9 100644
> --- a/arch/mips/mti-sead3/sead3-int.c
> +++ b/arch/mips/mti-sead3/sead3-int.c
> @@ -22,30 +22,6 @@
>   
>   static unsigned long sead3_config_reg;
>   
> -/*
> - * This table defines the setup for each external GIC interrupt. It is
> - * indexed by interrupt number.
> - */
> -#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
> -static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
> -	{ 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -	{ GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
> -};
> -
>   asmlinkage void plat_irq_dispatch(void)
>   {
>   	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
> @@ -81,7 +57,7 @@ void __init arch_init_irq(void)
>   		(current_cpu_data.options & MIPS_CPU_VEIC) ?  "on" : "off");
>   
>   	if (gic_present)
> -		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
> -			ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
> +		gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC,
> +			 MIPS_GIC_IRQ_BASE);
>   }
>   
> diff --git a/arch/mips/mti-sead3/sead3-net.c b/arch/mips/mti-sead3/sead3-net.c
> index dd11e7e..c9f728a 100644
> --- a/arch/mips/mti-sead3/sead3-net.c
> +++ b/arch/mips/mti-sead3/sead3-net.c
> @@ -10,6 +10,9 @@
>   #include <linux/platform_device.h>
>   #include <linux/smsc911x.h>
>   
> +#include <asm/gic.h>
> +#include <asm/mips-boards/sead3int.h>
> +
>   static struct smsc911x_platform_config sead3_smsc911x_data = {
>   	.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
>   	.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
> @@ -17,14 +20,13 @@ static struct smsc911x_platform_config sead3_smsc911x_data = {
>   	.phy_interface = PHY_INTERFACE_MODE_MII,
>   };
>   
> -struct resource sead3_net_resourcess[] = {
> +struct resource sead3_net_resources[] = {
>   	{
>   		.start			= 0x1f010000,
>   		.end			= 0x1f01ffff,
>   		.flags			= IORESOURCE_MEM
>   	},
>   	{
> -		.start			= MIPS_CPU_IRQ_BASE + 6,
>   		.flags			= IORESOURCE_IRQ
>   	}
>   };
> @@ -35,12 +37,16 @@ static struct platform_device sead3_net_device = {
>   	.dev			= {
>   		.platform_data	= &sead3_smsc911x_data,
>   	},
> -	.num_resources		= ARRAY_SIZE(sead3_net_resourcess),
> -	.resource		= sead3_net_resourcess
> +	.num_resources		= ARRAY_SIZE(sead3_net_resources),
> +	.resource		= sead3_net_resources
>   };
>   
>   static int __init sead3_net_init(void)
>   {
> +	if (gic_present)
> +		sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET;
> +	else
> +		sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET;
>   	return platform_device_register(&sead3_net_device);
>   }
>   
> diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c
> index 6c3b33d..d9661eb 100644
> --- a/arch/mips/mti-sead3/sead3-platform.c
> +++ b/arch/mips/mti-sead3/sead3-platform.c
> @@ -9,10 +9,13 @@
>   #include <linux/init.h>
>   #include <linux/serial_8250.h>
>   
> -#define UART(base, int)							\
> +#include <asm/gic.h>
> +#include <asm/mips-boards/sead3int.h>
> +
> +#define UART(base)							\
>   {									\
>   	.mapbase	= base,						\
> -	.irq		= int,						\
> +	.irq		= -1,						\
>   	.uartclk	= 14745600,					\
>   	.iotype		= UPIO_MEM32,					\
>   	.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \
> @@ -20,8 +23,8 @@
>   }
>   
>   static struct plat_serial8250_port uart8250_data[] = {
> -	UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4),   /* ttyS0 = USB   */
> -	UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4),   /* ttyS1 = RS232 */
> +	UART(0x1f000900),   /* ttyS0 = USB   */
> +	UART(0x1f000800),   /* ttyS1 = RS232 */
>   	{ },
>   };
>   
> @@ -35,6 +38,13 @@ static struct platform_device uart8250_device = {
>   
>   static int __init uart8250_init(void)
>   {
> +	if (gic_present) {
> +		uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0;
> +		uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1;
> +	} else {
> +		uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0;
> +		uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1;
> +	}
>   	return platform_device_register(&uart8250_device);
>   }
>   
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index b4d87c4..094be83 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -8,6 +8,8 @@
>    */
>   #include <linux/bitmap.h>
>   #include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/sched.h>
>   #include <linux/smp.h>
>   #include <linux/irq.h>
>   #include <linux/clocksource.h>
> @@ -22,11 +24,8 @@
>   unsigned int gic_frequency;
>   unsigned int gic_present;
>   unsigned long _gic_base;
> -unsigned int gic_irq_base;
>   unsigned int gic_irq_flags[GIC_NUM_INTRS];
> -
> -/* The index into this array is the vector # of the interrupt. */
> -struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
> +unsigned int gic_cpu_pin;
>   
>   struct gic_pcpu_mask {
>   	DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
> @@ -45,6 +44,8 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
>   static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
>   static struct irq_domain *gic_irq_domain;
>   
> +static void __gic_irq_dispatch(void);
> +
>   #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
>   cycle_t gic_read_count(void)
>   {
> @@ -116,21 +117,6 @@ void gic_send_ipi(unsigned int intr)
>   	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
>   }
>   
> -static void gic_eic_irq_dispatch(void)
> -{
> -	unsigned int cause = read_c0_cause();
> -	int irq;
> -
> -	irq = (cause & ST0_IM) >> STATUSB_IP2;
> -	if (irq == 0)
> -		irq = -1;
> -
> -	if (irq >= 0)
> -		do_IRQ(gic_irq_base + irq);
> -	else
> -		spurious_interrupt();
> -}
> -
>   static void __init vpe_local_setup(unsigned int numvpes)
>   {
>   	unsigned long timer_intr = GIC_INT_TMR;
> @@ -165,16 +151,15 @@ static void __init vpe_local_setup(unsigned int numvpes)
>   				 GIC_MAP_TO_PIN_MSK | timer_intr);
>   		if (cpu_has_veic) {
>   			set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
> -				gic_eic_irq_dispatch);
> -			gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
> +				       __gic_irq_dispatch);
>   		}
>   
>   		if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
>   			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
>   				 GIC_MAP_TO_PIN_MSK | perf_intr);
>   		if (cpu_has_veic) {
> -			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
> -			gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
> +			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET,
> +				       __gic_irq_dispatch);
>   		}
>   	}
>   }
> @@ -345,64 +330,100 @@ static struct irq_chip gic_irq_controller = {
>   #endif
>   };
>   
> -static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
> -	unsigned int pin, unsigned int polarity, unsigned int trigtype,
> -	unsigned int flags)
> +static void __gic_irq_dispatch(void)
>   {
> -	struct gic_shared_intr_map *map_ptr;
> -	int i;
> -
> -	/* Setup Intr to Pin mapping */
> -	if (pin & GIC_MAP_TO_NMI_MSK) {
> -		int i;
> +	unsigned int intr, virq;
>   
> -		GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
> -		/* FIXME: hack to route NMI to all cpu's */
> -		for (i = 0; i < NR_CPUS; i += 32) {
> -			GICWRITE(GIC_REG_ADDR(SHARED,
> -					  GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)),
> -				 0xffffffff);
> -		}
> -	} else {
> -		GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
> -			 GIC_MAP_TO_PIN_MSK | pin);
> -		/* Setup Intr to CPU mapping */
> -		GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
> -		if (cpu_has_veic) {
> -			set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
> -				gic_eic_irq_dispatch);
> -			map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
> -			if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
> -				BUG();
> -			map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
> -		}
> +	while ((intr = gic_get_int()) != GIC_NUM_INTRS) {
> +		virq = irq_linear_revmap(gic_irq_domain, intr);
> +		do_IRQ(virq);
>   	}
> +}
>   
> -	/* Setup Intr Polarity */
> -	GIC_SET_POLARITY(intr, polarity);
> +static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)
> +{
> +	__gic_irq_dispatch();
> +}
> +
> +#ifdef CONFIG_MIPS_GIC_IPI
> +static int gic_resched_int_base;
> +static int gic_call_int_base;
> +
> +unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
> +{
> +	return gic_resched_int_base + cpu;
> +}
>   
> -	/* Setup Intr Trigger Type */
> -	GIC_SET_TRIGGER(intr, trigtype);
> +unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
> +{
> +	return gic_call_int_base + cpu;
> +}
>   
> -	/* Init Intr Masks */
> -	GIC_CLR_INTR_MASK(intr);
> +static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
> +{
> +	scheduler_ipi();
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
> +{
> +	smp_call_function_interrupt();
> +
> +	return IRQ_HANDLED;
> +}
>   
> -	/* Initialise per-cpu Interrupt software masks */
> +static struct irqaction irq_resched = {
> +	.handler	= ipi_resched_interrupt,
> +	.flags		= IRQF_PERCPU,
> +	.name		= "IPI resched"
> +};
> +
> +static struct irqaction irq_call = {
> +	.handler	= ipi_call_interrupt,
> +	.flags		= IRQF_PERCPU,
> +	.name		= "IPI call"
> +};
> +
> +static __init void gic_ipi_init_one(unsigned int intr, int cpu,
> +				    struct irqaction *action)
> +{
> +	int virq = irq_create_mapping(gic_irq_domain, intr);
> +	int i;
> +
> +	GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
>   	for (i = 0; i < NR_CPUS; i++)
>   		clear_bit(intr, pcpu_masks[i].pcpu_mask);
>   	set_bit(intr, pcpu_masks[cpu].pcpu_mask);
>   
> -	if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
> -		GIC_SET_INTR_MASK(intr);
> -	if (trigtype == GIC_TRIG_EDGE)
> -		gic_irq_flags[intr] |= GIC_TRIG_EDGE;
> +	irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
> +
> +	irq_set_handler(virq, handle_percpu_irq);
> +	setup_irq(virq, action);
>   }
>   
> -static void __init gic_basic_init(int numintrs, int numvpes,
> -			struct gic_intr_map *intrmap, int mapsize)
> +static __init void gic_ipi_init(void)
>   {
> -	unsigned int i, cpu;
> -	unsigned int pin_offset = 0;
> +	int i;
> +
> +	/* Use last 2 * NR_CPUS interrupts as IPIs */
> +	gic_resched_int_base = GIC_NUM_INTRS - nr_cpu_ids;
> +	gic_call_int_base = gic_resched_int_base - nr_cpu_ids;
> +
> +	for (i = 0; i < nr_cpu_ids; i++) {
> +		gic_ipi_init_one(gic_call_int_base + i, i, &irq_call);
> +		gic_ipi_init_one(gic_resched_int_base + i, i, &irq_resched);
> +	}
> +}
> +#else
> +static inline void gic_ipi_init(void)
> +{
> +}
> +#endif
> +
> +static void __init gic_basic_init(int numintrs, int numvpes)
> +{
> +	unsigned int i;
>   
>   	board_bind_eic_interrupt = &gic_bind_eic_interrupt;
>   
> @@ -411,31 +432,8 @@ static void __init gic_basic_init(int numintrs, int numvpes,
>   		GIC_SET_POLARITY(i, GIC_POL_POS);
>   		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
>   		GIC_CLR_INTR_MASK(i);
> -		if (i < GIC_NUM_INTRS) {
> +		if (i < GIC_NUM_INTRS)
>   			gic_irq_flags[i] = 0;
> -			gic_shared_intr_map[i].num_shared_intr = 0;
> -			gic_shared_intr_map[i].local_intr_mask = 0;
> -		}
> -	}
> -
> -	/*
> -	 * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
> -	 * one because the GIC will add one (since 0=no intr).
> -	 */
> -	if (cpu_has_veic)
> -		pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
> -
> -	/* Setup specifics */
> -	for (i = 0; i < mapsize; i++) {
> -		cpu = intrmap[i].cpunum;
> -		if (cpu == GIC_UNUSED)
> -			continue;
> -		gic_setup_intr(i,
> -			intrmap[i].cpunum,
> -			intrmap[i].pin + pin_offset,
> -			intrmap[i].polarity,
> -			intrmap[i].trigtype,
> -			intrmap[i].flags);
>   	}
>   
>   	vpe_local_setup(numvpes);
> @@ -447,7 +445,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
>   	irq_set_chip_and_handler(virq, &gic_irq_controller, handle_level_irq);
>   
>   	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
> -		 GIC_MAP_TO_PIN_MSK | 0);
> +		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
>   	/* Map to VPE 0 by default */
>   	GIC_SH_MAP_TO_VPE_SMASK(hw, 0);
>   	set_bit(hw, pcpu_masks[0].pcpu_mask);
> @@ -461,8 +459,7 @@ static struct irq_domain_ops gic_irq_domain_ops = {
>   };
>   
>   void __init gic_init(unsigned long gic_base_addr,
> -		     unsigned long gic_addrspace_size,
> -		     struct gic_intr_map *intr_map, unsigned int intr_map_size,
> +		     unsigned long gic_addrspace_size, unsigned int cpu_vec,
>   		     unsigned int irqbase)
>   {
>   	unsigned int gicconfig;
> @@ -470,7 +467,6 @@ void __init gic_init(unsigned long gic_base_addr,
>   
>   	_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
>   						    gic_addrspace_size);
> -	gic_irq_base = irqbase;
>   
>   	GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
>   	numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
> @@ -481,10 +477,23 @@ void __init gic_init(unsigned long gic_base_addr,
>   		  GIC_SH_CONFIG_NUMVPES_SHF;
>   	numvpes = numvpes + 1;
>   
> +	if (cpu_has_veic) {
> +		/* Always use vector 1 in EIC mode */
> +		gic_cpu_pin = 0;
> +		set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
> +			       __gic_irq_dispatch);
> +	} else {
> +		gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
> +		irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
> +					gic_irq_dispatch);
> +	}
> +
>   	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase,
>   					       &gic_irq_domain_ops, NULL);
>   	if (!gic_irq_domain)
>   		panic("Failed to add GIC IRQ domain");
>   
> -	gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
> +	gic_basic_init(numintrs, numvpes);
> +
> +	gic_ipi_init();
>   }


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips
  2014-09-15 23:51 ` [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips Andrew Bresticker
@ 2014-09-17  9:24   ` Qais Yousef
  2014-09-17 17:15     ` Andrew Bresticker
  0 siblings, 1 reply; 40+ messages in thread
From: Qais Yousef @ 2014-09-17  9:24 UTC (permalink / raw)
  To: Andrew Bresticker, Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Jeffrey Deans, Markos Chandras, Paul Burton, Jonas Gorski,
	John Crispin, David Daney, linux-mips, linux-kernel

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> GIC edge-triggered interrupts must be acknowledged by clearing the edge
> detector via a write to GIC_SH_WEDGE.  Create a separate edge-triggered
> irq_chip with the appropriate irq_ack() callback.  This also allows us
> to get rid of gic_irq_flags.
>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> ---
>   arch/mips/include/asm/gic.h    |  1 -
>   drivers/irqchip/irq-mips-gic.c | 38 ++++++++++++++++++++++++--------------
>   2 files changed, 24 insertions(+), 15 deletions(-)
>
> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
> index 8d1e457..f245395 100644
> --- a/arch/mips/include/asm/gic.h
> +++ b/arch/mips/include/asm/gic.h
> @@ -345,7 +345,6 @@
>   extern unsigned int gic_present;
>   extern unsigned int gic_frequency;
>   extern unsigned long _gic_base;
> -extern unsigned int gic_irq_flags[];
>   extern unsigned int gic_cpu_pin;
>   
>   extern void gic_init(unsigned long gic_base_addr,
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index c9ba102..6682a4e 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -24,7 +24,6 @@
>   unsigned int gic_frequency;
>   unsigned int gic_present;
>   unsigned long _gic_base;
> -unsigned int gic_irq_flags[GIC_NUM_INTRS];
>   unsigned int gic_cpu_pin;
>   
>   struct gic_pcpu_mask {
> @@ -44,6 +43,7 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
>   static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
>   static struct irq_domain *gic_irq_domain;
>   static int gic_shared_intrs;
> +static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
>   
>   static void __gic_irq_dispatch(void);
>   
> @@ -228,11 +228,7 @@ static void gic_ack_irq(struct irq_data *d)
>   {
>   	unsigned int irq = d->hwirq;
>   
> -	GIC_CLR_INTR_MASK(irq);
> -
> -	/* Clear edge detector */
> -	if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
> -		GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
> +	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
>   }
>   
>   static int gic_set_type(struct irq_data *d, unsigned int type)
> @@ -275,11 +271,13 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
>   	}
>   
>   	if (is_edge) {
> -		gic_irq_flags[irq] |= GIC_TRIG_EDGE;
> -		__irq_set_handler_locked(d->irq, handle_edge_irq);
> +		__irq_set_chip_handler_name_locked(d->irq,
> +						   &gic_edge_irq_controller,
> +						   handle_edge_irq, NULL);
>   	} else {
> -		gic_irq_flags[irq] &= ~GIC_TRIG_EDGE;
> -		__irq_set_handler_locked(d->irq, handle_level_irq);
> +		__irq_set_chip_handler_name_locked(d->irq,
> +						   &gic_level_irq_controller,
> +						   handle_level_irq, NULL);
>   	}
>   
>   	return 0;
> @@ -318,11 +316,23 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
>   }
>   #endif
>   
> -static struct irq_chip gic_irq_controller = {
> +static struct irq_chip gic_level_irq_controller = {
> +	.name			=	"MIPS GIC",
> +	.irq_ack		=	gic_mask_irq,
> +	.irq_mask		=	gic_mask_irq,
> +	.irq_mask_ack		=	gic_mask_irq,
> +	.irq_unmask		=	gic_unmask_irq,
> +	.irq_eoi		=	gic_unmask_irq,
> +	.irq_set_type		=	gic_set_type,
> +#ifdef CONFIG_SMP
> +	.irq_set_affinity	=	gic_set_affinity,
> +#endif
> +};
> +

I don't think there's a need to provide irq_ack, irq_mask_ack and 
irq_eoi here.

> +static struct irq_chip gic_edge_irq_controller = {
>   	.name			=	"MIPS GIC",
>   	.irq_ack		=	gic_ack_irq,
>   	.irq_mask		=	gic_mask_irq,
> -	.irq_mask_ack		=	gic_ack_irq,
>   	.irq_unmask		=	gic_unmask_irq,
>   	.irq_eoi		=	gic_unmask_irq,
>   	.irq_set_type		=	gic_set_type,

irq_eoi can be removed from here as well.

Qais

> @@ -433,7 +443,6 @@ static void __init gic_basic_init(int numvpes)
>   		GIC_SET_POLARITY(i, GIC_POL_POS);
>   		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
>   		GIC_CLR_INTR_MASK(i);
> -		gic_irq_flags[i] = 0;
>   	}
>   
>   	vpe_local_setup(numvpes);
> @@ -442,7 +451,8 @@ static void __init gic_basic_init(int numvpes)
>   static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
>   			      irq_hw_number_t hw)
>   {
> -	irq_set_chip_and_handler(virq, &gic_irq_controller, handle_level_irq);
> +	irq_set_chip_and_handler(virq, &gic_level_irq_controller,
> +				 handle_level_irq);
>   
>   	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
>   		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 21/24] irqchip: mips-gic: Support local interrupts
  2014-09-15 23:51 ` [PATCH 21/24] irqchip: mips-gic: Support local interrupts Andrew Bresticker
@ 2014-09-17  9:50   ` Qais Yousef
  2014-09-17 17:40     ` Andrew Bresticker
  0 siblings, 1 reply; 40+ messages in thread
From: Qais Yousef @ 2014-09-17  9:50 UTC (permalink / raw)
  To: Andrew Bresticker, Ralf Baechle, Thomas Gleixner, Jason Cooper
  Cc: Jeffrey Deans, Markos Chandras, Paul Burton, Jonas Gorski,
	John Crispin, David Daney, linux-mips, linux-kernel

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> The MIPS GIC supports 7 local interrupts, 2 of which are the GIC
> local watchdog and count/compare timer.  The remainder are CPU
> interrupts which may optionally be re-routed through the GIC.
> GIC hardware IRQs 0-6 are now used for local interrupts while
> hardware IRQs 7+ are used for external (shared) interrupts.
>
> Note that the 5 CPU interrupts may not be re-routable through
> the GIC.  In that case mapping will fail and the vectors reported
> in C0_IntCtl should be used instead.  gic_get_c0_compare_int() and
> gic_get_c0_perfcount_int() will return the correct IRQ number to
> use for the C0 timer and perfcounter interrupts based on the
> routability of those interrupts through the GIC.
>
> Malta, SEAD-3, and the GIC clockevent driver have been updated
> to use local interrupts and the R4K clockevent driver has been
> updated to poll for C0 timer interrupts through the GIC when
> the GIC is present.
>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> ---
>   arch/mips/include/asm/gic.h                  |  29 +++-
>   arch/mips/include/asm/mips-boards/maltaint.h |   4 +-
>   arch/mips/include/asm/mips-boards/sead3int.h |  10 +-
>   arch/mips/kernel/cevt-gic.c                  |  15 +-
>   arch/mips/kernel/cevt-r4k.c                  |   2 +-
>   arch/mips/mti-malta/malta-int.c              |   6 +-
>   arch/mips/mti-malta/malta-time.c             |  13 +-
>   arch/mips/mti-sead3/sead3-time.c             |  34 +---
>   drivers/irqchip/irq-mips-gic.c               | 244 +++++++++++++++++++--------
>   9 files changed, 232 insertions(+), 125 deletions(-)
>
> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
> index f245395..6b99610 100644
> --- a/arch/mips/include/asm/gic.h
> +++ b/arch/mips/include/asm/gic.h
> @@ -209,6 +209,7 @@
>   #define GIC_VPE_WD_MAP_OFS		0x0040
>   #define GIC_VPE_COMPARE_MAP_OFS		0x0044
>   #define GIC_VPE_TIMER_MAP_OFS		0x0048
> +#define GIC_VPE_FDC_MAP_OFS		0x004c
>   #define GIC_VPE_PERFCTR_MAP_OFS		0x0050
>   #define GIC_VPE_SWINT0_MAP_OFS		0x0054
>   #define GIC_VPE_SWINT1_MAP_OFS		0x0058
> @@ -262,6 +263,10 @@
>   #define GIC_MAP_MSK			(MSK(6) << GIC_MAP_SHF)
>   
>   /* GIC_VPE_CTL Masks */
> +#define GIC_VPE_CTL_FDC_RTBL_SHF	4
> +#define GIC_VPE_CTL_FDC_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_FDC_RTBL_SHF)
> +#define GIC_VPE_CTL_SWINT_RTBL_SHF	3
> +#define GIC_VPE_CTL_SWINT_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_SWINT_RTBL_SHF)
>   #define GIC_VPE_CTL_PERFCNT_RTBL_SHF	2
>   #define GIC_VPE_CTL_PERFCNT_RTBL_MSK	(MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF)
>   #define GIC_VPE_CTL_TIMER_RTBL_SHF	1
> @@ -329,16 +334,30 @@
>   /* Add 2 to convert GIC CPU pin to core interrupt */
>   #define GIC_CPU_PIN_OFFSET	2
>   
> -/* Local GIC interrupts. */
> -#define GIC_INT_TMR		(GIC_CPU_INT5)
> -#define GIC_INT_PERFCTR		(GIC_CPU_INT5)
> -
>   /* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */
>   #define GIC_CPU_TO_VEC_OFFSET	(2)
>   
>   /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
>   #define GIC_PIN_TO_VEC_OFFSET	(1)
>   
> +/* Local GIC interrupts. */
> +#define GIC_LOCAL_INT_WD	0 /* GIC watchdog */
> +#define GIC_LOCAL_INT_COMPARE	1 /* GIC count and compare timer */
> +#define GIC_LOCAL_INT_TIMER	2 /* CPU timer interrupt */
> +#define GIC_LOCAL_INT_PERFCTR	3 /* CPU performance counter */
> +#define GIC_LOCAL_INT_SWINT0	4 /* CPU software interrupt 0 */
> +#define GIC_LOCAL_INT_SWINT1	5 /* CPU software interrupt 1 */
> +#define GIC_LOCAL_INT_FDC	6 /* CPU fast debug channel */
> +#define GIC_NUM_LOCAL_INTRS	7
> +
> +/* Convert between local/shared IRQ number and GIC HW IRQ number. */
> +#define GIC_LOCAL_HWIRQ_BASE	0
> +#define GIC_LOCAL_TO_HWIRQ(x)	(GIC_LOCAL_HWIRQ_BASE + (x))
> +#define GIC_HWIRQ_TO_LOCAL(x)	((x) - GIC_LOCAL_HWIRQ_BASE)
> +#define GIC_SHARED_HWIRQ_BASE	GIC_NUM_LOCAL_INTRS
> +#define GIC_SHARED_TO_HWIRQ(x)	(GIC_SHARED_HWIRQ_BASE + (x))
> +#define GIC_HWIRQ_TO_SHARED(x)	((x) - GIC_SHARED_HWIRQ_BASE)
> +
>   #include <linux/clocksource.h>
>   #include <linux/irq.h>
>   
> @@ -363,4 +382,6 @@ extern void gic_bind_eic_interrupt(int irq, int set);
>   extern unsigned int gic_get_timer_pending(void);
>   extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
>   extern unsigned int gic_get_int(void);
> +extern int gic_get_c0_compare_int(void);
> +extern int gic_get_c0_perfcount_int(void);
>   #endif /* _ASM_GICREGS_H */
> diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
> index bdd6f39..38b06a0 100644
> --- a/arch/mips/include/asm/mips-boards/maltaint.h
> +++ b/arch/mips/include/asm/mips-boards/maltaint.h
> @@ -10,6 +10,8 @@
>   #ifndef _MIPS_MALTAINT_H
>   #define _MIPS_MALTAINT_H
>   
> +#include <asm/gic.h>
> +

nit: I think gic.h should be split to driver/irqchip/irq-mips-gic.h for 
private definitions and include/linux/irqchip/irq-mips-gic.h for 
exported/public definitions.

>   /*
>    * Interrupts 0..15 are used for Malta ISA compatible interrupts
>    */
> @@ -61,6 +63,6 @@
>   #define MSC01E_INT_CPUCTR	11
>   
>   /* GIC external interrupts */
> -#define GIC_INT_I8259A		3
> +#define GIC_INT_I8259A		GIC_SHARED_TO_HWIRQ(3)
>   
>   #endif /* !(_MIPS_MALTAINT_H) */
> diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
> index a2e0095..59d6c32 100644
> --- a/arch/mips/include/asm/mips-boards/sead3int.h
> +++ b/arch/mips/include/asm/mips-boards/sead3int.h
> @@ -10,6 +10,8 @@
>   #ifndef _MIPS_SEAD3INT_H
>   #define _MIPS_SEAD3INT_H
>   
> +#include <asm/gic.h>
> +
>   /* SEAD-3 GIC address space definitions. */
>   #define GIC_BASE_ADDR		0x1b1c0000
>   #define GIC_ADDRSPACE_SZ	(128 * 1024)
> @@ -22,9 +24,9 @@
>   #define CPU_INT_NET		6
>   
>   /* GIC interrupt offsets */
> -#define GIC_INT_NET		0
> -#define GIC_INT_UART1		2
> -#define GIC_INT_UART0		3
> -#define GIC_INT_EHCI		5
> +#define GIC_INT_NET		GIC_SHARED_TO_HWIRQ(0)
> +#define GIC_INT_UART1		GIC_SHARED_TO_HWIRQ(2)
> +#define GIC_INT_UART0		GIC_SHARED_TO_HWIRQ(3)
> +#define GIC_INT_EHCI		GIC_SHARED_TO_HWIRQ(5)
>   
>   #endif /* !(_MIPS_SEAD3INT_H) */
> diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
> index a90bd4c..4f9262a 100644
> --- a/arch/mips/kernel/cevt-gic.c
> +++ b/arch/mips/kernel/cevt-gic.c
> @@ -68,7 +68,7 @@ int gic_clockevent_init(void)
>   	if (!cpu_has_counter || !gic_frequency)
>   		return -ENXIO;
>   
> -	irq = MIPS_GIC_IRQ_BASE;
> +	irq = MIPS_GIC_IRQ_BASE + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE);
>   
>   	cd = &per_cpu(gic_clockevent_device, cpu);
>   
> @@ -91,16 +91,13 @@ int gic_clockevent_init(void)
>   
>   	clockevents_register_device(cd);
>   
> -	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP),
> -		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
> -	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
> +	if (!gic_timer_irq_installed) {
> +		setup_percpu_irq(irq, &gic_compare_irqaction);
> +		gic_timer_irq_installed = 1;
> +	}
>   
> -	if (gic_timer_irq_installed)
> -		return 0;
> +	enable_percpu_irq(irq, IRQ_TYPE_NONE);
>   
> -	gic_timer_irq_installed = 1;
>   
> -	setup_irq(irq, &gic_compare_irqaction);
> -	irq_set_handler(irq, handle_percpu_irq);
>   	return 0;
>   }
> diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
> index 5b8f8e3..fd0ef8d 100644
> --- a/arch/mips/kernel/cevt-r4k.c
> +++ b/arch/mips/kernel/cevt-r4k.c
> @@ -86,7 +86,7 @@ void mips_event_handler(struct clock_event_device *dev)
>   static int c0_compare_int_pending(void)
>   {
>   #ifdef CONFIG_MIPS_GIC
> -	if (cpu_has_veic)
> +	if (gic_present)
>   		return gic_get_timer_pending();
>   #endif
>   	return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
> diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
> index 3b3bc1d..c6b3548 100644
> --- a/arch/mips/mti-malta/malta-int.c
> +++ b/arch/mips/mti-malta/malta-int.c
> @@ -273,11 +273,7 @@ asmlinkage void plat_irq_dispatch(void)
>   
>   	irq = irq_ffs(pending);
>   
> -	/* HACK: GIC doesn't properly dispatch local interrupts yet */
> -	if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int())
> -		do_IRQ(MIPS_GIC_IRQ_BASE);
> -	else
> -		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
> +	do_IRQ(MIPS_CPU_IRQ_BASE + irq);
>   }
>   
>   #ifdef CONFIG_MIPS_MT_SMP
> diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
> index 17cfc8a..f6ca8ea 100644
> --- a/arch/mips/mti-malta/malta-time.c
> +++ b/arch/mips/mti-malta/malta-time.c
> @@ -126,9 +126,9 @@ int get_c0_perfcount_int(void)
>   	if (cpu_has_veic) {
>   		set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
>   		mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
> +	} else if (gic_present) {
> +		mips_cpu_perf_irq = gic_get_c0_perfcount_int();
>   	} else if (cp0_perfcount_irq >= 0) {
> -		if (cpu_has_vint)
> -			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
>   		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
>   	} else {
>   		mips_cpu_perf_irq = -1;
> @@ -139,15 +139,12 @@ int get_c0_perfcount_int(void)
>   
>   unsigned int get_c0_compare_int(void)
>   {
> -#ifdef MSC01E_INT_BASE
>   	if (cpu_has_veic) {
>   		set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
>   		mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
> -	} else
> -#endif
> -	{
> -		if (cpu_has_vint)
> -			set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
> +	} else if (gic_present) {
> +		mips_cpu_timer_irq = gic_get_c0_compare_int();
> +	} else {
>   		mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
>   	}
>   
> diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c
> index f090c51..fd40de3 100644
> --- a/arch/mips/mti-sead3/sead3-time.c
> +++ b/arch/mips/mti-sead3/sead3-time.c
> @@ -8,24 +8,12 @@
>   #include <linux/init.h>
>   
>   #include <asm/cpu.h>
> +#include <asm/gic.h>
>   #include <asm/setup.h>
>   #include <asm/time.h>
>   #include <asm/irq.h>
>   #include <asm/mips-boards/generic.h>
>   
> -static int mips_cpu_timer_irq;
> -static int mips_cpu_perf_irq;
> -
> -static void mips_timer_dispatch(void)
> -{
> -	do_IRQ(mips_cpu_timer_irq);
> -}
> -
> -static void mips_perf_dispatch(void)
> -{
> -	do_IRQ(mips_cpu_perf_irq);
> -}
> -
>   static void __iomem *status_reg = (void __iomem *)0xbf000410;
>   
>   /*
> @@ -83,22 +71,18 @@ void read_persistent_clock(struct timespec *ts)
>   
>   int get_c0_perfcount_int(void)
>   {
> -	if (cp0_perfcount_irq >= 0) {
> -		if (cpu_has_vint)
> -			set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
> -		mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
> -	} else {
> -		mips_cpu_perf_irq = -1;
> -	}
> -	return mips_cpu_perf_irq;
> +	if (gic_present)
> +		return gic_get_c0_compare_int();
> +	if (cp0_perfcount_irq >= 0)
> +		return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
> +	return -1;
>   }
>   
>   unsigned int get_c0_compare_int(void)
>   {
> -	if (cpu_has_vint)
> -		set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
> -	mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
> -	return mips_cpu_timer_irq;
> +	if (gic_present)
> +		return gic_get_c0_compare_int();
> +	return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
>   }
>   
>   void __init plat_time_init(void)
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index 6682a4e..3abe310 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -43,6 +43,7 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
>   static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
>   static struct irq_domain *gic_irq_domain;
>   static int gic_shared_intrs;
> +static int gic_vpes;
>   static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
>   
>   static void __gic_irq_dispatch(void);
> @@ -95,12 +96,39 @@ cycle_t gic_read_compare(void)
>   }
>   #endif
>   
> +static bool gic_local_irq_is_routable(int intr)
> +{
> +	u32 vpe_ctl;
> +
> +	/* All local interrupts are routable in EIC mode. */
> +	if (cpu_has_veic)
> +		return true;
> +
> +	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
> +	switch (intr) {
> +	case GIC_LOCAL_INT_TIMER:
> +		return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
> +	case GIC_LOCAL_INT_PERFCTR:
> +		return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
> +	case GIC_LOCAL_INT_FDC:
> +		return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
> +	case GIC_LOCAL_INT_SWINT0:
> +	case GIC_LOCAL_INT_SWINT1:
> +		/*
> +		 * SWINT{0,1} are not routable in non-EIC mode, regardless
> +		 * of the setting of SWINT_ROUTABLE.
> +		 */
> +		return false;

Hmm AFAIK they are routable. Actually from hard reset they're 
automatically routed to vpe0 pin 0 which caught me a number of times 
when trying to use software interrupt on hardware that has GIC. When 
setting software interrupt I was seeing pin 0 going high too and thought 
it's a hardware bug for a while.

I think all local interrupts should be masked at GIC initialisation 
except for timer interrupt. I was preparing a set of patches for GIC but 
you beat me into it :)

> +	default:
> +		return true;
> +	}
> +}
> +
>   unsigned int gic_get_timer_pending(void)
>   {
>   	unsigned int vpe_pending;
>   
> -	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
> -	GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
> +	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), vpe_pending);
>   	return (vpe_pending & GIC_VPE_PEND_TIMER_MSK);
>   }
>   
> @@ -118,53 +146,6 @@ void gic_send_ipi(unsigned int intr)
>   	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
>   }
>   
> -static void __init vpe_local_setup(unsigned int numvpes)
> -{
> -	unsigned long timer_intr = GIC_INT_TMR;
> -	unsigned long perf_intr = GIC_INT_PERFCTR;
> -	unsigned int vpe_ctl;
> -	int i;
> -
> -	if (cpu_has_veic) {
> -		/*
> -		 * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
> -		 * map to pin X+2-1 (since GIC adds 1)
> -		 */
> -		timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
> -		/*
> -		 * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
> -		 * map to pin X+2-1 (since GIC adds 1)
> -		 */
> -		perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
> -	}
> -
> -	/*
> -	 * Setup the default performance counter timer interrupts
> -	 * for all VPEs
> -	 */
> -	for (i = 0; i < numvpes; i++) {
> -		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
> -
> -		/* Are Interrupts locally routable? */
> -		GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
> -		if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
> -			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
> -				 GIC_MAP_TO_PIN_MSK | timer_intr);
> -		if (cpu_has_veic) {
> -			set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
> -				       __gic_irq_dispatch);
> -		}
> -
> -		if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
> -			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
> -				 GIC_MAP_TO_PIN_MSK | perf_intr);
> -		if (cpu_has_veic) {
> -			set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET,
> -				       __gic_irq_dispatch);
> -		}
> -	}
> -}
> -
>   unsigned int gic_compare_int(void)
>   {
>   	unsigned int pending;
> @@ -176,6 +157,26 @@ unsigned int gic_compare_int(void)
>   		return 0;
>   }
>   
> +int gic_get_c0_compare_int(void)
> +{
> +	if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
> +		return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
> +	return irq_create_mapping(gic_irq_domain,
> +				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER));
> +}
> +
> +int gic_get_c0_perfcount_int(void)
> +{
> +	if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) {
> +		/* Is the erformance counter shared with the timer? */
> +		if (cp0_perfcount_irq < 0)
> +			return -1;
> +		return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
> +	}
> +	return irq_create_mapping(gic_irq_domain,
> +				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
> +}
> +
>   void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
>   {
>   	unsigned int i;
> @@ -216,24 +217,24 @@ unsigned int gic_get_int(void)
>   
>   static void gic_mask_irq(struct irq_data *d)
>   {
> -	GIC_CLR_INTR_MASK(d->hwirq);
> +	GIC_CLR_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
>   }
>   
>   static void gic_unmask_irq(struct irq_data *d)
>   {
> -	GIC_SET_INTR_MASK(d->hwirq);
> +	GIC_SET_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
>   }
>   
>   static void gic_ack_irq(struct irq_data *d)
>   {
> -	unsigned int irq = d->hwirq;
> +	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
>   
>   	GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
>   }
>   
>   static int gic_set_type(struct irq_data *d, unsigned int type)
>   {
> -	unsigned int irq = d->hwirq;
> +	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
>   	bool is_edge;
>   
>   	switch (type & IRQ_TYPE_SENSE_MASK) {
> @@ -289,7 +290,7 @@ static DEFINE_SPINLOCK(gic_lock);
>   static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
>   			    bool force)
>   {
> -	unsigned int irq = d->hwirq;
> +	unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
>   	cpumask_t	tmp = CPU_MASK_NONE;
>   	unsigned long	flags;
>   	int		i;
> @@ -341,12 +342,54 @@ static struct irq_chip gic_edge_irq_controller = {
>   #endif
>   };
>   
> +static unsigned int gic_get_local_int(void)
> +{
> +	unsigned long pending, masked;
> +
> +	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
> +	GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked);
> +
> +	bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
> +
> +	return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
> +}
> +
> +static void gic_mask_local_irq(struct irq_data *d)
> +{
> +	int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
> +
> +	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
> +}
> +
> +static void gic_unmask_local_irq(struct irq_data *d)
> +{
> +	int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
> +
> +	GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
> +}
> +
> +static struct irq_chip gic_local_irq_controller = {
> +	.name			=	"MIPS GIC Local",
> +	.irq_ack		=	gic_mask_local_irq,
> +	.irq_mask		=	gic_mask_local_irq,
> +	.irq_mask_ack		=	gic_mask_local_irq,
> +	.irq_unmask		=	gic_unmask_local_irq,
> +	.irq_eoi		=	gic_unmask_local_irq,
> +};
> +

again I don't think irq_ack, irq_mask_ack and irq_eoi are needed.

nice clean up here too :)

Qais

>   static void __gic_irq_dispatch(void)
>   {
>   	unsigned int intr, virq;
>   
> +	while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
> +		virq = irq_linear_revmap(gic_irq_domain,
> +					 GIC_LOCAL_TO_HWIRQ(intr));
> +		do_IRQ(virq);
> +	}
> +
>   	while ((intr = gic_get_int()) != gic_shared_intrs) {
> -		virq = irq_linear_revmap(gic_irq_domain, intr);
> +		virq = irq_linear_revmap(gic_irq_domain,
> +					 GIC_SHARED_TO_HWIRQ(intr));
>   		do_IRQ(virq);
>   	}
>   }
> @@ -399,7 +442,8 @@ static struct irqaction irq_call = {
>   static __init void gic_ipi_init_one(unsigned int intr, int cpu,
>   				    struct irqaction *action)
>   {
> -	int virq = irq_create_mapping(gic_irq_domain, intr);
> +	int virq = irq_create_mapping(gic_irq_domain,
> +				      GIC_SHARED_TO_HWIRQ(intr));
>   	int i;
>   
>   	GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
> @@ -432,7 +476,7 @@ static inline void gic_ipi_init(void)
>   }
>   #endif
>   
> -static void __init gic_basic_init(int numvpes)
> +static void __init gic_basic_init(void)
>   {
>   	unsigned int i;
>   
> @@ -444,25 +488,89 @@ static void __init gic_basic_init(int numvpes)
>   		GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
>   		GIC_CLR_INTR_MASK(i);
>   	}
> +}
> +
> +static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
> +				    irq_hw_number_t hw)
> +{
> +	int intr = GIC_HWIRQ_TO_LOCAL(hw);
> +	int i;
> +
> +	if (!gic_local_irq_is_routable(intr))
> +		return -EPERM;
>   
> -	vpe_local_setup(numvpes);
> +	irq_set_chip_and_handler(virq, &gic_local_irq_controller,
> +				 handle_percpu_irq);
> +
> +	/*
> +	 * HACK: These are all really percpu interrupts, but the rest
> +	 * of the MIPS kernel code does not use the percpu IRQ API for
> +	 * the CP0 timer and performance counter interrupts.
> +	 */
> +	if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR)
> +		irq_set_percpu_devid(virq);
> +
> +	for (i = 0; i < gic_vpes; i++) {
> +		u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
> +
> +		GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
> +
> +		switch (intr) {
> +		case GIC_LOCAL_INT_WD:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_COMPARE:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_TIMER:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_PERFCTR:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_SWINT0:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_SWINT1:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val);
> +			break;
> +		case GIC_LOCAL_INT_FDC:
> +			GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
> +			break;
> +		default:
> +			pr_err("Invalid local IRQ %d\n", intr);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
>   }
>   
> -static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
> -			      irq_hw_number_t hw)
> +static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
> +				     irq_hw_number_t hw)
>   {
> +	int intr = GIC_HWIRQ_TO_SHARED(hw);
> +
>   	irq_set_chip_and_handler(virq, &gic_level_irq_controller,
>   				 handle_level_irq);
>   
> -	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)),
> +	GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
>   		 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
>   	/* Map to VPE 0 by default */
> -	GIC_SH_MAP_TO_VPE_SMASK(hw, 0);
> -	set_bit(hw, pcpu_masks[0].pcpu_mask);
> +	GIC_SH_MAP_TO_VPE_SMASK(intr, 0);
> +	set_bit(intr, pcpu_masks[0].pcpu_mask);
>   
>   	return 0;
>   }
>   
> +static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
> +			      irq_hw_number_t hw)
> +{
> +	if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS)
> +		return gic_local_irq_domain_map(d, virq, hw);
> +	return gic_shared_irq_domain_map(d, virq, hw);
> +}
> +
>   static struct irq_domain_ops gic_irq_domain_ops = {
>   	.map = gic_irq_domain_map,
>   	.xlate = irq_domain_xlate_twocell,
> @@ -473,7 +581,6 @@ void __init gic_init(unsigned long gic_base_addr,
>   		     unsigned int irqbase)
>   {
>   	unsigned int gicconfig;
> -	int numvpes, numintrs;
>   
>   	_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
>   						    gic_addrspace_size);
> @@ -483,9 +590,9 @@ void __init gic_init(unsigned long gic_base_addr,
>   		   GIC_SH_CONFIG_NUMINTRS_SHF;
>   	gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
>   
> -	numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
> +	gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
>   		  GIC_SH_CONFIG_NUMVPES_SHF;
> -	numvpes = numvpes + 1;
> +	gic_vpes = gic_vpes + 1;
>   
>   	if (cpu_has_veic) {
>   		/* Always use vector 1 in EIC mode */
> @@ -498,12 +605,13 @@ void __init gic_init(unsigned long gic_base_addr,
>   					gic_irq_dispatch);
>   	}
>   
> -	gic_irq_domain = irq_domain_add_simple(NULL, gic_shared_intrs, irqbase,
> +	gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS +
> +					       gic_shared_intrs, irqbase,
>   					       &gic_irq_domain_ops, NULL);
>   	if (!gic_irq_domain)
>   		panic("Failed to add GIC IRQ domain");
>   
> -	gic_basic_init(numvpes);
> +	gic_basic_init();
>   
>   	gic_ipi_init();
>   }


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/24] MIPS GIC cleanup, part 1
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (23 preceding siblings ...)
  2014-09-15 23:51 ` [PATCH 24/24] MIPS: sead3: " Andrew Bresticker
@ 2014-09-17 10:20 ` Qais Yousef
  2014-09-17 17:42   ` Andrew Bresticker
  2014-09-17 14:07 ` Jason Cooper
  25 siblings, 1 reply; 40+ messages in thread
From: Qais Yousef @ 2014-09-17 10:20 UTC (permalink / raw)
  To: Andrew Bresticker, Jason Cooper
  Cc: Ralf Baechle, Thomas Gleixner, Jeffrey Deans, Markos Chandras,
	Paul Burton, Jonas Gorski, John Crispin, David Daney, linux-mips,
	linux-kernel

On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
> The current MIPS GIC driver and the platform code using it are rather
> ugly and could use a good cleanup before adding device-tree support [0].
> This major issues addressed in this series are converting the GIC (and
> platforms using it) to use IRQ domains and properly mapping interrupts
> through the GIC instead of using it transparently.  For part 2 I plan
> on: updating the driver to use proper iomem accessors, cleaning up and
> moving the GIC clocksource driver to drivers/clocksource/, adding DT
> support, and possibly converting the GIC driver to use generic irqchip.
>
> Patches 1-16 are cleanups for the existing GIC driver and prepare platforms
> using it for the switch to IRQ domains and using the GIC in a non-transparent
> way.
>
> Patches 17-24 convert the GIC driver to use IRQ domains and updates the
> platforms using it to properly map GIC interrupts instead of using the static
> routing tables to make the GIC appear transparent.
>
> I've tested this series on Malta and, with additional patches, on the
> DT-enabled Danube platform.  Unfortunately I do not have SEAD-3 hardware,
> so that has only been compile tested.  Compile tested on all other affected
> architectures (ath79, ralink, lantiq).

I boot tested this on sead3 without problems.

Cheers,
Qais

>
> [0] https://lkml.org/lkml/2014/9/5/542
>
> Andrew Bresticker (24):
>    MIPS: Always use IRQ domains for CPU IRQs
>    MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init()
>    MIPS: Provide a generic plat_irq_dispatch
>    MIPS: Set vint handler when mapping CPU interrupts
>    MIPS: i8259: Use IRQ domains
>    MIPS: Add hook to get C0 performance counter interrupt
>    MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs
>    MIPS: Remove gic_{enable,disable}_interrupt()
>    MIPS: sead3: Remove sead3-serial.c
>    MIPS: sead3: Do not overlap CPU/GIC IRQ ranges
>    MIPS: Malta: Move MSC01 interrupt base
>    MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h
>    MIPS: Move GIC to drivers/irqchip/
>    irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
>    irqchip: mips-gic: Implement irq_set_type callback
>    irqchip: mips-gic: Fix gic_set_affinity() return value
>    irqchip: mips-gic: Use IRQ domains
>    irqchip: mips-gic: Stop using per-platform mapping tables
>    irqchip: mips-gic: Probe for number of external interrupts
>    irqchip: mips-gic: Use separate edge/level irq_chips
>    irqchip: mips-gic: Support local interrupts
>    irqchip: mips-gic: Remove unnecessary globals
>    MIPS: Malta: Use generic plat_irq_dispatch
>    MIPS: sead3: Use generic plat_irq_dispatch
>
>   Documentation/devicetree/bindings/mips/cpu_irq.txt |   4 +-
>   arch/mips/Kconfig                                  |  12 +-
>   arch/mips/ath79/irq.c                              |   1 -
>   arch/mips/ath79/setup.c                            |   5 +
>   arch/mips/include/asm/gic.h                        |  82 ++-
>   arch/mips/include/asm/irq_cpu.h                    |   4 +-
>   arch/mips/include/asm/mach-generic/irq.h           |   6 +
>   arch/mips/include/asm/mach-malta/irq.h             |   1 -
>   arch/mips/include/asm/mach-sead3/irq.h             |   1 -
>   arch/mips/include/asm/mips-boards/maltaint.h       |  24 +-
>   arch/mips/include/asm/mips-boards/sead3int.h       |  15 +-
>   arch/mips/include/asm/time.h                       |   1 +
>   arch/mips/kernel/Makefile                          |   1 -
>   arch/mips/kernel/cevt-gic.c                        |  14 +-
>   arch/mips/kernel/cevt-r4k.c                        |   4 +-
>   arch/mips/kernel/i8259.c                           |  24 +-
>   arch/mips/kernel/irq-gic.c                         | 402 --------------
>   arch/mips/kernel/irq_cpu.c                         |  45 +-
>   arch/mips/kernel/perf_event_mipsxx.c               |  23 +-
>   arch/mips/kernel/smp-cps.c                         |   4 +-
>   arch/mips/kernel/smp-mt.c                          |   4 +-
>   arch/mips/lantiq/irq.c                             |   8 +-
>   arch/mips/mti-malta/malta-int.c                    | 307 ++---------
>   arch/mips/mti-malta/malta-time.c                   |  39 +-
>   arch/mips/mti-sead3/sead3-ehci.c                   |   8 +-
>   arch/mips/mti-sead3/sead3-int.c                    | 121 +----
>   arch/mips/mti-sead3/sead3-net.c                    |  14 +-
>   arch/mips/mti-sead3/sead3-platform.c               |  18 +-
>   arch/mips/mti-sead3/sead3-serial.c                 |  45 --
>   arch/mips/mti-sead3/sead3-time.c                   |  35 +-
>   arch/mips/oprofile/op_model_mipsxx.c               |  18 +-
>   arch/mips/ralink/irq.c                             |  10 +-
>   drivers/irqchip/Kconfig                            |   4 +
>   drivers/irqchip/Makefile                           |   1 +
>   drivers/irqchip/irq-mips-gic.c                     | 597 +++++++++++++++++++++
>   35 files changed, 867 insertions(+), 1035 deletions(-)
>   delete mode 100644 arch/mips/kernel/irq-gic.c
>   delete mode 100644 arch/mips/mti-sead3/sead3-serial.c
>   create mode 100644 drivers/irqchip/irq-mips-gic.c
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/24] MIPS GIC cleanup, part 1
  2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
                   ` (24 preceding siblings ...)
  2014-09-17 10:20 ` [PATCH 00/24] MIPS GIC cleanup, part 1 Qais Yousef
@ 2014-09-17 14:07 ` Jason Cooper
  25 siblings, 0 replies; 40+ messages in thread
From: Jason Cooper @ 2014-09-17 14:07 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Ralf Baechle, Thomas Gleixner, Jeffrey Deans, Markos Chandras,
	Paul Burton, Qais Yousef, Jonas Gorski, John Crispin,
	David Daney, linux-mips, linux-kernel

Andrew,

First, great work!

On Mon, Sep 15, 2014 at 04:51:03PM -0700, Andrew Bresticker wrote:
> The current MIPS GIC driver and the platform code using it are rather
> ugly and could use a good cleanup before adding device-tree support [0].
> This major issues addressed in this series are converting the GIC (and
> platforms using it) to use IRQ domains and properly mapping interrupts
> through the GIC instead of using it transparently.  For part 2 I plan
> on: updating the driver to use proper iomem accessors, cleaning up and
> moving the GIC clocksource driver to drivers/clocksource/, adding DT
> support, and possibly converting the GIC driver to use generic irqchip.
> 
> Patches 1-16 are cleanups for the existing GIC driver and prepare platforms
> using it for the switch to IRQ domains and using the GIC in a non-transparent
> way.
> 
> Patches 17-24 convert the GIC driver to use IRQ domains and updates the
> platforms using it to properly map GIC interrupts instead of using the static
> routing tables to make the GIC appear transparent.
> 
> I've tested this series on Malta and, with additional patches, on the
> DT-enabled Danube platform.  Unfortunately I do not have SEAD-3 hardware,
> so that has only been compile tested.  Compile tested on all other affected
> architectures (ath79, ralink, lantiq).
> 
> [0] https://lkml.org/lkml/2014/9/5/542
> 
> Andrew Bresticker (24):
...
>   MIPS: Move GIC to drivers/irqchip/
>   irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
>   irqchip: mips-gic: Implement irq_set_type callback
>   irqchip: mips-gic: Fix gic_set_affinity() return value
>   irqchip: mips-gic: Use IRQ domains
>   irqchip: mips-gic: Stop using per-platform mapping tables
>   irqchip: mips-gic: Probe for number of external interrupts
>   irqchip: mips-gic: Use separate edge/level irq_chips
>   irqchip: mips-gic: Support local interrupts
>   irqchip: mips-gic: Remove unnecessary globals
...
>  drivers/irqchip/Kconfig                            |   4 +
>  drivers/irqchip/Makefile                           |   1 +
>  drivers/irqchip/irq-mips-gic.c                     | 597 +++++++++++++++++++++

It would be too much of a pia to have this go through irqchip, so

Acked-by: Jason Cooper <jason@lakedaemon.net>

Please make sure to add the Tested-by's, etc before merging through
mips.

thx,

Jason.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch
  2014-09-17  8:56   ` Qais Yousef
@ 2014-09-17 16:36     ` Andrew Bresticker
  0 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 16:36 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 1:56 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
> Hi Andrew,
>
>
> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>
>> For platforms which boot with device-tree or have correctly chained
>> all external interrupt controllers, a generic plat_irq_dispatch() can
>> be used.  Implement a plat_irq_dispatch() which simply handles all the
>> pending interrupts as reported by C0_Cause.
>>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> ---
>>   arch/mips/kernel/irq_cpu.c | 15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
>> index ca98a9f..f17bd08 100644
>> --- a/arch/mips/kernel/irq_cpu.c
>> +++ b/arch/mips/kernel/irq_cpu.c
>> @@ -94,6 +94,21 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
>>         .irq_eoi        = unmask_mips_irq,
>>   };
>>   +asmlinkage void __weak plat_irq_dispatch(void)
>> +{
>> +       unsigned long pending = read_c0_cause() & read_c0_status() &
>> ST0_IM;
>> +       int irq;
>> +
>> +       if (!pending) {
>> +               spurious_interrupt();
>> +               return;
>> +       }
>> +
>> +       pending >>= CAUSEB_IP;
>> +       for_each_set_bit(irq, &pending, 8)
>> +               do_IRQ(MIPS_CPU_IRQ_BASE + irq);
>> +}
>> +
>
>
> If I read the for_each_set_bit() macro correctly it'll iterate through the
> bits from least to most significant ones which is the reversed priority
> expected. Some platforms set timer interrupt to bit 7 which is should be the
> highest priority interrupt. Also when cpu_has_vint is set the hardware
> prioritirise from most significant to least significant bits so if
> plat_irq_dispatch() is used with set_vi_handler() it'll cause interrupts to
> be serviced in the wrong order.

Ah, right.  I'll flip the order here.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks
  2014-09-17  9:14   ` Qais Yousef
@ 2014-09-17 17:14     ` Andrew Bresticker
  0 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 17:14 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 2:14 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
> Hi Andrew,
>
>
> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>
>> There's no need for platforms to have their own GIC irq_ack/irq_eoi
>> callbacks.  Move them to the GIC irqchip driver.
>>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> ---
>>   arch/mips/include/asm/gic.h     |  2 --
>>   arch/mips/mti-malta/malta-int.c | 16 ----------------
>>   arch/mips/mti-sead3/sead3-int.c | 21 ---------------------
>>   drivers/irqchip/irq-mips-gic.c  | 15 ++++++++++++---
>>   4 files changed, 12 insertions(+), 42 deletions(-)
>>
>> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
>> index 022d831..1bf7985 100644
>> --- a/arch/mips/include/asm/gic.h
>> +++ b/arch/mips/include/asm/gic.h
>> @@ -376,7 +376,5 @@ extern void gic_bind_eic_interrupt(int irq, int set);
>>   extern unsigned int gic_get_timer_pending(void);
>>   extern void gic_get_int_mask(unsigned long *dst, const unsigned long
>> *src);
>>   extern unsigned int gic_get_int(void);
>> -extern void gic_irq_ack(struct irq_data *d);
>> -extern void gic_finish_irq(struct irq_data *d);
>>   extern void gic_platform_init(int irqs, struct irq_chip
>> *irq_controller);
>>   #endif /* _ASM_GICREGS_H */
>> diff --git a/arch/mips/mti-malta/malta-int.c
>> b/arch/mips/mti-malta/malta-int.c
>> index 5c31208..b60adfd 100644
>> --- a/arch/mips/mti-malta/malta-int.c
>> +++ b/arch/mips/mti-malta/malta-int.c
>> @@ -715,22 +715,6 @@ int malta_be_handler(struct pt_regs *regs, int
>> is_fixup)
>>         return retval;
>>   }
>>   -void gic_irq_ack(struct irq_data *d)
>> -{
>> -       int irq = (d->irq - gic_irq_base);
>> -
>> -       GIC_CLR_INTR_MASK(irq);
>> -
>> -       if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
>> -               GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
>> -}
>> -
>> -void gic_finish_irq(struct irq_data *d)
>> -{
>> -       /* Enable interrupts. */
>> -       GIC_SET_INTR_MASK(d->irq - gic_irq_base);
>> -}
>> -
>>   void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
>>   {
>>         int i;
>> diff --git a/arch/mips/mti-sead3/sead3-int.c
>> b/arch/mips/mti-sead3/sead3-int.c
>> index 9d5b5bd..03f9865 100644
>> --- a/arch/mips/mti-sead3/sead3-int.c
>> +++ b/arch/mips/mti-sead3/sead3-int.c
>> @@ -85,27 +85,6 @@ void __init arch_init_irq(void)
>>                         ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
>>   }
>>   -void gic_irq_ack(struct irq_data *d)
>> -{
>> -       GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
>> -}
>> -
>> -void gic_finish_irq(struct irq_data *d)
>> -{
>> -       unsigned int irq = (d->irq - gic_irq_base);
>> -       unsigned int i, irq_source;
>> -
>> -       /* Clear edge detectors. */
>> -       for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) {
>> -               irq_source = gic_shared_intr_map[irq].intr_list[i];
>> -               if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE)
>> -                       GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE),
>> irq_source);
>> -       }
>> -
>> -       /* Enable interrupts. */
>> -       GIC_SET_INTR_MASK(irq);
>> -}
>> -
>>   void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
>>   {
>>         int i;
>> diff --git a/drivers/irqchip/irq-mips-gic.c
>> b/drivers/irqchip/irq-mips-gic.c
>> index 9e9d8b9..0dc2972 100644
>> --- a/drivers/irqchip/irq-mips-gic.c
>> +++ b/drivers/irqchip/irq-mips-gic.c
>> @@ -237,6 +237,15 @@ static void gic_unmask_irq(struct irq_data *d)
>>         GIC_SET_INTR_MASK(d->irq - gic_irq_base);
>>   }
>>   +static void gic_ack_irq(struct irq_data *d)
>> +{
>> +       GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
>> +
>> +       /* Clear edge detector */
>> +       if (gic_irq_flags[d->irq - gic_irq_base] & GIC_TRIG_EDGE)
>> +               GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq -
>> gic_irq_base);
>> +}
>> +
>>   #ifdef CONFIG_SMP
>>   static DEFINE_SPINLOCK(gic_lock);
>>   @@ -272,11 +281,11 @@ static int gic_set_affinity(struct irq_data *d,
>> const struct cpumask *cpumask,
>>     static struct irq_chip gic_irq_controller = {
>>         .name                   =       "MIPS GIC",
>> -       .irq_ack                =       gic_irq_ack,
>> +       .irq_ack                =       gic_ack_irq,
>>         .irq_mask               =       gic_mask_irq,
>> -       .irq_mask_ack           =       gic_mask_irq,
>> +       .irq_mask_ack           =       gic_ack_irq,
>>         .irq_unmask             =       gic_unmask_irq,
>> -       .irq_eoi                =       gic_finish_irq,
>> +       .irq_eoi                =       gic_unmask_irq,
>>   #ifdef CONFIG_SMP
>>         .irq_set_affinity       =       gic_set_affinity,
>>   #endif
>
>
> I'm no expert in irq_chip api but I think providing irq_mask_ack and irq_eoi
> makes no sense to GIC and can be removed.

Ok, yeah, I think both irq_mask_ack and irq_eoi can go away here.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips
  2014-09-17  9:24   ` Qais Yousef
@ 2014-09-17 17:15     ` Andrew Bresticker
  0 siblings, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 17:15 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 2:24 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>
>> GIC edge-triggered interrupts must be acknowledged by clearing the edge
>> detector via a write to GIC_SH_WEDGE.  Create a separate edge-triggered
>> irq_chip with the appropriate irq_ack() callback.  This also allows us
>> to get rid of gic_irq_flags.
>>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> ---
>>   arch/mips/include/asm/gic.h    |  1 -
>>   drivers/irqchip/irq-mips-gic.c | 38
>> ++++++++++++++++++++++++--------------
>>   2 files changed, 24 insertions(+), 15 deletions(-)
>>
>> diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
>> index 8d1e457..f245395 100644
>> --- a/arch/mips/include/asm/gic.h
>> +++ b/arch/mips/include/asm/gic.h
>> @@ -345,7 +345,6 @@
>>   extern unsigned int gic_present;
>>   extern unsigned int gic_frequency;
>>   extern unsigned long _gic_base;
>> -extern unsigned int gic_irq_flags[];
>>   extern unsigned int gic_cpu_pin;
>>     extern void gic_init(unsigned long gic_base_addr,
>> diff --git a/drivers/irqchip/irq-mips-gic.c
>> b/drivers/irqchip/irq-mips-gic.c
>> index c9ba102..6682a4e 100644
>> --- a/drivers/irqchip/irq-mips-gic.c
>> +++ b/drivers/irqchip/irq-mips-gic.c
>> @@ -24,7 +24,6 @@
>>   unsigned int gic_frequency;
>>   unsigned int gic_present;
>>   unsigned long _gic_base;
>> -unsigned int gic_irq_flags[GIC_NUM_INTRS];
>>   unsigned int gic_cpu_pin;
>>     struct gic_pcpu_mask {
>> @@ -44,6 +43,7 @@ static struct gic_pending_regs pending_regs[NR_CPUS];
>>   static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
>>   static struct irq_domain *gic_irq_domain;
>>   static int gic_shared_intrs;
>> +static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
>>     static void __gic_irq_dispatch(void);
>>   @@ -228,11 +228,7 @@ static void gic_ack_irq(struct irq_data *d)
>>   {
>>         unsigned int irq = d->hwirq;
>>   -     GIC_CLR_INTR_MASK(irq);
>> -
>> -       /* Clear edge detector */
>> -       if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
>> -               GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
>> +       GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
>>   }
>>     static int gic_set_type(struct irq_data *d, unsigned int type)
>> @@ -275,11 +271,13 @@ static int gic_set_type(struct irq_data *d, unsigned
>> int type)
>>         }
>>         if (is_edge) {
>> -               gic_irq_flags[irq] |= GIC_TRIG_EDGE;
>> -               __irq_set_handler_locked(d->irq, handle_edge_irq);
>> +               __irq_set_chip_handler_name_locked(d->irq,
>> +
>> &gic_edge_irq_controller,
>> +                                                  handle_edge_irq, NULL);
>>         } else {
>> -               gic_irq_flags[irq] &= ~GIC_TRIG_EDGE;
>> -               __irq_set_handler_locked(d->irq, handle_level_irq);
>> +               __irq_set_chip_handler_name_locked(d->irq,
>> +
>> &gic_level_irq_controller,
>> +                                                  handle_level_irq,
>> NULL);
>>         }
>>         return 0;
>> @@ -318,11 +316,23 @@ static int gic_set_affinity(struct irq_data *d,
>> const struct cpumask *cpumask,
>>   }
>>   #endif
>>   -static struct irq_chip gic_irq_controller = {
>> +static struct irq_chip gic_level_irq_controller = {
>> +       .name                   =       "MIPS GIC",
>> +       .irq_ack                =       gic_mask_irq,
>> +       .irq_mask               =       gic_mask_irq,
>> +       .irq_mask_ack           =       gic_mask_irq,
>> +       .irq_unmask             =       gic_unmask_irq,
>> +       .irq_eoi                =       gic_unmask_irq,
>> +       .irq_set_type           =       gic_set_type,
>> +#ifdef CONFIG_SMP
>> +       .irq_set_affinity       =       gic_set_affinity,
>> +#endif
>> +};
>> +
>
>
> I don't think there's a need to provide irq_ack, irq_mask_ack and irq_eoi
> here.
>
>> +static struct irq_chip gic_edge_irq_controller = {
>>         .name                   =       "MIPS GIC",
>>         .irq_ack                =       gic_ack_irq,
>>         .irq_mask               =       gic_mask_irq,
>> -       .irq_mask_ack           =       gic_ack_irq,
>>         .irq_unmask             =       gic_unmask_irq,
>>         .irq_eoi                =       gic_unmask_irq,
>>         .irq_set_type           =       gic_set_type,
>
>
> irq_eoi can be removed from here as well.

Right, I'll fix up both of these.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 21/24] irqchip: mips-gic: Support local interrupts
  2014-09-17  9:50   ` Qais Yousef
@ 2014-09-17 17:40     ` Andrew Bresticker
  2014-09-17 21:09       ` Andrew Bresticker
  2014-09-18  6:57       ` Qais Yousef
  0 siblings, 2 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 17:40 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 2:50 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>
>> The MIPS GIC supports 7 local interrupts, 2 of which are the GIC
>> local watchdog and count/compare timer.  The remainder are CPU
>> interrupts which may optionally be re-routed through the GIC.
>> GIC hardware IRQs 0-6 are now used for local interrupts while
>> hardware IRQs 7+ are used for external (shared) interrupts.
>>
>> Note that the 5 CPU interrupts may not be re-routable through
>> the GIC.  In that case mapping will fail and the vectors reported
>> in C0_IntCtl should be used instead.  gic_get_c0_compare_int() and
>> gic_get_c0_perfcount_int() will return the correct IRQ number to
>> use for the C0 timer and perfcounter interrupts based on the
>> routability of those interrupts through the GIC.
>>
>> Malta, SEAD-3, and the GIC clockevent driver have been updated
>> to use local interrupts and the R4K clockevent driver has been
>> updated to poll for C0 timer interrupts through the GIC when
>> the GIC is present.
>>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>

>> diff --git a/arch/mips/include/asm/mips-boards/maltaint.h
>> b/arch/mips/include/asm/mips-boards/maltaint.h
>> index bdd6f39..38b06a0 100644
>> --- a/arch/mips/include/asm/mips-boards/maltaint.h
>> +++ b/arch/mips/include/asm/mips-boards/maltaint.h
>> @@ -10,6 +10,8 @@
>>   #ifndef _MIPS_MALTAINT_H
>>   #define _MIPS_MALTAINT_H
>>   +#include <asm/gic.h>
>> +
>
>
> nit: I think gic.h should be split to driver/irqchip/irq-mips-gic.h for
> private definitions and include/linux/irqchip/irq-mips-gic.h for
> exported/public definitions.

Yup, I was planning on doing this in the next series :).  Malta and
the clockevent/clocksource driver need to get cleaned up first though,
so that they don't have to use the private register definitions.

>> diff --git a/drivers/irqchip/irq-mips-gic.c
>> b/drivers/irqchip/irq-mips-gic.c
>> index 6682a4e..3abe310 100644
>> --- a/drivers/irqchip/irq-mips-gic.c
>> +++ b/drivers/irqchip/irq-mips-gic.c

>> @@ -95,12 +96,39 @@ cycle_t gic_read_compare(void)
>>   }
>>   #endif
>>   +static bool gic_local_irq_is_routable(int intr)
>> +{
>> +       u32 vpe_ctl;
>> +
>> +       /* All local interrupts are routable in EIC mode. */
>> +       if (cpu_has_veic)
>> +               return true;
>> +
>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
>> +       switch (intr) {
>> +       case GIC_LOCAL_INT_TIMER:
>> +               return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
>> +       case GIC_LOCAL_INT_PERFCTR:
>> +               return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
>> +       case GIC_LOCAL_INT_FDC:
>> +               return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
>> +       case GIC_LOCAL_INT_SWINT0:
>> +       case GIC_LOCAL_INT_SWINT1:
>> +               /*
>> +                * SWINT{0,1} are not routable in non-EIC mode, regardless
>> +                * of the setting of SWINT_ROUTABLE.
>> +                */
>> +               return false;
>
>
> Hmm AFAIK they are routable. Actually from hard reset they're automatically
> routed to vpe0 pin 0 which caught me a number of times when trying to use
> software interrupt on hardware that has GIC. When setting software interrupt
> I was seeing pin 0 going high too and thought it's a hardware bug for a
> while.

Interesting, the interAptiv User's Manual I have, in section 9.4.7.1,
says: "Note that Software Interrupts from the VPE are routed
internally by the CPU in vectored interrupt mode, and are only routed
through the GIC when the GIC is in EIC mode, regardless of the
GIC_VPEi_CTL register."  IIRC, there's a similar statement in the
proAptiv manual as well.  I didn't play with the SWINT bits myself, so
I wouldn't be surprised if that's wrong :).

> I think all local interrupts should be masked at GIC initialisation except
> for timer interrupt. I was preparing a set of patches for GIC but you beat
> me into it :)

If SWINT gets routed both through the GIC and directly to the CPU,
then that's probably the best thing to do.  I suspect we'll also want
to leave the performance counter interrupt unmasked too, since,
unfortunately, both the HW perf event driver and oprofile do not use
the percpu IRQ API.

>> @@ -341,12 +342,54 @@ static struct irq_chip gic_edge_irq_controller = {
>>   #endif
>>   };
>>   +static unsigned int gic_get_local_int(void)
>> +{
>> +       unsigned long pending, masked;
>> +
>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked);
>> +
>> +       bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
>> +
>> +       return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
>> +}
>> +
>> +static void gic_mask_local_irq(struct irq_data *d)
>> +{
>> +       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
>> +
>> +       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
>> +}
>> +
>> +static void gic_unmask_local_irq(struct irq_data *d)
>> +{
>> +       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
>> +
>> +       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
>> +}
>> +
>> +static struct irq_chip gic_local_irq_controller = {
>> +       .name                   =       "MIPS GIC Local",
>> +       .irq_ack                =       gic_mask_local_irq,
>> +       .irq_mask               =       gic_mask_local_irq,
>> +       .irq_mask_ack           =       gic_mask_local_irq,
>> +       .irq_unmask             =       gic_unmask_local_irq,
>> +       .irq_eoi                =       gic_unmask_local_irq,
>> +};
>> +
>
>
> again I don't think irq_ack, irq_mask_ack and irq_eoi are needed.

Yup, will do.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/24] MIPS GIC cleanup, part 1
  2014-09-17 10:20 ` [PATCH 00/24] MIPS GIC cleanup, part 1 Qais Yousef
@ 2014-09-17 17:42   ` Andrew Bresticker
  2014-09-18  7:08     ` Qais Yousef
  0 siblings, 1 reply; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 17:42 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Jason Cooper, Ralf Baechle, Thomas Gleixner, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 3:20 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>
>> The current MIPS GIC driver and the platform code using it are rather
>> ugly and could use a good cleanup before adding device-tree support [0].
>> This major issues addressed in this series are converting the GIC (and
>> platforms using it) to use IRQ domains and properly mapping interrupts
>> through the GIC instead of using it transparently.  For part 2 I plan
>> on: updating the driver to use proper iomem accessors, cleaning up and
>> moving the GIC clocksource driver to drivers/clocksource/, adding DT
>> support, and possibly converting the GIC driver to use generic irqchip.
>>
>> Patches 1-16 are cleanups for the existing GIC driver and prepare
>> platforms
>> using it for the switch to IRQ domains and using the GIC in a
>> non-transparent
>> way.
>>
>> Patches 17-24 convert the GIC driver to use IRQ domains and updates the
>> platforms using it to properly map GIC interrupts instead of using the
>> static
>> routing tables to make the GIC appear transparent.
>>
>> I've tested this series on Malta and, with additional patches, on the
>> DT-enabled Danube platform.  Unfortunately I do not have SEAD-3 hardware,
>> so that has only been compile tested.  Compile tested on all other
>> affected
>> architectures (ath79, ralink, lantiq).
>
>
> I boot tested this on sead3 without problems.

Thanks Qais!  Can I add your Tested-by for the series?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 21/24] irqchip: mips-gic: Support local interrupts
  2014-09-17 17:40     ` Andrew Bresticker
@ 2014-09-17 21:09       ` Andrew Bresticker
  2014-09-18  6:57       ` Qais Yousef
  1 sibling, 0 replies; 40+ messages in thread
From: Andrew Bresticker @ 2014-09-17 21:09 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On Wed, Sep 17, 2014 at 10:40 AM, Andrew Bresticker
<abrestic@chromium.org> wrote:
> On Wed, Sep 17, 2014 at 2:50 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
>> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>>
>>> The MIPS GIC supports 7 local interrupts, 2 of which are the GIC
>>> local watchdog and count/compare timer.  The remainder are CPU
>>> interrupts which may optionally be re-routed through the GIC.
>>> GIC hardware IRQs 0-6 are now used for local interrupts while
>>> hardware IRQs 7+ are used for external (shared) interrupts.
>>>
>>> Note that the 5 CPU interrupts may not be re-routable through
>>> the GIC.  In that case mapping will fail and the vectors reported
>>> in C0_IntCtl should be used instead.  gic_get_c0_compare_int() and
>>> gic_get_c0_perfcount_int() will return the correct IRQ number to
>>> use for the C0 timer and perfcounter interrupts based on the
>>> routability of those interrupts through the GIC.
>>>
>>> Malta, SEAD-3, and the GIC clockevent driver have been updated
>>> to use local interrupts and the R4K clockevent driver has been
>>> updated to poll for C0 timer interrupts through the GIC when
>>> the GIC is present.
>>>
>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>
>>> diff --git a/arch/mips/include/asm/mips-boards/maltaint.h
>>> b/arch/mips/include/asm/mips-boards/maltaint.h
>>> index bdd6f39..38b06a0 100644
>>> --- a/arch/mips/include/asm/mips-boards/maltaint.h
>>> +++ b/arch/mips/include/asm/mips-boards/maltaint.h
>>> @@ -10,6 +10,8 @@
>>>   #ifndef _MIPS_MALTAINT_H
>>>   #define _MIPS_MALTAINT_H
>>>   +#include <asm/gic.h>
>>> +
>>
>>
>> nit: I think gic.h should be split to driver/irqchip/irq-mips-gic.h for
>> private definitions and include/linux/irqchip/irq-mips-gic.h for
>> exported/public definitions.
>
> Yup, I was planning on doing this in the next series :).  Malta and
> the clockevent/clocksource driver need to get cleaned up first though,
> so that they don't have to use the private register definitions.
>
>>> diff --git a/drivers/irqchip/irq-mips-gic.c
>>> b/drivers/irqchip/irq-mips-gic.c
>>> index 6682a4e..3abe310 100644
>>> --- a/drivers/irqchip/irq-mips-gic.c
>>> +++ b/drivers/irqchip/irq-mips-gic.c
>
>>> @@ -95,12 +96,39 @@ cycle_t gic_read_compare(void)
>>>   }
>>>   #endif
>>>   +static bool gic_local_irq_is_routable(int intr)
>>> +{
>>> +       u32 vpe_ctl;
>>> +
>>> +       /* All local interrupts are routable in EIC mode. */
>>> +       if (cpu_has_veic)
>>> +               return true;
>>> +
>>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
>>> +       switch (intr) {
>>> +       case GIC_LOCAL_INT_TIMER:
>>> +               return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_PERFCTR:
>>> +               return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_FDC:
>>> +               return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_SWINT0:
>>> +       case GIC_LOCAL_INT_SWINT1:
>>> +               /*
>>> +                * SWINT{0,1} are not routable in non-EIC mode, regardless
>>> +                * of the setting of SWINT_ROUTABLE.
>>> +                */
>>> +               return false;
>>
>>
>> Hmm AFAIK they are routable. Actually from hard reset they're automatically
>> routed to vpe0 pin 0 which caught me a number of times when trying to use
>> software interrupt on hardware that has GIC. When setting software interrupt
>> I was seeing pin 0 going high too and thought it's a hardware bug for a
>> while.
>
> Interesting, the interAptiv User's Manual I have, in section 9.4.7.1,
> says: "Note that Software Interrupts from the VPE are routed
> internally by the CPU in vectored interrupt mode, and are only routed
> through the GIC when the GIC is in EIC mode, regardless of the
> GIC_VPEi_CTL register."  IIRC, there's a similar statement in the
> proAptiv manual as well.  I didn't play with the SWINT bits myself, so
> I wouldn't be surprised if that's wrong :).
>
>> I think all local interrupts should be masked at GIC initialisation except
>> for timer interrupt. I was preparing a set of patches for GIC but you beat
>> me into it :)
>
> If SWINT gets routed both through the GIC and directly to the CPU,
> then that's probably the best thing to do.  I suspect we'll also want
> to leave the performance counter interrupt unmasked too, since,
> unfortunately, both the HW perf event driver and oprofile do not use
> the percpu IRQ API.

Instead of leaving those two unmasked, perhaps the better thing to do
is to have a separate irq_chip which masks/unmasks on all VPEs.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 21/24] irqchip: mips-gic: Support local interrupts
  2014-09-17 17:40     ` Andrew Bresticker
  2014-09-17 21:09       ` Andrew Bresticker
@ 2014-09-18  6:57       ` Qais Yousef
  1 sibling, 0 replies; 40+ messages in thread
From: Qais Yousef @ 2014-09-18  6:57 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Ralf Baechle, Thomas Gleixner, Jason Cooper, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On 09/17/2014 06:40 PM, Andrew Bresticker wrote:
> On Wed, Sep 17, 2014 at 2:50 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
>> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>> The MIPS GIC supports 7 local interrupts, 2 of which are the GIC
>>> local watchdog and count/compare timer.  The remainder are CPU
>>> interrupts which may optionally be re-routed through the GIC.
>>> GIC hardware IRQs 0-6 are now used for local interrupts while
>>> hardware IRQs 7+ are used for external (shared) interrupts.
>>>
>>> Note that the 5 CPU interrupts may not be re-routable through
>>> the GIC.  In that case mapping will fail and the vectors reported
>>> in C0_IntCtl should be used instead.  gic_get_c0_compare_int() and
>>> gic_get_c0_perfcount_int() will return the correct IRQ number to
>>> use for the C0 timer and perfcounter interrupts based on the
>>> routability of those interrupts through the GIC.
>>>
>>> Malta, SEAD-3, and the GIC clockevent driver have been updated
>>> to use local interrupts and the R4K clockevent driver has been
>>> updated to poll for C0 timer interrupts through the GIC when
>>> the GIC is present.
>>>
>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>>> diff --git a/arch/mips/include/asm/mips-boards/maltaint.h
>>> b/arch/mips/include/asm/mips-boards/maltaint.h
>>> index bdd6f39..38b06a0 100644
>>> --- a/arch/mips/include/asm/mips-boards/maltaint.h
>>> +++ b/arch/mips/include/asm/mips-boards/maltaint.h
>>> @@ -10,6 +10,8 @@
>>>    #ifndef _MIPS_MALTAINT_H
>>>    #define _MIPS_MALTAINT_H
>>>    +#include <asm/gic.h>
>>> +
>>
>> nit: I think gic.h should be split to driver/irqchip/irq-mips-gic.h for
>> private definitions and include/linux/irqchip/irq-mips-gic.h for
>> exported/public definitions.
> Yup, I was planning on doing this in the next series :).  Malta and
> the clockevent/clocksource driver need to get cleaned up first though,
> so that they don't have to use the private register definitions.
>
>>> diff --git a/drivers/irqchip/irq-mips-gic.c
>>> b/drivers/irqchip/irq-mips-gic.c
>>> index 6682a4e..3abe310 100644
>>> --- a/drivers/irqchip/irq-mips-gic.c
>>> +++ b/drivers/irqchip/irq-mips-gic.c
>>> @@ -95,12 +96,39 @@ cycle_t gic_read_compare(void)
>>>    }
>>>    #endif
>>>    +static bool gic_local_irq_is_routable(int intr)
>>> +{
>>> +       u32 vpe_ctl;
>>> +
>>> +       /* All local interrupts are routable in EIC mode. */
>>> +       if (cpu_has_veic)
>>> +               return true;
>>> +
>>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
>>> +       switch (intr) {
>>> +       case GIC_LOCAL_INT_TIMER:
>>> +               return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_PERFCTR:
>>> +               return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_FDC:
>>> +               return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
>>> +       case GIC_LOCAL_INT_SWINT0:
>>> +       case GIC_LOCAL_INT_SWINT1:
>>> +               /*
>>> +                * SWINT{0,1} are not routable in non-EIC mode, regardless
>>> +                * of the setting of SWINT_ROUTABLE.
>>> +                */
>>> +               return false;
>>
>> Hmm AFAIK they are routable. Actually from hard reset they're automatically
>> routed to vpe0 pin 0 which caught me a number of times when trying to use
>> software interrupt on hardware that has GIC. When setting software interrupt
>> I was seeing pin 0 going high too and thought it's a hardware bug for a
>> while.
> Interesting, the interAptiv User's Manual I have, in section 9.4.7.1,
> says: "Note that Software Interrupts from the VPE are routed
> internally by the CPU in vectored interrupt mode, and are only routed
> through the GIC when the GIC is in EIC mode, regardless of the
> GIC_VPEi_CTL register."  IIRC, there's a similar statement in the
> proAptiv manual as well.  I didn't play with the SWINT bits myself, so
> I wouldn't be surprised if that's wrong :).
>
>> I think all local interrupts should be masked at GIC initialisation except
>> for timer interrupt. I was preparing a set of patches for GIC but you beat
>> me into it :)
> If SWINT gets routed both through the GIC and directly to the CPU,
> then that's probably the best thing to do.  I suspect we'll also want
> to leave the performance counter interrupt unmasked too, since,
> unfortunately, both the HW perf event driver and oprofile do not use
> the percpu IRQ API.

Yeah probably. I haven't played much with the perf counters to be honest.

>>> @@ -341,12 +342,54 @@ static struct irq_chip gic_edge_irq_controller = {
>>>    #endif
>>>    };
>>>    +static unsigned int gic_get_local_int(void)
>>> +{
>>> +       unsigned long pending, masked;
>>> +
>>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
>>> +       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked);
>>> +
>>> +       bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
>>> +
>>> +       return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
>>> +}
>>> +
>>> +static void gic_mask_local_irq(struct irq_data *d)
>>> +{
>>> +       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
>>> +
>>> +       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
>>> +}
>>> +
>>> +static void gic_unmask_local_irq(struct irq_data *d)
>>> +{
>>> +       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
>>> +
>>> +       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
>>> +}
>>> +
>>> +static struct irq_chip gic_local_irq_controller = {
>>> +       .name                   =       "MIPS GIC Local",
>>> +       .irq_ack                =       gic_mask_local_irq,
>>> +       .irq_mask               =       gic_mask_local_irq,
>>> +       .irq_mask_ack           =       gic_mask_local_irq,
>>> +       .irq_unmask             =       gic_unmask_local_irq,
>>> +       .irq_eoi                =       gic_unmask_local_irq,
>>> +};
>>> +
>>
>> again I don't think irq_ack, irq_mask_ack and irq_eoi are needed.
> Yup, will do.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/24] MIPS GIC cleanup, part 1
  2014-09-17 17:42   ` Andrew Bresticker
@ 2014-09-18  7:08     ` Qais Yousef
  0 siblings, 0 replies; 40+ messages in thread
From: Qais Yousef @ 2014-09-18  7:08 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Jason Cooper, Ralf Baechle, Thomas Gleixner, Jeffrey Deans,
	Markos Chandras, Paul Burton, Jonas Gorski, John Crispin,
	David Daney, Linux-MIPS, linux-kernel

On 09/17/2014 06:42 PM, Andrew Bresticker wrote:
> On Wed, Sep 17, 2014 at 3:20 AM, Qais Yousef <qais.yousef@imgtec.com> wrote:
>> On 09/16/2014 12:51 AM, Andrew Bresticker wrote:
>>> The current MIPS GIC driver and the platform code using it are rather
>>> ugly and could use a good cleanup before adding device-tree support [0].
>>> This major issues addressed in this series are converting the GIC (and
>>> platforms using it) to use IRQ domains and properly mapping interrupts
>>> through the GIC instead of using it transparently.  For part 2 I plan
>>> on: updating the driver to use proper iomem accessors, cleaning up and
>>> moving the GIC clocksource driver to drivers/clocksource/, adding DT
>>> support, and possibly converting the GIC driver to use generic irqchip.
>>>
>>> Patches 1-16 are cleanups for the existing GIC driver and prepare
>>> platforms
>>> using it for the switch to IRQ domains and using the GIC in a
>>> non-transparent
>>> way.
>>>
>>> Patches 17-24 convert the GIC driver to use IRQ domains and updates the
>>> platforms using it to properly map GIC interrupts instead of using the
>>> static
>>> routing tables to make the GIC appear transparent.
>>>
>>> I've tested this series on Malta and, with additional patches, on the
>>> DT-enabled Danube platform.  Unfortunately I do not have SEAD-3 hardware,
>>> so that has only been compile tested.  Compile tested on all other
>>> affected
>>> architectures (ath79, ralink, lantiq).
>>
>> I boot tested this on sead3 without problems.
> Thanks Qais!  Can I add your Tested-by for the series?

Tested-and-reviewed-by: Qais Yousef <qais.yousef@imgtec.com>

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2014-09-18  7:08 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-15 23:51 [PATCH 00/24] MIPS GIC cleanup, part 1 Andrew Bresticker
2014-09-15 23:51 ` [PATCH 01/24] MIPS: Always use IRQ domains for CPU IRQs Andrew Bresticker
2014-09-15 23:51 ` [PATCH 02/24] MIPS: Rename mips_cpu_intc_init() -> mips_cpu_irq_of_init() Andrew Bresticker
2014-09-15 23:51 ` [PATCH 03/24] MIPS: Provide a generic plat_irq_dispatch Andrew Bresticker
2014-09-17  8:56   ` Qais Yousef
2014-09-17 16:36     ` Andrew Bresticker
2014-09-15 23:51 ` [PATCH 04/24] MIPS: Set vint handler when mapping CPU interrupts Andrew Bresticker
2014-09-15 23:51 ` [PATCH 05/24] MIPS: i8259: Use IRQ domains Andrew Bresticker
2014-09-15 23:51 ` [PATCH 06/24] MIPS: Add hook to get C0 performance counter interrupt Andrew Bresticker
2014-09-15 23:51 ` [PATCH 07/24] MIPS: smp-cps: Enable all hardware interrupts on secondary CPUs Andrew Bresticker
2014-09-15 23:51 ` [PATCH 08/24] MIPS: Remove gic_{enable,disable}_interrupt() Andrew Bresticker
2014-09-15 23:51 ` [PATCH 09/24] MIPS: sead3: Remove sead3-serial.c Andrew Bresticker
2014-09-15 23:51 ` [PATCH 10/24] MIPS: sead3: Do not overlap CPU/GIC IRQ ranges Andrew Bresticker
2014-09-15 23:51 ` [PATCH 11/24] MIPS: Malta: Move MSC01 interrupt base Andrew Bresticker
2014-09-15 23:51 ` [PATCH 12/24] MIPS: Move MIPS_GIC_IRQ_BASE into platform irq.h Andrew Bresticker
2014-09-15 23:51 ` [PATCH 13/24] MIPS: Move GIC to drivers/irqchip/ Andrew Bresticker
2014-09-15 23:51 ` [PATCH 14/24] irqchip: mips-gic: Implement generic irq_ack/irq_eoi callbacks Andrew Bresticker
2014-09-17  9:14   ` Qais Yousef
2014-09-17 17:14     ` Andrew Bresticker
2014-09-15 23:51 ` [PATCH 15/24] irqchip: mips-gic: Implement irq_set_type callback Andrew Bresticker
2014-09-15 23:51 ` [PATCH 16/24] irqchip: mips-gic: Fix gic_set_affinity() return value Andrew Bresticker
2014-09-15 23:51 ` [PATCH 17/24] irqchip: mips-gic: Use IRQ domains Andrew Bresticker
2014-09-15 23:51 ` [PATCH 18/24] irqchip: mips-gic: Stop using per-platform mapping tables Andrew Bresticker
2014-09-17  9:21   ` Qais Yousef
2014-09-15 23:51 ` [PATCH 19/24] irqchip: mips-gic: Probe for number of external interrupts Andrew Bresticker
2014-09-15 23:51 ` [PATCH 20/24] irqchip: mips-gic: Use separate edge/level irq_chips Andrew Bresticker
2014-09-17  9:24   ` Qais Yousef
2014-09-17 17:15     ` Andrew Bresticker
2014-09-15 23:51 ` [PATCH 21/24] irqchip: mips-gic: Support local interrupts Andrew Bresticker
2014-09-17  9:50   ` Qais Yousef
2014-09-17 17:40     ` Andrew Bresticker
2014-09-17 21:09       ` Andrew Bresticker
2014-09-18  6:57       ` Qais Yousef
2014-09-15 23:51 ` [PATCH 22/24] irqchip: mips-gic: Remove unnecessary globals Andrew Bresticker
2014-09-15 23:51 ` [PATCH 23/24] MIPS: Malta: Use generic plat_irq_dispatch Andrew Bresticker
2014-09-15 23:51 ` [PATCH 24/24] MIPS: sead3: " Andrew Bresticker
2014-09-17 10:20 ` [PATCH 00/24] MIPS GIC cleanup, part 1 Qais Yousef
2014-09-17 17:42   ` Andrew Bresticker
2014-09-18  7:08     ` Qais Yousef
2014-09-17 14:07 ` Jason Cooper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).