All of lore.kernel.org
 help / color / mirror / Atom feed
From: Max Filippov <jcmvbkbc@gmail.com>
To: Chris Zankel <chris@zankel.net>
Cc: Marc Gauthier <marc@tensilica.com>,
	linux-xtensa@linux-xtensa.org, linux-arch@vger.kernel.org,
	Max Filippov <jcmvbkbc@gmail.com>
Subject: [PATCH v3 11/17] xtensa: move built-in PIC to drivers/irqchip
Date: Sun,  1 Dec 2013 12:04:56 +0400	[thread overview]
Message-ID: <1385885097-28972-2-git-send-email-jcmvbkbc@gmail.com> (raw)
In-Reply-To: <1385885097-28972-1-git-send-email-jcmvbkbc@gmail.com>

Extract xtensa built-in interrupt controller implementation from
xtensa/kernel/irq.c and move it to other irqchips, providing way to
instantiate it from the device tree.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
Changes v1 -> v3:
- update compatible string for PIC irqchip

 arch/xtensa/include/asm/irq.h      |   7 ++
 arch/xtensa/kernel/irq.c           | 137 ++++++++-----------------------------
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-xtensa-pic.c   | 108 +++++++++++++++++++++++++++++
 include/linux/irqchip/xtensa-pic.h |  18 +++++
 5 files changed, 164 insertions(+), 107 deletions(-)
 create mode 100644 drivers/irqchip/irq-xtensa-pic.c
 create mode 100644 include/linux/irqchip/xtensa-pic.h

diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h
index 4c0ccc9..16464f2 100644
--- a/arch/xtensa/include/asm/irq.h
+++ b/arch/xtensa/include/asm/irq.h
@@ -43,5 +43,12 @@ static __inline__ int irq_canonicalize(int irq)
 }
 
 struct irqaction;
+struct irq_domain;
+
+int xtensa_irq_domain_xlate(const u32 *intspec, unsigned int intsize,
+		unsigned long int_irq, unsigned long ext_irq,
+		unsigned long *out_hwirq, unsigned int *out_type);
+int xtensa_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw);
+unsigned xtensa_map_ext_irq(unsigned ext_irq);
 
 #endif	/* _XTENSA_IRQ_H */
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index 6f4f974..ada1e48 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -18,28 +18,20 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/xtensa-pic.h>
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 
 #include <asm/uaccess.h>
 #include <asm/platform.h>
 
-static unsigned int cached_irq_mask;
-
 atomic_t irq_err_count;
 
-static struct irq_domain *root_domain;
-
-/*
- * do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- */
-
 asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
-	int irq = irq_find_mapping(root_domain, hwirq);
+	int irq = irq_find_mapping(NULL, hwirq);
 
 	if (hwirq >= NR_IRQS) {
 		printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -74,83 +66,57 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 	return 0;
 }
 
-static void xtensa_irq_mask(struct irq_data *d)
-{
-	cached_irq_mask &= ~(1 << d->hwirq);
-	set_sr (cached_irq_mask, intenable);
-}
-
-static void xtensa_irq_unmask(struct irq_data *d)
-{
-	cached_irq_mask |= 1 << d->hwirq;
-	set_sr (cached_irq_mask, intenable);
-}
-
-static void xtensa_irq_enable(struct irq_data *d)
-{
-	variant_irq_enable(d->hwirq);
-	xtensa_irq_unmask(d);
-}
-
-static void xtensa_irq_disable(struct irq_data *d)
-{
-	xtensa_irq_mask(d);
-	variant_irq_disable(d->hwirq);
-}
-
-static void xtensa_irq_ack(struct irq_data *d)
-{
-	set_sr(1 << d->hwirq, intclear);
-}
-
-static int xtensa_irq_retrigger(struct irq_data *d)
+int xtensa_irq_domain_xlate(const u32 *intspec, unsigned int intsize,
+		unsigned long int_irq, unsigned long ext_irq,
+		unsigned long *out_hwirq, unsigned int *out_type)
 {
-	set_sr(1 << d->hwirq, intset);
-	return 1;
+	if (WARN_ON(intsize < 1 || intsize > 2))
+		return -EINVAL;
+	if (intsize == 2 && intspec[1] == 1) {
+		int_irq = xtensa_map_ext_irq(ext_irq);
+		if (int_irq < XCHAL_NUM_INTERRUPTS)
+			*out_hwirq = int_irq;
+		else
+			return -EINVAL;
+	} else {
+		*out_hwirq = int_irq;
+	}
+	*out_type = IRQ_TYPE_NONE;
+	return 0;
 }
 
-static struct irq_chip xtensa_irq_chip = {
-	.name		= "xtensa",
-	.irq_enable	= xtensa_irq_enable,
-	.irq_disable	= xtensa_irq_disable,
-	.irq_mask	= xtensa_irq_mask,
-	.irq_unmask	= xtensa_irq_unmask,
-	.irq_ack	= xtensa_irq_ack,
-	.irq_retrigger	= xtensa_irq_retrigger,
-};
-
-static int xtensa_irq_map(struct irq_domain *d, unsigned int irq,
+int xtensa_irq_map(struct irq_domain *d, unsigned int irq,
 		irq_hw_number_t hw)
 {
+	struct irq_chip *irq_chip = d->host_data;
 	u32 mask = 1 << hw;
 
 	if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) {
-		irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+		irq_set_chip_and_handler_name(irq, irq_chip,
 				handle_simple_irq, "level");
 		irq_set_status_flags(irq, IRQ_LEVEL);
 	} else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) {
-		irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+		irq_set_chip_and_handler_name(irq, irq_chip,
 				handle_edge_irq, "edge");
 		irq_clear_status_flags(irq, IRQ_LEVEL);
 	} else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) {
-		irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+		irq_set_chip_and_handler_name(irq, irq_chip,
 				handle_level_irq, "level");
 		irq_set_status_flags(irq, IRQ_LEVEL);
 	} else if (mask & XCHAL_INTTYPE_MASK_TIMER) {
-		irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
-				handle_edge_irq, "edge");
+		irq_set_chip_and_handler_name(irq, irq_chip,
+				handle_percpu_irq, "timer");
 		irq_clear_status_flags(irq, IRQ_LEVEL);
 	} else {/* XCHAL_INTTYPE_MASK_WRITE_ERROR */
 		/* XCHAL_INTTYPE_MASK_NMI */
-
-		irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+		irq_set_chip_and_handler_name(irq, irq_chip,
 				handle_level_irq, "level");
 		irq_set_status_flags(irq, IRQ_LEVEL);
 	}
 	return 0;
 }
 
-static unsigned map_ext_irq(unsigned ext_irq)
+unsigned xtensa_map_ext_irq(unsigned ext_irq)
 {
 	unsigned mask = XCHAL_INTTYPE_MASK_EXTERN_EDGE |
 		XCHAL_INTTYPE_MASK_EXTERN_LEVEL;
@@ -163,55 +129,12 @@ static unsigned map_ext_irq(unsigned ext_irq)
 	return XCHAL_NUM_INTERRUPTS;
 }
 
-/*
- * Device Tree IRQ specifier translation function which works with one or
- * two cell bindings. First cell value maps directly to the hwirq number.
- * Second cell if present specifies whether hwirq number is external (1) or
- * internal (0).
- */
-int xtensa_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
-		const u32 *intspec, unsigned int intsize,
-		unsigned long *out_hwirq, unsigned int *out_type)
-{
-	if (WARN_ON(intsize < 1 || intsize > 2))
-		return -EINVAL;
-	if (intsize == 2 && intspec[1] == 1) {
-		unsigned int_irq = map_ext_irq(intspec[0]);
-		if (int_irq < XCHAL_NUM_INTERRUPTS)
-			*out_hwirq = int_irq;
-		else
-			return -EINVAL;
-	} else {
-		*out_hwirq = intspec[0];
-	}
-	*out_type = IRQ_TYPE_NONE;
-	return 0;
-}
-
-static const struct irq_domain_ops xtensa_irq_domain_ops = {
-	.xlate = xtensa_irq_domain_xlate,
-	.map = xtensa_irq_map,
-};
-
 void __init init_IRQ(void)
 {
-	struct device_node *intc = NULL;
-
-	cached_irq_mask = 0;
-	set_sr(~0, intclear);
-
 #ifdef CONFIG_OF
-	/* The interrupt controller device node is mandatory */
-	intc = of_find_compatible_node(NULL, NULL, "xtensa,pic");
-	BUG_ON(!intc);
-
-	root_domain = irq_domain_add_linear(intc, NR_IRQS,
-			&xtensa_irq_domain_ops, NULL);
+	irqchip_init();
 #else
-	root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
-			&xtensa_irq_domain_ops, NULL);
+	xtensa_pic_init_legacy(NULL);
 #endif
-	irq_set_default_host(root_domain);
-
 	variant_init_irq();
 }
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index c60b901..c81a7f3 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_VT8500)		+= irq-vt8500.o
 obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
+obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c
new file mode 100644
index 0000000..7d71126
--- /dev/null
+++ b/drivers/irqchip/irq-xtensa-pic.c
@@ -0,0 +1,108 @@
+/*
+ * Xtensa built-in interrupt controller
+ *
+ * Copyright (C) 2002 - 2013 Tensilica, Inc.
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * 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.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+
+#include "irqchip.h"
+
+unsigned int cached_irq_mask;
+
+/*
+ * Device Tree IRQ specifier translation function which works with one or
+ * two cell bindings. First cell value maps directly to the hwirq number.
+ * Second cell if present specifies whether hwirq number is external (1) or
+ * internal (0).
+ */
+static int xtensa_pic_irq_domain_xlate(struct irq_domain *d,
+		struct device_node *ctrlr,
+		const u32 *intspec, unsigned int intsize,
+		unsigned long *out_hwirq, unsigned int *out_type)
+{
+	return xtensa_irq_domain_xlate(intspec, intsize,
+			intspec[0], intspec[0],
+			out_hwirq, out_type);
+}
+
+static const struct irq_domain_ops xtensa_irq_domain_ops = {
+	.xlate = xtensa_pic_irq_domain_xlate,
+	.map = xtensa_irq_map,
+};
+
+static void xtensa_irq_mask(struct irq_data *d)
+{
+	cached_irq_mask &= ~(1 << d->hwirq);
+	set_sr(cached_irq_mask, intenable);
+}
+
+static void xtensa_irq_unmask(struct irq_data *d)
+{
+	cached_irq_mask |= 1 << d->hwirq;
+	set_sr(cached_irq_mask, intenable);
+}
+
+static void xtensa_irq_enable(struct irq_data *d)
+{
+	variant_irq_enable(d->hwirq);
+	xtensa_irq_unmask(d);
+}
+
+static void xtensa_irq_disable(struct irq_data *d)
+{
+	xtensa_irq_mask(d);
+	variant_irq_disable(d->hwirq);
+}
+
+static void xtensa_irq_ack(struct irq_data *d)
+{
+	set_sr(1 << d->hwirq, intclear);
+}
+
+static int xtensa_irq_retrigger(struct irq_data *d)
+{
+	set_sr(1 << d->hwirq, intset);
+	return 1;
+}
+
+static struct irq_chip xtensa_irq_chip = {
+	.name		= "xtensa",
+	.irq_enable	= xtensa_irq_enable,
+	.irq_disable	= xtensa_irq_disable,
+	.irq_mask	= xtensa_irq_mask,
+	.irq_unmask	= xtensa_irq_unmask,
+	.irq_ack	= xtensa_irq_ack,
+	.irq_retrigger	= xtensa_irq_retrigger,
+};
+
+int __init xtensa_pic_init_legacy(struct device_node *interrupt_parent)
+{
+	struct irq_domain *root_domain =
+		irq_domain_add_legacy(NULL, NR_IRQS, 0, 0,
+				&xtensa_irq_domain_ops, &xtensa_irq_chip);
+	irq_set_default_host(root_domain);
+	return 0;
+}
+
+static int __init xtensa_pic_init(struct device_node *np,
+		struct device_node *interrupt_parent)
+{
+	struct irq_domain *root_domain =
+		irq_domain_add_linear(np, NR_IRQS, &xtensa_irq_domain_ops,
+				&xtensa_irq_chip);
+	irq_set_default_host(root_domain);
+	return 0;
+}
+IRQCHIP_DECLARE(xtensa_irq_chip, "cdns,xtensa-pic", xtensa_pic_init);
diff --git a/include/linux/irqchip/xtensa-pic.h b/include/linux/irqchip/xtensa-pic.h
new file mode 100644
index 0000000..48718ae
--- /dev/null
+++ b/include/linux/irqchip/xtensa-pic.h
@@ -0,0 +1,18 @@
+/*
+ * Xtensa built-in interrupt controller
+ *
+ * Copyright (C) 2002 - 2013 Tensilica, Inc.
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_IRQCHIP_XTENSA_PIC_H
+#define __LINUX_IRQCHIP_XTENSA_PIC_H
+
+struct device_node;
+int xtensa_pic_init_legacy(struct device_node *interrupt_parent);
+
+#endif /* __LINUX_IRQCHIP_XTENSA_PIC_H */
-- 
1.8.1.4

  reply	other threads:[~2013-12-01  8:05 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-01  8:04 [PATCH v3 00/17] xtensa SMP queue update Max Filippov
2013-12-01  8:04 ` Max Filippov [this message]
2013-12-01  8:18   ` [Linux-Xtensa] [PATCH v3 11/17] xtensa: move built-in PIC to drivers/irqchip Baruch Siach
2013-12-01  8:59     ` [PATCH v4 " Max Filippov
2013-12-01  8:04 ` [PATCH v3 14/17] xtensa: add MX irqchip Max Filippov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1385885097-28972-2-git-send-email-jcmvbkbc@gmail.com \
    --to=jcmvbkbc@gmail.com \
    --cc=chris@zankel.net \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-xtensa@linux-xtensa.org \
    --cc=marc@tensilica.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.