From: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
To: linux-sh@vger.kernel.org
Subject: [PATCH] sh: fix INTC group handling
Date: Mon, 09 Feb 2009 11:38:08 +0000 [thread overview]
Message-ID: <499015A0.9060105@renesas.com> (raw)
In a grouped interrupt such as DMAC of SH7785, there was the problem that
a certain interrupt masked the other interrupts when it was masked.
Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
---
drivers/sh/intc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 58d24c5..f1826d2 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -39,6 +39,12 @@ struct intc_handle_int {
unsigned long handle;
};
+struct intc_groups_int {
+ unsigned long handle;
+ int irq[32];
+ unsigned long enabled_bit;
+};
+
struct intc_desc_int {
unsigned long *reg;
#ifdef CONFIG_SMP
@@ -49,6 +55,9 @@ struct intc_desc_int {
unsigned int nr_prio;
struct intc_handle_int *sense;
unsigned int nr_sense;
+ struct intc_groups_int *group;
+ int group_index[NR_IRQS];
+ unsigned long group_bit[NR_IRQS];
struct irq_chip chip;
};
@@ -206,6 +215,9 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)
unsigned long addr;
unsigned int cpu;
+ if (d->group_bit[irq])
+ d->group[d->group_index[irq]].enabled_bit |= d->group_bit[irq];
+
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
@@ -218,13 +230,21 @@ static void intc_enable(unsigned int irq)
_intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
}
-static void intc_disable(unsigned int irq)
+static void _intc_disable(unsigned int irq, int mask_ack)
{
struct intc_desc_int *d = get_intc_desc(irq);
unsigned long handle = (unsigned long) get_irq_chip_data(irq);
unsigned long addr;
unsigned int cpu;
+ if (!mask_ack && d->group_bit[irq]) {
+ struct intc_groups_int *g = &d->group[d->group_index[irq]];
+
+ g->enabled_bit &= ~d->group_bit[irq];
+ if (g->enabled_bit)
+ return;
+ }
+
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
@@ -232,6 +252,16 @@ static void intc_disable(unsigned int irq)
}
}
+static void intc_disable(unsigned int irq)
+{
+ _intc_disable(irq, 0);
+}
+
+static void intc_disable_mask_ack(unsigned int irq)
+{
+ _intc_disable(irq, 1);
+}
+
#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static void intc_mask_ack(unsigned int irq)
{
@@ -546,13 +576,38 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,
return 0;
}
+static void __init intc_group_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ int irq,
+ unsigned long handle)
+{
+ struct intc_group *g = desc->groups;
+ struct intc_groups_int *gi;
+ int i, j;
+
+ for (i = 0; g && i < desc->nr_groups; i++) {
+ gi = &d->group[i];
+ if (!gi->handle || (gi->handle = handle)) {
+ gi->handle = handle;
+ for (j = 0; j < ARRAY_SIZE(gi->irq); j++) {
+ if (!gi->irq[j]) {
+ gi->irq[j] = irq;
+ d->group_index[irq] = i;
+ d->group_bit[irq] = 1 << j;
+ return;
+ }
+ }
+ }
+ }
+}
+
static void __init intc_register_irq(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id,
unsigned int irq)
{
struct intc_handle_int *hp;
- unsigned int data[2], primary;
+ unsigned int data[2], primary, groups;
/* Prefer single interrupt source bitmap over other combinations:
* 1. bitmap, single interrupt source
@@ -568,6 +623,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
if (!data[0] && data[1])
primary = 1;
+ groups = 0;
+ if (!data[primary])
+ groups = 1;
+
data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
@@ -608,6 +667,9 @@ static void __init intc_register_irq(struct intc_desc *desc,
d->nr_prio++;
}
+ if (groups)
+ intc_group_data(desc, d, irq, data[primary]);
+
/* add irq to d->sense list if sense is available */
data[0] = intc_sense_data(desc, d, enum_id);
if (data[0]) {
@@ -688,10 +750,13 @@ void __init register_intc_controller(struct intc_desc *desc)
}
}
+ if (desc->nr_groups)
+ d->group = alloc_bootmem(desc->nr_groups * sizeof(*d->group));
+
d->chip.name = desc->name;
d->chip.mask = intc_disable;
d->chip.unmask = intc_enable;
- d->chip.mask_ack = intc_disable;
+ d->chip.mask_ack = intc_disable_mask_ack;
d->chip.set_type = intc_set_sense;
#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
--
1.5.5
next reply other threads:[~2009-02-09 11:38 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-09 11:38 Yoshihiro Shimoda [this message]
2009-02-17 3:49 ` [PATCH] sh: fix INTC group handling Magnus Damm
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=499015A0.9060105@renesas.com \
--to=shimoda.yoshihiro@renesas.com \
--cc=linux-sh@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox