All of lore.kernel.org
 help / color / mirror / Atom feed
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.

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.