amiints.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Amiga Linux interrupt handling code
  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. * 11/07/96: rewritten interrupt handling, irq lists are exists now only for
  9. * this sources where it makes sense (VERTB/PORTS/EXTER) and you must
  10. * be careful that dev_id for this sources is unique since this the
  11. * only possibility to distinguish between different handlers for
  12. * free_irq. irq lists also have different irq flags:
  13. * - IRQ_FLG_FAST: handler is inserted at top of list (after other
  14. * fast handlers)
  15. * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
  16. * they're executed irq level is set to the previous
  17. * one, but handlers don't need to be reentrant, if
  18. * reentrance occurred, slow handlers will be just
  19. * called again.
  20. * The whole interrupt handling for CIAs is moved to cia.c
  21. * /Roman Zippel
  22. *
  23. * 07/08/99: rewamp of the interrupt handling - we now have two types of
  24. * interrupts, normal and fast handlers, fast handlers being
  25. * marked with SA_INTERRUPT and runs with all other interrupts
  26. * disabled. Normal interrupts disable their own source but
  27. * run with all other interrupt sources enabled.
  28. * PORTS and EXTER interrupts are always shared even if the
  29. * drivers do not explicitly mark this when calling
  30. * request_irq which they really should do.
  31. * This is similar to the way interrupts are handled on all
  32. * other architectures and makes a ton of sense besides
  33. * having the advantage of making it easier to share
  34. * drivers.
  35. * /Jes
  36. */
  37. #include <linux/types.h>
  38. #include <linux/kernel.h>
  39. #include <linux/sched.h>
  40. #include <linux/interrupt.h>
  41. #include <linux/irq.h>
  42. #include <linux/kernel_stat.h>
  43. #include <linux/init.h>
  44. #include <asm/system.h>
  45. #include <asm/irq.h>
  46. #include <asm/traps.h>
  47. #include <asm/amigahw.h>
  48. #include <asm/amigaints.h>
  49. #include <asm/amipcmcia.h>
  50. #ifdef CONFIG_APUS
  51. #include <asm/amigappc.h>
  52. #endif
  53. extern void cia_init_IRQ(struct ciabase *base);
  54. unsigned short ami_intena_vals[AMI_STD_IRQS] = {
  55. IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
  56. IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
  57. };
  58. static const unsigned char ami_servers[AMI_STD_IRQS] = {
  59. 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
  60. };
  61. static short ami_ablecount[AMI_IRQS];
  62. static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
  63. {
  64. /* num_spurious += 1;*/
  65. }
  66. /*
  67. * void amiga_init_IRQ(void)
  68. *
  69. * Parameters: None
  70. *
  71. * Returns: Nothing
  72. *
  73. * This function should be called during kernel startup to initialize
  74. * the amiga IRQ handling routines.
  75. */
  76. __init
  77. void amiga_init_IRQ(void)
  78. {
  79. int i;
  80. for (i = 0; i < AMI_IRQS; i++)
  81. ami_ablecount[i] = 0;
  82. /* turn off PCMCIA interrupts */
  83. if (AMIGAHW_PRESENT(PCMCIA))
  84. gayle.inten = GAYLE_IRQ_IDE;
  85. /* turn off all interrupts... */
  86. amiga_custom.intena = 0x7fff;
  87. amiga_custom.intreq = 0x7fff;
  88. #ifdef CONFIG_APUS
  89. /* Clear any inter-CPU interrupt requests. Circumvents bug in
  90. Blizzard IPL emulation HW (or so it appears). */
  91. APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
  92. /* Init IPL emulation. */
  93. APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL);
  94. APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
  95. APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
  96. #endif
  97. /* ... and enable the master interrupt bit */
  98. amiga_custom.intena = IF_SETCLR | IF_INTEN;
  99. cia_init_IRQ(&ciaa_base);
  100. cia_init_IRQ(&ciab_base);
  101. }
  102. /*
  103. * Enable/disable a particular machine specific interrupt source.
  104. * Note that this may affect other interrupts in case of a shared interrupt.
  105. * This function should only be called for a _very_ short time to change some
  106. * internal data, that may not be changed by the interrupt at the same time.
  107. * ami_(enable|disable)_irq calls may also be nested.
  108. */
  109. void amiga_enable_irq(unsigned int irq)
  110. {
  111. if (irq >= AMI_IRQS) {
  112. printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
  113. return;
  114. }
  115. ami_ablecount[irq]--;
  116. if (ami_ablecount[irq]<0)
  117. ami_ablecount[irq]=0;
  118. else if (ami_ablecount[irq])
  119. return;
  120. /* No action for auto-vector interrupts */
  121. if (irq >= IRQ_AMIGA_AUTO){
  122. printk("%s: Trying to enable auto-vector IRQ %i\n",
  123. __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  124. return;
  125. }
  126. if (irq >= IRQ_AMIGA_CIAA) {
  127. cia_set_irq(irq, 0);
  128. cia_able_irq(irq, 1);
  129. return;
  130. }
  131. /* enable the interrupt */
  132. amiga_custom.intena = IF_SETCLR | ami_intena_vals[irq];
  133. }
  134. void amiga_disable_irq(unsigned int irq)
  135. {
  136. if (irq >= AMI_IRQS) {
  137. printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
  138. return;
  139. }
  140. if (ami_ablecount[irq]++)
  141. return;
  142. /* No action for auto-vector interrupts */
  143. if (irq >= IRQ_AMIGA_AUTO) {
  144. printk("%s: Trying to disable auto-vector IRQ %i\n",
  145. __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  146. return;
  147. }
  148. if (irq >= IRQ_AMIGA_CIAA) {
  149. cia_able_irq(irq, 0);
  150. return;
  151. }
  152. /* disable the interrupt */
  153. amiga_custom.intena = ami_intena_vals[irq];
  154. }
  155. inline void amiga_do_irq(int irq, struct pt_regs *fp)
  156. {
  157. irq_desc_t *desc = irq_desc + irq;
  158. struct irqaction *action = desc->action;
  159. kstat_cpu(0).irqs[irq]++;
  160. action->handler(irq, action->dev_id, fp);
  161. }
  162. void amiga_do_irq_list(int irq, struct pt_regs *fp)
  163. {
  164. irq_desc_t *desc = irq_desc + irq;
  165. struct irqaction *action;
  166. kstat_cpu(0).irqs[irq]++;
  167. amiga_custom.intreq = ami_intena_vals[irq];
  168. for (action = desc->action; action; action = action->next)
  169. action->handler(irq, action->dev_id, fp);
  170. }
  171. /*
  172. * The builtin Amiga hardware interrupt handlers.
  173. */
  174. static void ami_int1(int irq, void *dev_id, struct pt_regs *fp)
  175. {
  176. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  177. /* if serial transmit buffer empty, interrupt */
  178. if (ints & IF_TBE) {
  179. amiga_custom.intreq = IF_TBE;
  180. amiga_do_irq(IRQ_AMIGA_TBE, fp);
  181. }
  182. /* if floppy disk transfer complete, interrupt */
  183. if (ints & IF_DSKBLK) {
  184. amiga_custom.intreq = IF_DSKBLK;
  185. amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
  186. }
  187. /* if software interrupt set, interrupt */
  188. if (ints & IF_SOFT) {
  189. amiga_custom.intreq = IF_SOFT;
  190. amiga_do_irq(IRQ_AMIGA_SOFT, fp);
  191. }
  192. }
  193. static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
  194. {
  195. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  196. /* if a blitter interrupt */
  197. if (ints & IF_BLIT) {
  198. amiga_custom.intreq = IF_BLIT;
  199. amiga_do_irq(IRQ_AMIGA_BLIT, fp);
  200. }
  201. /* if a copper interrupt */
  202. if (ints & IF_COPER) {
  203. amiga_custom.intreq = IF_COPER;
  204. amiga_do_irq(IRQ_AMIGA_COPPER, fp);
  205. }
  206. /* if a vertical blank interrupt */
  207. if (ints & IF_VERTB)
  208. amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
  209. }
  210. static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
  211. {
  212. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  213. /* if audio 0 interrupt */
  214. if (ints & IF_AUD0) {
  215. amiga_custom.intreq = IF_AUD0;
  216. amiga_do_irq(IRQ_AMIGA_AUD0, fp);
  217. }
  218. /* if audio 1 interrupt */
  219. if (ints & IF_AUD1) {
  220. amiga_custom.intreq = IF_AUD1;
  221. amiga_do_irq(IRQ_AMIGA_AUD1, fp);
  222. }
  223. /* if audio 2 interrupt */
  224. if (ints & IF_AUD2) {
  225. amiga_custom.intreq = IF_AUD2;
  226. amiga_do_irq(IRQ_AMIGA_AUD2, fp);
  227. }
  228. /* if audio 3 interrupt */
  229. if (ints & IF_AUD3) {
  230. amiga_custom.intreq = IF_AUD3;
  231. amiga_do_irq(IRQ_AMIGA_AUD3, fp);
  232. }
  233. }
  234. static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
  235. {
  236. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  237. /* if serial receive buffer full interrupt */
  238. if (ints & IF_RBF) {
  239. /* acknowledge of IF_RBF must be done by the serial interrupt */
  240. amiga_do_irq(IRQ_AMIGA_RBF, fp);
  241. }
  242. /* if a disk sync interrupt */
  243. if (ints & IF_DSKSYN) {
  244. amiga_custom.intreq = IF_DSKSYN;
  245. amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
  246. }
  247. }
  248. static void ami_int7(int irq, void *dev_id, struct pt_regs *fp)
  249. {
  250. panic ("level 7 interrupt received\n");
  251. }
  252. #ifdef CONFIG_APUS
  253. /* The PPC irq handling links all handlers requested on the same vector
  254. and executes them in a loop. Having ami_badint at the end of the chain
  255. is a bad idea. */
  256. struct irqaction amiga_sys_irqaction[AUTO_IRQS] = {
  257. { .handler = ami_badint, .name = "spurious int" },
  258. { .handler = ami_int1, .name = "int1 handler" },
  259. { 0, /* CIAA */ },
  260. { .handler = ami_int3, .name = "int3 handler" },
  261. { .handler = ami_int4, .name = "int4 handler" },
  262. { .handler = ami_int5, .name = "int5 handler" },
  263. { 0, /* CIAB */ },
  264. { .handler = ami_int7, .name = "int7 handler" },
  265. };
  266. #else
  267. void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
  268. ami_badint, ami_int1, ami_badint, ami_int3,
  269. ami_int4, ami_int5, ami_badint, ami_int7
  270. };
  271. #endif