malta-int.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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. * Carsten Langgaard, carstenl@mips.com
  7. * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
  8. * Copyright (C) 2001 Ralf Baechle
  9. * Copyright (C) 2013 Imagination Technologies Ltd.
  10. *
  11. * Routines for generic manipulation of the interrupts found on the MIPS
  12. * Malta board. The interrupt controller is located in the South Bridge
  13. * a PIIX4 device with two internal 82C95 interrupt controllers.
  14. */
  15. #include <linux/init.h>
  16. #include <linux/irq.h>
  17. #include <linux/irqchip.h>
  18. #include <linux/sched.h>
  19. #include <linux/smp.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/io.h>
  22. #include <linux/irqchip/mips-gic.h>
  23. #include <linux/of_irq.h>
  24. #include <linux/kernel_stat.h>
  25. #include <linux/kernel.h>
  26. #include <linux/random.h>
  27. #include <asm/traps.h>
  28. #include <asm/i8259.h>
  29. #include <asm/irq_cpu.h>
  30. #include <asm/irq_regs.h>
  31. #include <asm/mips-cm.h>
  32. #include <asm/mips-boards/malta.h>
  33. #include <asm/mips-boards/maltaint.h>
  34. #include <asm/gt64120.h>
  35. #include <asm/mips-boards/generic.h>
  36. #include <asm/mips-boards/msc01_pci.h>
  37. #include <asm/msc01_ic.h>
  38. #include <asm/setup.h>
  39. #include <asm/rtlx.h>
  40. static inline int mips_pcibios_iack(void)
  41. {
  42. int irq;
  43. /*
  44. * Determine highest priority pending interrupt by performing
  45. * a PCI Interrupt Acknowledge cycle.
  46. */
  47. switch (mips_revision_sconid) {
  48. case MIPS_REVISION_SCON_SOCIT:
  49. case MIPS_REVISION_SCON_ROCIT:
  50. case MIPS_REVISION_SCON_SOCITSC:
  51. case MIPS_REVISION_SCON_SOCITSCP:
  52. MSC_READ(MSC01_PCI_IACK, irq);
  53. irq &= 0xff;
  54. break;
  55. case MIPS_REVISION_SCON_GT64120:
  56. irq = GT_READ(GT_PCI0_IACK_OFS);
  57. irq &= 0xff;
  58. break;
  59. case MIPS_REVISION_SCON_BONITO:
  60. /* The following will generate a PCI IACK cycle on the
  61. * Bonito controller. It's a little bit kludgy, but it
  62. * was the easiest way to implement it in hardware at
  63. * the given time.
  64. */
  65. BONITO_PCIMAP_CFG = 0x20000;
  66. /* Flush Bonito register block */
  67. (void) BONITO_PCIMAP_CFG;
  68. iob(); /* sync */
  69. irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg);
  70. iob(); /* sync */
  71. irq &= 0xff;
  72. BONITO_PCIMAP_CFG = 0;
  73. break;
  74. default:
  75. pr_emerg("Unknown system controller.\n");
  76. return -1;
  77. }
  78. return irq;
  79. }
  80. static void corehi_irqdispatch(void)
  81. {
  82. unsigned int intedge, intsteer, pcicmd, pcibadaddr;
  83. unsigned int pcimstat, intisr, inten, intpol;
  84. unsigned int intrcause, datalo, datahi;
  85. struct pt_regs *regs = get_irq_regs();
  86. pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n");
  87. pr_emerg("epc : %08lx\nStatus: %08lx\n"
  88. "Cause : %08lx\nbadVaddr : %08lx\n",
  89. regs->cp0_epc, regs->cp0_status,
  90. regs->cp0_cause, regs->cp0_badvaddr);
  91. /* Read all the registers and then print them as there is a
  92. problem with interspersed printk's upsetting the Bonito controller.
  93. Do it for the others too.
  94. */
  95. switch (mips_revision_sconid) {
  96. case MIPS_REVISION_SCON_SOCIT:
  97. case MIPS_REVISION_SCON_ROCIT:
  98. case MIPS_REVISION_SCON_SOCITSC:
  99. case MIPS_REVISION_SCON_SOCITSCP:
  100. ll_msc_irq();
  101. break;
  102. case MIPS_REVISION_SCON_GT64120:
  103. intrcause = GT_READ(GT_INTRCAUSE_OFS);
  104. datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
  105. datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
  106. pr_emerg("GT_INTRCAUSE = %08x\n", intrcause);
  107. pr_emerg("GT_CPUERR_ADDR = %02x%08x\n",
  108. datahi, datalo);
  109. break;
  110. case MIPS_REVISION_SCON_BONITO:
  111. pcibadaddr = BONITO_PCIBADADDR;
  112. pcimstat = BONITO_PCIMSTAT;
  113. intisr = BONITO_INTISR;
  114. inten = BONITO_INTEN;
  115. intpol = BONITO_INTPOL;
  116. intedge = BONITO_INTEDGE;
  117. intsteer = BONITO_INTSTEER;
  118. pcicmd = BONITO_PCICMD;
  119. pr_emerg("BONITO_INTISR = %08x\n", intisr);
  120. pr_emerg("BONITO_INTEN = %08x\n", inten);
  121. pr_emerg("BONITO_INTPOL = %08x\n", intpol);
  122. pr_emerg("BONITO_INTEDGE = %08x\n", intedge);
  123. pr_emerg("BONITO_INTSTEER = %08x\n", intsteer);
  124. pr_emerg("BONITO_PCICMD = %08x\n", pcicmd);
  125. pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr);
  126. pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat);
  127. break;
  128. }
  129. die("CoreHi interrupt", regs);
  130. }
  131. static irqreturn_t corehi_handler(int irq, void *dev_id)
  132. {
  133. corehi_irqdispatch();
  134. return IRQ_HANDLED;
  135. }
  136. #ifdef CONFIG_MIPS_MT_SMP
  137. #define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
  138. #define C_RESCHED C_SW0
  139. #define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
  140. #define C_CALL C_SW1
  141. static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
  142. static void ipi_resched_dispatch(void)
  143. {
  144. do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
  145. }
  146. static void ipi_call_dispatch(void)
  147. {
  148. do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
  149. }
  150. static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
  151. {
  152. #ifdef CONFIG_MIPS_VPE_APSP_API_CMP
  153. if (aprp_hook)
  154. aprp_hook();
  155. #endif
  156. scheduler_ipi();
  157. return IRQ_HANDLED;
  158. }
  159. static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
  160. {
  161. generic_smp_call_function_interrupt();
  162. return IRQ_HANDLED;
  163. }
  164. static struct irqaction irq_resched = {
  165. .handler = ipi_resched_interrupt,
  166. .flags = IRQF_PERCPU,
  167. .name = "IPI_resched"
  168. };
  169. static struct irqaction irq_call = {
  170. .handler = ipi_call_interrupt,
  171. .flags = IRQF_PERCPU,
  172. .name = "IPI_call"
  173. };
  174. #endif /* CONFIG_MIPS_MT_SMP */
  175. static struct irqaction corehi_irqaction = {
  176. .handler = corehi_handler,
  177. .name = "CoreHi",
  178. .flags = IRQF_NO_THREAD,
  179. };
  180. static msc_irqmap_t msc_irqmap[] __initdata = {
  181. {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
  182. {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
  183. };
  184. static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap);
  185. static msc_irqmap_t msc_eicirqmap[] __initdata = {
  186. {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
  187. {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
  188. {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0},
  189. {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0},
  190. {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0},
  191. {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0},
  192. {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
  193. {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
  194. {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
  195. {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
  196. };
  197. static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
  198. void __init arch_init_ipiirq(int irq, struct irqaction *action)
  199. {
  200. setup_irq(irq, action);
  201. irq_set_handler(irq, handle_percpu_irq);
  202. }
  203. void __init arch_init_irq(void)
  204. {
  205. int corehi_irq;
  206. i8259_set_poll(mips_pcibios_iack);
  207. irqchip_init();
  208. switch (mips_revision_sconid) {
  209. case MIPS_REVISION_SCON_SOCIT:
  210. case MIPS_REVISION_SCON_ROCIT:
  211. if (cpu_has_veic)
  212. init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
  213. MSC01E_INT_BASE, msc_eicirqmap,
  214. msc_nr_eicirqs);
  215. else
  216. init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
  217. MSC01C_INT_BASE, msc_irqmap,
  218. msc_nr_irqs);
  219. break;
  220. case MIPS_REVISION_SCON_SOCITSC:
  221. case MIPS_REVISION_SCON_SOCITSCP:
  222. if (cpu_has_veic)
  223. init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
  224. MSC01E_INT_BASE, msc_eicirqmap,
  225. msc_nr_eicirqs);
  226. else
  227. init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
  228. MSC01C_INT_BASE, msc_irqmap,
  229. msc_nr_irqs);
  230. }
  231. if (gic_present) {
  232. corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
  233. } else {
  234. #if defined(CONFIG_MIPS_MT_SMP)
  235. /* set up ipi interrupts */
  236. if (cpu_has_veic) {
  237. set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch);
  238. set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch);
  239. cpu_ipi_resched_irq = MSC01E_INT_SW0;
  240. cpu_ipi_call_irq = MSC01E_INT_SW1;
  241. } else {
  242. cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE +
  243. MIPS_CPU_IPI_RESCHED_IRQ;
  244. cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE +
  245. MIPS_CPU_IPI_CALL_IRQ;
  246. }
  247. arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched);
  248. arch_init_ipiirq(cpu_ipi_call_irq, &irq_call);
  249. #endif
  250. if (cpu_has_veic) {
  251. set_vi_handler(MSC01E_INT_COREHI,
  252. corehi_irqdispatch);
  253. corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
  254. } else {
  255. corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
  256. }
  257. }
  258. setup_irq(corehi_irq, &corehi_irqaction);
  259. }