diff options
Diffstat (limited to 'arch/s390/kernel/irq.c')
| -rw-r--r-- | arch/s390/kernel/irq.c | 124 | 
1 files changed, 75 insertions, 49 deletions
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index bf24293970c..9df824ea166 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -24,43 +24,65 @@  #include <asm/irq.h>  #include "entry.h" +DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); +EXPORT_PER_CPU_SYMBOL_GPL(irq_stat); +  struct irq_class {  	char *name;  	char *desc;  }; -static const struct irq_class intrclass_names[] = { +/* + * The list of "main" irq classes on s390. This is the list of interrrupts + * that appear both in /proc/stat ("intr" line) and /proc/interrupts. + * Historically only external and I/O interrupts have been part of /proc/stat. + * We can't add the split external and I/O sub classes since the first field + * in the "intr" line in /proc/stat is supposed to be the sum of all other + * fields. + * Since the external and I/O interrupt fields are already sums we would end + * up with having a sum which accounts each interrupt twice. + */ +static const struct irq_class irqclass_main_desc[NR_IRQS] = {  	[EXTERNAL_INTERRUPT] = {.name = "EXT"}, -	[IO_INTERRUPT]	     = {.name = "I/O"}, -	[EXTINT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, -	[EXTINT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, -	[EXTINT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, -	[EXTINT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, -	[EXTINT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, -	[EXTINT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, -	[EXTINT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, -	[EXTINT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, -	[EXTINT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, -	[EXTINT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, -	[EXTINT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, -	[EXTINT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, -	[EXTINT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, -	[IOINT_CIO]  = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, -	[IOINT_QAI]  = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, -	[IOINT_DAS]  = {.name = "DAS", .desc = "[I/O] DASD"}, -	[IOINT_C15]  = {.name = "C15", .desc = "[I/O] 3215"}, -	[IOINT_C70]  = {.name = "C70", .desc = "[I/O] 3270"}, -	[IOINT_TAP]  = {.name = "TAP", .desc = "[I/O] Tape"}, -	[IOINT_VMR]  = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, -	[IOINT_LCS]  = {.name = "LCS", .desc = "[I/O] LCS"}, -	[IOINT_CLW]  = {.name = "CLW", .desc = "[I/O] CLAW"}, -	[IOINT_CTC]  = {.name = "CTC", .desc = "[I/O] CTC"}, -	[IOINT_APB]  = {.name = "APB", .desc = "[I/O] AP Bus"}, -	[IOINT_ADM]  = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, -	[IOINT_CSC]  = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, -	[IOINT_PCI]  = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, -	[IOINT_MSI] =  {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, +	[IO_INTERRUPT]	     = {.name = "I/O"} +}; + +/* + * The list of split external and I/O interrupts that appear only in + * /proc/interrupts. + * In addition this list contains non external / I/O events like NMIs. + */ +static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { +	[IRQEXT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, +	[IRQEXT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, +	[IRQEXT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, +	[IRQEXT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, +	[IRQEXT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, +	[IRQEXT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, +	[IRQEXT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, +	[IRQEXT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, +	[IRQEXT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, +	[IRQEXT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, +	[IRQEXT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, +	[IRQEXT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, +	[IRQEXT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, +	[IRQIO_CIO]  = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, +	[IRQIO_QAI]  = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, +	[IRQIO_DAS]  = {.name = "DAS", .desc = "[I/O] DASD"}, +	[IRQIO_C15]  = {.name = "C15", .desc = "[I/O] 3215"}, +	[IRQIO_C70]  = {.name = "C70", .desc = "[I/O] 3270"}, +	[IRQIO_TAP]  = {.name = "TAP", .desc = "[I/O] Tape"}, +	[IRQIO_VMR]  = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, +	[IRQIO_LCS]  = {.name = "LCS", .desc = "[I/O] LCS"}, +	[IRQIO_CLW]  = {.name = "CLW", .desc = "[I/O] CLAW"}, +	[IRQIO_CTC]  = {.name = "CTC", .desc = "[I/O] CTC"}, +	[IRQIO_APB]  = {.name = "APB", .desc = "[I/O] AP Bus"}, +	[IRQIO_ADM]  = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, +	[IRQIO_CSC]  = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, +	[IRQIO_PCI]  = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, +	[IRQIO_MSI]  = {.name = "MSI", .desc = "[I/O] MSI Interrupt" },  	[NMI_NMI]    = {.name = "NMI", .desc = "[NMI] Machine Check"}, +	[CPU_RST]    = {.name = "RST", .desc = "[CPU] CPU Restart"},  };  /* @@ -68,30 +90,34 @@ static const struct irq_class intrclass_names[] = {   */  int show_interrupts(struct seq_file *p, void *v)  { -	int i = *(loff_t *) v, j; +	int irq = *(loff_t *) v; +	int cpu;  	get_online_cpus(); -	if (i == 0) { +	if (irq == 0) {  		seq_puts(p, "           "); -		for_each_online_cpu(j) -			seq_printf(p, "CPU%d       ",j); +		for_each_online_cpu(cpu) +			seq_printf(p, "CPU%d       ", cpu);  		seq_putc(p, '\n');  	} - -	if (i < NR_IRQS) { -		seq_printf(p, "%s: ", intrclass_names[i].name); -#ifndef CONFIG_SMP -		seq_printf(p, "%10u ", kstat_irqs(i)); -#else -		for_each_online_cpu(j) -			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif -		if (intrclass_names[i].desc) -			seq_printf(p, "  %s", intrclass_names[i].desc); -                seq_putc(p, '\n'); -        } +	if (irq < NR_IRQS) { +		seq_printf(p, "%s: ", irqclass_main_desc[irq].name); +		for_each_online_cpu(cpu) +			seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[irq]); +		seq_putc(p, '\n'); +		goto skip_arch_irqs; +	} +	for (irq = 0; irq < NR_ARCH_IRQS; irq++) { +		seq_printf(p, "%s: ", irqclass_sub_desc[irq].name); +		for_each_online_cpu(cpu) +			seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).irqs[irq]); +		if (irqclass_sub_desc[irq].desc) +			seq_printf(p, "  %s", irqclass_sub_desc[irq].desc); +		seq_putc(p, '\n'); +	} +skip_arch_irqs:  	put_online_cpus(); -        return 0; +	return 0;  }  /* @@ -222,7 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,  		/* Serve timer interrupts first. */  		clock_comparator_work();  	} -	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; +	kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);  	if (ext_code.code != 0x1004)  		__get_cpu_var(s390_idle).nohz_delay = 1;  |