| .. | .. |
|---|
| 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); |
|---|