amiints.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * arch/ppc/amiga/amiints.c -- 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/config.h>
  38. #include <linux/types.h>
  39. #include <linux/kernel.h>
  40. #include <linux/sched.h>
  41. #include <linux/interrupt.h>
  42. #include <linux/irq.h>
  43. #include <linux/kernel_stat.h>
  44. #include <linux/init.h>
  45. #include <asm/system.h>
  46. #include <asm/irq.h>
  47. #include <asm/traps.h>
  48. #include <asm/amigahw.h>
  49. #include <asm/amigaints.h>
  50. #include <asm/amipcmcia.h>
  51. #ifdef CONFIG_APUS
  52. #include <asm/amigappc.h>
  53. #endif
  54. extern void cia_init_IRQ(struct ciabase *base);
  55. unsigned short ami_intena_vals[AMI_STD_IRQS] = {
  56. IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
  57. IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
  58. };
  59. static const unsigned char ami_servers[AMI_STD_IRQS] = {
  60. 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
  61. };
  62. static short ami_ablecount[AMI_IRQS];
  63. static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
  64. {
  65. /* num_spurious += 1;*/
  66. }
  67. /*
  68. * void amiga_init_IRQ(void)
  69. *
  70. * Parameters: None
  71. *
  72. * Returns: Nothing
  73. *
  74. * This function should be called during kernel startup to initialize
  75. * the amiga IRQ handling routines.
  76. */
  77. __init
  78. void amiga_init_IRQ(void)
  79. {
  80. int i;
  81. for (i = 0; i < AMI_IRQS; i++)
  82. ami_ablecount[i] = 0;
  83. /* turn off PCMCIA interrupts */
  84. if (AMIGAHW_PRESENT(PCMCIA))
  85. gayle.inten = GAYLE_IRQ_IDE;
  86. /* turn off all interrupts... */
  87. custom.intena = 0x7fff;
  88. custom.intreq = 0x7fff;
  89. #ifdef CONFIG_APUS
  90. /* Clear any inter-CPU interrupt requests. Circumvents bug in
  91. Blizzard IPL emulation HW (or so it appears). */
  92. APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
  93. /* Init IPL emulation. */
  94. APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL);
  95. APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
  96. APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
  97. #endif
  98. /* ... and enable the master interrupt bit */
  99. custom.intena = IF_SETCLR | IF_INTEN;
  100. cia_init_IRQ(&ciaa_base);
  101. cia_init_IRQ(&ciab_base);
  102. }
  103. /*
  104. * Enable/disable a particular machine specific interrupt source.
  105. * Note that this may affect other interrupts in case of a shared interrupt.
  106. * This function should only be called for a _very_ short time to change some
  107. * internal data, that may not be changed by the interrupt at the same time.
  108. * ami_(enable|disable)_irq calls may also be nested.
  109. */
  110. void amiga_enable_irq(unsigned int irq)
  111. {
  112. if (irq >= AMI_IRQS) {
  113. printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
  114. return;
  115. }
  116. ami_ablecount[irq]--;
  117. if (ami_ablecount[irq]<0)
  118. ami_ablecount[irq]=0;
  119. else if (ami_ablecount[irq])
  120. return;
  121. /* No action for auto-vector interrupts */
  122. if (irq >= IRQ_AMIGA_AUTO){
  123. printk("%s: Trying to enable auto-vector IRQ %i\n",
  124. __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  125. return;
  126. }
  127. if (irq >= IRQ_AMIGA_CIAA) {
  128. cia_set_irq(irq, 0);
  129. cia_able_irq(irq, 1);
  130. return;
  131. }
  132. /* enable the interrupt */
  133. custom.intena = IF_SETCLR | ami_intena_vals[irq];
  134. }
  135. void amiga_disable_irq(unsigned int irq)
  136. {
  137. if (irq >= AMI_IRQS) {
  138. printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
  139. return;
  140. }
  141. if (ami_ablecount[irq]++)
  142. return;
  143. /* No action for auto-vector interrupts */
  144. if (irq >= IRQ_AMIGA_AUTO) {
  145. printk("%s: Trying to disable auto-vector IRQ %i\n",
  146. __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  147. return;
  148. }
  149. if (irq >= IRQ_AMIGA_CIAA) {
  150. cia_able_irq(irq, 0);
  151. return;
  152. }
  153. /* disable the interrupt */
  154. custom.intena = ami_intena_vals[irq];
  155. }
  156. inline void amiga_do_irq(int irq, struct pt_regs *fp)
  157. {
  158. irq_desc_t *desc = irq_desc + irq;
  159. struct irqaction *action = desc->action;
  160. kstat_cpu(0).irqs[irq]++;
  161. action->handler(irq, action->dev_id, fp);
  162. }
  163. void amiga_do_irq_list(int irq, struct pt_regs *fp)
  164. {
  165. irq_desc_t *desc = irq_desc + irq;
  166. struct irqaction *action;
  167. kstat_cpu(0).irqs[irq]++;
  168. custom.intreq = ami_intena_vals[irq];
  169. for (action = desc->action; action; action = action->next)
  170. action->handler(irq, action->dev_id, fp);
  171. }
  172. /*
  173. * The builtin Amiga hardware interrupt handlers.
  174. */
  175. static void ami_int1(int irq, void *dev_id, struct pt_regs *fp)
  176. {
  177. unsigned short ints = custom.intreqr & custom.intenar;
  178. /* if serial transmit buffer empty, interrupt */
  179. if (ints & IF_TBE) {
  180. custom.intreq = IF_TBE;
  181. amiga_do_irq(IRQ_AMIGA_TBE, fp);
  182. }
  183. /* if floppy disk transfer complete, interrupt */
  184. if (ints & IF_DSKBLK) {
  185. custom.intreq = IF_DSKBLK;
  186. amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
  187. }
  188. /* if software interrupt set, interrupt */
  189. if (ints & IF_SOFT) {
  190. custom.intreq = IF_SOFT;
  191. amiga_do_irq(IRQ_AMIGA_SOFT, fp);
  192. }
  193. }
  194. static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
  195. {
  196. unsigned short ints = custom.intreqr & custom.intenar;
  197. /* if a blitter interrupt */
  198. if (ints & IF_BLIT) {
  199. custom.intreq = IF_BLIT;
  200. amiga_do_irq(IRQ_AMIGA_BLIT, fp);
  201. }
  202. /* if a copper interrupt */
  203. if (ints & IF_COPER) {
  204. custom.intreq = IF_COPER;
  205. amiga_do_irq(IRQ_AMIGA_COPPER, fp);
  206. }
  207. /* if a vertical blank interrupt */
  208. if (ints & IF_VERTB)
  209. amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
  210. }
  211. static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
  212. {
  213. unsigned short ints = custom.intreqr & custom.intenar;
  214. /* if audio 0 interrupt */
  215. if (ints & IF_AUD0) {
  216. custom.intreq = IF_AUD0;
  217. amiga_do_irq(IRQ_AMIGA_AUD0, fp);
  218. }
  219. /* if audio 1 interrupt */
  220. if (ints & IF_AUD1) {
  221. custom.intreq = IF_AUD1;
  222. amiga_do_irq(IRQ_AMIGA_AUD1, fp);
  223. }
  224. /* if audio 2 interrupt */
  225. if (ints & IF_AUD2) {
  226. custom.intreq = IF_AUD2;
  227. amiga_do_irq(IRQ_AMIGA_AUD2, fp);
  228. }
  229. /* if audio 3 interrupt */
  230. if (ints & IF_AUD3) {
  231. custom.intreq = IF_AUD3;
  232. amiga_do_irq(IRQ_AMIGA_AUD3, fp);
  233. }
  234. }
  235. static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
  236. {
  237. unsigned short ints = custom.intreqr & custom.intenar;
  238. /* if serial receive buffer full interrupt */
  239. if (ints & IF_RBF) {
  240. /* acknowledge of IF_RBF must be done by the serial interrupt */
  241. amiga_do_irq(IRQ_AMIGA_RBF, fp);
  242. }
  243. /* if a disk sync interrupt */
  244. if (ints & IF_DSKSYN) {
  245. custom.intreq = IF_DSKSYN;
  246. amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
  247. }
  248. }
  249. static void ami_int7(int irq, void *dev_id, struct pt_regs *fp)
  250. {
  251. panic ("level 7 interrupt received\n");
  252. }
  253. #ifdef CONFIG_APUS
  254. /* The PPC irq handling links all handlers requested on the same vector
  255. and executes them in a loop. Having ami_badint at the end of the chain
  256. is a bad idea. */
  257. struct irqaction amiga_sys_irqaction[AUTO_IRQS] = {
  258. { .handler = ami_badint, .name = "spurious int" },
  259. { .handler = ami_int1, .name = "int1 handler" },
  260. { 0, /* CIAA */ },
  261. { .handler = ami_int3, .name = "int3 handler" },
  262. { .handler = ami_int4, .name = "int4 handler" },
  263. { .handler = ami_int5, .name = "int5 handler" },
  264. { 0, /* CIAB */ },
  265. { .handler = ami_int7, .name = "int7 handler" },
  266. };
  267. #else
  268. void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
  269. ami_badint, ami_int1, ami_badint, ami_int3,
  270. ami_int4, ami_int5, ami_badint, ami_int7
  271. };
  272. #endif