• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <loongson.h>
2 #include <irq.h>
3 #include <linux/interrupt.h>
4 #include <linux/module.h>
5 
6 #include <asm/irq_cpu.h>
7 #include <asm/i8259.h>
8 #include <asm/mipsregs.h>
9 
10 #include "smp.h"
11 
12 unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
13 
ht_irqdispatch(void)14 static void ht_irqdispatch(void)
15 {
16 	unsigned int i, irq;
17 
18 	irq = LOONGSON_HT1_INT_VECTOR(0);
19 	LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
20 
21 	for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
22 		if (irq & (0x1 << ht_irq[i]))
23 			do_IRQ(ht_irq[i]);
24 	}
25 }
26 
mach_irq_dispatch(unsigned int pending)27 void mach_irq_dispatch(unsigned int pending)
28 {
29 	if (pending & CAUSEF_IP7)
30 		do_IRQ(LOONGSON_TIMER_IRQ);
31 #if defined(CONFIG_SMP)
32 	else if (pending & CAUSEF_IP6)
33 		loongson3_ipi_interrupt(NULL);
34 #endif
35 	else if (pending & CAUSEF_IP3)
36 		ht_irqdispatch();
37 	else if (pending & CAUSEF_IP2)
38 		do_IRQ(LOONGSON_UART_IRQ);
39 	else {
40 		pr_err("%s : spurious interrupt\n", __func__);
41 		spurious_interrupt();
42 	}
43 }
44 
45 static struct irqaction cascade_irqaction = {
46 	.handler = no_action,
47 	.flags = IRQF_NO_SUSPEND,
48 	.name = "cascade",
49 };
50 
mask_loongson_irq(struct irq_data * d)51 static inline void mask_loongson_irq(struct irq_data *d)
52 {
53 	clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
54 	irq_disable_hazard();
55 
56 	/* Workaround: UART IRQ may deliver to any core */
57 	if (d->irq == LOONGSON_UART_IRQ) {
58 		int cpu = smp_processor_id();
59 		int node_id = cpu / loongson_sysconf.cores_per_node;
60 		int core_id = cpu % loongson_sysconf.cores_per_node;
61 		u64 intenclr_addr = smp_group[node_id] |
62 			(u64)(&LOONGSON_INT_ROUTER_INTENCLR);
63 		u64 introuter_lpc_addr = smp_group[node_id] |
64 			(u64)(&LOONGSON_INT_ROUTER_LPC);
65 
66 		*(volatile u32 *)intenclr_addr = 1 << 10;
67 		*(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
68 	}
69 }
70 
unmask_loongson_irq(struct irq_data * d)71 static inline void unmask_loongson_irq(struct irq_data *d)
72 {
73 	/* Workaround: UART IRQ may deliver to any core */
74 	if (d->irq == LOONGSON_UART_IRQ) {
75 		int cpu = smp_processor_id();
76 		int node_id = cpu / loongson_sysconf.cores_per_node;
77 		int core_id = cpu % loongson_sysconf.cores_per_node;
78 		u64 intenset_addr = smp_group[node_id] |
79 			(u64)(&LOONGSON_INT_ROUTER_INTENSET);
80 		u64 introuter_lpc_addr = smp_group[node_id] |
81 			(u64)(&LOONGSON_INT_ROUTER_LPC);
82 
83 		*(volatile u32 *)intenset_addr = 1 << 10;
84 		*(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
85 	}
86 
87 	set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
88 	irq_enable_hazard();
89 }
90 
91  /* For MIPS IRQs which shared by all cores */
92 static struct irq_chip loongson_irq_chip = {
93 	.name		= "Loongson",
94 	.irq_ack	= mask_loongson_irq,
95 	.irq_mask	= mask_loongson_irq,
96 	.irq_mask_ack	= mask_loongson_irq,
97 	.irq_unmask	= unmask_loongson_irq,
98 	.irq_eoi	= unmask_loongson_irq,
99 };
100 
irq_router_init(void)101 void irq_router_init(void)
102 {
103 	int i;
104 
105 	/* route LPC int to cpu core0 int 0 */
106 	LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0;
107 	/* route HT1 int0 ~ int7 to cpu core0 INT1*/
108 	for (i = 0; i < 8; i++)
109 		LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1;
110 	/* enable HT1 interrupt */
111 	LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
112 	/* enable router interrupt intenset */
113 	LOONGSON_INT_ROUTER_INTENSET =
114 		LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
115 }
116 
mach_init_irq(void)117 void __init mach_init_irq(void)
118 {
119 	clear_c0_status(ST0_IM | ST0_BEV);
120 
121 	irq_router_init();
122 	mips_cpu_irq_init();
123 	init_i8259_irqs();
124 	irq_set_chip_and_handler(LOONGSON_UART_IRQ,
125 			&loongson_irq_chip, handle_level_irq);
126 
127 	/* setup HT1 irq */
128 	setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
129 
130 	set_c0_status(STATUSF_IP2 | STATUSF_IP6);
131 }
132 
133 #ifdef CONFIG_HOTPLUG_CPU
134 
fixup_irqs(void)135 void fixup_irqs(void)
136 {
137 	irq_cpu_offline();
138 	clear_c0_status(ST0_IM);
139 }
140 
141 #endif
142