1/* 2 * linux/arch/ia64/kernel/irq.c 3 * 4 * Copyright (C) 1998-2001 Hewlett-Packard Co 5 * Stephane Eranian <eranian@hpl.hp.com> 6 * David Mosberger-Tang <davidm@hpl.hp.com> 7 * 8 * 6/10/99: Updated to bring in sync with x86 version to facilitate 9 * support for SMP and different interrupt controllers. 10 * 11 * 09/15/00 Goutham Rao <goutham.rao@intel.com> Implemented pci_irq_to_vector 12 * PCI to vector allocation routine. 13 */ 14 15#include <linux/config.h> 16 17#include <linux/sched.h> 18#include <linux/errno.h> 19#include <linux/init.h> 20#include <linux/interrupt.h> 21#include <linux/ioport.h> 22#include <linux/kernel_stat.h> 23#include <linux/slab.h> 24#include <linux/ptrace.h> 25#include <linux/random.h> /* for rand_initialize_irq() */ 26#include <linux/signal.h> 27#include <linux/smp.h> 28#include <linux/smp_lock.h> 29#include <linux/threads.h> 30 31#include <asm/bitops.h> 32#include <asm/delay.h> 33#include <asm/io.h> 34#include <asm/hw_irq.h> 35#include <asm/machvec.h> 36#include <asm/pgtable.h> 37#include <asm/system.h> 38 39#ifdef CONFIG_PERFMON 40# include <asm/perfmon.h> 41#endif 42 43#define IRQ_DEBUG 0 44 45/* default base addr of IPI table */ 46unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); 47 48/* 49 * Legacy IRQ to IA-64 vector translation table. 50 */ 51__u8 isa_irq_to_vector_map[16] = { 52 /* 8259 IRQ translation, first 16 entries */ 53 0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 54 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 55}; 56 57int 58ia64_alloc_vector (void) 59{ 60 static int next_vector = IA64_FIRST_DEVICE_VECTOR; 61 62 if (next_vector > IA64_LAST_DEVICE_VECTOR) 63 panic("%s: out of interrupt vectors!", __FUNCTION__); 64 return next_vector++; 65} 66 67extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); 68 69/* 70 * That's where the IVT branches when we get an external 71 * interrupt. This branches to the correct hardware IRQ handler via 72 * function ptr. 73 */ 74void 75ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) 76{ 77 unsigned long saved_tpr; 78#ifdef CONFIG_SMP 79# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) 80#else 81# define IS_RESCHEDULE(vec) (0) 82#endif 83 84#if IRQ_DEBUG 85 { 86 unsigned long bsp, sp; 87 88 /* 89 * Note: if the interrupt happened while executing in 90 * the context switch routine (ia64_switch_to), we may 91 * get a spurious stack overflow here. This is 92 * because the register and the memory stack are not 93 * switched atomically. 94 */ 95 asm ("mov %0=ar.bsp" : "=r"(bsp)); 96 asm ("mov %0=sp" : "=r"(sp)); 97 98 if ((sp - bsp) < 1024) { 99 static unsigned char count; 100 static long last_time; 101 102 if (jiffies - last_time > 5*HZ) 103 count = 0; 104 if (++count < 5) { 105 last_time = jiffies; 106 printk("ia64_handle_irq: DANGER: less than " 107 "1KB of free stack space!!\n" 108 "(bsp=0x%lx, sp=%lx)\n", bsp, sp); 109 } 110 } 111 } 112#endif /* IRQ_DEBUG */ 113 114 /* 115 * Always set TPR to limit maximum interrupt nesting depth to 116 * 16 (without this, it would be ~240, which could easily lead 117 * to kernel stack overflows). 118 */ 119 saved_tpr = ia64_get_tpr(); 120 ia64_srlz_d(); 121 while (vector != IA64_SPURIOUS_INT_VECTOR) { 122 if (!IS_RESCHEDULE(vector)) { 123 ia64_set_tpr(vector); 124 ia64_srlz_d(); 125 126 do_IRQ(local_vector_to_irq(vector), regs); 127 128 /* 129 * Disable interrupts and send EOI: 130 */ 131 local_irq_disable(); 132 ia64_set_tpr(saved_tpr); 133 } 134 ia64_eoi(); 135 vector = ia64_get_ivr(); 136 } 137 /* 138 * This must be done *after* the ia64_eoi(). For example, the keyboard softirq 139 * handler needs to be able to wait for further keyboard interrupts, which can't 140 * come through until ia64_eoi() has been done. 141 */ 142 if (local_softirq_pending()) 143 do_softirq(); 144} 145 146#ifdef CONFIG_SMP 147extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs); 148 149static struct irqaction ipi_irqaction = { 150 handler: handle_IPI, 151 flags: SA_INTERRUPT, 152 name: "IPI" 153}; 154#endif 155 156void 157register_percpu_irq (ia64_vector vec, struct irqaction *action) 158{ 159 irq_desc_t *desc; 160 unsigned int irq; 161 162 for (irq = 0; irq < NR_IRQS; ++irq) 163 if (irq_to_vector(irq) == vec) { 164 desc = irq_desc(irq); 165 desc->status |= IRQ_PER_CPU; 166 desc->handler = &irq_type_ia64_lsapic; 167 if (action) 168 setup_irq(irq, action); 169 } 170} 171 172void __init 173init_IRQ (void) 174{ 175 register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); 176#ifdef CONFIG_SMP 177 register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); 178#endif 179#ifdef CONFIG_PERFMON 180 perfmon_init_percpu(); 181#endif 182 platform_irq_init(); 183} 184 185void 186ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) 187{ 188 unsigned long ipi_addr; 189 unsigned long ipi_data; 190 unsigned long phys_cpu_id; 191 192#ifdef CONFIG_SMP 193 phys_cpu_id = cpu_physical_id(cpu); 194#else 195 phys_cpu_id = (ia64_get_lid() >> 16) & 0xffff; 196#endif 197 198 /* 199 * cpu number is in 8bit ID and 8bit EID 200 */ 201 202 ipi_data = (delivery_mode << 8) | (vector & 0xff); 203 ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1) << 3); 204 205 writeq(ipi_data, ipi_addr); 206} 207