From: David Gibson <david@gibson.dropbear.id.au>
To: Paul Mackerras <paulus@samba.org>,
Josh Boyer <jwboyer@linux.vnet.ibm.com>
Cc: linuxppc-dev@ozlabs.org
Subject: [PATCH 2/3] Fix irq flow handler for 4xx UIC
Date: Tue, 14 Aug 2007 13:52:42 +1000 (EST) [thread overview]
Message-ID: <20070814035242.9674EDDEF0@ozlabs.org> (raw)
In-Reply-To: <20070814034811.GA8791@localhost.localdomain>
At present the driver for the UIC (the embedded interrupt controller
in 4xx chips) uses the handle_level_irq() flow handler. It turns out
this does not correctly handle level triggered interrupts on the UIC.
Specifically, acknowledging an irq on the UIC (i.e. clearing the
relevant bit in UIC_SR) will have no effect for a level interrupt
which is still asserted by the external device, even if the irq is
already masked. Therefore, unlike handle_level_irq() we must ack the
interrupt after invoking the ISR (which should cause the device to
stop asserting the irq) instead of acking it when we mask it, before
the ISR.
This patch implements this change, in a new handle_uic_irq(), a
customised irq flow handler for the UIC. For edge triggered
interrupts, handle_uic_irq() still uses the old flow - we must ack
edge triggered interrupt before the ISR not after, or we could miss a
second event which occurred between invoking the ISR and acking the
irq.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
arch/powerpc/sysdev/uic.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
Index: working-2.6/arch/powerpc/sysdev/uic.c
===================================================================
--- working-2.6.orig/arch/powerpc/sysdev/uic.c 2007-08-14 13:17:52.000000000 +1000
+++ working-2.6/arch/powerpc/sysdev/uic.c 2007-08-14 13:17:57.000000000 +1000
@@ -24,6 +24,7 @@
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/prom.h>
@@ -159,6 +160,64 @@ static struct irq_chip uic_irq_chip = {
.set_type = uic_set_irq_type,
};
+/**
+ * handle_uic_irq - irq flow handler for UIC
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+ *
+ * This is modified version of the generic handle_level_irq() suitable
+ * for the UIC. On the UIC, acking (i.e. clearing the SR bit) a level
+ * irq will have no effect if the interrupt is still asserted by the
+ * device, even if the interrupt is already masked. Therefore, unlike
+ * the standard handle_level_irq(), we must ack the interrupt *after*
+ * invoking the ISR (which should have de-asserted the interrupt in
+ * the external source). For edge interrupts we ack at the beginning
+ * instead of the end, to keep the window in which we can miss an
+ * interrupt as small as possible.
+ */
+void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int cpu = smp_processor_id();
+ struct irqaction *action;
+ irqreturn_t action_ret;
+
+ spin_lock(&desc->lock);
+ if (desc->status & IRQ_LEVEL)
+ desc->chip->mask(irq);
+ else
+ desc->chip->mask_ack(irq);
+
+ if (unlikely(desc->status & IRQ_INPROGRESS))
+ goto out_unlock;
+ desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+ kstat_cpu(cpu).irqs[irq]++;
+
+ /*
+ * If its disabled or no action available
+ * keep it masked and get out of here
+ */
+ action = desc->action;
+ if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
+ desc->status |= IRQ_PENDING;
+ goto out_unlock;
+ }
+
+ desc->status |= IRQ_INPROGRESS;
+ desc->status &= ~IRQ_PENDING;
+ spin_unlock(&desc->lock);
+
+ action_ret = handle_IRQ_event(irq, action);
+
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_INPROGRESS;
+ if (desc->status & IRQ_LEVEL)
+ desc->chip->ack(irq);
+ if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+ desc->chip->unmask(irq);
+out_unlock:
+ spin_unlock(&desc->lock);
+}
+
static int uic_host_match(struct irq_host *h, struct device_node *node)
{
struct uic *uic = h->host_data;
@@ -173,7 +232,7 @@ static int uic_host_map(struct irq_host
set_irq_chip_data(virq, uic);
/* Despite the name, handle_level_irq() works for both level
* and edge irqs on UIC. FIXME: check this is correct */
- set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
+ set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq);
/* Set default irq type */
set_irq_type(virq, IRQ_TYPE_NONE);
next prev parent reply other threads:[~2007-08-14 3:52 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-14 3:48 [0/3] UIC fixes David Gibson
2007-08-14 3:52 ` [PATCH 1/3] Fix setting of irq trigger type in UIC driver David Gibson
2007-08-15 19:13 ` Josh Boyer
2007-08-14 3:52 ` [PATCH 3/3] Improve robustness of the UIC cascade handler David Gibson
2007-08-15 19:25 ` Josh Boyer
2007-08-14 3:52 ` David Gibson [this message]
2007-08-15 19:13 ` [PATCH 2/3] Fix irq flow handler for 4xx UIC Josh Boyer
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=20070814035242.9674EDDEF0@ozlabs.org \
--to=david@gibson.dropbear.id.au \
--cc=jwboyer@linux.vnet.ibm.com \
--cc=linuxppc-dev@ozlabs.org \
--cc=paulus@samba.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;
as well as URLs for NNTP newsgroup(s).