interrupt.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Celleb/Beat Interrupt controller
  3. *
  4. * (C) Copyright 2006-2007 TOSHIBA CORPORATION
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include <linux/init.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/irq.h>
  23. #include <linux/percpu.h>
  24. #include <linux/types.h>
  25. #include <asm/machdep.h>
  26. #include "interrupt.h"
  27. #include "beat_wrapper.h"
  28. #define MAX_IRQS NR_IRQS
  29. static DEFINE_SPINLOCK(beatic_irq_mask_lock);
  30. static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64];
  31. static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64];
  32. static struct irq_host *beatic_host = NULL;
  33. /*
  34. * In this implementation, "virq" == "IRQ plug number",
  35. * "(irq_hw_number_t)hwirq" == "IRQ outlet number".
  36. */
  37. /* assumption: locked */
  38. static inline void beatic_update_irq_mask(unsigned int irq_plug)
  39. {
  40. int off;
  41. unsigned long masks[4];
  42. off = (irq_plug / 256) * 4;
  43. masks[0] = beatic_irq_mask_enable[off + 0]
  44. & beatic_irq_mask_ack[off + 0];
  45. masks[1] = beatic_irq_mask_enable[off + 1]
  46. & beatic_irq_mask_ack[off + 1];
  47. masks[2] = beatic_irq_mask_enable[off + 2]
  48. & beatic_irq_mask_ack[off + 2];
  49. masks[3] = beatic_irq_mask_enable[off + 3]
  50. & beatic_irq_mask_ack[off + 3];
  51. if (beat_set_interrupt_mask(irq_plug&~255UL,
  52. masks[0], masks[1], masks[2], masks[3]) != 0)
  53. panic("Failed to set mask IRQ!");
  54. }
  55. static void beatic_mask_irq(unsigned int irq_plug)
  56. {
  57. unsigned long flags;
  58. spin_lock_irqsave(&beatic_irq_mask_lock, flags);
  59. beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
  60. beatic_update_irq_mask(irq_plug);
  61. spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
  62. }
  63. static void beatic_unmask_irq(unsigned int irq_plug)
  64. {
  65. unsigned long flags;
  66. spin_lock_irqsave(&beatic_irq_mask_lock, flags);
  67. beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
  68. beatic_update_irq_mask(irq_plug);
  69. spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
  70. }
  71. static void beatic_ack_irq(unsigned int irq_plug)
  72. {
  73. unsigned long flags;
  74. spin_lock_irqsave(&beatic_irq_mask_lock, flags);
  75. beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
  76. beatic_update_irq_mask(irq_plug);
  77. spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
  78. }
  79. static void beatic_end_irq(unsigned int irq_plug)
  80. {
  81. s64 err;
  82. unsigned long flags;
  83. if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
  84. if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
  85. panic("Failed to downcount IRQ! Error = %16lx", err);
  86. printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
  87. }
  88. spin_lock_irqsave(&beatic_irq_mask_lock, flags);
  89. beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
  90. beatic_update_irq_mask(irq_plug);
  91. spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
  92. }
  93. static struct irq_chip beatic_pic = {
  94. .typename = " CELL-BEAT ",
  95. .unmask = beatic_unmask_irq,
  96. .mask = beatic_mask_irq,
  97. .eoi = beatic_end_irq,
  98. };
  99. /*
  100. * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq),
  101. * update flags.
  102. *
  103. * Note that the number (virq) is already assigned at upper layer.
  104. */
  105. static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
  106. {
  107. beat_destruct_irq_plug(virq);
  108. }
  109. /*
  110. * Create or update binding hardware IRQ number (hw) and Virtuql
  111. * IRQ number (virq). This is called only once for a given mapping.
  112. *
  113. * Note that the number (virq) is already assigned at upper layer.
  114. */
  115. static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
  116. irq_hw_number_t hw)
  117. {
  118. struct irq_desc *desc = get_irq_desc(virq);
  119. int64_t err;
  120. if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0)
  121. return -EIO;
  122. desc->status |= IRQ_LEVEL;
  123. set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq);
  124. return 0;
  125. }
  126. /*
  127. * Update binding hardware IRQ number (hw) and Virtuql
  128. * IRQ number (virq). This is called only once for a given mapping.
  129. */
  130. static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
  131. irq_hw_number_t hw)
  132. {
  133. beat_construct_and_connect_irq_plug(virq, hw);
  134. }
  135. /*
  136. * Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
  137. * to pass away to irq_create_mapping().
  138. *
  139. * Called from irq_create_of_mapping() only.
  140. * Note: We have only 1 entry to translate.
  141. */
  142. static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
  143. u32 *intspec, unsigned int intsize,
  144. irq_hw_number_t *out_hwirq,
  145. unsigned int *out_flags)
  146. {
  147. u64 *intspec2 = (u64 *)intspec;
  148. *out_hwirq = *intspec2;
  149. *out_flags |= IRQ_TYPE_LEVEL_LOW;
  150. return 0;
  151. }
  152. static struct irq_host_ops beatic_pic_host_ops = {
  153. .map = beatic_pic_host_map,
  154. .remap = beatic_pic_host_remap,
  155. .unmap = beatic_pic_host_unmap,
  156. .xlate = beatic_pic_host_xlate,
  157. };
  158. /*
  159. * Get an IRQ number
  160. * Note: returns VIRQ
  161. */
  162. static inline unsigned int beatic_get_irq_plug(void)
  163. {
  164. int i;
  165. uint64_t pending[4], ub;
  166. for (i = 0; i < MAX_IRQS; i += 256) {
  167. beat_detect_pending_interrupts(i, pending);
  168. __asm__ ("cntlzd %0,%1":"=r"(ub):
  169. "r"(pending[0] & beatic_irq_mask_enable[i/64+0]
  170. & beatic_irq_mask_ack[i/64+0]));
  171. if (ub != 64)
  172. return i + ub + 0;
  173. __asm__ ("cntlzd %0,%1":"=r"(ub):
  174. "r"(pending[1] & beatic_irq_mask_enable[i/64+1]
  175. & beatic_irq_mask_ack[i/64+1]));
  176. if (ub != 64)
  177. return i + ub + 64;
  178. __asm__ ("cntlzd %0,%1":"=r"(ub):
  179. "r"(pending[2] & beatic_irq_mask_enable[i/64+2]
  180. & beatic_irq_mask_ack[i/64+2]));
  181. if (ub != 64)
  182. return i + ub + 128;
  183. __asm__ ("cntlzd %0,%1":"=r"(ub):
  184. "r"(pending[3] & beatic_irq_mask_enable[i/64+3]
  185. & beatic_irq_mask_ack[i/64+3]));
  186. if (ub != 64)
  187. return i + ub + 192;
  188. }
  189. return NO_IRQ;
  190. }
  191. unsigned int beatic_get_irq(void)
  192. {
  193. unsigned int ret;
  194. ret = beatic_get_irq_plug();
  195. if (ret != NO_IRQ)
  196. beatic_ack_irq(ret);
  197. return ret;
  198. }
  199. /*
  200. */
  201. void __init beatic_init_IRQ(void)
  202. {
  203. int i;
  204. memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable));
  205. memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack));
  206. for (i = 0; i < MAX_IRQS; i += 256)
  207. beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L);
  208. /* Set out get_irq function */
  209. ppc_md.get_irq = beatic_get_irq;
  210. /* Allocate an irq host */
  211. beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0,
  212. &beatic_pic_host_ops,
  213. 0);
  214. BUG_ON(beatic_host == NULL);
  215. irq_set_default_host(beatic_host);
  216. }
  217. #ifdef CONFIG_SMP
  218. /* Nullified to compile with SMP mode */
  219. void beatic_setup_cpu(int cpu)
  220. {
  221. }
  222. void beatic_cause_IPI(int cpu, int mesg)
  223. {
  224. }
  225. void beatic_request_IPIs(void)
  226. {
  227. }
  228. #endif /* CONFIG_SMP */
  229. void beatic_deinit_IRQ(void)
  230. {
  231. int i;
  232. for (i = 1; i < NR_IRQS; i++)
  233. beat_destruct_irq_plug(i);
  234. }