1 /* 2 * Interrupt request handling routines. On the 3 * Sparc the IRQs are basically 'cast in stone' 4 * and you are supposed to probe the prom's device 5 * node trees to find out who's got which IRQ. 6 * 7 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 8 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 9 * Copyright (C) 1995,2002 Pete A. Zaitcev (zaitcev@yahoo.com) 10 * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 11 * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) 12 */ 13 14 #include <linux/kernel_stat.h> 15 #include <linux/seq_file.h> 16 17 #include <asm/cacheflush.h> 18 #include <asm/cpudata.h> 19 #include <asm/pcic.h> 20 #include <asm/leon.h> 21 22 #include "kernel.h" 23 #include "irq.h" 24 25 #ifdef CONFIG_SMP 26 #define SMP_NOP2 "nop; nop;\n\t" 27 #define SMP_NOP3 "nop; nop; nop;\n\t" 28 #else 29 #define SMP_NOP2 30 #define SMP_NOP3 31 #endif /* SMP */ 32 33 /* platform specific irq setup */ 34 struct sparc_irq_config sparc_irq_config; 35 36 unsigned long arch_local_irq_save(void) 37 { 38 unsigned long retval; 39 unsigned long tmp; 40 41 __asm__ __volatile__( 42 "rd %%psr, %0\n\t" 43 SMP_NOP3 /* Sun4m + Cypress + SMP bug */ 44 "or %0, %2, %1\n\t" 45 "wr %1, 0, %%psr\n\t" 46 "nop; nop; nop\n" 47 : "=&r" (retval), "=r" (tmp) 48 : "i" (PSR_PIL) 49 : "memory"); 50 51 return retval; 52 } 53 EXPORT_SYMBOL(arch_local_irq_save); 54 55 void arch_local_irq_enable(void) 56 { 57 unsigned long tmp; 58 59 __asm__ __volatile__( 60 "rd %%psr, %0\n\t" 61 SMP_NOP3 /* Sun4m + Cypress + SMP bug */ 62 "andn %0, %1, %0\n\t" 63 "wr %0, 0, %%psr\n\t" 64 "nop; nop; nop\n" 65 : "=&r" (tmp) 66 : "i" (PSR_PIL) 67 : "memory"); 68 } 69 EXPORT_SYMBOL(arch_local_irq_enable); 70 71 void arch_local_irq_restore(unsigned long old_psr) 72 { 73 unsigned long tmp; 74 75 __asm__ __volatile__( 76 "rd %%psr, %0\n\t" 77 "and %2, %1, %2\n\t" 78 SMP_NOP2 /* Sun4m + Cypress + SMP bug */ 79 "andn %0, %1, %0\n\t" 80 "wr %0, %2, %%psr\n\t" 81 "nop; nop; nop\n" 82 : "=&r" (tmp) 83 : "i" (PSR_PIL), "r" (old_psr) 84 : "memory"); 85 } 86 EXPORT_SYMBOL(arch_local_irq_restore); 87 88 /* 89 * Dave Redman (djhr@tadpole.co.uk) 90 * 91 * IRQ numbers.. These are no longer restricted to 15.. 92 * 93 * this is done to enable SBUS cards and onboard IO to be masked 94 * correctly. using the interrupt level isn't good enough. 95 * 96 * For example: 97 * A device interrupting at sbus level6 and the Floppy both come in 98 * at IRQ11, but enabling and disabling them requires writing to 99 * different bits in the SLAVIO/SEC. 100 * 101 * As a result of these changes sun4m machines could now support 102 * directed CPU interrupts using the existing enable/disable irq code 103 * with tweaks. 104 * 105 * Sun4d complicates things even further. IRQ numbers are arbitrary 106 * 32-bit values in that case. Since this is similar to sparc64, 107 * we adopt a virtual IRQ numbering scheme as is done there. 108 * Virutal interrupt numbers are allocated by build_irq(). So NR_IRQS 109 * just becomes a limit of how many interrupt sources we can handle in 110 * a single system. Even fully loaded SS2000 machines top off at 111 * about 32 interrupt sources or so, therefore a NR_IRQS value of 64 112 * is more than enough. 113 * 114 * We keep a map of per-PIL enable interrupts. These get wired 115 * up via the irq_chip->startup() method which gets invoked by 116 * the generic IRQ layer during request_irq(). 117 */ 118 119 120 /* Table of allocated irqs. Unused entries has irq == 0 */ 121 static struct irq_bucket irq_table[NR_IRQS]; 122 /* Protect access to irq_table */ 123 static DEFINE_SPINLOCK(irq_table_lock); 124 125 /* Map between the irq identifier used in hw to the irq_bucket. */ 126 struct irq_bucket *irq_map[SUN4D_MAX_IRQ]; 127 /* Protect access to irq_map */ 128 static DEFINE_SPINLOCK(irq_map_lock); 129 130 /* Allocate a new irq from the irq_table */ 131 unsigned int irq_alloc(unsigned int real_irq, unsigned int pil) 132 { 133 unsigned long flags; 134 unsigned int i; 135 136 spin_lock_irqsave(&irq_table_lock, flags); 137 for (i = 1; i < NR_IRQS; i++) { 138 if (irq_table[i].real_irq == real_irq && irq_table[i].pil == pil) 139 goto found; 140 } 141 142 for (i = 1; i < NR_IRQS; i++) { 143 if (!irq_table[i].irq) 144 break; 145 } 146 147 if (i < NR_IRQS) { 148 irq_table[i].real_irq = real_irq; 149 irq_table[i].irq = i; 150 irq_table[i].pil = pil; 151 } else { 152 printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); 153 i = 0; 154 } 155 found: 156 spin_unlock_irqrestore(&irq_table_lock, flags); 157 158 return i; 159 } 160 161 /* Based on a single pil handler_irq may need to call several 162 * interrupt handlers. Use irq_map as entry to irq_table, 163 * and let each entry in irq_table point to the next entry. 164 */ 165 void irq_link(unsigned int irq) 166 { 167 struct irq_bucket *p; 168 unsigned long flags; 169 unsigned int pil; 170 171 BUG_ON(irq >= NR_IRQS); 172 173 spin_lock_irqsave(&irq_map_lock, flags); 174 175 p = &irq_table[irq]; 176 pil = p->pil; 177 BUG_ON(pil > SUN4D_MAX_IRQ); 178 p->next = irq_map[pil]; 179 irq_map[pil] = p; 180 181 spin_unlock_irqrestore(&irq_map_lock, flags); 182 } 183 184 void irq_unlink(unsigned int irq) 185 { 186 struct irq_bucket *p, **pnext; 187 unsigned long flags; 188 189 BUG_ON(irq >= NR_IRQS); 190 191 spin_lock_irqsave(&irq_map_lock, flags); 192 193 p = &irq_table[irq]; 194 BUG_ON(p->pil > SUN4D_MAX_IRQ); 195 pnext = &irq_map[p->pil]; 196 while (*pnext != p) 197 pnext = &(*pnext)->next; 198 *pnext = p->next; 199 200 spin_unlock_irqrestore(&irq_map_lock, flags); 201 } 202 203 204 /* /proc/interrupts printing */ 205 int arch_show_interrupts(struct seq_file *p, int prec) 206 { 207 int j; 208 209 #ifdef CONFIG_SMP 210 seq_printf(p, "RES: "); 211 for_each_online_cpu(j) 212 seq_printf(p, "%10u ", cpu_data(j).irq_resched_count); 213 seq_printf(p, " IPI rescheduling interrupts\n"); 214 seq_printf(p, "CAL: "); 215 for_each_online_cpu(j) 216 seq_printf(p, "%10u ", cpu_data(j).irq_call_count); 217 seq_printf(p, " IPI function call interrupts\n"); 218 #endif 219 seq_printf(p, "NMI: "); 220 for_each_online_cpu(j) 221 seq_printf(p, "%10u ", cpu_data(j).counter); 222 seq_printf(p, " Non-maskable interrupts\n"); 223 return 0; 224 } 225 226 void handler_irq(unsigned int pil, struct pt_regs *regs) 227 { 228 struct pt_regs *old_regs; 229 struct irq_bucket *p; 230 231 BUG_ON(pil > 15); 232 old_regs = set_irq_regs(regs); 233 irq_enter(); 234 235 p = irq_map[pil]; 236 while (p) { 237 struct irq_bucket *next = p->next; 238 239 generic_handle_irq(p->irq); 240 p = next; 241 } 242 irq_exit(); 243 set_irq_regs(old_regs); 244 } 245 246 #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) 247 static unsigned int floppy_irq; 248 249 int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) 250 { 251 unsigned int cpu_irq; 252 int err; 253 254 #if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON 255 struct tt_entry *trap_table; 256 #endif 257 258 err = request_irq(irq, irq_handler, 0, "floppy", NULL); 259 if (err) 260 return -1; 261 262 /* Save for later use in floppy interrupt handler */ 263 floppy_irq = irq; 264 265 cpu_irq = (irq & (NR_IRQS - 1)); 266 267 /* Dork with trap table if we get this far. */ 268 #define INSTANTIATE(table) \ 269 table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \ 270 table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \ 271 SPARC_BRANCH((unsigned long) floppy_hardint, \ 272 (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\ 273 table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \ 274 table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; 275 276 INSTANTIATE(sparc_ttable) 277 #if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON 278 trap_table = &trapbase_cpu1; 279 INSTANTIATE(trap_table) 280 trap_table = &trapbase_cpu2; 281 INSTANTIATE(trap_table) 282 trap_table = &trapbase_cpu3; 283 INSTANTIATE(trap_table) 284 #endif 285 #undef INSTANTIATE 286 /* 287 * XXX Correct thing whould be to flush only I- and D-cache lines 288 * which contain the handler in question. But as of time of the 289 * writing we have no CPU-neutral interface to fine-grained flushes. 290 */ 291 flush_cache_all(); 292 return 0; 293 } 294 EXPORT_SYMBOL(sparc_floppy_request_irq); 295 296 /* 297 * These variables are used to access state from the assembler 298 * interrupt handler, floppy_hardint, so we cannot put these in 299 * the floppy driver image because that would not work in the 300 * modular case. 301 */ 302 volatile unsigned char *fdc_status; 303 EXPORT_SYMBOL(fdc_status); 304 305 char *pdma_vaddr; 306 EXPORT_SYMBOL(pdma_vaddr); 307 308 unsigned long pdma_size; 309 EXPORT_SYMBOL(pdma_size); 310 311 volatile int doing_pdma; 312 EXPORT_SYMBOL(doing_pdma); 313 314 char *pdma_base; 315 EXPORT_SYMBOL(pdma_base); 316 317 unsigned long pdma_areasize; 318 EXPORT_SYMBOL(pdma_areasize); 319 320 /* Use the generic irq support to call floppy_interrupt 321 * which was setup using request_irq() in sparc_floppy_request_irq(). 322 * We only have one floppy interrupt so we do not need to check 323 * for additional handlers being wired up by irq_link() 324 */ 325 void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) 326 { 327 struct pt_regs *old_regs; 328 329 old_regs = set_irq_regs(regs); 330 irq_enter(); 331 generic_handle_irq(floppy_irq); 332 irq_exit(); 333 set_irq_regs(old_regs); 334 } 335 #endif 336 337 /* djhr 338 * This could probably be made indirect too and assigned in the CPU 339 * bits of the code. That would be much nicer I think and would also 340 * fit in with the idea of being able to tune your kernel for your machine 341 * by removing unrequired machine and device support. 342 * 343 */ 344 345 void __init init_IRQ(void) 346 { 347 switch (sparc_cpu_model) { 348 case sun4c: 349 case sun4: 350 sun4c_init_IRQ(); 351 break; 352 353 case sun4m: 354 pcic_probe(); 355 if (pcic_present()) 356 sun4m_pci_init_IRQ(); 357 else 358 sun4m_init_IRQ(); 359 break; 360 361 case sun4d: 362 sun4d_init_IRQ(); 363 break; 364 365 case sparc_leon: 366 leon_init_IRQ(); 367 break; 368 369 default: 370 prom_printf("Cannot initialize IRQs on this Sun machine..."); 371 break; 372 } 373 btfixup(); 374 } 375 376