static void tasklet_hi_action(struct softirq_action *a) { struct tasklet_struct *list; local_irq_disable(); list = __this_cpu_read(tasklet_hi_vec.head); __this_cpu_write(tasklet_hi_vec.head, NULL); __this_cpu_write(tasklet_hi_vec.tail, &__get_cpu_var(tasklet_hi_vec).head); local_irq_enable(); while (list) { struct tasklet_struct *t = list; list = list->next; if (tasklet_trylock(t)) { if (!atomic_read(&t->count)) { #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE unsigned long long start_time, end_time; start_time = sec_debug_clock(); #endif if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); sec_debug_softirq_log(9998, t->func, 7); t->func(t->data); sec_debug_softirq_log(9998, t->func, 8); #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE end_time = sec_debug_clock(); if (start_time + 950000000 < end_time) { sec_debug_aux_log(SEC_DEBUG_AUXLOG_IRQ, "TH:%llu %pf", start_time, t->func); } #endif tasklet_unlock(t); continue; } tasklet_unlock(t); } local_irq_disable(); t->next = NULL; *__this_cpu_read(tasklet_hi_vec.tail) = t; __this_cpu_write(tasklet_hi_vec.tail, &(t->next)); __raise_softirq_irqoff(HI_SOFTIRQ); local_irq_enable(); } }
asmlinkage void __do_softirq(void) { struct softirq_action *h; __u32 pending; unsigned long end = jiffies + MAX_SOFTIRQ_TIME; int cpu; unsigned long old_flags = current->flags; int max_restart = MAX_SOFTIRQ_RESTART; /* * Mask out PF_MEMALLOC s current task context is borrowed for the * softirq. A softirq handled such as network RX might set PF_MEMALLOC * again if the socket is related to swap */ current->flags &= ~PF_MEMALLOC; pending = local_softirq_pending(); account_irq_enter_time(current); __local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET); lockdep_softirq_enter(); cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); local_irq_enable(); h = softirq_vec; do { if (pending & 1) { unsigned int vec_nr = h - softirq_vec; int prev_count = preempt_count(); #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE unsigned long long start_time, end_time; start_time = sec_debug_clock(); #endif kstat_incr_softirqs_this_cpu(vec_nr); trace_softirq_entry(vec_nr); sec_debug_softirq_log(9999, h->action, 7); h->action(h); sec_debug_softirq_log(9999, h->action, 8); trace_softirq_exit(vec_nr); #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE end_time = sec_debug_clock(); if (start_time + 950000000 < end_time) { sec_debug_aux_log(SEC_DEBUG_AUXLOG_IRQ, "S:%llu %pf", start_time, h->action); } #endif if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %u %s %p" "with preempt_count %08x," " exited with %08x?\n", vec_nr, softirq_to_name[vec_nr], h->action, prev_count, preempt_count()); preempt_count() = prev_count; } rcu_bh_qs(cpu); } h++; pending >>= 1; } while (pending); local_irq_disable(); pending = local_softirq_pending(); if (pending) { if (time_before(jiffies, end) && !need_resched() && --max_restart) goto restart; wakeup_softirqd(); } lockdep_softirq_exit(); account_irq_exit_time(current); __local_bh_enable(SOFTIRQ_OFFSET); tsk_restore_flags(current, old_flags, PF_MEMALLOC); }
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) { irqreturn_t retval = IRQ_NONE; unsigned int flags = 0, irq = desc->irq_data.irq; do { irqreturn_t res; #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE unsigned long long start_time, end_time; start_time = sec_debug_clock(); #endif sec_debug_irq_log(irq, (void *)action->handler, 1); trace_irq_handler_entry(irq, action); exynos_ss_irq(irq, (void *)action->handler, (int)irqs_disabled(), ESS_FLAG_IN); res = action->handler(irq, action->dev_id); exynos_ss_irq(irq, (void *)action->handler, (int)irqs_disabled(), ESS_FLAG_OUT); trace_irq_handler_exit(irq, action, res); sec_debug_irq_log(irq, (void *)action->handler, 2); #ifdef CONFIG_SEC_DEBUG_RT_THROTTLE_ACTIVE end_time = sec_debug_clock(); if (start_time + 950000000 < end_time) { sec_debug_aux_log(SEC_DEBUG_AUXLOG_IRQ, "I:%llu %pf", start_time, action->handler); } #endif if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n", irq, action->handler)) local_irq_disable(); switch (res) { case IRQ_WAKE_THREAD: /* * Catch drivers which return WAKE_THREAD but * did not set up a thread function */ if (unlikely(!action->thread_fn)) { warn_no_thread(irq, action); break; } irq_wake_thread(desc, action); /* Fall through to add to randomness */ case IRQ_HANDLED: flags |= action->flags; break; default: break; } retval |= res; action = action->next; } while (action); add_interrupt_randomness(irq, flags); if (!noirqdebug) note_interrupt(irq, desc, retval); return retval; }