1 /* 2 * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. 3 * 4 * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) 5 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 6 * Copyright (C) 1999 - 2001 Kanoj Sarcar 7 */ 8 9 #undef DEBUG 10 11 #include <linux/init.h> 12 #include <linux/irq.h> 13 #include <linux/errno.h> 14 #include <linux/signal.h> 15 #include <linux/sched.h> 16 #include <linux/types.h> 17 #include <linux/interrupt.h> 18 #include <linux/ioport.h> 19 #include <linux/timex.h> 20 #include <linux/smp.h> 21 #include <linux/random.h> 22 #include <linux/kernel.h> 23 #include <linux/kernel_stat.h> 24 #include <linux/delay.h> 25 #include <linux/bitops.h> 26 27 #include <asm/bootinfo.h> 28 #include <asm/io.h> 29 #include <asm/mipsregs.h> 30 31 #include <asm/processor.h> 32 #include <asm/sn/addrs.h> 33 #include <asm/sn/agent.h> 34 #include <asm/sn/arch.h> 35 #include <asm/sn/hub.h> 36 #include <asm/sn/intr.h> 37 38 /* 39 * Linux has a controller-independent x86 interrupt architecture. 40 * every controller has a 'controller-template', that is used 41 * by the main code to do the right thing. Each driver-visible 42 * interrupt source is transparently wired to the appropriate 43 * controller. Thus drivers need not be aware of the 44 * interrupt-controller. 45 * 46 * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, 47 * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. 48 * (IO-APICs assumed to be messaging to Pentium local-APICs) 49 * 50 * the code is designed to be easily extended with new/different 51 * interrupt controllers, without having to do assembly magic. 52 */ 53 54 extern asmlinkage void ip27_irq(void); 55 56 /* 57 * Find first bit set 58 */ 59 static int ms1bit(unsigned long x) 60 { 61 int b = 0, s; 62 63 s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s; 64 s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s; 65 s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s; 66 s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s; 67 s = 1; if (x >> 1 == 0) s = 0; b += s; 68 69 return b; 70 } 71 72 /* 73 * This code is unnecessarily complex, because we do 74 * intr enabling. Basically, once we grab the set of intrs we need 75 * to service, we must mask _all_ these interrupts; firstly, to make 76 * sure the same intr does not intr again, causing recursion that 77 * can lead to stack overflow. Secondly, we can not just mask the 78 * one intr we are do_IRQing, because the non-masked intrs in the 79 * first set might intr again, causing multiple servicings of the 80 * same intr. This effect is mostly seen for intercpu intrs. 81 * Kanoj 05.13.00 82 */ 83 84 static void ip27_do_irq_mask0(void) 85 { 86 int irq, swlevel; 87 hubreg_t pend0, mask0; 88 cpuid_t cpu = smp_processor_id(); 89 int pi_int_mask0 = 90 (cputoslice(cpu) == 0) ? PI_INT_MASK0_A : PI_INT_MASK0_B; 91 92 /* copied from Irix intpend0() */ 93 pend0 = LOCAL_HUB_L(PI_INT_PEND0); 94 mask0 = LOCAL_HUB_L(pi_int_mask0); 95 96 pend0 &= mask0; /* Pick intrs we should look at */ 97 if (!pend0) 98 return; 99 100 swlevel = ms1bit(pend0); 101 #ifdef CONFIG_SMP 102 if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) { 103 LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ); 104 scheduler_ipi(); 105 } else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) { 106 LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ); 107 scheduler_ipi(); 108 } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { 109 LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ); 110 smp_call_function_interrupt(); 111 } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) { 112 LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ); 113 smp_call_function_interrupt(); 114 } else 115 #endif 116 { 117 /* "map" swlevel to irq */ 118 struct slice_data *si = cpu_data[cpu].data; 119 120 irq = si->level_to_irq[swlevel]; 121 do_IRQ(irq); 122 } 123 124 LOCAL_HUB_L(PI_INT_PEND0); 125 } 126 127 static void ip27_do_irq_mask1(void) 128 { 129 int irq, swlevel; 130 hubreg_t pend1, mask1; 131 cpuid_t cpu = smp_processor_id(); 132 int pi_int_mask1 = (cputoslice(cpu) == 0) ? PI_INT_MASK1_A : PI_INT_MASK1_B; 133 struct slice_data *si = cpu_data[cpu].data; 134 135 /* copied from Irix intpend0() */ 136 pend1 = LOCAL_HUB_L(PI_INT_PEND1); 137 mask1 = LOCAL_HUB_L(pi_int_mask1); 138 139 pend1 &= mask1; /* Pick intrs we should look at */ 140 if (!pend1) 141 return; 142 143 swlevel = ms1bit(pend1); 144 /* "map" swlevel to irq */ 145 irq = si->level_to_irq[swlevel]; 146 LOCAL_HUB_CLR_INTR(swlevel); 147 do_IRQ(irq); 148 149 LOCAL_HUB_L(PI_INT_PEND1); 150 } 151 152 static void ip27_prof_timer(void) 153 { 154 panic("CPU %d got a profiling interrupt", smp_processor_id()); 155 } 156 157 static void ip27_hub_error(void) 158 { 159 panic("CPU %d got a hub error interrupt", smp_processor_id()); 160 } 161 162 asmlinkage void plat_irq_dispatch(void) 163 { 164 unsigned long pending = read_c0_cause() & read_c0_status(); 165 extern unsigned int rt_timer_irq; 166 167 if (pending & CAUSEF_IP4) 168 do_IRQ(rt_timer_irq); 169 else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */ 170 ip27_do_irq_mask0(); 171 else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */ 172 ip27_do_irq_mask1(); 173 else if (pending & CAUSEF_IP5) 174 ip27_prof_timer(); 175 else if (pending & CAUSEF_IP6) 176 ip27_hub_error(); 177 } 178 179 void __init arch_init_irq(void) 180 { 181 } 182 183 void install_ipi(void) 184 { 185 int slice = LOCAL_HUB_L(PI_CPU_NUM); 186 int cpu = smp_processor_id(); 187 struct slice_data *si = cpu_data[cpu].data; 188 struct hub_data *hub = hub_data(cpu_to_node(cpu)); 189 int resched, call; 190 191 resched = CPU_RESCHED_A_IRQ + slice; 192 __set_bit(resched, hub->irq_alloc_mask); 193 __set_bit(resched, si->irq_enable_mask); 194 LOCAL_HUB_CLR_INTR(resched); 195 196 call = CPU_CALL_A_IRQ + slice; 197 __set_bit(call, hub->irq_alloc_mask); 198 __set_bit(call, si->irq_enable_mask); 199 LOCAL_HUB_CLR_INTR(call); 200 201 if (slice == 0) { 202 LOCAL_HUB_S(PI_INT_MASK0_A, si->irq_enable_mask[0]); 203 LOCAL_HUB_S(PI_INT_MASK1_A, si->irq_enable_mask[1]); 204 } else { 205 LOCAL_HUB_S(PI_INT_MASK0_B, si->irq_enable_mask[0]); 206 LOCAL_HUB_S(PI_INT_MASK1_B, si->irq_enable_mask[1]); 207 } 208 } 209