diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2011-10-30 10:16:04 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-10-30 10:16:15 -0400 |
commit | de400d6b78d15a73023485f050bc6b1709dc7a79 (patch) | |
tree | 2d2e7233a76982db4cf12ff0859054a33e46a911 /drivers/s390/cio | |
parent | ce949717b559709423c1ef716a9db16d1dcadaed (diff) |
[S390] fix mismatch in summation of I/O IRQ statistics
Current IRQ statistics support does not show detail counts for I/O
interrupts which are processed internally only. The result is a
summation count which is way off such as this one:
CPU0 CPU1 CPU2
I/O: 1331 710 442
[...]
QAI: 15 16 16 [I/O] QDIO Adapter Interrupt
QDI: 1 0 0 [I/O] QDIO Interrupt
DAS: 706 645 381 [I/O] DASD
C15: 26 10 0 [I/O] 3215
C70: 0 0 0 [I/O] 3270
TAP: 0 0 0 [I/O] Tape
VMR: 0 0 0 [I/O] Unit Record Devices
LCS: 0 0 0 [I/O] LCS
CLW: 0 0 0 [I/O] CLAW
CTC: 0 0 0 [I/O] CTC
APB: 0 0 0 [I/O] AP Bus
Fix this by moving I/O interrupt accounting into the common I/O layer.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/cio.c | 17 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 13 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 2 |
5 files changed, 41 insertions, 6 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index eb3140ee821e..5586c1376cb0 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -622,6 +622,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
622 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 622 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
623 | if (!sch) { | 623 | if (!sch) { |
624 | /* Clear pending interrupt condition. */ | 624 | /* Clear pending interrupt condition. */ |
625 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
625 | tsch(tpi_info->schid, irb); | 626 | tsch(tpi_info->schid, irb); |
626 | continue; | 627 | continue; |
627 | } | 628 | } |
@@ -634,7 +635,10 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
634 | /* Call interrupt handler if there is one. */ | 635 | /* Call interrupt handler if there is one. */ |
635 | if (sch->driver && sch->driver->irq) | 636 | if (sch->driver && sch->driver->irq) |
636 | sch->driver->irq(sch); | 637 | sch->driver->irq(sch); |
637 | } | 638 | else |
639 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
640 | } else | ||
641 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
638 | spin_unlock(sch->lock); | 642 | spin_unlock(sch->lock); |
639 | /* | 643 | /* |
640 | * Are more interrupts pending? | 644 | * Are more interrupts pending? |
@@ -667,18 +671,23 @@ static int cio_tpi(void) | |||
667 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | 671 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; |
668 | if (tpi(NULL) != 1) | 672 | if (tpi(NULL) != 1) |
669 | return 0; | 673 | return 0; |
674 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | ||
670 | if (tpi_info->adapter_IO) { | 675 | if (tpi_info->adapter_IO) { |
671 | do_adapter_IO(tpi_info->isc); | 676 | do_adapter_IO(tpi_info->isc); |
672 | return 1; | 677 | return 1; |
673 | } | 678 | } |
674 | irb = (struct irb *)&S390_lowcore.irb; | 679 | irb = (struct irb *)&S390_lowcore.irb; |
675 | /* Store interrupt response block to lowcore. */ | 680 | /* Store interrupt response block to lowcore. */ |
676 | if (tsch(tpi_info->schid, irb) != 0) | 681 | if (tsch(tpi_info->schid, irb) != 0) { |
677 | /* Not status pending or not operational. */ | 682 | /* Not status pending or not operational. */ |
683 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
678 | return 1; | 684 | return 1; |
685 | } | ||
679 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 686 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
680 | if (!sch) | 687 | if (!sch) { |
688 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
681 | return 1; | 689 | return 1; |
690 | } | ||
682 | irq_context = in_interrupt(); | 691 | irq_context = in_interrupt(); |
683 | if (!irq_context) | 692 | if (!irq_context) |
684 | local_bh_disable(); | 693 | local_bh_disable(); |
@@ -687,6 +696,8 @@ static int cio_tpi(void) | |||
687 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); | 696 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); |
688 | if (sch->driver && sch->driver->irq) | 697 | if (sch->driver && sch->driver->irq) |
689 | sch->driver->irq(sch); | 698 | sch->driver->irq(sch); |
699 | else | ||
700 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
690 | spin_unlock(sch->lock); | 701 | spin_unlock(sch->lock); |
691 | irq_exit(); | 702 | irq_exit(); |
692 | if (!irq_context) | 703 | if (!irq_context) |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8e04c00cf0ad..d734f4a0ecac 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/timer.h> | 23 | #include <linux/timer.h> |
24 | #include <linux/kernel_stat.h> | ||
24 | 25 | ||
25 | #include <asm/ccwdev.h> | 26 | #include <asm/ccwdev.h> |
26 | #include <asm/cio.h> | 27 | #include <asm/cio.h> |
@@ -747,6 +748,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
747 | struct ccw_device *cdev) | 748 | struct ccw_device *cdev) |
748 | { | 749 | { |
749 | cdev->private->cdev = cdev; | 750 | cdev->private->cdev = cdev; |
751 | cdev->private->int_class = IOINT_CIO; | ||
750 | atomic_set(&cdev->private->onoff, 0); | 752 | atomic_set(&cdev->private->onoff, 0); |
751 | cdev->dev.parent = &sch->dev; | 753 | cdev->dev.parent = &sch->dev; |
752 | cdev->dev.release = ccw_device_release; | 754 | cdev->dev.release = ccw_device_release; |
@@ -1010,6 +1012,8 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
1010 | CIO_TRACE_EVENT(6, dev_name(&sch->dev)); | 1012 | CIO_TRACE_EVENT(6, dev_name(&sch->dev)); |
1011 | if (cdev) | 1013 | if (cdev) |
1012 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1014 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
1015 | else | ||
1016 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
1013 | } | 1017 | } |
1014 | 1018 | ||
1015 | void io_subchannel_init_config(struct subchannel *sch) | 1019 | void io_subchannel_init_config(struct subchannel *sch) |
@@ -1621,6 +1625,7 @@ ccw_device_probe_console(void) | |||
1621 | memset(&console_private, 0, sizeof(struct ccw_device_private)); | 1625 | memset(&console_private, 0, sizeof(struct ccw_device_private)); |
1622 | console_cdev.private = &console_private; | 1626 | console_cdev.private = &console_private; |
1623 | console_private.cdev = &console_cdev; | 1627 | console_private.cdev = &console_cdev; |
1628 | console_private.int_class = IOINT_CIO; | ||
1624 | ret = ccw_device_console_enable(&console_cdev, sch); | 1629 | ret = ccw_device_console_enable(&console_cdev, sch); |
1625 | if (ret) { | 1630 | if (ret) { |
1626 | cio_release_console(); | 1631 | cio_release_console(); |
@@ -1702,11 +1707,18 @@ ccw_device_probe (struct device *dev) | |||
1702 | int ret; | 1707 | int ret; |
1703 | 1708 | ||
1704 | cdev->drv = cdrv; /* to let the driver call _set_online */ | 1709 | cdev->drv = cdrv; /* to let the driver call _set_online */ |
1710 | /* Note: we interpret class 0 in this context as an uninitialized | ||
1711 | * field since it translates to a non-I/O interrupt class. */ | ||
1712 | if (cdrv->int_class != 0) | ||
1713 | cdev->private->int_class = cdrv->int_class; | ||
1714 | else | ||
1715 | cdev->private->int_class = IOINT_CIO; | ||
1705 | 1716 | ||
1706 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; | 1717 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; |
1707 | 1718 | ||
1708 | if (ret) { | 1719 | if (ret) { |
1709 | cdev->drv = NULL; | 1720 | cdev->drv = NULL; |
1721 | cdev->private->int_class = IOINT_CIO; | ||
1710 | return ret; | 1722 | return ret; |
1711 | } | 1723 | } |
1712 | 1724 | ||
@@ -1740,6 +1752,7 @@ ccw_device_remove (struct device *dev) | |||
1740 | } | 1752 | } |
1741 | ccw_device_set_timeout(cdev, 0); | 1753 | ccw_device_set_timeout(cdev, 0); |
1742 | cdev->drv = NULL; | 1754 | cdev->drv = NULL; |
1755 | cdev->private->int_class = IOINT_CIO; | ||
1743 | return 0; | 1756 | return 0; |
1744 | } | 1757 | } |
1745 | 1758 | ||
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0b7245c72d5e..179824b3082f 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/atomic.h> | 5 | #include <linux/atomic.h> |
6 | #include <linux/wait.h> | 6 | #include <linux/wait.h> |
7 | #include <linux/notifier.h> | 7 | #include <linux/notifier.h> |
8 | #include <linux/kernel_stat.h> | ||
8 | #include "io_sch.h" | 9 | #include "io_sch.h" |
9 | 10 | ||
10 | /* | 11 | /* |
@@ -56,7 +57,17 @@ extern fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS]; | |||
56 | static inline void | 57 | static inline void |
57 | dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) | 58 | dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) |
58 | { | 59 | { |
59 | dev_jumptable[cdev->private->state][dev_event](cdev, dev_event); | 60 | int state = cdev->private->state; |
61 | |||
62 | if (dev_event == DEV_EVENT_INTERRUPT) { | ||
63 | if (state == DEV_STATE_ONLINE) | ||
64 | kstat_cpu(smp_processor_id()). | ||
65 | irqs[cdev->private->int_class]++; | ||
66 | else if (state != DEV_STATE_CMFCHANGE && | ||
67 | state != DEV_STATE_CMFUPDATE) | ||
68 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
69 | } | ||
70 | dev_jumptable[state][dev_event](cdev, dev_event); | ||
60 | } | 71 | } |
61 | 72 | ||
62 | /* | 73 | /* |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index ba31ad88f4f7..2ebb492a5c17 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <asm/schid.h> | 5 | #include <asm/schid.h> |
6 | #include <asm/ccwdev.h> | 6 | #include <asm/ccwdev.h> |
7 | #include <asm/irq.h> | ||
7 | #include "css.h" | 8 | #include "css.h" |
8 | #include "orb.h" | 9 | #include "orb.h" |
9 | 10 | ||
@@ -157,6 +158,7 @@ struct ccw_device_private { | |||
157 | struct list_head cmb_list; /* list of measured devices */ | 158 | struct list_head cmb_list; /* list of measured devices */ |
158 | u64 cmb_start_time; /* clock value of cmb reset */ | 159 | u64 cmb_start_time; /* clock value of cmb reset */ |
159 | void *cmb_wait; /* deferred cmb enable/disable */ | 160 | void *cmb_wait; /* deferred cmb enable/disable */ |
161 | enum interruption_class int_class; | ||
160 | }; | 162 | }; |
161 | 163 | ||
162 | static inline int rsch(struct subchannel_id schid) | 164 | static inline int rsch(struct subchannel_id schid) |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 6547ff469410..7ded1b26fd25 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/gfp.h> | 16 | #include <linux/gfp.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/kernel_stat.h> | ||
19 | #include <linux/atomic.h> | 18 | #include <linux/atomic.h> |
20 | #include <asm/debug.h> | 19 | #include <asm/debug.h> |
21 | #include <asm/qdio.h> | 20 | #include <asm/qdio.h> |
@@ -1128,7 +1127,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1128 | return; | 1127 | return; |
1129 | } | 1128 | } |
1130 | 1129 | ||
1131 | kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++; | ||
1132 | if (irq_ptr->perf_stat_enabled) | 1130 | if (irq_ptr->perf_stat_enabled) |
1133 | irq_ptr->perf_stat.qdio_int++; | 1131 | irq_ptr->perf_stat.qdio_int++; |
1134 | 1132 | ||