ints.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * linux/arch/m68knommu/platform/68328/ints.c
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file COPYING in the main directory of this archive
  6. * for more details.
  7. *
  8. * Copyright 1996 Roman Zippel
  9. * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
  10. */
  11. #include <linux/module.h>
  12. #include <linux/types.h>
  13. #include <linux/kernel.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel_stat.h>
  16. #include <linux/errno.h>
  17. #include <linux/interrupt.h>
  18. #include <asm/system.h>
  19. #include <asm/irq.h>
  20. #include <asm/irqnode.h>
  21. #include <asm/traps.h>
  22. #include <asm/io.h>
  23. #include <asm/machdep.h>
  24. #include <asm/setup.h>
  25. #if defined(CONFIG_M68328)
  26. #include <asm/MC68328.h>
  27. #elif defined(CONFIG_M68EZ328)
  28. #include <asm/MC68EZ328.h>
  29. #elif defined(CONFIG_M68VZ328)
  30. #include <asm/MC68VZ328.h>
  31. #endif
  32. /* assembler routines */
  33. asmlinkage void system_call(void);
  34. asmlinkage void buserr(void);
  35. asmlinkage void trap(void);
  36. asmlinkage void trap3(void);
  37. asmlinkage void trap4(void);
  38. asmlinkage void trap5(void);
  39. asmlinkage void trap6(void);
  40. asmlinkage void trap7(void);
  41. asmlinkage void trap8(void);
  42. asmlinkage void trap9(void);
  43. asmlinkage void trap10(void);
  44. asmlinkage void trap11(void);
  45. asmlinkage void trap12(void);
  46. asmlinkage void trap13(void);
  47. asmlinkage void trap14(void);
  48. asmlinkage void trap15(void);
  49. asmlinkage void trap33(void);
  50. asmlinkage void trap34(void);
  51. asmlinkage void trap35(void);
  52. asmlinkage void trap36(void);
  53. asmlinkage void trap37(void);
  54. asmlinkage void trap38(void);
  55. asmlinkage void trap39(void);
  56. asmlinkage void trap40(void);
  57. asmlinkage void trap41(void);
  58. asmlinkage void trap42(void);
  59. asmlinkage void trap43(void);
  60. asmlinkage void trap44(void);
  61. asmlinkage void trap45(void);
  62. asmlinkage void trap46(void);
  63. asmlinkage void trap47(void);
  64. asmlinkage irqreturn_t bad_interrupt(int, void *);
  65. asmlinkage irqreturn_t inthandler(void);
  66. asmlinkage irqreturn_t inthandler1(void);
  67. asmlinkage irqreturn_t inthandler2(void);
  68. asmlinkage irqreturn_t inthandler3(void);
  69. asmlinkage irqreturn_t inthandler4(void);
  70. asmlinkage irqreturn_t inthandler5(void);
  71. asmlinkage irqreturn_t inthandler6(void);
  72. asmlinkage irqreturn_t inthandler7(void);
  73. extern e_vector *_ramvec;
  74. /* The number of spurious interrupts */
  75. volatile unsigned int num_spurious;
  76. unsigned int local_irq_count[NR_CPUS];
  77. /* irq node variables for the 32 (potential) on chip sources */
  78. static irq_node_t int_irq_list[NR_IRQS];
  79. /*
  80. * This function should be called during kernel startup to initialize
  81. * the IRQ handling routines.
  82. */
  83. void init_IRQ(void)
  84. {
  85. int i;
  86. /* set up the vectors */
  87. for (i = 72; i < 256; ++i)
  88. _ramvec[i] = (e_vector) bad_interrupt;
  89. _ramvec[32] = system_call;
  90. _ramvec[65] = (e_vector) inthandler1;
  91. _ramvec[66] = (e_vector) inthandler2;
  92. _ramvec[67] = (e_vector) inthandler3;
  93. _ramvec[68] = (e_vector) inthandler4;
  94. _ramvec[69] = (e_vector) inthandler5;
  95. _ramvec[70] = (e_vector) inthandler6;
  96. _ramvec[71] = (e_vector) inthandler7;
  97. IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
  98. /* initialize handlers */
  99. for (i = 0; i < NR_IRQS; i++) {
  100. int_irq_list[i].handler = bad_interrupt;
  101. int_irq_list[i].flags = IRQ_FLG_STD;
  102. int_irq_list[i].dev_id = NULL;
  103. int_irq_list[i].devname = NULL;
  104. }
  105. /* turn off all interrupts */
  106. IMR = ~0;
  107. }
  108. int request_irq(
  109. unsigned int irq,
  110. irq_handler_t handler,
  111. unsigned long flags,
  112. const char *devname,
  113. void *dev_id)
  114. {
  115. if (irq >= NR_IRQS) {
  116. printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
  117. return -ENXIO;
  118. }
  119. if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
  120. if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
  121. printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
  122. __FUNCTION__, irq, int_irq_list[irq].devname);
  123. return -EBUSY;
  124. }
  125. if (flags & IRQ_FLG_REPLACE) {
  126. printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
  127. __FUNCTION__, devname, irq, int_irq_list[irq].devname);
  128. return -EBUSY;
  129. }
  130. }
  131. int_irq_list[irq].handler = handler;
  132. int_irq_list[irq].flags = flags;
  133. int_irq_list[irq].dev_id = dev_id;
  134. int_irq_list[irq].devname = devname;
  135. IMR &= ~(1<<irq);
  136. return 0;
  137. }
  138. EXPORT_SYMBOL(request_irq);
  139. void free_irq(unsigned int irq, void *dev_id)
  140. {
  141. if (irq >= NR_IRQS) {
  142. printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
  143. return;
  144. }
  145. if (int_irq_list[irq].dev_id != dev_id)
  146. printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
  147. __FUNCTION__, irq, int_irq_list[irq].devname);
  148. int_irq_list[irq].handler = bad_interrupt;
  149. int_irq_list[irq].flags = IRQ_FLG_STD;
  150. int_irq_list[irq].dev_id = NULL;
  151. int_irq_list[irq].devname = NULL;
  152. IMR |= 1<<irq;
  153. }
  154. EXPORT_SYMBOL(free_irq);
  155. int show_interrupts(struct seq_file *p, void *v)
  156. {
  157. int i = *(loff_t *) v;
  158. if (i < NR_IRQS) {
  159. if (int_irq_list[i].devname) {
  160. seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
  161. if (int_irq_list[i].flags & IRQ_FLG_LOCK)
  162. seq_printf(p, "L ");
  163. else
  164. seq_printf(p, " ");
  165. seq_printf(p, "%s\n", int_irq_list[i].devname);
  166. }
  167. }
  168. if (i == NR_IRQS)
  169. seq_printf(p, " : %10u spurious\n", num_spurious);
  170. return 0;
  171. }
  172. /* The 68k family did not have a good way to determine the source
  173. * of interrupts until later in the family. The EC000 core does
  174. * not provide the vector number on the stack, we vector everything
  175. * into one vector and look in the blasted mask register...
  176. * This code is designed to be fast, almost constant time, not clean!
  177. */
  178. void process_int(int vec, struct pt_regs *fp)
  179. {
  180. int irq;
  181. int mask;
  182. unsigned long pend = ISR;
  183. while (pend) {
  184. if (pend & 0x0000ffff) {
  185. if (pend & 0x000000ff) {
  186. if (pend & 0x0000000f) {
  187. mask = 0x00000001;
  188. irq = 0;
  189. } else {
  190. mask = 0x00000010;
  191. irq = 4;
  192. }
  193. } else {
  194. if (pend & 0x00000f00) {
  195. mask = 0x00000100;
  196. irq = 8;
  197. } else {
  198. mask = 0x00001000;
  199. irq = 12;
  200. }
  201. }
  202. } else {
  203. if (pend & 0x00ff0000) {
  204. if (pend & 0x000f0000) {
  205. mask = 0x00010000;
  206. irq = 16;
  207. } else {
  208. mask = 0x00100000;
  209. irq = 20;
  210. }
  211. } else {
  212. if (pend & 0x0f000000) {
  213. mask = 0x01000000;
  214. irq = 24;
  215. } else {
  216. mask = 0x10000000;
  217. irq = 28;
  218. }
  219. }
  220. }
  221. while (! (mask & pend)) {
  222. mask <<=1;
  223. irq++;
  224. }
  225. kstat_cpu(0).irqs[irq]++;
  226. if (int_irq_list[irq].handler) {
  227. int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp);
  228. } else {
  229. printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq);
  230. IMR |= mask;
  231. }
  232. pend &= ~mask;
  233. }
  234. }