Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 309d1dcb authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'irq-fixes-for-linus' of...

Merge branch 'irq-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'irq-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  genirq: Move two IRQ functions from .init.text to .text
  genirq: Protect access to irq_desc->action in can_request_irq()
  genirq: Prevent oneshot irq thread race
parents 8128f55a 860652bf
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
		if (desc->chip->ack)
			desc->chip->ack(irq);
	}
	desc->status |= IRQ_MASKED;
}

static inline void mask_irq(struct irq_desc *desc, int irq)
{
	if (desc->chip->mask) {
		desc->chip->mask(irq);
		desc->status |= IRQ_MASKED;
	}
}

static inline void unmask_irq(struct irq_desc *desc, int irq)
{
	if (desc->chip->unmask) {
		desc->chip->unmask(irq);
		desc->status &= ~IRQ_MASKED;
	}
}

/*
@@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
	raw_spin_lock(&desc->lock);
	desc->status &= ~IRQ_INPROGRESS;

	if (unlikely(desc->status & IRQ_ONESHOT))
		desc->status |= IRQ_MASKED;
	else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
		desc->chip->unmask(irq);
	if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))
		unmask_irq(desc, irq);
out_unlock:
	raw_spin_unlock(&desc->lock);
}
@@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
	action = desc->action;
	if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
		desc->status |= IRQ_PENDING;
		if (desc->chip->mask)
			desc->chip->mask(irq);
		mask_irq(desc, irq);
		goto out;
	}

@@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
		irqreturn_t action_ret;

		if (unlikely(!action)) {
			desc->chip->mask(irq);
			mask_irq(desc, irq);
			goto out_unlock;
		}

@@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
		if (unlikely((desc->status &
			       (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
			      (IRQ_PENDING | IRQ_MASKED))) {
			desc->chip->unmask(irq);
			desc->status &= ~IRQ_MASKED;
			unmask_irq(desc, irq);
		}

		desc->status &= ~IRQ_PENDING;
@@ -716,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
	__set_irq_handler(irq, handle, 0, name);
}

void __init set_irq_noprobe(unsigned int irq)
void set_irq_noprobe(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	unsigned long flags;
@@ -731,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq)
	raw_spin_unlock_irqrestore(&desc->lock, flags);
}

void __init set_irq_probe(unsigned int irq)
void set_irq_probe(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	unsigned long flags;
+22 −0
Original line number Diff line number Diff line
@@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
{
	struct irq_desc *desc = irq_to_desc(irq);
	struct irqaction *action;
	unsigned long flags;

	if (!desc)
		return 0;
@@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
	if (desc->status & IRQ_NOREQUEST)
		return 0;

	raw_spin_lock_irqsave(&desc->lock, flags);
	action = desc->action;
	if (action)
		if (irqflags & action->flags & IRQF_SHARED)
			action = NULL;

	raw_spin_unlock_irqrestore(&desc->lock, flags);

	return !action;
}

@@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action)
 */
static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
{
again:
	chip_bus_lock(irq, desc);
	raw_spin_lock_irq(&desc->lock);

	/*
	 * Implausible though it may be we need to protect us against
	 * the following scenario:
	 *
	 * The thread is faster done than the hard interrupt handler
	 * on the other CPU. If we unmask the irq line then the
	 * interrupt can come in again and masks the line, leaves due
	 * to IRQ_INPROGRESS and the irq line is masked forever.
	 */
	if (unlikely(desc->status & IRQ_INPROGRESS)) {
		raw_spin_unlock_irq(&desc->lock);
		chip_bus_sync_unlock(irq, desc);
		cpu_relax();
		goto again;
	}

	if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
		desc->status &= ~IRQ_MASKED;
		desc->chip->unmask(irq);