irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 2000, 2001 Broadcom Corporation
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  */
  18. #include <linux/config.h>
  19. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/linkage.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/spinlock.h>
  24. #include <linux/mm.h>
  25. #include <linux/slab.h>
  26. #include <asm/errno.h>
  27. #include <asm/signal.h>
  28. #include <asm/system.h>
  29. #include <asm/ptrace.h>
  30. #include <asm/sibyte/sb1250_regs.h>
  31. #include <asm/sibyte/sb1250_int.h>
  32. #include <asm/sibyte/sb1250_uart.h>
  33. #include <asm/sibyte/sb1250_scd.h>
  34. #include <asm/sibyte/sb1250.h>
  35. #include <asm/sibyte/64bit.h>
  36. /*
  37.  * These are the routines that handle all the low level interrupt stuff.
  38.  * Actions handled here are: initialization of the interrupt map, requesting of
  39.  * interrupt lines by handlers, dispatching if interrupts to handlers, probing
  40.  * for interrupt lines
  41.  */
  42. #define shutdown_sb1250_irq disable_sb1250_irq
  43. static void end_sb1250_irq(unsigned int irq);
  44. static void enable_sb1250_irq(unsigned int irq);
  45. static void disable_sb1250_irq(unsigned int irq);
  46. static unsigned int startup_sb1250_irq(unsigned int irq);
  47. static void ack_sb1250_irq(unsigned int irq);
  48. #ifdef CONFIG_REMOTE_DEBUG
  49. extern void breakpoint(void);
  50. extern void set_debug_traps(void);
  51. /* kgdb is on when configured.  Pass "nokgdb" kernel arg to turn it off */
  52. static int kgdb_flag = 1;
  53. static int __init nokgdb(char *str)
  54. {
  55. kgdb_flag = 0;
  56. }
  57. __setup("nokgdb", nokgdb);
  58. #endif
  59. #define NR_IRQS 64
  60. static struct hw_interrupt_type sb1250_irq_type = {
  61. "SB1250-IMR",
  62. startup_sb1250_irq,
  63. shutdown_sb1250_irq,
  64. enable_sb1250_irq,
  65. disable_sb1250_irq,
  66. ack_sb1250_irq,
  67. end_sb1250_irq,
  68. NULL
  69. };
  70. spinlock_t sb1250_imr_lock = SPIN_LOCK_UNLOCKED;
  71. void sb1250_mask_irq(int cpu, int irq)
  72. {
  73. unsigned long flags;
  74. u64 cur_ints;
  75. spin_lock_irqsave(&sb1250_imr_lock, flags);
  76. cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);
  77. cur_ints |= (((u64) 1) << irq);
  78. out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);
  79. spin_unlock_irqrestore(&sb1250_imr_lock, flags);
  80. }
  81. void sb1250_unmask_irq(int cpu, int irq)
  82. {
  83. unsigned long flags;
  84. u64 cur_ints;
  85. spin_lock_irqsave(&sb1250_imr_lock, flags);
  86. cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);
  87. cur_ints &= ~(((u64) 1) << irq);
  88. out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);
  89. spin_unlock_irqrestore(&sb1250_imr_lock, flags);
  90. }
  91. /* Defined in arch/mips/sibyte/sb1250/irq_handler.S */
  92. extern void sb1250_irq_handler(void);
  93. /*****************************************************************************/
  94. static unsigned int startup_sb1250_irq(unsigned int irq)
  95. {
  96. sb1250_unmask_irq(0, irq);
  97. return 0; /* never anything pending */
  98. }
  99. static void disable_sb1250_irq(unsigned int irq)
  100. {
  101. sb1250_mask_irq(0, irq);
  102. }
  103. static void enable_sb1250_irq(unsigned int irq)
  104. {
  105. sb1250_unmask_irq(0, irq);
  106. }
  107. static void ack_sb1250_irq(unsigned int irq)
  108. {
  109. u64 pending;
  110. /*
  111.  * If the interrupt was an LDT interrupt, now is the time
  112.  * to clear it.
  113.  */
  114. pending = in64(KSEG1 + A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT));
  115. pending &= ((u64)1 << (irq));
  116. if (pending)
  117. out64(pending, KSEG1+A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT_CLR));
  118. sb1250_mask_irq(0, irq);
  119. }
  120. static void end_sb1250_irq(unsigned int irq)
  121. {
  122. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
  123. sb1250_unmask_irq(0, irq);
  124. }
  125. }
  126. void __init init_sb1250_irqs(void)
  127. {
  128. int i;
  129. for (i = 0; i < NR_IRQS; i++) {
  130. irq_desc[i].status = IRQ_DISABLED;
  131. irq_desc[i].action = 0;
  132. irq_desc[i].depth = 1;
  133. irq_desc[i].handler = &sb1250_irq_type;
  134. }
  135. }
  136. static void sb1250_dummy_handler(int irq, void *dev_id, struct pt_regs *regs)
  137. {
  138. }
  139. static struct irqaction sb1250_dummy_action = {
  140. handler: sb1250_dummy_handler,
  141. flags:   0,
  142. mask:    0,
  143. name:    "sb1250-private",
  144. next:    NULL,
  145. dev_id:  0
  146. };
  147. int sb1250_steal_irq(int irq)
  148. {
  149. irq_desc_t *desc = irq_desc + irq;
  150. unsigned long flags;
  151. int retval = 0;
  152. if (irq >= NR_IRQS)
  153. return -EINVAL;
  154. spin_lock_irqsave(&desc->lock,flags);
  155. /* Don't allow sharing at all for these */
  156. if (desc->action != NULL)
  157. retval = -EBUSY;
  158. else {
  159. desc->action = &sb1250_dummy_action;
  160. desc->depth = 0;
  161. }
  162. spin_unlock_irqrestore(&desc->lock,flags);
  163. }
  164. /*
  165.  *  init_IRQ is called early in the boot sequence from init/main.c.  It
  166.  *  is responsible for setting up the interrupt mapper and installing the
  167.  *  handler that will be responsible for dispatching interrupts to the
  168.  *  "right" place.
  169.  */
  170. /*
  171.  * For now, map all interrupts to IP[2].  We could save
  172.  * some cycles by parceling out system interrupts to different
  173.  * IP lines, but keep it simple for bringup.  We'll also direct
  174.  * all interrupts to a single CPU; we should probably route
  175.  * PCI and LDT to one cpu and everything else to the other
  176.  * to balance the load a bit.
  177.  *
  178.  * On the second cpu, everything is set to IP5, which is
  179.  * ignored, EXCEPT the mailbox interrupt.  That one is
  180.  * set to IP[2] so it is handled.  This is needed so we
  181.  * can do cross-cpu function calls, as requred by SMP
  182.  */
  183. #define IMR_IP2_VAL K_INT_MAP_I0
  184. #define IMR_IP3_VAL K_INT_MAP_I1
  185. #define IMR_IP4_VAL K_INT_MAP_I2
  186. #define IMR_IP5_VAL K_INT_MAP_I3
  187. #define IMR_IP6_VAL K_INT_MAP_I4
  188. void __init init_IRQ(void)
  189. {
  190. unsigned int i;
  191. u64 tmp;
  192. unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
  193. STATUSF_IP1 | STATUSF_IP0;
  194. /* Default everything to IP2 */
  195. for (i = 0; i < NR_IRQS; i++) { /* was I0 */
  196. out64(IMR_IP2_VAL,
  197.       KSEG1 + A_IMR_REGISTER(0,
  198.      R_IMR_INTERRUPT_MAP_BASE) +
  199.       (i << 3));
  200. out64(IMR_IP2_VAL,
  201.       KSEG1 + A_IMR_REGISTER(1,
  202.      R_IMR_INTERRUPT_MAP_BASE) +
  203.       (i << 3));
  204. }
  205. init_sb1250_irqs();
  206. /*
  207.  * Map the high 16 bits of the mailbox registers to IP[3], for
  208.  * inter-cpu messages
  209.  */
  210. /* Was I1 */
  211. out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
  212.                    (K_INT_MBOX_0 << 3));
  213. out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MAP_BASE) +
  214.                    (K_INT_MBOX_0 << 3));
  215. /* Clear the mailboxes.  The firmware may leave them dirty */
  216. out64(0xffffffffffffffff,
  217.       KSEG1 + A_IMR_REGISTER(0, R_IMR_MAILBOX_CLR_CPU));
  218. out64(0xffffffffffffffff,
  219.       KSEG1 + A_IMR_REGISTER(1, R_IMR_MAILBOX_CLR_CPU));
  220. /* Mask everything except the mailbox registers for both cpus */
  221. tmp = ~((u64) 0) ^ (((u64) 1) << K_INT_MBOX_0);
  222. out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
  223. out64(tmp, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK));
  224. sb1250_steal_irq(K_INT_MBOX_0);
  225. /*
  226.  * Note that the timer interrupts are also mapped, but this is
  227.  * done in sb1250_time_init()
  228.  */
  229. #ifdef CONFIG_BCM1250_PROF
  230. imask |= STATUSF_IP7;
  231. #endif
  232. #ifdef CONFIG_REMOTE_DEBUG
  233. imask |= STATUSF_IP6;
  234. #endif
  235. /* Enable necessary IPs, disable the rest */
  236. change_cp0_status(ST0_IM, imask);
  237. set_except_vector(0, sb1250_irq_handler);
  238. #ifdef CONFIG_REMOTE_DEBUG
  239. if (kgdb_flag) {
  240. /* Setup uart 1 settings, mapper */
  241. out64(M_DUART_IMR_BRK, KSEG1 + A_DUART + R_DUART_IMR_B);
  242. out64(IMR_IP6_VAL,
  243. KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_UART_1<<3));
  244. tmp = in64(KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
  245. tmp &= ~(1<<K_INT_UART_1);
  246. out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
  247. set_debug_traps();
  248. breakpoint();
  249. }
  250. #endif
  251. }
  252. #ifdef CONFIG_REMOTE_DEBUG
  253. #include <linux/delay.h>
  254. extern void set_async_breakpoint(unsigned int epc);
  255. #define duart_out(reg, val)     out64(val, KSEG1 + A_DUART_CHANREG(1,reg))
  256. #define duart_in(reg)           in64(KSEG1 + A_DUART_CHANREG(1,reg))
  257. void sb1250_kgdb_interrupt(struct pt_regs *regs)
  258. {
  259. /*
  260.  * Clear break-change status (allow some time for the remote
  261.  * host to stop the break, since we would see another
  262.  * interrupt on the end-of-break too)
  263.  */
  264. mdelay(500);
  265. duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
  266. M_DUART_RX_EN | M_DUART_TX_EN);
  267. if (!user_mode(regs))
  268. set_async_breakpoint(regs->cp0_epc);
  269. }
  270. #endif  /* CONFIG_REMOTE_DEBUG */