irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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