Skip to content

Commit df9541a

Browse files
KAGA-KOKOglikely
authored andcommitted
gpio: pch9: Use proper flow type handlers
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 <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Grant Likely <[email protected]>
1 parent 6edd94d commit df9541a

File tree

1 file changed

+28
-29
lines changed

1 file changed

+28
-29
lines changed

drivers/gpio/gpio-pch.c

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,12 @@ static void pch_gpio_setup(struct pch_gpio *chip)
230230

231231
static int pch_irq_type(struct irq_data *d, unsigned int type)
232232
{
233-
u32 im;
234-
u32 __iomem *im_reg;
235-
u32 ien;
236-
u32 im_pos;
237-
int ch;
238-
unsigned long flags;
239-
u32 val;
240-
int irq = d->irq;
241233
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
242234
struct pch_gpio *chip = gc->private;
235+
u32 im, im_pos, val;
236+
u32 __iomem *im_reg;
237+
unsigned long flags;
238+
int ch, irq = d->irq;
243239

244240
ch = irq - chip->irq_base;
245241
if (irq <= chip->irq_base + 7) {
@@ -270,30 +266,22 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
270266
case IRQ_TYPE_LEVEL_LOW:
271267
val = PCH_LEVEL_L;
272268
break;
273-
case IRQ_TYPE_PROBE:
274-
goto end;
275269
default:
276-
dev_warn(chip->dev, "%s: unknown type(%dd)",
277-
__func__, type);
278-
goto end;
270+
goto unlock;
279271
}
280272

281273
/* Set interrupt mode */
282274
im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
283275
iowrite32(im | (val << (im_pos * 4)), im_reg);
284276

285-
/* iclr */
286-
iowrite32(BIT(ch), &chip->reg->iclr);
277+
/* And the handler */
278+
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
279+
__irq_set_handler_locked(d->irq, handle_level_irq);
280+
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
281+
__irq_set_handler_locked(d->irq, handle_edge_irq);
287282

288-
/* IMASKCLR */
289-
iowrite32(BIT(ch), &chip->reg->imaskclr);
290-
291-
/* Enable interrupt */
292-
ien = ioread32(&chip->reg->ien);
293-
iowrite32(ien | BIT(ch), &chip->reg->ien);
294-
end:
283+
unlock:
295284
spin_unlock_irqrestore(&chip->spinlock, flags);
296-
297285
return 0;
298286
}
299287

@@ -313,18 +301,24 @@ static void pch_irq_mask(struct irq_data *d)
313301
iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask);
314302
}
315303

304+
static void pch_irq_ack(struct irq_data *d)
305+
{
306+
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
307+
struct pch_gpio *chip = gc->private;
308+
309+
iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->iclr);
310+
}
311+
316312
static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
317313
{
318314
struct pch_gpio *chip = dev_id;
319315
u32 reg_val = ioread32(&chip->reg->istatus);
320-
int i;
321-
int ret = IRQ_NONE;
316+
int i, ret = IRQ_NONE;
322317

323318
for (i = 0; i < gpio_pins[chip->ioh]; i++) {
324319
if (reg_val & BIT(i)) {
325320
dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n",
326321
__func__, i, irq, reg_val);
327-
iowrite32(BIT(i), &chip->reg->iclr);
328322
generic_handle_irq(chip->irq_base + i);
329323
ret = IRQ_HANDLED;
330324
}
@@ -343,6 +337,7 @@ static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
343337
gc->private = chip;
344338
ct = gc->chip_types;
345339

340+
ct->chip.irq_ack = pch_irq_ack;
346341
ct->chip.irq_mask = pch_irq_mask;
347342
ct->chip.irq_unmask = pch_irq_unmask;
348343
ct->chip.irq_set_type = pch_irq_type;
@@ -357,6 +352,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
357352
s32 ret;
358353
struct pch_gpio *chip;
359354
int irq_base;
355+
u32 msk;
360356

361357
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
362358
if (chip == NULL)
@@ -408,8 +404,13 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
408404
}
409405
chip->irq_base = irq_base;
410406

407+
/* Mask all interrupts, but enable them */
408+
msk = (1 << gpio_pins[chip->ioh]) - 1;
409+
iowrite32(msk, &chip->reg->imask);
410+
iowrite32(msk, &chip->reg->ien);
411+
411412
ret = request_irq(pdev->irq, pch_gpio_handler,
412-
IRQF_SHARED, KBUILD_MODNAME, chip);
413+
IRQF_SHARED, KBUILD_MODNAME, chip);
413414
if (ret != 0) {
414415
dev_err(&pdev->dev,
415416
"%s request_irq failed\n", __func__);
@@ -418,8 +419,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
418419

419420
pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
420421

421-
/* Initialize interrupt ien register */
422-
iowrite32(0, &chip->reg->ien);
423422
end:
424423
return 0;
425424

0 commit comments

Comments
 (0)