linux/arch/x86/kernel/irq_32.c
<<
>>
Prefs
   1/*
   2 *      Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
   3 *
   4 * This file contains the lowest level x86-specific interrupt
   5 * entry, irq-stacks and irq statistics code. All the remaining
   6 * irq logic is done by the generic kernel/irq/ code and
   7 * by the x86-specific irq controller code. (e.g. i8259.c and
   8 * io_apic.c.)
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/seq_file.h>
  13#include <linux/interrupt.h>
  14#include <linux/kernel_stat.h>
  15#include <linux/notifier.h>
  16#include <linux/cpu.h>
  17#include <linux/delay.h>
  18
  19#include <asm/apic.h>
  20#include <asm/uaccess.h>
  21
  22DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
  23EXPORT_PER_CPU_SYMBOL(irq_stat);
  24
  25DEFINE_PER_CPU(struct pt_regs *, irq_regs);
  26EXPORT_PER_CPU_SYMBOL(irq_regs);
  27
  28#ifdef CONFIG_DEBUG_STACKOVERFLOW
  29/* Debugging check for stack overflow: is there less than 1KB free? */
  30static int check_stack_overflow(void)
  31{
  32        long sp;
  33
  34        __asm__ __volatile__("andl %%esp,%0" :
  35                             "=r" (sp) : "0" (THREAD_SIZE - 1));
  36
  37        return sp < (sizeof(struct thread_info) + STACK_WARN);
  38}
  39
  40static void print_stack_overflow(void)
  41{
  42        printk(KERN_WARNING "low stack detected by irq handler\n");
  43        dump_stack();
  44}
  45
  46#else
  47static inline int check_stack_overflow(void) { return 0; }
  48static inline void print_stack_overflow(void) { }
  49#endif
  50
  51#ifdef CONFIG_4KSTACKS
  52/*
  53 * per-CPU IRQ handling contexts (thread information and stack)
  54 */
  55union irq_ctx {
  56        struct thread_info      tinfo;
  57        u32                     stack[THREAD_SIZE/sizeof(u32)];
  58};
  59
  60static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
  61static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
  62
  63static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
  64static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
  65
  66static void call_on_stack(void *func, void *stack)
  67{
  68        asm volatile("xchgl     %%ebx,%%esp     \n"
  69                     "call      *%%edi          \n"
  70                     "movl      %%ebx,%%esp     \n"
  71                     : "=b" (stack)
  72                     : "0" (stack),
  73                       "D"(func)
  74                     : "memory", "cc", "edx", "ecx", "eax");
  75}
  76
  77static inline int
  78execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
  79{
  80        union irq_ctx *curctx, *irqctx;
  81        u32 *isp, arg1, arg2;
  82
  83        curctx = (union irq_ctx *) current_thread_info();
  84        irqctx = hardirq_ctx[smp_processor_id()];
  85
  86        /*
  87         * this is where we switch to the IRQ stack. However, if we are
  88         * already using the IRQ stack (because we interrupted a hardirq
  89         * handler) we can't do that and just have to keep using the
  90         * current stack (which is the irq stack already after all)
  91         */
  92        if (unlikely(curctx == irqctx))
  93                return 0;
  94
  95        /* build the stack frame on the IRQ stack */
  96        isp = (u32 *) ((char*)irqctx + sizeof(*irqctx));
  97        irqctx->tinfo.task = curctx->tinfo.task;
  98        irqctx->tinfo.previous_esp = current_stack_pointer;
  99
 100        /*
 101         * Copy the softirq bits in preempt_count so that the
 102         * softirq checks work in the hardirq context.
 103         */
 104        irqctx->tinfo.preempt_count =
 105                (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
 106                (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
 107
 108        if (unlikely(overflow))
 109                call_on_stack(print_stack_overflow, isp);
 110
 111        asm volatile("xchgl     %%ebx,%%esp     \n"
 112                     "call      *%%edi          \n"
 113                     "movl      %%ebx,%%esp     \n"
 114                     : "=a" (arg1), "=d" (arg2), "=b" (isp)
 115                     :  "0" (irq),   "1" (desc),  "2" (isp),
 116                        "D" (desc->handle_irq)
 117                     : "memory", "cc", "ecx");
 118        return 1;
 119}
 120
 121/*
 122 * allocate per-cpu stacks for hardirq and for softirq processing
 123 */
 124void __cpuinit irq_ctx_init(int cpu)
 125{
 126        union irq_ctx *irqctx;
 127
 128        if (hardirq_ctx[cpu])
 129                return;
 130
 131        irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
 132        irqctx->tinfo.task              = NULL;
 133        irqctx->tinfo.exec_domain       = NULL;
 134        irqctx->tinfo.cpu               = cpu;
 135        irqctx->tinfo.preempt_count     = HARDIRQ_OFFSET;
 136        irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
 137
 138        hardirq_ctx[cpu] = irqctx;
 139
 140        irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
 141        irqctx->tinfo.task              = NULL;
 142        irqctx->tinfo.exec_domain       = NULL;
 143        irqctx->tinfo.cpu               = cpu;
 144        irqctx->tinfo.preempt_count     = 0;
 145        irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
 146
 147        softirq_ctx[cpu] = irqctx;
 148
 149        printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
 150               cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
 151}
 152
 153void irq_ctx_exit(int cpu)
 154{
 155        hardirq_ctx[cpu] = NULL;
 156}
 157
 158asmlinkage void do_softirq(void)
 159{
 160        unsigned long flags;
 161        struct thread_info *curctx;
 162        union irq_ctx *irqctx;
 163        u32 *isp;
 164
 165        if (in_interrupt())
 166                return;
 167
 168        local_irq_save(flags);
 169
 170        if (local_softirq_pending()) {
 171                curctx = current_thread_info();
 172                irqctx = softirq_ctx[smp_processor_id()];
 173                irqctx->tinfo.task = curctx->task;
 174                irqctx->tinfo.previous_esp = current_stack_pointer;
 175
 176                /* build the stack frame on the softirq stack */
 177                isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
 178
 179                call_on_stack(__do_softirq, isp);
 180                /*
 181                 * Shouldnt happen, we returned above if in_interrupt():
 182                 */
 183                WARN_ON_ONCE(softirq_count());
 184        }
 185
 186        local_irq_restore(flags);
 187}
 188
 189#else
 190static inline int
 191execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) { return 0; }
 192#endif
 193
 194/*
 195 * do_IRQ handles all normal device IRQ's (the special
 196 * SMP cross-CPU interrupts have their own specific
 197 * handlers).
 198 */
 199unsigned int do_IRQ(struct pt_regs *regs)
 200{
 201        struct pt_regs *old_regs;
 202        /* high bit used in ret_from_ code */
 203        int overflow;
 204        unsigned vector = ~regs->orig_ax;
 205        struct irq_desc *desc;
 206        unsigned irq;
 207
 208
 209        old_regs = set_irq_regs(regs);
 210        irq_enter();
 211        irq = __get_cpu_var(vector_irq)[vector];
 212
 213        overflow = check_stack_overflow();
 214
 215        desc = irq_to_desc(irq);
 216        if (unlikely(!desc)) {
 217                printk(KERN_EMERG "%s: cannot handle IRQ %d vector %#x cpu %d\n",
 218                                        __func__, irq, vector, smp_processor_id());
 219                BUG();
 220        }
 221
 222        if (!execute_on_irq_stack(overflow, desc, irq)) {
 223                if (unlikely(overflow))
 224                        print_stack_overflow();
 225                desc->handle_irq(irq, desc);
 226        }
 227
 228        irq_exit();
 229        set_irq_regs(old_regs);
 230        return 1;
 231}
 232
 233#ifdef CONFIG_HOTPLUG_CPU
 234#include <mach_apic.h>
 235
 236void fixup_irqs(cpumask_t map)
 237{
 238        unsigned int irq;
 239        static int warned;
 240        struct irq_desc *desc;
 241
 242        for_each_irq_desc(irq, desc) {
 243                cpumask_t mask;
 244
 245                if (irq == 2)
 246                        continue;
 247
 248                cpus_and(mask, desc->affinity, map);
 249                if (any_online_cpu(mask) == NR_CPUS) {
 250                        printk("Breaking affinity for irq %i\n", irq);
 251                        mask = map;
 252                }
 253                if (desc->chip->set_affinity)
 254                        desc->chip->set_affinity(irq, mask);
 255                else if (desc->action && !(warned++))
 256                        printk("Cannot set affinity for irq %i\n", irq);
 257        }
 258
 259#if 0
 260        barrier();
 261        /* Ingo Molnar says: "after the IO-APIC masks have been redirected
 262           [note the nop - the interrupt-enable boundary on x86 is two
 263           instructions from sti] - to flush out pending hardirqs and
 264           IPIs. After this point nothing is supposed to reach this CPU." */
 265        __asm__ __volatile__("sti; nop; cli");
 266        barrier();
 267#else
 268        /* That doesn't seem sufficient.  Give it 1ms. */
 269        local_irq_enable();
 270        mdelay(1);
 271        local_irq_disable();
 272#endif
 273}
 274#endif
 275
 276
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.