.. | .. |
---|
26 | 26 | #include <asm/lowcore.h> |
---|
27 | 27 | #include <asm/irq.h> |
---|
28 | 28 | #include <asm/hw_irq.h> |
---|
| 29 | +#include <asm/stacktrace.h> |
---|
29 | 30 | #include "entry.h" |
---|
30 | 31 | |
---|
31 | 32 | DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); |
---|
.. | .. |
---|
73 | 74 | {.irq = IRQEXT_CMC, .name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, |
---|
74 | 75 | {.irq = IRQEXT_FTP, .name = "FTP", .desc = "[EXT] HMC FTP Service"}, |
---|
75 | 76 | {.irq = IRQIO_CIO, .name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, |
---|
76 | | - {.irq = IRQIO_QAI, .name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, |
---|
77 | 77 | {.irq = IRQIO_DAS, .name = "DAS", .desc = "[I/O] DASD"}, |
---|
78 | 78 | {.irq = IRQIO_C15, .name = "C15", .desc = "[I/O] 3215"}, |
---|
79 | 79 | {.irq = IRQIO_C70, .name = "C70", .desc = "[I/O] 3270"}, |
---|
.. | .. |
---|
81 | 81 | {.irq = IRQIO_VMR, .name = "VMR", .desc = "[I/O] Unit Record Devices"}, |
---|
82 | 82 | {.irq = IRQIO_LCS, .name = "LCS", .desc = "[I/O] LCS"}, |
---|
83 | 83 | {.irq = IRQIO_CTC, .name = "CTC", .desc = "[I/O] CTC"}, |
---|
84 | | - {.irq = IRQIO_APB, .name = "APB", .desc = "[I/O] AP Bus"}, |
---|
85 | 84 | {.irq = IRQIO_ADM, .name = "ADM", .desc = "[I/O] EADM Subchannel"}, |
---|
86 | 85 | {.irq = IRQIO_CSC, .name = "CSC", .desc = "[I/O] CHSC Subchannel"}, |
---|
87 | | - {.irq = IRQIO_PCI, .name = "PCI", .desc = "[I/O] PCI Interrupt" }, |
---|
88 | | - {.irq = IRQIO_MSI, .name = "MSI", .desc = "[I/O] MSI Interrupt" }, |
---|
89 | 86 | {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, |
---|
90 | | - {.irq = IRQIO_VAI, .name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"}, |
---|
| 87 | + {.irq = IRQIO_QAI, .name = "QAI", .desc = "[AIO] QDIO Adapter Interrupt"}, |
---|
| 88 | + {.irq = IRQIO_APB, .name = "APB", .desc = "[AIO] AP Bus"}, |
---|
| 89 | + {.irq = IRQIO_PCF, .name = "PCF", .desc = "[AIO] PCI Floating Interrupt"}, |
---|
| 90 | + {.irq = IRQIO_PCD, .name = "PCD", .desc = "[AIO] PCI Directed Interrupt"}, |
---|
| 91 | + {.irq = IRQIO_MSI, .name = "MSI", .desc = "[AIO] MSI Interrupt"}, |
---|
| 92 | + {.irq = IRQIO_VAI, .name = "VAI", .desc = "[AIO] Virtual I/O Devices AI"}, |
---|
| 93 | + {.irq = IRQIO_GAL, .name = "GAL", .desc = "[AIO] GIB Alert"}, |
---|
91 | 94 | {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"}, |
---|
92 | 95 | {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"}, |
---|
93 | 96 | }; |
---|
94 | | - |
---|
95 | | -void __init init_IRQ(void) |
---|
96 | | -{ |
---|
97 | | - BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS); |
---|
98 | | - init_cio_interrupts(); |
---|
99 | | - init_airq_interrupts(); |
---|
100 | | - init_ext_interrupts(); |
---|
101 | | -} |
---|
102 | 97 | |
---|
103 | 98 | void do_IRQ(struct pt_regs *regs, int irq) |
---|
104 | 99 | { |
---|
.. | .. |
---|
115 | 110 | set_irq_regs(old_regs); |
---|
116 | 111 | } |
---|
117 | 112 | |
---|
| 113 | +static void show_msi_interrupt(struct seq_file *p, int irq) |
---|
| 114 | +{ |
---|
| 115 | + struct irq_desc *desc; |
---|
| 116 | + unsigned long flags; |
---|
| 117 | + int cpu; |
---|
| 118 | + |
---|
| 119 | + irq_lock_sparse(); |
---|
| 120 | + desc = irq_to_desc(irq); |
---|
| 121 | + if (!desc) |
---|
| 122 | + goto out; |
---|
| 123 | + |
---|
| 124 | + raw_spin_lock_irqsave(&desc->lock, flags); |
---|
| 125 | + seq_printf(p, "%3d: ", irq); |
---|
| 126 | + for_each_online_cpu(cpu) |
---|
| 127 | + seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu)); |
---|
| 128 | + |
---|
| 129 | + if (desc->irq_data.chip) |
---|
| 130 | + seq_printf(p, " %8s", desc->irq_data.chip->name); |
---|
| 131 | + |
---|
| 132 | + if (desc->action) |
---|
| 133 | + seq_printf(p, " %s", desc->action->name); |
---|
| 134 | + |
---|
| 135 | + seq_putc(p, '\n'); |
---|
| 136 | + raw_spin_unlock_irqrestore(&desc->lock, flags); |
---|
| 137 | +out: |
---|
| 138 | + irq_unlock_sparse(); |
---|
| 139 | +} |
---|
| 140 | + |
---|
118 | 141 | /* |
---|
119 | 142 | * show_interrupts is needed by /proc/interrupts. |
---|
120 | 143 | */ |
---|
.. | .. |
---|
127 | 150 | if (index == 0) { |
---|
128 | 151 | seq_puts(p, " "); |
---|
129 | 152 | for_each_online_cpu(cpu) |
---|
130 | | - seq_printf(p, "CPU%d ", cpu); |
---|
| 153 | + seq_printf(p, "CPU%-8d", cpu); |
---|
131 | 154 | seq_putc(p, '\n'); |
---|
132 | 155 | } |
---|
133 | 156 | if (index < NR_IRQS_BASE) { |
---|
.. | .. |
---|
138 | 161 | seq_putc(p, '\n'); |
---|
139 | 162 | goto out; |
---|
140 | 163 | } |
---|
141 | | - if (index > NR_IRQS_BASE) |
---|
| 164 | + if (index < nr_irqs) { |
---|
| 165 | + show_msi_interrupt(p, index); |
---|
142 | 166 | goto out; |
---|
143 | | - |
---|
| 167 | + } |
---|
144 | 168 | for (index = 0; index < NR_ARCH_IRQS; index++) { |
---|
145 | 169 | seq_printf(p, "%s: ", irqclass_sub_desc[index].name); |
---|
146 | 170 | irq = irqclass_sub_desc[index].irq; |
---|
.. | .. |
---|
172 | 196 | /* Check against async. stack address range. */ |
---|
173 | 197 | new = S390_lowcore.async_stack; |
---|
174 | 198 | if (((new - old) >> (PAGE_SHIFT + THREAD_SIZE_ORDER)) != 0) { |
---|
175 | | - /* Need to switch to the async. stack. */ |
---|
176 | | - new -= STACK_FRAME_OVERHEAD; |
---|
177 | | - ((struct stack_frame *) new)->back_chain = old; |
---|
178 | | - asm volatile(" la 15,0(%0)\n" |
---|
179 | | - " brasl 14,__do_softirq\n" |
---|
180 | | - " la 15,0(%1)\n" |
---|
181 | | - : : "a" (new), "a" (old) |
---|
182 | | - : "0", "1", "2", "3", "4", "5", "14", |
---|
183 | | - "cc", "memory" ); |
---|
| 199 | + CALL_ON_STACK(__do_softirq, new, 0); |
---|
184 | 200 | } else { |
---|
185 | 201 | /* We are already on the async stack. */ |
---|
186 | 202 | __do_softirq(); |
---|
.. | .. |
---|
270 | 286 | return IRQ_HANDLED; |
---|
271 | 287 | } |
---|
272 | 288 | |
---|
273 | | -static struct irqaction external_interrupt = { |
---|
274 | | - .name = "EXT", |
---|
275 | | - .handler = do_ext_interrupt, |
---|
276 | | -}; |
---|
277 | | - |
---|
278 | | -void __init init_ext_interrupts(void) |
---|
| 289 | +static void __init init_ext_interrupts(void) |
---|
279 | 290 | { |
---|
280 | 291 | int idx; |
---|
281 | 292 | |
---|
.. | .. |
---|
284 | 295 | |
---|
285 | 296 | irq_set_chip_and_handler(EXT_INTERRUPT, |
---|
286 | 297 | &dummy_irq_chip, handle_percpu_irq); |
---|
287 | | - setup_irq(EXT_INTERRUPT, &external_interrupt); |
---|
| 298 | + if (request_irq(EXT_INTERRUPT, do_ext_interrupt, 0, "EXT", NULL)) |
---|
| 299 | + panic("Failed to register EXT interrupt\n"); |
---|
| 300 | +} |
---|
| 301 | + |
---|
| 302 | +void __init init_IRQ(void) |
---|
| 303 | +{ |
---|
| 304 | + BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS); |
---|
| 305 | + init_cio_interrupts(); |
---|
| 306 | + init_airq_interrupts(); |
---|
| 307 | + init_ext_interrupts(); |
---|
288 | 308 | } |
---|
289 | 309 | |
---|
290 | 310 | static DEFINE_SPINLOCK(irq_subclass_lock); |
---|