public inbox for linux-sh@vger.kernel.org
 help / color / mirror / Atom feed
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


             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