* [PATCH v2 1/4] irq: Get rid of irq_domain_for_each_hwirq().
2011-12-15 2:32 [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support David Daney
@ 2011-12-15 2:32 ` David Daney
2011-12-15 2:32 ` [PATCH v2 2/4] irq/of/ARM: Make irq_domain hwirq type consistent throughout the kernel David Daney
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: David Daney @ 2011-12-15 2:32 UTC (permalink / raw)
To: Thomas Gleixner, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, linux-mips, David Daney
From: David Daney <david.daney@cavium.com>
It is not used anywhere in the kernel.
Signed-off-by: David Daney <david.daney@cavium.com>
---
include/linux/irqdomain.h | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 99834e58..0914a54 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -81,9 +81,6 @@ static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
return d->irq_base + hwirq - d->hwirq_base;
}
-#define irq_domain_for_each_hwirq(d, hw) \
- for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
-
#define irq_domain_for_each_irq(d, hw, irq) \
for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
hw < d->hwirq_base + d->nr_irq; \
--
1.7.2.3
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 2/4] irq/of/ARM: Make irq_domain hwirq type consistent throughout the kernel.
2011-12-15 2:32 [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support David Daney
2011-12-15 2:32 ` [PATCH v2 1/4] irq: Get rid of irq_domain_for_each_hwirq() David Daney
@ 2011-12-15 2:32 ` David Daney
2011-12-15 2:32 ` [PATCH v2 3/4] irq/of/ARM: Enhance irq iteration capability of irq_domain code David Daney
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: David Daney @ 2011-12-15 2:32 UTC (permalink / raw)
To: Thomas Gleixner, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, linux-mips, David Daney
From: David Daney <david.daney@cavium.com>
There is a mixture of unsigned long and unsigned int being used with
hwirq and hwirq_base. Change it so we use unsigned int everywhere.
Signed-off-by: David Daney <david.daney@cavium.com>
---
arch/arm/common/gic.c | 2 +-
include/linux/irqdomain.h | 6 +++---
kernel/irq/irqdomain.c | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index b2dc2dd..171061f 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -625,7 +625,7 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
static int gic_irq_domain_dt_translate(struct irq_domain *d,
struct device_node *controller,
const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type)
+ unsigned int *out_hwirq, unsigned int *out_type)
{
if (d->of_node != controller)
return -EINVAL;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 0914a54..16ba5a9 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -31,12 +31,12 @@ struct irq_domain;
* the hardware irq number and linux irq type value.
*/
struct irq_domain_ops {
- unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
+ unsigned int (*to_irq)(struct irq_domain *d, unsigned int hwirq);
#ifdef CONFIG_OF
int (*dt_translate)(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type);
+ unsigned int *out_hwirq, unsigned int *out_type);
#endif /* CONFIG_OF */
};
@@ -72,7 +72,7 @@ struct irq_domain {
* be overridden if the irq_domain implements a .to_irq() hook.
*/
static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
- unsigned long hwirq)
+ unsigned int hwirq)
{
if (d->ops->to_irq)
return d->ops->to_irq(d, hwirq);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 200ce83..7bae422 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -20,7 +20,7 @@ static DEFINE_MUTEX(irq_domain_mutex);
void irq_domain_add(struct irq_domain *domain)
{
struct irq_data *d;
- int hwirq, irq;
+ unsigned int hwirq, irq;
/*
* This assumes that the irq_domain owner has already allocated
@@ -54,7 +54,7 @@ void irq_domain_add(struct irq_domain *domain)
void irq_domain_del(struct irq_domain *domain)
{
struct irq_data *d;
- int hwirq, irq;
+ unsigned int hwirq, irq;
mutex_lock(&irq_domain_mutex);
list_del(&domain->list);
@@ -82,7 +82,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
const u32 *intspec, unsigned int intsize)
{
struct irq_domain *domain;
- unsigned long hwirq;
+ unsigned int hwirq;
unsigned int irq, type;
int rc = -EINVAL;
@@ -129,7 +129,7 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping);
int irq_domain_simple_dt_translate(struct irq_domain *d,
struct device_node *controller,
const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type)
+ unsigned int *out_hwirq, unsigned int *out_type)
{
if (d->of_node != controller)
return -EINVAL;
--
1.7.2.3
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 3/4] irq/of/ARM: Enhance irq iteration capability of irq_domain code.
2011-12-15 2:32 [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support David Daney
2011-12-15 2:32 ` [PATCH v2 1/4] irq: Get rid of irq_domain_for_each_hwirq() David Daney
2011-12-15 2:32 ` [PATCH v2 2/4] irq/of/ARM: Make irq_domain hwirq type consistent throughout the kernel David Daney
@ 2011-12-15 2:32 ` David Daney
2011-12-15 2:32 ` [PATCH v2 4/4] MIPS: Octeon: Add irq_create_of_mapping() and GPIO interrupts David Daney
2011-12-30 15:30 ` [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support Rob Herring
4 siblings, 0 replies; 7+ messages in thread
From: David Daney @ 2011-12-15 2:32 UTC (permalink / raw)
To: Thomas Gleixner, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, linux-mips, David Daney
From: David Daney <david.daney@cavium.com>
Not all irq_domain have linear sequences of irq numbers, so add hooks
for domain specific iteration of the irqs in the domain.
There is an optional function in irq_domain_ops (each_irq) that iterates over the
irqs in the domain calling a callback function on each one. If it is
not present, the new helper functions irq_domain_each_irq() and
irq_domain_each_hwirq() iterate using the existing semantics.
arch/arm/common/gic.c had to be modified to use the new iteration
method as part of the change.
Signed-off-by: David Daney <david.daney@cavium.com>
---
arch/arm/common/gic.c | 32 ++++++++++-------
include/linux/irqdomain.h | 14 +++++---
kernel/irq/irqdomain.c | 84 ++++++++++++++++++++++++++++++++------------
3 files changed, 89 insertions(+), 41 deletions(-)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 171061f..2e091b7 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -345,6 +345,24 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
+static int __init gic_dist_init_domain_cb(struct irq_domain *domain,
+ unsigned int irq,
+ unsigned int hwirq)
+{
+ if (hwirq < 32) {
+ irq_set_percpu_devid(irq);
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_percpu_devid_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+ } else {
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_fasteoi_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ irq_set_chip_data(irq, gic);
+ return 0;
+}
+
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i, irq;
@@ -392,19 +410,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
/*
* Setup the Linux IRQ subsystem.
*/
- irq_domain_for_each_irq(domain, i, irq) {
- if (i < 32) {
- irq_set_percpu_devid(irq);
- irq_set_chip_and_handler(irq, &gic_chip,
- handle_percpu_devid_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
- } else {
- irq_set_chip_and_handler(irq, &gic_chip,
- handle_fasteoi_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- }
- irq_set_chip_data(irq, gic);
- }
+ irq_domain_each_irq(domain, gic_dist_init_domain_cb);
writel_relaxed(1, base + GIC_DIST_CTRL);
}
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 16ba5a9..68d031b 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -27,12 +27,16 @@ struct irq_domain;
* @to_irq: (optional) given a local hardware irq number, return the linux
* irq number. If to_irq is not implemented, then the irq_domain
* will use this translation: irq = (domain->irq_base + hwirq)
+ * @each_irq: (optional) call the cb function for each irq that is a
+ * member of the domain.
* @dt_translate: Given a device tree node and interrupt specifier, decode
* the hardware irq number and linux irq type value.
*/
struct irq_domain_ops {
unsigned int (*to_irq)(struct irq_domain *d, unsigned int hwirq);
-
+ int (*each_irq)(struct irq_domain *d,
+ int (*cb)(struct irq_domain *d,
+ unsigned int irq, unsigned int hwirq));
#ifdef CONFIG_OF
int (*dt_translate)(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize,
@@ -81,10 +85,10 @@ static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
return d->irq_base + hwirq - d->hwirq_base;
}
-#define irq_domain_for_each_irq(d, hw, irq) \
- for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
- hw < d->hwirq_base + d->nr_irq; \
- hw++, irq = irq_domain_to_irq(d, hw))
+extern int irq_domain_each_irq(struct irq_domain *d,
+ int (*cb)(struct irq_domain *d,
+ unsigned int irq,
+ unsigned int hwirq));
extern void irq_domain_add(struct irq_domain *domain);
extern void irq_domain_del(struct irq_domain *domain);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 7bae422..c9cec12 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -9,6 +9,25 @@
static LIST_HEAD(irq_domain_list);
static DEFINE_MUTEX(irq_domain_mutex);
+static int irq_domain_add_per_irq(struct irq_domain *domain, unsigned int irq,
+ unsigned int hwirq)
+{
+ struct irq_data *d = irq_get_irq_data(irq);
+
+ if (!d) {
+ WARN(1, "error: assigning domain to non existant irq_desc");
+ return 1;
+ }
+ if (d->domain) {
+ /* things are broken; just report, don't clean up */
+ WARN(1, "error: irq_desc already assigned to a domain");
+ return 1;
+ }
+ d->domain = domain;
+ d->hwirq = hwirq;
+ return 0;
+}
+
/**
* irq_domain_add() - Register an irq_domain
* @domain: ptr to initialized irq_domain structure
@@ -19,52 +38,71 @@ static DEFINE_MUTEX(irq_domain_mutex);
*/
void irq_domain_add(struct irq_domain *domain)
{
- struct irq_data *d;
- unsigned int hwirq, irq;
-
/*
* This assumes that the irq_domain owner has already allocated
* the irq_descs. This block will be removed when support for dynamic
* allocation of irq_descs is added to irq_domain.
*/
- irq_domain_for_each_irq(domain, hwirq, irq) {
- d = irq_get_irq_data(irq);
- if (!d) {
- WARN(1, "error: assigning domain to non existant irq_desc");
- return;
- }
- if (d->domain) {
- /* things are broken; just report, don't clean up */
- WARN(1, "error: irq_desc already assigned to a domain");
- return;
- }
- d->domain = domain;
- d->hwirq = hwirq;
- }
+ irq_domain_each_irq(domain, irq_domain_add_per_irq);
mutex_lock(&irq_domain_mutex);
list_add(&domain->list, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
}
+static int irq_domain_del_per_irq(struct irq_domain *domain, unsigned int irq,
+ unsigned int hwirq)
+{
+ struct irq_data *d = irq_get_irq_data(irq);
+
+ d->domain = NULL;
+ return 0;
+}
+
/**
* irq_domain_del() - Unregister an irq_domain
* @domain: ptr to registered irq_domain.
*/
void irq_domain_del(struct irq_domain *domain)
{
- struct irq_data *d;
- unsigned int hwirq, irq;
-
mutex_lock(&irq_domain_mutex);
list_del(&domain->list);
mutex_unlock(&irq_domain_mutex);
/* Clear the irq_domain assignments */
- irq_domain_for_each_irq(domain, hwirq, irq) {
- d = irq_get_irq_data(irq);
- d->domain = NULL;
+ irq_domain_each_irq(domain, irq_domain_del_per_irq);
+}
+
+/**
+ * irq_domain_each_irq() - Iterate over each irq in an irq_domain
+ * @d: Pointer to the irq_domain to iterate over.
+ * @cb: Pointer to a function to be called for each irq in the
+ * irq_domain.
+ *
+ * The cb() function is called for each irq in the irq_domain. If it
+ * returns non-zero, the iteration is stopped.
+ *
+ * Returns: The value returned by the last invocation of cb().
+ */
+int irq_domain_each_irq(struct irq_domain *d,
+ int (*cb)(struct irq_domain *d, unsigned int irq,
+ unsigned int hwirq))
+{
+ unsigned int hw, irq;
+ int ret = 0;
+
+ if (d->ops->each_irq)
+ return d->ops->each_irq(d, cb);
+
+ for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw);
+ hw < d->hwirq_base + d->nr_irq;
+ hw++, irq = irq_domain_to_irq(d, hw)) {
+ ret = cb(d, irq, hw);
+ if (ret)
+ break;
}
+
+ return ret;
}
#if defined(CONFIG_OF_IRQ)
--
1.7.2.3
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 4/4] MIPS: Octeon: Add irq_create_of_mapping() and GPIO interrupts.
2011-12-15 2:32 [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support David Daney
` (2 preceding siblings ...)
2011-12-15 2:32 ` [PATCH v2 3/4] irq/of/ARM: Enhance irq iteration capability of irq_domain code David Daney
@ 2011-12-15 2:32 ` David Daney
2011-12-30 15:30 ` [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support Rob Herring
4 siblings, 0 replies; 7+ messages in thread
From: David Daney @ 2011-12-15 2:32 UTC (permalink / raw)
To: Thomas Gleixner, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, linux-mips, David Daney
From: David Daney <david.daney@cavium.com>
This is needed for Octeon to use the Device Tree.
The GPIO interrupts are configured based on Device Tree properties
Signed-off-by: David Daney <david.daney@cavium.com>
---
arch/mips/Kconfig | 1 +
arch/mips/cavium-octeon/octeon-irq.c | 259 +++++++++++++++++++++++++++++++++-
2 files changed, 259 insertions(+), 1 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 825ded9..6685497 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1432,6 +1432,7 @@ config CPU_CAVIUM_OCTEON
select WEAK_ORDERING
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_HUGEPAGES
+ select IRQ_DOMAIN
help
The Cavium Octeon processor is a highly integrated chip containing
many ethernet hardware widgets for networking tasks. The processor
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index ffd4ae6..9a9d4a7 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -7,12 +7,16 @@
*/
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/bitops.h>
+#include <linux/module.h>
#include <linux/percpu.h>
+#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-gpio-defs.h>
static DEFINE_RAW_SPINLOCK(octeon_irq_ciu0_lock);
static DEFINE_RAW_SPINLOCK(octeon_irq_ciu1_lock);
@@ -58,6 +62,158 @@ static void __init octeon_irq_set_ciu_mapping(int irq, int line, int bit,
octeon_irq_ciu_to_irq[line][bit] = irq;
}
+static int octeon_irq_gpio_dt_translate(struct irq_domain *d,
+ struct device_node *node,
+ const u32 *intspec,
+ unsigned int intsize,
+ unsigned int *out_hwirq,
+ unsigned int *out_type)
+{
+ unsigned int irq;
+ unsigned int type;
+ unsigned int ciu = 0, bit = 0;
+ unsigned int pin;
+ unsigned int trigger;
+ bool set_edge_handler = false;
+
+ if (d->of_node != node)
+ return -EINVAL;
+
+ if (intsize < 2)
+ return -EINVAL;
+
+ pin = be32_to_cpup(intspec);
+ if (pin >= 16)
+ return -EINVAL;
+
+ trigger = be32_to_cpup(intspec + 1);
+
+ switch (trigger) {
+ case 1:
+ type = IRQ_TYPE_EDGE_RISING;
+ set_edge_handler = true;
+ break;
+ case 2:
+ type = IRQ_TYPE_EDGE_FALLING;
+ set_edge_handler = true;
+ break;
+ case 4:
+ type = IRQ_TYPE_LEVEL_HIGH;
+ break;
+ case 8:
+ type = IRQ_TYPE_LEVEL_LOW;
+ break;
+ default:
+ pr_err("Error: (%s) Invalid irq trigger specification: %x\n",
+ node->name,
+ trigger);
+ type = IRQ_TYPE_LEVEL_LOW;
+ break;
+ }
+ *out_type = type;
+ *out_hwirq = d->hwirq_base + pin;
+
+ ciu = *out_hwirq >> 6;
+ bit = *out_hwirq & 0x3f;
+
+ irq = octeon_irq_ciu_to_irq[ciu][bit];
+
+ if (set_edge_handler)
+ __irq_set_handler(irq, handle_edge_irq, 0, NULL);
+
+
+ return 0;
+}
+
+/*
+ * octeon_irq_ciu_dt_translate - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Octeon irq maps are a pair of indexes. The first selects either
+ * ciu0 or ciu1, the second is the bit within the ciu register.
+ */
+static int octeon_irq_ciu_dt_translate(struct irq_domain *d,
+ struct device_node *node,
+ const u32 *intspec,
+ unsigned int intsize,
+ unsigned int *out_hwirq,
+ unsigned int *out_type)
+{
+ unsigned int ciu, bit;
+
+ ciu = be32_to_cpup(intspec);
+ bit = be32_to_cpup(intspec + 1);
+
+ if (ciu > 1 || bit > 63)
+ return -EINVAL;
+
+ if (octeon_irq_ciu_to_irq[ciu][bit] == 0)
+ return -EINVAL;
+
+ *out_hwirq = (ciu << 6) | bit;
+ *out_type = 0;
+
+ return 0;
+}
+
+static unsigned int octeon_irq_ciu_to_irqf(struct irq_domain *d,
+ unsigned int hwirq)
+{
+ unsigned int ciu, bit;
+
+ ciu = (hwirq >> 6) & 1;
+ bit = hwirq & 0x3f;
+ return octeon_irq_ciu_to_irq[ciu][bit];
+}
+
+static bool octeon_irq_ciu_in_domain(unsigned int irq)
+{
+ return (irq != 0) &&
+ !(irq >= OCTEON_IRQ_GPIO0 && irq < OCTEON_IRQ_GPIO0 + 16);
+}
+
+static int octeon_irq_ciu_each_irq(struct irq_domain *d,
+ int (*cb)(struct irq_domain *d,
+ unsigned int irq,
+ unsigned int hwirq))
+{
+ int ciu, bit;
+ int ret = 0;
+ unsigned int irq, hwirq;
+
+ for (ciu = 0; ciu <= 1; ciu++)
+ for (bit = 0; bit <= 63; bit++) {
+ irq = octeon_irq_ciu_to_irq[ciu][bit];
+ hwirq = (ciu << 6) | bit;
+ if (octeon_irq_ciu_in_domain(irq)) {
+ ret = cb(d, irq, hwirq);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops octeon_irq_ciu_domain_ops = {
+ .to_irq = octeon_irq_ciu_to_irqf,
+ .each_irq = octeon_irq_ciu_each_irq,
+ .dt_translate = octeon_irq_ciu_dt_translate,
+};
+
+static const struct irq_domain_ops octeon_irq_gpio_domain_ops = {
+ .to_irq = octeon_irq_ciu_to_irqf,
+ .dt_translate = octeon_irq_gpio_dt_translate,
+};
+
+static struct irq_domain octeon_irq_ciu_domain = {
+ .ops = &octeon_irq_ciu_domain_ops
+};
+
+static struct irq_domain octeon_irq_gpio_domain = {
+ .irq_base = OCTEON_IRQ_GPIO0,
+ .nr_irq = 16,
+ .ops = &octeon_irq_gpio_domain_ops
+};
+
static int octeon_coreid_for_cpu(int cpu)
{
#ifdef CONFIG_SMP
@@ -505,6 +661,72 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data)
}
}
+static void octeon_irq_gpio_setup(struct irq_data *data)
+{
+ union cvmx_gpio_bit_cfgx cfg;
+ int bit = data->irq - OCTEON_IRQ_GPIO0;
+ u32 t = irqd_get_trigger_type(data);
+
+ cfg.u64 = 0;
+ cfg.s.int_en = 1;
+ cfg.s.int_type = (t & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) != 0;
+ cfg.s.rx_xor = (t & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) != 0;
+
+ /* 1 uS glitch filter*/
+ cfg.s.fil_cnt = 7;
+ cfg.s.fil_sel = 3;
+
+ cvmx_write_csr(CVMX_GPIO_BIT_CFGX(bit), cfg.u64);
+}
+
+static void octeon_irq_ciu_enable_gpio_v2(struct irq_data *data)
+{
+ octeon_irq_gpio_setup(data);
+ octeon_irq_ciu_enable_v2(data);
+}
+
+static void octeon_irq_ciu_enable_gpio(struct irq_data *data)
+{
+ octeon_irq_gpio_setup(data);
+ octeon_irq_ciu_enable(data);
+}
+
+static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t)
+{
+ u32 current_type = irqd_get_trigger_type(data);
+
+ /* If the type has been set, don't change it */
+ if (current_type && current_type != t)
+ return -EINVAL;
+
+ irqd_set_trigger_type(data, t);
+ return IRQ_SET_MASK_OK;
+}
+
+static void octeon_irq_ciu_disable_gpio_v2(struct irq_data *data)
+{
+ int bit = data->irq - OCTEON_IRQ_GPIO0;
+ cvmx_write_csr(CVMX_GPIO_BIT_CFGX(bit), 0);
+
+ octeon_irq_ciu_disable_all_v2(data);
+}
+
+static void octeon_irq_ciu_disable_gpio(struct irq_data *data)
+{
+ int bit = data->irq - OCTEON_IRQ_GPIO0;
+ cvmx_write_csr(CVMX_GPIO_BIT_CFGX(bit), 0);
+
+ octeon_irq_ciu_disable_all(data);
+}
+
+static void octeon_irq_ciu_gpio_ack(struct irq_data *data)
+{
+ int bit = data->irq - OCTEON_IRQ_GPIO0;
+ u64 mask = 1ull << bit;
+
+ cvmx_write_csr(CVMX_GPIO_INT_CLR, mask);
+}
+
#ifdef CONFIG_SMP
static void octeon_irq_cpu_offline_ciu(struct irq_data *data)
@@ -717,6 +939,31 @@ static struct irq_chip octeon_irq_chip_ciu_mbox = {
.flags = IRQCHIP_ONOFFLINE_ENABLED,
};
+static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = {
+ .name = "CIU-GPIO",
+ .irq_enable = octeon_irq_ciu_enable_gpio_v2,
+ .irq_disable = octeon_irq_ciu_disable_gpio_v2,
+ .irq_ack = octeon_irq_ciu_gpio_ack,
+ .irq_mask = octeon_irq_ciu_disable_local_v2,
+ .irq_unmask = octeon_irq_ciu_enable_v2,
+ .irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
+#endif
+};
+
+static struct irq_chip octeon_irq_chip_ciu_gpio = {
+ .name = "CIU-GPIO",
+ .irq_enable = octeon_irq_ciu_enable_gpio,
+ .irq_disable = octeon_irq_ciu_disable_gpio,
+ .irq_mask = octeon_irq_dummy_mask,
+ .irq_ack = octeon_irq_ciu_gpio_ack,
+ .irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = octeon_irq_ciu_set_affinity,
+#endif
+};
+
/*
* Watchdog interrupts are special. They are associated with a single
* core, so we hardwire the affinity to that core.
@@ -890,6 +1137,7 @@ static void __init octeon_irq_init_ciu(void)
struct irq_chip *chip_edge;
struct irq_chip *chip_mbox;
struct irq_chip *chip_wd;
+ struct irq_chip *chip_gpio;
octeon_irq_init_ciu_percpu();
octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -904,6 +1152,7 @@ static void __init octeon_irq_init_ciu(void)
chip_edge = &octeon_irq_chip_ciu_edge_v2;
chip_mbox = &octeon_irq_chip_ciu_mbox_v2;
chip_wd = &octeon_irq_chip_ciu_wd_v2;
+ chip_gpio = &octeon_irq_chip_ciu_gpio_v2;
} else {
octeon_irq_ip2 = octeon_irq_ip2_v1;
octeon_irq_ip3 = octeon_irq_ip3_v1;
@@ -911,6 +1160,7 @@ static void __init octeon_irq_init_ciu(void)
chip_edge = &octeon_irq_chip_ciu_edge;
chip_mbox = &octeon_irq_chip_ciu_mbox;
chip_wd = &octeon_irq_chip_ciu_wd;
+ chip_gpio = &octeon_irq_chip_ciu_gpio;
}
octeon_irq_ip4 = octeon_irq_ip4_mask;
@@ -921,7 +1171,7 @@ static void __init octeon_irq_init_ciu(void)
for (i = 0; i < 16; i++)
octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
for (i = 0; i < 16; i++)
- octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip, handle_level_irq);
+ octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip_gpio, handle_level_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
@@ -995,6 +1245,13 @@ static void __init octeon_irq_init_ciu(void)
octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFM, 1, 56, chip, handle_level_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_RST, 1, 63, chip, handle_level_irq);
+ octeon_irq_ciu_domain.of_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
+ irq_domain_add(&octeon_irq_ciu_domain);
+
+ octeon_irq_gpio_domain.of_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
+ octeon_irq_gpio_domain.hwirq_base = ((0 << 6) | 16);
+ irq_domain_add(&octeon_irq_gpio_domain);
+
/* Enable the CIU lines */
set_c0_status(STATUSF_IP3 | STATUSF_IP2);
clear_c0_status(STATUSF_IP4);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support.
2011-12-15 2:32 [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support David Daney
` (3 preceding siblings ...)
2011-12-15 2:32 ` [PATCH v2 4/4] MIPS: Octeon: Add irq_create_of_mapping() and GPIO interrupts David Daney
@ 2011-12-30 15:30 ` Rob Herring
2011-12-30 18:19 ` Grant Likely
4 siblings, 1 reply; 7+ messages in thread
From: Rob Herring @ 2011-12-30 15:30 UTC (permalink / raw)
To: David Daney
Cc: Thomas Gleixner, devicetree-discuss, Grant Likely, Rob Herring,
linux-mips, linux-kernel, David Daney
David,
On 12/14/2011 08:32 PM, David Daney wrote:
> From: David Daney <david.daney@cavium.com>
>
> Back in early Nov. I send the first version of this patch set. Now
> things are heating up again in the world of irq_domain, so I wanted to
> try to get some closure on the issues I had. The Octeon patch is
> included here to show how I am using irq_domain, but is part of a much
> larger effort to merge Octeon device tree support.
>
> The basic problem I am attempting to solve is using irq domains when
> there is a 'non-linear' mapping of hwirq <--> irq within a domain.
> Octeon has a single set of irq numbers that is used across two
> different implementations of the interrupt controller as well as more
> than 10 different SOCs all which use different subsets of the irq
> number space. The result is that the hwirq to irq mapping function
> contains many gaps and discontinuities, it is really quite random.
>
> The existing irq domain infrastructure assumes a continuous linear
> mapping of hwirq to irq that can be encapsulated by the irq_base,
> hwirq_base and nr_irq elements of struct irq_domain. This is not
> suitable for the Octeon implementation.
>
> The gist of my change is to add an optional iterator function to
> irq_domain_ops which knows how to iterate over the irq numbers in a
> given domain. For simple linear domains (those currently supported),
> we iterate using the current method based on irq_base, hwirq_base and
> nr_irq.
>
> Summary of the patches:
>
> 1) Get rid of some unused code to make subsequent changes simpler.
>
> 2) Cleanup the data type used by various hwirq functions and users.
>
> 3) Add the irq iterator, and fix up the ARM GIC code to use it instead
> of the current irq_domain_for_each_irq().
>
> 4) Add the Octeon users of the interface.
>
> In an earlier exchange, Rob Herring had said:
>
> ... Handling sparse irqs is a potentially common problem, so we
> should address that in the core irqdomain code.
>
> Which is what this patch set is doing.
>
> There was a suggestion that perhaps having .to_irq() return a magic
> value if there was no mapping would also work. However I prefer this
> approach as it separates the concepts of iteration and mapping of irq
> numbers.
>
> Please comment.
Can we first have a patch that just allows irq domains to be enabled on
MIPS. It collides because of multiple versions of irq_create_of_mapping.
Rob
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support.
2011-12-30 15:30 ` [PATCH v2 0/4] irq/of: Cleanup and Enchance irq_domain support Rob Herring
@ 2011-12-30 18:19 ` Grant Likely
0 siblings, 0 replies; 7+ messages in thread
From: Grant Likely @ 2011-12-30 18:19 UTC (permalink / raw)
To: Rob Herring
Cc: David Daney, Thomas Gleixner, devicetree-discuss, Rob Herring,
linux-mips, linux-kernel, David Daney
On Fri, Dec 30, 2011 at 8:30 AM, Rob Herring <robherring2@gmail.com> wrote:
> David,
>
> On 12/14/2011 08:32 PM, David Daney wrote:
>> From: David Daney <david.daney@cavium.com>
>>
>> Back in early Nov. I send the first version of this patch set. Now
>> things are heating up again in the world of irq_domain, so I wanted to
>> try to get some closure on the issues I had. The Octeon patch is
>> included here to show how I am using irq_domain, but is part of a much
>> larger effort to merge Octeon device tree support.
>>
>> The basic problem I am attempting to solve is using irq domains when
>> there is a 'non-linear' mapping of hwirq <--> irq within a domain.
>> Octeon has a single set of irq numbers that is used across two
>> different implementations of the interrupt controller as well as more
>> than 10 different SOCs all which use different subsets of the irq
>> number space. The result is that the hwirq to irq mapping function
>> contains many gaps and discontinuities, it is really quite random.
>>
>> The existing irq domain infrastructure assumes a continuous linear
>> mapping of hwirq to irq that can be encapsulated by the irq_base,
>> hwirq_base and nr_irq elements of struct irq_domain. This is not
>> suitable for the Octeon implementation.
>>
>> The gist of my change is to add an optional iterator function to
>> irq_domain_ops which knows how to iterate over the irq numbers in a
>> given domain. For simple linear domains (those currently supported),
>> we iterate using the current method based on irq_base, hwirq_base and
>> nr_irq.
>>
>> Summary of the patches:
>>
>> 1) Get rid of some unused code to make subsequent changes simpler.
>>
>> 2) Cleanup the data type used by various hwirq functions and users.
>>
>> 3) Add the irq iterator, and fix up the ARM GIC code to use it instead
>> of the current irq_domain_for_each_irq().
>>
>> 4) Add the Octeon users of the interface.
>>
>> In an earlier exchange, Rob Herring had said:
>>
>> ... Handling sparse irqs is a potentially common problem, so we
>> should address that in the core irqdomain code.
>>
>> Which is what this patch set is doing.
>>
>> There was a suggestion that perhaps having .to_irq() return a magic
>> value if there was no mapping would also work. However I prefer this
>> approach as it separates the concepts of iteration and mapping of irq
>> numbers.
>>
>> Please comment.
>
> Can we first have a patch that just allows irq domains to be enabled on
> MIPS. It collides because of multiple versions of irq_create_of_mapping.
I'm working on this. I made some poor decisions when first
implementing irq_domain which have made it difficult to bring into
sync with powerpc. Right now I'm working on a series to replace the
new irq_domain with the existing (working-for-years) powerpc code and
converting over all the users. Basically what I should have done in
the first place.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 7+ messages in thread