ints.c 6.4 KB

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