Hi Tejun, Today's linux-next merge of the lost-spurious-irq tree got a conflict in kernel/irq/spurious.c between commits 6b8ff3120c758340505dddf08ad685ebb841d5d5 ("genirq: Convert core code to irq_data") and bd151412263a67b5321e9dd1d5b4bf6d96fdebf3 ("genirq: Provide config option to disable deprecated code") from the tip tree and commits 32b5d378f49485f3ae172eb0ac2bfc4ebbbdb060 ("irq: cleanup irqfixup") and 80f97e2b33c3e66c11b10abd2890506a3abeb320 ("irq: make spurious poll timer per desc") from the lost-spurious-irq tree. I think I fixed it all up (see below). I can carry this fix (or a better one) as necessary. -- Cheers, Stephen Rothwell sfr@xxxxxxxxxxxxxxxx diff --cc kernel/irq/spurious.c index 3089d3b,b34b023..0000000 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@@ -16,14 -75,558 +75,558 @@@ #include "internals.h" - static int irqfixup __read_mostly; + /* + * I spent quite some time thinking about each parameter but they + * still are just numbers pulled out of my ass. If you think your ass + * is prettier than mine, please go ahead and suggest better ones. + * + * Most parameters are intentionally fixed constants and not + * adjustable through API. The nature of IRQ delivery failures isn't + * usually dependent on specific drivers and the timing parameters are + * more about human perceivable latencies rather than any specific + * controller timing details, so figuring out constant values which + * can work for most cases shouldn't be too hard. This allows tighter + * control over polling behaviors, eases future changes and makes the + * interface easy for drivers. + */ + enum { + /* irqfixup levels */ + IRQFIXUP_SPURIOUS = 0, /* spurious storm detection */ + IRQFIXUP_MISROUTED = 1, /* misrouted IRQ fixup */ + IRQFIXUP_POLL = 2, /* enable polling by default */ + + /* IRQ polling common parameters */ + IRQ_POLL_SLOW_INTV = 3 * HZ, /* not too slow for ppl, slow enough for machine */ + IRQ_POLL_INTV = HZ / 100, /* from the good ol' 100HZ tick */ + IRQ_POLL_QUICK_INTV = HZ / 1000, /* on every tick, basically */ + + IRQ_POLL_SLOW_SLACK = HZ, + IRQ_POLL_SLACK = HZ / 250, /* 1 tick slack w/ the popular 250HZ config */ + IRQ_POLL_QUICK_SLACK = HZ / 10000, /* no slack, basically */ + + /* + * IRQ expect parameters. + * + * Because IRQ expecting is tightly coupled with the actual + * activity of the controller, we can be slightly aggressive + * and try to minimize the effect of lost interrupts. + * + * An irqaction must accumulate VERIFY_GOAL good deliveries, + * where one bad delivery (delivered by polling) costs + * BAD_FACTOR good ones, before reaching the verified state. + * + * QUICK_SAMPLES IRQ deliveries are examined and if + * >=QUICK_THRESHOLD of them are polled on the first poll, the + * IRQ is considered to be quick and QUICK_INTV is used + * instead. + * + * Keep QUICK_SAMPLES much higher than VERIFY_GOAL so that + * quick polling doesn't interfact with the initial + * verification attempt (quicker polling increases the chance + * of polled deliveries). + */ + IRQ_EXP_BAD_FACTOR = 10, + IRQ_EXP_VERIFY_GOAL = 256, + IRQ_EXP_QUICK_SAMPLES = IRQ_EXP_VERIFY_GOAL * 4, + IRQ_EXP_QUICK_THRESHOLD = IRQ_EXP_QUICK_SAMPLES * 8 / 10, + + /* IRQ expect flags */ + IRQ_EXPECTING = (1 << 0), /* expecting in progress */ + IRQ_EXP_VERIFIED = (1 << 1), /* delivery verified, use slow interval */ + IRQ_EXP_QUICK = (1 << 2), /* quick polling enabled */ + IRQ_EXP_WARNED = (1 << 3), /* already whined */ + + /* + * IRQ watch parameters. + * + * As IRQ watching has much less information about what's + * going on, the parameters are more conservative. It will + * terminate unless it can reliably determine that IRQ + * delivery isn't working. + * + * IRQs are watched in timed intervals which is BASE_PERIOD + * long by default. Polling interval starts at BASE_INTV and + * grows upto SLOW_INTV if no bad delivery is detected. + * + * If a period contains zero sample and no bad delivery was + * seen since watch started, watch terminates. + * + * If a period contains >=1 but <MIN_SAMPLES deliveries, + * collected samples are inherited to the next period. + * + * If it contains enough samples, the ratio between good and + * bad deliveries are examined, if >=BAD_PCT% are bad, the + * irqaction is tagged bad and watched indefinitely. if + * BAD_PCT% > nr_bad >= WARY_PCT%, WARY_PERIOD is used instead + * of BASE_PERIOD and the whole process is restarted. If + * <WARY_PCT% are bad, watch terminates. + */ + IRQ_WAT_MIN_SAMPLES = 10, + IRQ_WAT_BASE_INTV = HZ / 2, + IRQ_WAT_BASE_PERIOD = 60 * HZ, + IRQ_WAT_WARY_PERIOD = 600 * HZ, + IRQ_WAT_WARY_PCT = 1, + IRQ_WAT_BAD_PCT = 10, + + /* IRQ watch flags */ + IRQ_WATCHING = (1 << 0), + IRQ_WAT_POLLED = (1 << 1), + IRQ_WAT_WARY = (1 << 2), + IRQ_WAT_BAD = (1 << 3), + + /* + * Spurious IRQ handling parameters. + * + * As this per-IRQ spurious handling is cheaper than the + * previous system wide spurious handling, it can afford to + * use more responsive settings but these parameters are still + * pretty conservative. If ever necessary, making it more + * responsive shouldn't cause any problem. + * + * Spurious IRQs are monitored in segments of PERIOD_SAMPLES + * IRQs which can stretch PERIOD_DURATION at maximum. If + * there are less than PERIOD_SAMPLES IRQs per + * PERIOD_DURATION, the period is considered good. + * + * If >=BAD_THRESHOLD IRQs are bad ones, the period is + * considered bad and spurious IRQ handling kicks in - the IRQ + * is disabled and polled. The IRQ is given another shot + * after certain number IRQs are handled, which is at minimum + * POLL_CNT_MIN, increased by 1 << POLL_CNT_INC_SHIFT times + * after each bad period and decreased by factor of + * POLL_CNT_INC_DEC_SHIFT after each good one. + */ + IRQ_SPR_PERIOD_DURATION = 10 * HZ, + IRQ_SPR_PERIOD_SAMPLES = 10000, + IRQ_SPR_BAD_THRESHOLD = 9900, + IRQ_SPR_POLL_CNT_MIN = 10000, + IRQ_SPR_POLL_CNT_INF = UINT_MAX, + IRQ_SPR_POLL_CNT_INC_SHIFT = 3, + IRQ_SPR_POLL_CNT_DEC_SHIFT = 1, + IRQ_SPR_POLL_CNT_MAX_DEC_SHIFT = BITS_PER_BYTE * sizeof(int) / 4, + }; + + struct irq_expect { + struct irq_expect *next; + struct irq_desc *desc; /* the associated IRQ desc */ + struct irqaction *act; /* the associated IRQ action */ + + unsigned int flags; /* IRQ_EXP_* flags */ + unsigned int nr_samples; /* nr of collected samples in this period */ + unsigned int nr_quick; /* nr of polls completed after single attempt */ + unsigned int nr_good; /* nr of good IRQ deliveries */ + unsigned long started; /* when this period started */ + }; + + int noirqdebug __read_mostly; + static int irqfixup __read_mostly = IRQFIXUP_SPURIOUS; + + static struct irqaction *find_irq_action(struct irq_desc *desc, void *dev_id) + { + struct irqaction *act; + + for (act = desc->action; act; act = act->next) + if (act->dev_id == dev_id) + return act; + return NULL; + } + + static void print_irq_handlers(struct irq_desc *desc) + { + struct irqaction *action; + + printk(KERN_ERR "handlers:\n"); + + action = desc->action; + while (action) { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", (unsigned long)action->handler); + printk("\n"); + action = action->next; + } + } + + static void warn_irq_poll(struct irq_desc *desc, struct irqaction *act) + { + if (desc->poll_warned) + return; + + desc->poll_warned = true; + + printk(KERN_WARNING "IRQ %u: %s: can't verify IRQ, will keep polling\n", - desc->irq, act->name); ++ desc->irq_data.irq, act->name); + printk(KERN_WARNING "IRQ %u: %s: system performance may be affected\n", - desc->irq, act->name); ++ desc->irq_data.irq, act->name); + } + + static unsigned long irq_poll_slack(unsigned long intv) + { + if (intv >= IRQ_POLL_SLOW_INTV) + return IRQ_POLL_SLOW_SLACK; + else if (intv >= IRQ_POLL_INTV) + return IRQ_POLL_SLACK; + else + return IRQ_POLL_QUICK_SLACK; + } + + /** + * irq_schedule_poll - schedule IRQ poll + * @desc: IRQ desc to schedule poll for + * @intv: poll interval + * + * Schedules @desc->poll_timer. If the timer is already scheduled, + * it's modified iff jiffies + @intv + slack is before the timer's + * expires. poll_timers aren't taken offline behind this function's + * back and the users of this function are guaranteed that poll_irq() + * will be called at or before jiffies + @intv + slack. + * + * CONTEXT: + * desc->lock + */ + static void irq_schedule_poll(struct irq_desc *desc, unsigned long intv) + { + unsigned long expires = jiffies + intv; + int slack = irq_poll_slack(intv); + + if (timer_pending(&desc->poll_timer) && + time_before_eq(desc->poll_timer.expires, expires + slack)) + return; + + set_timer_slack(&desc->poll_timer, slack); + mod_timer(&desc->poll_timer, expires); + } + + static unsigned long irq_exp_intv(struct irq_expect *exp) + { + if (!(exp->flags & IRQ_EXPECTING)) + return MAX_JIFFY_OFFSET; + if (exp->flags & IRQ_EXP_VERIFIED) + return IRQ_POLL_SLOW_INTV; + if (exp->flags & IRQ_EXP_QUICK) + return IRQ_POLL_QUICK_INTV; + return IRQ_POLL_INTV; + } + + /** + * init_irq_expect - initialize IRQ expecting + * @irq: IRQ to expect + * @dev_id: dev_id of the irqaction to expect + * + * Initializes IRQ expecting and returns expect token to use. This + * function can be called multiple times for the same irqaction and + * each token can be used independently. + * + * CONTEXT: + * Does GFP_KERNEL allocation. + * + * RETURNS: + * irq_expect token to use on success, %NULL on failure. + */ + struct irq_expect *init_irq_expect(unsigned int irq, void *dev_id) + { + struct irq_desc *desc = irq_to_desc(irq); + struct irqaction *act; + struct irq_expect *exp; + unsigned long flags; + + if (noirqdebug || WARN_ON_ONCE(!desc)) + return NULL; + + exp = kzalloc(sizeof(*exp), GFP_KERNEL); + if (!exp) { + printk(KERN_WARNING "IRQ %u: failed to initialize IRQ expect, " + "allocation failed\n", irq); + return NULL; + } + + exp->desc = desc; + + raw_spin_lock_irqsave(&desc->lock, flags); + + act = find_irq_action(desc, dev_id); + if (!WARN_ON_ONCE(!act)) { + exp->act = act; + exp->next = act->expects; + act->expects = exp; + } else { + kfree(exp); + exp = NULL; + } + + raw_spin_unlock_irqrestore(&desc->lock, flags); + + return exp; + } + EXPORT_SYMBOL_GPL(init_irq_expect); + + /** + * expect_irq - expect IRQ + * @exp: expect token acquired from init_irq_expect(), %NULL is allowed + * + * Tell IRQ subsystem to expect an IRQ. The IRQ might be polled until + * unexpect_irq() is called on @exp. If @exp is %NULL, this function + * becomes noop. + * + * This function is fairly cheap and drivers can call it for each + * interrupt driven operation without adding noticeable overhead in + * most cases. + * + * CONTEXT: + * Don't care. The caller is responsible for ensuring + * [un]expect_irq() calls don't overlap. Overlapping may lead to + * unexpected polling behaviors but won't directly cause a failure. + */ + void expect_irq(struct irq_expect *exp) + { + struct irq_desc *desc; + unsigned long intv, deadline; + unsigned long flags; + + /* @exp is NULL if noirqdebug */ + if (unlikely(!exp)) + return; + + desc = exp->desc; + exp->flags |= IRQ_EXPECTING; + + /* + * Paired with mb in poll_irq(). Either we see timer pending + * cleared or poll_irq() sees IRQ_EXPECTING. + */ + smp_mb(); + + exp->started = jiffies; + intv = irq_exp_intv(exp); + deadline = exp->started + intv + irq_poll_slack(intv); + + /* + * poll_timer is never explicitly killed unless there's no + * action left on the irq; also, while it's online, timer + * duration is only shortened, which means that if we see + * ->expires in the future and not later than our deadline, + * the timer is guaranteed to fire before it. + */ + if (!timer_pending(&desc->poll_timer) || + time_after_eq(jiffies, desc->poll_timer.expires) || + time_before(deadline, desc->poll_timer.expires)) { + raw_spin_lock_irqsave(&desc->lock, flags); + irq_schedule_poll(desc, intv); + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + } + EXPORT_SYMBOL_GPL(expect_irq); + + /** + * unexpect_irq - unexpect IRQ + * @exp: expect token acquired from init_irq_expect(), %NULL is allowed + * @timedout: did the IRQ timeout? + * + * Tell IRQ subsystem to stop expecting an IRQ. Set @timedout to + * %true if the expected IRQ never arrived. If @exp is %NULL, this + * function becomes noop. + * + * This function is fairly cheap and drivers can call it for each + * interrupt driven operation without adding noticeable overhead in + * most cases. + * + * CONTEXT: + * Don't care. The caller is responsible for ensuring + * [un]expect_irq() calls don't overlap. Overlapping may lead to + * unexpected polling behaviors but won't directly cause a failure. + */ + void unexpect_irq(struct irq_expect *exp, bool timedout) + { + struct irq_desc *desc; + + /* @exp is NULL if noirqdebug */ + if (unlikely(!exp) || (!(exp->flags & IRQ_EXPECTING) && !timedout)) + return; + + desc = exp->desc; + exp->flags &= ~IRQ_EXPECTING; + + /* succesful completion from IRQ? */ + if (likely(!(desc->status & IRQ_IN_POLLING) && !timedout)) { + /* + * IRQ seems a bit more trustworthy. Allow nr_good to + * increase till VERIFY_GOAL + BAD_FACTOR - 1 so that + * single succesful delivery can recover verified + * state after an accidental polling hit. + */ + if (unlikely(exp->nr_good < + IRQ_EXP_VERIFY_GOAL + IRQ_EXP_BAD_FACTOR - 1) && + ++exp->nr_good >= IRQ_EXP_VERIFY_GOAL) { + exp->flags |= IRQ_EXP_VERIFIED; + exp->nr_samples = 0; + exp->nr_quick = 0; + } + return; + } + + /* timedout or polled */ + if (timedout) { + exp->nr_good = 0; + } else { + exp->nr_good -= min_t(unsigned int, + exp->nr_good, IRQ_EXP_BAD_FACTOR); + + if (time_before_eq(jiffies, exp->started + IRQ_POLL_INTV)) + exp->nr_quick++; + + if (++exp->nr_samples >= IRQ_EXP_QUICK_SAMPLES) { + /* + * Use quick sampling checkpoints as warning + * checkpoints too. + */ + if (!(exp->flags & IRQ_EXP_WARNED) && + !desc->spr.poll_rem) { + warn_irq_poll(desc, exp->act); + exp->flags |= IRQ_EXP_WARNED; + } + + exp->flags &= ~IRQ_EXP_QUICK; + if (exp->nr_quick >= IRQ_EXP_QUICK_THRESHOLD) + exp->flags |= IRQ_EXP_QUICK; + exp->nr_samples = 0; + exp->nr_quick = 0; + } + } + + exp->flags &= ~IRQ_EXP_VERIFIED; + } + EXPORT_SYMBOL_GPL(unexpect_irq); + + /** + * irq_update_watch - IRQ handled, update watch state + * @desc: IRQ desc of interest + * @act: IRQ action of interest + * @via_poll: IRQ was handled via poll + * + * Called after IRQ is successfully delievered or polled. Updates + * watch state accordingly and determines which watch interval to use. + * + * CONTEXT: + * desc->lock + * + * RETURNS: + * Watch poll interval to use, MAX_JIFFY_OFFSET if watch polling isn't + * necessary. + */ + static unsigned long irq_update_watch(struct irq_desc *desc, + struct irqaction *act, bool via_poll) + { + struct irq_watch *wat = &act->watch; + unsigned long period = wat->flags & IRQ_WAT_WARY ? + IRQ_WAT_WARY_PERIOD : IRQ_WAT_BASE_PERIOD; + + /* if not watching or already determined to be bad, it's easy */ + if (!(wat->flags & IRQ_WATCHING)) + return MAX_JIFFY_OFFSET; + if (wat->flags & IRQ_WAT_BAD) + return IRQ_POLL_INTV; + + /* don't expire watch period while spurious polling is in effect */ + if (desc->spr.poll_rem) { + wat->started = jiffies; + return IRQ_POLL_INTV; + } + + /* IRQ was handled, record whether it was a good or bad delivery */ + if (wat->last_ret == IRQ_HANDLED) { + wat->nr_samples++; + if (via_poll) { + wat->nr_polled++; + wat->flags |= IRQ_WAT_POLLED; + } + } + + /* is this watch period over? */ + if (time_after(jiffies, wat->started + period)) { + unsigned int wry_thr = wat->nr_samples * IRQ_WAT_WARY_PCT / 100; + unsigned int bad_thr = wat->nr_samples * IRQ_WAT_BAD_PCT / 100; + + if (wat->nr_samples >= IRQ_WAT_MIN_SAMPLES) { + /* have enough samples, determine what to do */ + if (wat->nr_polled <= wry_thr) + wat->flags &= ~IRQ_WATCHING; + else if (wat->nr_polled <= bad_thr) + wat->flags |= IRQ_WAT_WARY; + else { + warn_irq_poll(desc, act); + wat->flags |= IRQ_WAT_BAD; + } + wat->nr_samples = 0; + wat->nr_polled = 0; + } else if (!wat->nr_samples || !(wat->flags & IRQ_WAT_POLLED)) { + /* not sure but let's not hold onto it */ + wat->flags &= ~IRQ_WATCHING; + } + + wat->started = jiffies; + } + + if (!(wat->flags & IRQ_WATCHING)) + return MAX_JIFFY_OFFSET; + if (wat->flags & IRQ_WAT_POLLED) + return IRQ_POLL_INTV; + /* every delivery upto this point has been successful, grow interval */ + return clamp_t(unsigned long, jiffies - wat->started, + IRQ_WAT_BASE_INTV, IRQ_POLL_SLOW_INTV); + } + + /** + * watch_irq - watch an irqaction + * @irq: IRQ the irqaction to watch belongs to + * @dev_id: dev_id for the irqaction to watch + * + * LOCKING: + * Grabs and releases desc->lock. + */ + void watch_irq(unsigned int irq, void *dev_id) + { + struct irq_desc *desc = irq_to_desc(irq); + struct irqaction *act; + unsigned long flags; + + if (WARN_ON_ONCE(!desc)) + return; + + raw_spin_lock_irqsave(&desc->lock, flags); + + act = find_irq_action(desc, dev_id); + if (!WARN_ON_ONCE(!act)) { + struct irq_watch *wat = &act->watch; + + wat->flags |= IRQ_WATCHING; + wat->started = jiffies; + wat->nr_samples = 0; + wat->nr_polled = 0; + desc->status |= IRQ_CHECK_WATCHES; + irq_schedule_poll(desc, IRQ_WAT_BASE_INTV); + } + + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + EXPORT_SYMBOL_GPL(watch_irq); + + /* start a new spurious handling period */ + static void irq_spr_new_period(struct irq_spr *spr) + { + spr->period_start = jiffies; + spr->nr_samples = 0; + spr->nr_bad = 0; + } - #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10) - static void poll_spurious_irqs(unsigned long dummy); - static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0); + /* Reset spurious handling. After this, poll_timer will offline itself soon. */ + static void irq_spr_reset(struct irq_spr *spr) + { + irq_spr_new_period(spr); + spr->poll_cnt = IRQ_SPR_POLL_CNT_MIN; + spr->poll_rem = 0; + } /* - * Recovery handler for misrouted interrupts. + * Perform an actual poll. */ static int try_one_irq(int irq, struct irq_desc *desc) { @@@ -80,9 -682,8 +682,8 @@@ * If we did actual work for the real IRQ line we must let the * IRQ controller clean up too */ - if (work && desc->chip && desc->chip->end) - desc->chip->end(irq); + if (work) + irq_end(irq, desc); - raw_spin_unlock(&desc->lock); return ok; } @@@ -106,165 -709,266 +709,266 @@@ static int misrouted_irq(int irq return ok; } - static void poll_spurious_irqs(unsigned long dummy) + /* + * IRQ delivery notification function. Called after each IRQ delivery. + */ + void __note_interrupt(unsigned int irq, struct irq_desc *desc, + irqreturn_t action_ret) { - struct irq_desc *desc; - int i; + struct irq_spr *spr = &desc->spr; + unsigned long dur; + unsigned int cnt, abbr; + char unit = 'k'; - for_each_irq_desc(i, desc) { - unsigned int status; + /* first, take care of IRQ watches */ + if (unlikely(desc->status & IRQ_CHECK_WATCHES)) { + unsigned long intv = MAX_JIFFY_OFFSET; + struct irqaction *act; - if (!i) - continue; + raw_spin_lock(&desc->lock); - /* Racy but it doesn't matter */ - status = desc->status; - barrier(); - if (!(status & IRQ_SPURIOUS_DISABLED)) - continue; + for (act = desc->action; act; act = act->next) + intv = min(intv, irq_update_watch(desc, act, false)); - local_irq_disable(); - try_one_irq(i, desc); - local_irq_enable(); + if (intv < MAX_JIFFY_OFFSET) + irq_schedule_poll(desc, intv); + else + desc->status &= ~IRQ_CHECK_WATCHES; + + raw_spin_unlock(&desc->lock); + } + + /* + * Account for unhandled interrupt. We don't care whether + * spurious accounting update races with irq open/close and + * gets some values wrong. Do it w/o locking. + */ + if (unlikely(action_ret != IRQ_HANDLED)) { + static int bogus_count = 100; + + spr->last_bad = jiffies - INITIAL_JIFFIES; + spr->nr_bad++; + if (likely(action_ret == IRQ_NONE)) { + if (unlikely(irqfixup >= IRQFIXUP_MISROUTED && + misrouted_irq(irq))) + spr->nr_bad--; + } else if (bogus_count > 0) { + bogus_count--; + printk(KERN_ERR "IRQ %u: bogus return value %x\n", + irq, action_ret); + dump_stack(); + print_irq_handlers(desc); + } } - mod_timer(&poll_spurious_irq_timer, - jiffies + POLL_SPURIOUS_IRQ_INTERVAL); + /* did we finish this spurious period? */ + spr->nr_samples++; + if (likely(spr->nr_samples < IRQ_SPR_PERIOD_SAMPLES)) + return; + + /* if so, was it a good one? */ + dur = jiffies - spr->period_start; + if (likely(spr->nr_bad < IRQ_SPR_BAD_THRESHOLD || + dur > IRQ_SPR_PERIOD_DURATION)) { + /* + * If longer than PERIOD_DURATION has passed, consider + * multiple good periods have happened. + */ + int sft = IRQ_SPR_POLL_CNT_DEC_SHIFT * + (dur >> order_base_2(IRQ_SPR_PERIOD_DURATION)); + + /* but don't kill poll_cnt at once */ + sft = clamp(sft, 1, IRQ_SPR_POLL_CNT_MAX_DEC_SHIFT); + + spr->poll_cnt >>= sft; + irq_spr_new_period(spr); + return; + } + + /* + * It was a bad one, start polling. This is a slow path and + * we're gonna be changing states which require proper + * synchronization, grab desc->lock. + */ + raw_spin_lock(&desc->lock); + + irq_spr_new_period(spr); + + /* update spr_poll_cnt considering the lower and upper bounds */ + cnt = max_t(unsigned int, spr->poll_cnt, IRQ_SPR_POLL_CNT_MIN); + spr->poll_cnt = cnt << IRQ_SPR_POLL_CNT_INC_SHIFT; + if (spr->poll_cnt < cnt) /* did it overflow? */ + spr->poll_cnt = IRQ_SPR_POLL_CNT_INF; + + /* whine, plug IRQ and kick poll timer */ + abbr = cnt / 1000; + if (abbr > 1000) { + abbr /= 1000; + unit = 'm'; + } + printk(KERN_ERR "IRQ %u: too many spurious IRQs, disabling and " + "polling for %u%c %umsec intervals.\n", - desc->irq, abbr, unit, jiffies_to_msecs(IRQ_POLL_INTV)); ++ desc->irq_data.irq, abbr, unit, jiffies_to_msecs(IRQ_POLL_INTV)); + printk(KERN_ERR "IRQ %u: system performance may be affected\n", - desc->irq); ++ desc->irq_data.irq); + print_irq_handlers(desc); + + desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; + desc->depth++; - desc->chip->disable(desc->irq); ++ desc->irq_data.chip->irq_disable(&desc->irq_data); + + spr->poll_rem = cnt; + irq_schedule_poll(desc, IRQ_POLL_INTV); + + raw_spin_unlock(&desc->lock); } /* - * If 99,900 of the previous 100,000 interrupts have not been handled - * then assume that the IRQ is stuck in some manner. Drop a diagnostic - * and try to turn the IRQ off. - * - * (The other 100-of-100,000 interrupts may have been a correctly - * functioning device sharing an IRQ with the failing one) - * - * Called under desc->lock + * IRQ poller. Called from desc->poll_timer. */ - - static void - __report_bad_irq(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) + void poll_irq(unsigned long arg) { - struct irqaction *action; + struct irq_desc *desc = (void *)arg; + struct irq_spr *spr = &desc->spr; + unsigned long intv = MAX_JIFFY_OFFSET; + bool reenable_irq = false; + struct irqaction *act; + struct irq_expect *exp; + + raw_spin_lock_irq(&desc->lock); + + /* poll the IRQ */ + desc->status |= IRQ_IN_POLLING; - try_one_irq(desc->irq, desc); ++ try_one_irq(desc->irq_data.irq, desc); + desc->status &= ~IRQ_IN_POLLING; + + /* take care of spurious handling */ + if (spr->poll_rem) { + if (spr->poll_rem != IRQ_SPR_POLL_CNT_INF) + spr->poll_rem--; + if (spr->poll_rem) + intv = IRQ_POLL_INTV; + else + irq_spr_new_period(spr); + } + if (!spr->poll_rem) + reenable_irq = desc->status & IRQ_SPURIOUS_DISABLED; - if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { - printk(KERN_ERR "irq event %d: bogus return value %x\n", - irq, action_ret); - } else { - printk(KERN_ERR "irq %d: nobody cared (try booting with " - "the \"irqpoll\" option)\n", irq); + /* + * Paired with mb in expect_irq() so that either they see + * timer pending cleared or irq_exp_intv() below sees + * IRQ_EXPECTING. + */ + smp_mb(); + + /* take care of expects and watches */ + for (act = desc->action; act; act = act->next) { + intv = min(irq_update_watch(desc, act, true), intv); + for (exp = act->expects; exp; exp = exp->next) + intv = min(irq_exp_intv(exp), intv); } - dump_stack(); - printk(KERN_ERR "handlers:\n"); - action = desc->action; - while (action) { - printk(KERN_ERR "[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; + /* need to poll again? */ + if (intv < MAX_JIFFY_OFFSET) + irq_schedule_poll(desc, intv); + + raw_spin_unlock_irq(&desc->lock); + + if (!reenable_irq) + return; + + /* need to do locking dance for chip_bus_lock() to reenable IRQ */ - chip_bus_lock(desc->irq, desc); ++ chip_bus_lock(desc->irq_data.irq, desc); + raw_spin_lock_irq(&desc->lock); + + /* make sure we haven't raced with anyone inbetween */ + if (!spr->poll_rem && (desc->status & IRQ_SPURIOUS_DISABLED)) { + printk(KERN_INFO "IRQ %u: spurious polling finished, " - "reenabling IRQ\n", desc->irq); - __enable_irq(desc, desc->irq, false); ++ "reenabling IRQ\n", desc->irq_data.irq); ++ __enable_irq(desc, desc->irq_data.irq, false); + desc->status &= ~IRQ_SPURIOUS_DISABLED; } + + raw_spin_unlock_irq(&desc->lock); - chip_bus_sync_unlock(desc->irq, desc); ++ chip_bus_sync_unlock(desc->irq_data.irq, desc); } - static void - report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) + void irq_poll_action_added(struct irq_desc *desc, struct irqaction *action) { - static int count = 100; + struct irq_spr *spr = &desc->spr; + unsigned long flags; - if (count > 0) { - count--; - __report_bad_irq(irq, desc, action_ret); + raw_spin_lock_irqsave(&desc->lock, flags); + + if ((action->flags & IRQF_SHARED) && irqfixup >= IRQFIXUP_POLL) { + if (!spr->poll_rem) + printk(KERN_INFO "IRQ %u: starting IRQFIXUP_POLL\n", - desc->irq); ++ desc->irq_data.irq); + spr->poll_rem = IRQ_SPR_POLL_CNT_INF; + irq_schedule_poll(desc, IRQ_POLL_INTV); + } else { + /* new irqaction registered, give the IRQ another chance */ + irq_spr_reset(spr); } + + raw_spin_unlock_irqrestore(&desc->lock, flags); } - static inline int - try_misrouted_irq(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) + void irq_poll_action_removed(struct irq_desc *desc, struct irqaction *action) { - struct irqaction *action; + bool irq_enabled = false, timer_killed = false; + struct irq_expect *exp, *next; + unsigned long flags; + int rc; - if (!irqfixup) - return 0; + raw_spin_lock_irqsave(&desc->lock, flags); - /* We didn't actually handle the IRQ - see if it was misrouted? */ - if (action_ret == IRQ_NONE) - return 1; + /* give the IRQ another chance */ + if (irqfixup < IRQFIXUP_POLL) + irq_spr_reset(&desc->spr); /* - * But for 'irqfixup == 2' we also do it for handled interrupts if - * they are marked as IRQF_IRQPOLL (or for irq zero, which is the - * traditional PC timer interrupt.. Legacy) + * Make sure the timer is offline if no irqaction is left as + * the irq_desc will be reinitialized when the next irqaction + * is added; otherwise, the timer can be left alone. It will + * offline itself if no longer necessary. */ - if (irqfixup < 2) - return 0; - - if (!irq) - return 1; + while (!desc->action) { + rc = try_to_del_timer_sync(&desc->poll_timer); + if (rc >= 0) { + timer_killed = rc > 0; + break; + } + raw_spin_unlock_irqrestore(&desc->lock, flags); + cpu_relax(); + raw_spin_lock_irqsave(&desc->lock, flags); + } /* - * Since we don't get the descriptor lock, "action" can - * change under us. We don't really care, but we don't - * want to follow a NULL pointer. So tell the compiler to - * just load it once by using a barrier. + * If the timer was forcefully shut down, it might not have + * had the chance to reenable IRQ. Make sure it's enabled. */ - action = desc->action; - barrier(); - return action && (action->flags & IRQF_IRQPOLL); - } - - void note_interrupt(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) - { - if (unlikely(action_ret != IRQ_HANDLED)) { - /* - * If we are seeing only the odd spurious IRQ caused by - * bus asynchronicity then don't eventually trigger an error, - * otherwise the counter becomes a doomsday timer for otherwise - * working systems - */ - if (time_after(jiffies, desc->last_unhandled + HZ/10)) - desc->irqs_unhandled = 1; - else - desc->irqs_unhandled++; - desc->last_unhandled = jiffies; - if (unlikely(action_ret != IRQ_NONE)) - report_bad_irq(irq, desc, action_ret); + if (timer_killed && (desc->status & IRQ_SPURIOUS_DISABLED)) { - __enable_irq(desc, desc->irq, false); ++ __enable_irq(desc, desc->irq_data.irq, false); + desc->status &= ~IRQ_SPURIOUS_DISABLED; + irq_enabled = true; } - if (unlikely(try_misrouted_irq(irq, desc, action_ret))) { - int ok = misrouted_irq(irq); - if (action_ret == IRQ_NONE) - desc->irqs_unhandled -= ok; - } - - desc->irq_count++; - if (likely(desc->irq_count < 100000)) - return; + if (timer_killed || irq_enabled) - printk(KERN_INFO "IRQ %u:%s%s%s\n", desc->irq, ++ printk(KERN_INFO "IRQ %u:%s%s%s\n", desc->irq_data.irq, + timer_killed ? " polling stopped" : "", + timer_killed && irq_enabled ? " and" : "", + irq_enabled ? " IRQ reenabled" : ""); - desc->irq_count = 0; - if (unlikely(desc->irqs_unhandled > 99900)) { - /* - * The interrupt is stuck - */ - __report_bad_irq(irq, desc, action_ret); - /* - * Now kill the IRQ - */ - printk(KERN_EMERG "Disabling IRQ #%d\n", irq); - desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; - desc->depth++; - desc->irq_data.chip->irq_disable(&desc->irq_data); - - mod_timer(&poll_spurious_irq_timer, - jiffies + POLL_SPURIOUS_IRQ_INTERVAL); + /* free expect tokens */ + for (exp = action->expects; exp; exp = next) { + next = exp->next; + kfree(exp); } - desc->irqs_unhandled = 0; - } + action->expects = NULL; - int noirqdebug __read_mostly; + raw_spin_unlock_irqrestore(&desc->lock, flags); + } int noirqdebug_setup(char *str) { -- To unsubscribe from this list: send the line "unsubscribe linux-next" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html