1/* 2 * Code to handle Baget/MIPS IRQs plus some generic interrupt stuff. 3 * 4 * Copyright (C) 1998 Vladimir Roganov & Gleb Raiko 5 * Code (mostly sleleton and comments) derived from DECstation IRQ 6 * handling. 7 */ 8#include <linux/errno.h> 9#include <linux/init.h> 10#include <linux/kernel_stat.h> 11#include <linux/signal.h> 12#include <linux/sched.h> 13#include <linux/types.h> 14#include <linux/interrupt.h> 15#include <linux/ioport.h> 16#include <linux/timex.h> 17#include <linux/slab.h> 18#include <linux/random.h> 19#include <linux/delay.h> 20 21#include <asm/bitops.h> 22#include <asm/bootinfo.h> 23#include <asm/io.h> 24#include <asm/irq.h> 25#include <asm/mipsregs.h> 26#include <asm/system.h> 27 28#include <asm/baget/baget.h> 29 30volatile unsigned long irq_err_count; 31 32/* 33 * This table is a correspondence between IRQ numbers and CPU PILs 34 */ 35 36static int irq_to_pil_map[BAGET_IRQ_NR] = { 37 7YYDELETEMEYY,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x00 - 0x0f */ 38 -1,-1,-1,-1, 3,-1,-1,-1, 2, 2, 2,-1, 3,-1,-1,3YYDELETEMEYY, /* 0x10 - 0x1f */ 39 -1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1, 7,-1,-1,-1, /* 0x20 - 0x2f */ 40 -1, 3, 2YYDELETEMEYY, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0x30 - 0x3f */ 41}; 42 43static inline int irq_to_pil(int irq_nr) 44{ 45 int pil = -1; 46 47 if (irq_nr >= BAGET_IRQ_NR) 48 baget_printk("irq_to_pil: too large irq_nr = 0x%x\n", irq_nr); 49 else { 50 pil = irq_to_pil_map[irq_nr]; 51 if (pil == -1) 52 baget_printk("irq_to_pil: unknown irq = 0x%x\n", irq_nr); 53 } 54 55 return pil; 56} 57 58/* Function for careful CP0 interrupt mask access */ 59 60static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) 61{ 62 unsigned long status = read_c0_status(); 63 status &= ~((clr_mask & 0xFF) << 8); 64 status |= (set_mask & 0xFF) << 8; 65 write_c0_status(status); 66} 67 68/* 69 * These two functions may be used for unconditional IRQ 70 * masking via their PIL protection. 71 */ 72 73static inline void mask_irq(unsigned int irq_nr) 74{ 75 modify_cp0_intmask(irq_to_pil(irq_nr), 0); 76} 77 78static inline void unmask_irq(unsigned int irq_nr) 79{ 80 modify_cp0_intmask(0, irq_to_pil(irq_nr)); 81} 82 83/* 84 * The following section is introduced for masking/unasking IRQ 85 * only while no more IRQs uses same CPU PIL. 86 * 87 * These functions are used in request_irq, free_irq, but it looks 88 * they cannot change something: CP0_STATUS is private for any 89 * process, and their action is invisible for system. 90 */ 91 92static volatile unsigned int pil_in_use[BAGET_PIL_NR] = { 0, }; 93 94void mask_irq_count(int irq_nr) 95{ 96 unsigned long flags; 97 int pil = irq_to_pil(irq_nr); 98 99 save_and_cli(flags); 100 if (!--pil_in_use[pil]) 101 mask_irq(irq_nr); 102 restore_flags(flags); 103} 104 105void unmask_irq_count(int irq_nr) 106{ 107 unsigned long flags; 108 int pil = irq_to_pil(irq_nr); 109 110 save_and_cli(flags); 111 if (!pil_in_use[pil]++) 112 unmask_irq(irq_nr); 113 restore_flags(flags); 114} 115 116/* 117 * Two functions below are exported versions of mask/unmask IRQ 118 */ 119 120void disable_irq(unsigned int irq_nr) 121{ 122 unsigned long flags; 123 124 save_and_cli(flags); 125 mask_irq(irq_nr); 126 restore_flags(flags); 127} 128 129void enable_irq(unsigned int irq_nr) 130{ 131 unsigned long flags; 132 133 save_and_cli(flags); 134 unmask_irq(irq_nr); 135 restore_flags(flags); 136} 137 138/* 139 * Pointers to the low-level handlers: first the general ones, then the 140 * fast ones, then the bad ones. 141 */ 142static struct irqaction *irq_action[BAGET_IRQ_NR] = { NULL, }; 143 144int get_irq_list(char *buf) 145{ 146 int i, len = 0; 147 struct irqaction * action; 148 149 for (i = 0 ; i < BAGET_IRQ_NR ; i++) { 150 action = irq_action[i]; 151 if (!action) 152 continue; 153 len += sprintf(buf+len, "%2d: %8d %c %s", 154 i, kstat.irqs[0][i], 155 (action->flags & SA_INTERRUPT) ? '+' : ' ', 156 action->name); 157 for (action=action->next; action; action = action->next) { 158 len += sprintf(buf+len, ",%s %s", 159 (action->flags & SA_INTERRUPT) ? " +" : "", 160 action->name); 161 } 162 len += sprintf(buf+len, "\n"); 163 } 164 return len; 165} 166 167 168/* 169 * do_IRQ handles IRQ's that have been installed without the 170 * SA_INTERRUPT flag: it uses the full signal-handling return 171 * and runs with other interrupts enabled. All relatively slow 172 * IRQ's should use this format: notably the keyboard/timer 173 * routines. 174 */ 175static void do_IRQ(int irq, struct pt_regs * regs) 176{ 177 struct irqaction *action; 178 int do_random, cpu; 179 180 cpu = smp_processor_id(); 181 irq_enter(cpu, irq); 182 kstat.irqs[cpu][irq]++; 183 184 mask_irq(irq); 185 action = *(irq + irq_action); 186 if (action) { 187 if (!(action->flags & SA_INTERRUPT)) 188 __sti(); 189 action = *(irq + irq_action); 190 do_random = 0; 191 do { 192 do_random |= action->flags; 193 action->handler(irq, action->dev_id, regs); 194 action = action->next; 195 } while (action); 196 if (do_random & SA_SAMPLE_RANDOM) 197 add_interrupt_randomness(irq); 198 __cli(); 199 } else { 200 printk("do_IRQ: Unregistered IRQ (0x%X) occurred\n", irq); 201 } 202 unmask_irq(irq); 203 irq_exit(cpu, irq); 204 205 /* unmasking and bottom half handling is done magically for us. */ 206} 207 208/* 209 * What to do in case of 'no VIC register available' for current interrupt 210 */ 211static void vic_reg_error(unsigned long address, unsigned char active_pils) 212{ 213 printk("\nNo VIC register found: reg=%08lx active_pils=%02x\n" 214 "Current interrupt mask from CP0_CAUSE: %02x\n", 215 address, 0xff & active_pils, 216 0xff & (read_c0_cause()>>8)); 217 { int i; for (i=0; i<10000; i++) udelay(1000); } 218} 219 220static char baget_fpu_irq = BAGET_FPU_IRQ; 221#define BAGET_INT_FPU {(unsigned long)&baget_fpu_irq, 1} 222 223/* 224 * Main interrupt handler: interrupt demultiplexer 225 */ 226asmlinkage void baget_interrupt(struct pt_regs *regs) 227{ 228 static struct baget_int_reg int_reg[BAGET_PIL_NR] = { 229 BAGET_INT_NONE, BAGET_INT_NONE, BAGET_INT0_ACK, BAGET_INT1_ACK, 230 BAGET_INT_NONE, BAGET_INT_FPU, BAGET_INT_NONE, BAGET_INT5_ACK 231 }; 232 unsigned char active_pils; 233 while ((active_pils = read_c0_cause()>>8)) { 234 int pil; 235 struct baget_int_reg* reg; 236 237 for (pil = 0; pil < BAGET_PIL_NR; pil++) { 238 if (!(active_pils & (1<<pil))) continue; 239 240 reg = &int_reg[pil]; 241 242 if (reg->address) { 243 extern int try_read(unsigned long,int); 244 int irq = try_read(reg->address, reg->size); 245 246 if (irq != -1) 247 do_IRQ(BAGET_IRQ_MASK(irq), regs); 248 else 249 vic_reg_error(reg->address, active_pils); 250 } else { 251 printk("baget_interrupt: unknown interrupt " 252 "(pil = %d)\n", pil); 253 } 254 } 255 } 256} 257 258/* 259 * Idea is to put all interrupts 260 * in a single table and differenciate them just by number. 261 */ 262int setup_baget_irq(int irq, struct irqaction * new) 263{ 264 int shared = 0; 265 struct irqaction *old, **p; 266 unsigned long flags; 267 268 p = irq_action + irq; 269 if ((old = *p) != NULL) { 270 /* Can't share interrupts unless both agree to */ 271 if (!(old->flags & new->flags & SA_SHIRQ)) 272 return -EBUSY; 273 274 /* Can't share interrupts unless both are same type */ 275 if ((old->flags ^ new->flags) & SA_INTERRUPT) 276 return -EBUSY; 277 278 /* add new interrupt at end of irq queue */ 279 do { 280 p = &old->next; 281 old = *p; 282 } while (old); 283 shared = 1; 284 } 285 286 if (new->flags & SA_SAMPLE_RANDOM) 287 rand_initialize_irq(irq); 288 289 save_and_cli(flags); 290 *p = new; 291 restore_flags(flags); 292 293 if (!shared) { 294 unmask_irq_count(irq); 295 } 296 297 return 0; 298} 299 300int request_irq(unsigned int irq, 301 void (*handler)(int, void *, struct pt_regs *), 302 unsigned long irqflags, 303 const char * devname, 304 void *dev_id) 305{ 306 int retval; 307 struct irqaction * action; 308 309 if (irq >= BAGET_IRQ_NR) 310 return -EINVAL; 311 if (!handler) 312 return -EINVAL; 313 if (irq_to_pil_map[irq] < 0) 314 return -EINVAL; 315 316 action = (struct irqaction *) 317 kmalloc(sizeof(struct irqaction), GFP_KERNEL); 318 if (!action) 319 return -ENOMEM; 320 321 action->handler = handler; 322 action->flags = irqflags; 323 action->mask = 0; 324 action->name = devname; 325 action->next = NULL; 326 action->dev_id = dev_id; 327 328 retval = setup_baget_irq(irq, action); 329 330 if (retval) 331 kfree(action); 332 333 return retval; 334} 335 336void free_irq(unsigned int irq, void *dev_id) 337{ 338 struct irqaction * action, **p; 339 unsigned long flags; 340 341 if (irq >= BAGET_IRQ_NR) 342 printk("Trying to free IRQ%d\n",irq); 343 344 for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { 345 if (action->dev_id != dev_id) 346 continue; 347 348 /* Found it - now free it */ 349 save_and_cli(flags); 350 *p = action->next; 351 if (!irq[irq_action]) 352 unmask_irq_count(irq); 353 restore_flags(flags); 354 kfree(action); 355 return; 356 } 357 printk("Trying to free free IRQ%d\n",irq); 358} 359 360unsigned long probe_irq_on (void) 361{ 362 /* TODO */ 363 return 0; 364} 365 366int probe_irq_off (unsigned long irqs) 367{ 368 /* TODO */ 369 return 0; 370} 371 372 373static void write_err_interrupt(int irq, void *dev_id, struct pt_regs * regs) 374{ 375 *(volatile char*) BAGET_WRERR_ACK = 0; 376} 377 378static struct irqaction irq0 = 379{ write_err_interrupt, SA_INTERRUPT, 0, "bus write error", NULL, NULL}; 380 381void __init init_IRQ(void) 382{ 383 irq_setup(); 384 385 /* Enable access to VIC interrupt registers */ 386 vac_outw(0xacef | 0x8200, VAC_PIO_FUNC); 387 388 /* Enable interrupts for pils 2 and 3 (lines 0 and 1) */ 389 modify_cp0_intmask(0, (1<<2)|(1<<3)); 390 391 if (setup_baget_irq(0, &irq0) < 0) 392 printk("init_IRQ: unable to register write_err irq\n"); 393} 394