From: Grant Likely <grant.likely@secretlab.ca>
To: Thomas Gleixner <tglx@linutronix.de>,
Jean-Francois Dagenais <jeff.dagenais@gmail.com>
Cc: open list <linux-kernel@vger.kernel.org>,
alexander.stein@systec-electronic.com, qi.wang@intel.com,
yong.y.wang@intel.com, joel.clark@intel.com,
kok.howg.ewe@intel.com, tomoya.rohm@gmail.com
Subject: Re: [PATCH] gpio: pch9: Use proper flow type handlers
Date: Fri, 11 May 2012 18:20:10 -0600 [thread overview]
Message-ID: <20120512002010.ECE643E0791@localhost> (raw)
In-Reply-To: <alpine.LFD.2.02.1204281012420.6271@ionos>
On Sat, 28 Apr 2012 10:13:45 +0200 (CEST), Thomas Gleixner <tglx@linutronix.de> wrote:
> Jean-Francois Dagenais reported:
>
> Configuring a gpio pin with the gpio-pch driver with
> "IRQF_TRIGGER_LOW | IRQF_ONESHOT" generates an interrupt storm for
> threaded ISR until the ISR thread actually gets to physically clear
> the interrupt on the triggering chip!! The immediate observable
> symptom is the high CPU usage for my ISR thread task and the
> interrupt count in /proc/interrupts incrementing radically.
>
> The driver is wrong in several ways:
>
> 1) Using handle_simple_irq() does not provide proper flow control
> handling. In the case of oneshot threaded handlers for the
> demultiplexed interrupts this results in an interrupt storm because
> the simple handler does not deal with masking/unmasking. Even
> without threaded oneshot handlers an interrupt storm for level type
> interrupts can easily be triggered when the interrupt is disabled
> and the interrupt line is activated from the device.
>
> 2) Acknowlegding the demultiplexed interrupt before calling the
> handler is wrong for level type interrupts.
>
> 3) The set_type function unconditionally enables the interrupt. It's
> supposed to set the type and nothing else. The unmasking is done by
> the core code.
>
> Move the acknowledge code into a separate function and add it to the
> demux irqchip callbacks.
>
> Remove the unconditional enabling from the set_type() callback and set
> the proper flow handlers depending on the selected type (level/edge).
>
> Reported-and-tested-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: alexander.stein@systec-electronic.com
> Cc: qi.wang@intel.com
> Cc: yong.y.wang@intel.com
> Cc: joel.clark@intel.com
> Cc: kok.howg.ewe@intel.com
> Cc: toshiharu-linux@dsn.okisemi.com
> Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1204252332070.2542@ionos
Applied, thanks. I'll push to Linus right away.
g.
> ---
> drivers/gpio/gpio-pch.c | 57 +++++++++++++++++++++++-------------------------
> 1 file changed, 28 insertions(+), 29 deletions(-)
>
> Index: linux-2.6/drivers/gpio/gpio-pch.c
> ===================================================================
> --- linux-2.6.orig/drivers/gpio/gpio-pch.c
> +++ linux-2.6/drivers/gpio/gpio-pch.c
> @@ -230,16 +230,12 @@ static void pch_gpio_setup(struct pch_gp
>
> static int pch_irq_type(struct irq_data *d, unsigned int type)
> {
> - u32 im;
> - u32 __iomem *im_reg;
> - u32 ien;
> - u32 im_pos;
> - int ch;
> - unsigned long flags;
> - u32 val;
> - int irq = d->irq;
> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> struct pch_gpio *chip = gc->private;
> + u32 im, im_pos, val;
> + u32 __iomem *im_reg;
> + unsigned long flags;
> + int ch, irq = d->irq;
>
> ch = irq - chip->irq_base;
> if (irq <= chip->irq_base + 7) {
> @@ -270,30 +266,22 @@ static int pch_irq_type(struct irq_data
> case IRQ_TYPE_LEVEL_LOW:
> val = PCH_LEVEL_L;
> break;
> - case IRQ_TYPE_PROBE:
> - goto end;
> default:
> - dev_warn(chip->dev, "%s: unknown type(%dd)",
> - __func__, type);
> - goto end;
> + goto unlock;
> }
>
> /* Set interrupt mode */
> im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
> iowrite32(im | (val << (im_pos * 4)), im_reg);
>
> - /* iclr */
> - iowrite32(BIT(ch), &chip->reg->iclr);
> + /* And the handler */
> + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
> + __irq_set_handler_locked(d->irq, handle_level_irq);
> + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
> + __irq_set_handler_locked(d->irq, handle_edge_irq);
>
> - /* IMASKCLR */
> - iowrite32(BIT(ch), &chip->reg->imaskclr);
> -
> - /* Enable interrupt */
> - ien = ioread32(&chip->reg->ien);
> - iowrite32(ien | BIT(ch), &chip->reg->ien);
> -end:
> +unlock:
> spin_unlock_irqrestore(&chip->spinlock, flags);
> -
> return 0;
> }
>
> @@ -313,18 +301,24 @@ static void pch_irq_mask(struct irq_data
> iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask);
> }
>
> +static void pch_irq_ack(struct irq_data *d)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> + struct pch_gpio *chip = gc->private;
> +
> + iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->iclr);
> +}
> +
> static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
> {
> struct pch_gpio *chip = dev_id;
> u32 reg_val = ioread32(&chip->reg->istatus);
> - int i;
> - int ret = IRQ_NONE;
> + int i, ret = IRQ_NONE;
>
> for (i = 0; i < gpio_pins[chip->ioh]; i++) {
> if (reg_val & BIT(i)) {
> dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n",
> __func__, i, irq, reg_val);
> - iowrite32(BIT(i), &chip->reg->iclr);
> generic_handle_irq(chip->irq_base + i);
> ret = IRQ_HANDLED;
> }
> @@ -343,6 +337,7 @@ static __devinit void pch_gpio_alloc_gen
> gc->private = chip;
> ct = gc->chip_types;
>
> + ct->chip.irq_ack = pch_irq_ack;
> ct->chip.irq_mask = pch_irq_mask;
> ct->chip.irq_unmask = pch_irq_unmask;
> ct->chip.irq_set_type = pch_irq_type;
> @@ -357,6 +352,7 @@ static int __devinit pch_gpio_probe(stru
> s32 ret;
> struct pch_gpio *chip;
> int irq_base;
> + u32 msk;
>
> chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> if (chip == NULL)
> @@ -408,8 +404,13 @@ static int __devinit pch_gpio_probe(stru
> }
> chip->irq_base = irq_base;
>
> + /* Mask all interrupts, but enable them */
> + msk = (1 << gpio_pins[chip->ioh]) - 1;
> + iowrite32(msk, &chip->reg->imask);
> + iowrite32(msk, &chip->reg->ien);
> +
> ret = request_irq(pdev->irq, pch_gpio_handler,
> - IRQF_SHARED, KBUILD_MODNAME, chip);
> + IRQF_SHARED, KBUILD_MODNAME, chip);
> if (ret != 0) {
> dev_err(&pdev->dev,
> "%s request_irq failed\n", __func__);
> @@ -418,8 +419,6 @@ static int __devinit pch_gpio_probe(stru
>
> pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
>
> - /* Initialize interrupt ien register */
> - iowrite32(0, &chip->reg->ien);
> end:
> return 0;
>
--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.
next prev parent reply other threads:[~2012-05-12 0:20 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-21 0:19 [PATCH 1/6 v2] gpio-pch: Delete invalid "restore" code in suspend() Tomoya MORINAGA
2011-07-21 0:19 ` [PATCH 2/6 v2] gpio-pch: add spinlock in suspend/resume processing Tomoya MORINAGA
2011-07-21 0:19 ` [PATCH 3/6 v2] gpio-pch: support ML7223 IOH n-Bus Tomoya MORINAGA
2011-07-21 0:19 ` [PATCH 4/6 v2] gpio-pch: modify gpio_nums and mask Tomoya MORINAGA
2011-07-21 0:19 ` [PATCH 5/6 v2] gpio-pch: Save register value in suspend() Tomoya MORINAGA
2011-07-21 0:19 ` [PATCH 6/6 v6] gpio-pch: Support interrupt function Tomoya MORINAGA
2011-12-08 19:37 ` gpio-pch: does not honour IRQF_ONESHOT? Jean-Francois Dagenais
2012-04-25 20:09 ` gpio-pch: BUG - driver does not honour IRQF_ONESHOT Jean-Francois Dagenais
2012-04-25 23:03 ` gpio-pch: BUG - driver does not honour IRQF_ONESHOTn Thomas Gleixner
2012-04-27 20:14 ` Jean-Francois Dagenais
2012-04-28 8:13 ` [PATCH] gpio: pch9: Use proper flow type handlers Thomas Gleixner
2012-05-12 0:20 ` Grant Likely [this message]
2011-10-05 18:00 ` [PATCH 1/6 v2] gpio-pch: Delete invalid "restore" code in suspend() Grant Likely
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=20120512002010.ECE643E0791@localhost \
--to=grant.likely@secretlab.ca \
--cc=alexander.stein@systec-electronic.com \
--cc=jeff.dagenais@gmail.com \
--cc=joel.clark@intel.com \
--cc=kok.howg.ewe@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=qi.wang@intel.com \
--cc=tglx@linutronix.de \
--cc=tomoya.rohm@gmail.com \
--cc=yong.y.wang@intel.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 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).