irq.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 1992 Linus Torvalds
  7. * Copyright (C) 1994 - 2000 Ralf Baechle
  8. */
  9. #include <linux/delay.h>
  10. #include <linux/init.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/irq.h>
  13. #include <linux/kernel.h>
  14. #include <linux/spinlock.h>
  15. #include <asm/i8259.h>
  16. #include <asm/io.h>
  17. #include <asm/sni.h>
  18. DEFINE_SPINLOCK(pciasic_lock);
  19. static void enable_pciasic_irq(unsigned int irq)
  20. {
  21. unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
  22. unsigned long flags;
  23. spin_lock_irqsave(&pciasic_lock, flags);
  24. *(volatile u8 *) PCIMT_IRQSEL |= mask;
  25. spin_unlock_irqrestore(&pciasic_lock, flags);
  26. }
  27. static unsigned int startup_pciasic_irq(unsigned int irq)
  28. {
  29. enable_pciasic_irq(irq);
  30. return 0; /* never anything pending */
  31. }
  32. #define shutdown_pciasic_irq disable_pciasic_irq
  33. void disable_pciasic_irq(unsigned int irq)
  34. {
  35. unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
  36. unsigned long flags;
  37. spin_lock_irqsave(&pciasic_lock, flags);
  38. *(volatile u8 *) PCIMT_IRQSEL &= mask;
  39. spin_unlock_irqrestore(&pciasic_lock, flags);
  40. }
  41. #define mask_and_ack_pciasic_irq disable_pciasic_irq
  42. static void end_pciasic_irq(unsigned int irq)
  43. {
  44. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  45. enable_pciasic_irq(irq);
  46. }
  47. static struct hw_interrupt_type pciasic_irq_type = {
  48. .typename = "ASIC-PCI",
  49. .startup = startup_pciasic_irq,
  50. .shutdown = shutdown_pciasic_irq,
  51. .enable = enable_pciasic_irq,
  52. .disable = disable_pciasic_irq,
  53. .ack = mask_and_ack_pciasic_irq,
  54. .end = end_pciasic_irq,
  55. };
  56. /*
  57. * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
  58. * button interrupts. Later ...
  59. */
  60. static void pciasic_hwint0(struct pt_regs *regs)
  61. {
  62. panic("Received int0 but no handler yet ...");
  63. }
  64. /* This interrupt was used for the com1 console on the first prototypes. */
  65. static void pciasic_hwint2(struct pt_regs *regs)
  66. {
  67. /* I think this shouldn't happen on production machines. */
  68. panic("hwint2 and no handler yet");
  69. }
  70. /* hwint5 is the r4k count / compare interrupt */
  71. static void pciasic_hwint5(struct pt_regs *regs)
  72. {
  73. panic("hwint5 and no handler yet");
  74. }
  75. static unsigned int ls1bit8(unsigned int x)
  76. {
  77. int b = 7, s;
  78. s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s;
  79. s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s;
  80. s = 1; if ((x & 0x40) == 0) s = 0; b -= s;
  81. return b;
  82. }
  83. /*
  84. * hwint 1 deals with EISA and SCSI interrupts,
  85. *
  86. * The EISA_INT bit in CSITPEND is high active, all others are low active.
  87. */
  88. static void pciasic_hwint1(struct pt_regs *regs)
  89. {
  90. u8 pend = *(volatile char *)PCIMT_CSITPEND;
  91. unsigned long flags;
  92. if (pend & IT_EISA) {
  93. int irq;
  94. /*
  95. * Note: ASIC PCI's builtin interrupt achknowledge feature is
  96. * broken. Using it may result in loss of some or all i8259
  97. * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
  98. */
  99. irq = i8259_irq();
  100. if (unlikely(irq < 0))
  101. return;
  102. do_IRQ(irq, regs);
  103. }
  104. if (!(pend & IT_SCSI)) {
  105. flags = read_c0_status();
  106. clear_c0_status(ST0_IM);
  107. do_IRQ(PCIMT_IRQ_SCSI, regs);
  108. write_c0_status(flags);
  109. }
  110. }
  111. /*
  112. * hwint 3 should deal with the PCI A - D interrupts,
  113. */
  114. static void pciasic_hwint3(struct pt_regs *regs)
  115. {
  116. u8 pend = *(volatile char *)PCIMT_CSITPEND;
  117. int irq;
  118. pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
  119. clear_c0_status(IE_IRQ3);
  120. irq = PCIMT_IRQ_INT2 + ls1bit8(pend);
  121. do_IRQ(irq, regs);
  122. set_c0_status(IE_IRQ3);
  123. }
  124. /*
  125. * hwint 4 is used for only the onboard PCnet 32.
  126. */
  127. static void pciasic_hwint4(struct pt_regs *regs)
  128. {
  129. clear_c0_status(IE_IRQ4);
  130. do_IRQ(PCIMT_IRQ_ETHERNET, regs);
  131. set_c0_status(IE_IRQ4);
  132. }
  133. asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
  134. {
  135. unsigned int pending = read_c0_status() & read_c0_cause();
  136. static unsigned char led_cache;
  137. *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
  138. if (pending & 0x0800)
  139. pciasic_hwint1(regs);
  140. else if (pending & 0x4000)
  141. pciasic_hwint4(regs);
  142. else if (pending & 0x2000)
  143. pciasic_hwint3(regs);
  144. else if (pending & 0x1000)
  145. pciasic_hwint2(regs);
  146. else if (pending & 0x8000)
  147. pciasic_hwint5(regs);
  148. else if (pending & 0x0400)
  149. pciasic_hwint0(regs);
  150. }
  151. void __init init_pciasic(void)
  152. {
  153. unsigned long flags;
  154. spin_lock_irqsave(&pciasic_lock, flags);
  155. * (volatile u8 *) PCIMT_IRQSEL =
  156. IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD;
  157. spin_unlock_irqrestore(&pciasic_lock, flags);
  158. }
  159. /*
  160. * On systems with i8259-style interrupt controllers we assume for
  161. * driver compatibility reasons interrupts 0 - 15 to be the i8295
  162. * interrupts even if the hardware uses a different interrupt numbering.
  163. */
  164. void __init arch_init_irq(void)
  165. {
  166. int i;
  167. init_i8259_irqs(); /* Integrated i8259 */
  168. init_pciasic();
  169. /* Actually we've got more interrupts to handle ... */
  170. for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) {
  171. irq_desc[i].status = IRQ_DISABLED;
  172. irq_desc[i].action = 0;
  173. irq_desc[i].depth = 1;
  174. irq_desc[i].handler = &pciasic_irq_type;
  175. }
  176. change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4);
  177. }