aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2011-10-30 15:16:04 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 15:16:15 +0100
commitde400d6b78d15a73023485f050bc6b1709dc7a79 (patch)
tree2d2e7233a76982db4cf12ff0859054a33e46a911 /drivers/s390/cio/device.c
parentMerge git://github.com/rustyrussell/linux (diff)
downloadlinux-dev-de400d6b78d15a73023485f050bc6b1709dc7a79.tar.xz
linux-dev-de400d6b78d15a73023485f050bc6b1709dc7a79.zip
[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/device.c')
-rw-r--r--drivers/s390/cio/device.c13
1 files changed, 13 insertions, 0 deletions
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 @@
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
+#include <linux/kernel_stat.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -747,6 +748,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
struct ccw_device *cdev)
{
cdev->private->cdev = cdev;
+ cdev->private->int_class = IOINT_CIO;
atomic_set(&cdev->private->onoff, 0);
cdev->dev.parent = &sch->dev;
cdev->dev.release = ccw_device_release;
@@ -1010,6 +1012,8 @@ static void io_subchannel_irq(struct subchannel *sch)
CIO_TRACE_EVENT(6, dev_name(&sch->dev));
if (cdev)
dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+ else
+ kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
}
void io_subchannel_init_config(struct subchannel *sch)
@@ -1621,6 +1625,7 @@ ccw_device_probe_console(void)
memset(&console_private, 0, sizeof(struct ccw_device_private));
console_cdev.private = &console_private;
console_private.cdev = &console_cdev;
+ console_private.int_class = IOINT_CIO;
ret = ccw_device_console_enable(&console_cdev, sch);
if (ret) {
cio_release_console();
@@ -1702,11 +1707,18 @@ ccw_device_probe (struct device *dev)
int ret;
cdev->drv = cdrv; /* to let the driver call _set_online */
+ /* Note: we interpret class 0 in this context as an uninitialized
+ * field since it translates to a non-I/O interrupt class. */
+ if (cdrv->int_class != 0)
+ cdev->private->int_class = cdrv->int_class;
+ else
+ cdev->private->int_class = IOINT_CIO;
ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
if (ret) {
cdev->drv = NULL;
+ cdev->private->int_class = IOINT_CIO;
return ret;
}
@@ -1740,6 +1752,7 @@ ccw_device_remove (struct device *dev)
}
ccw_device_set_timeout(cdev, 0);
cdev->drv = NULL;
+ cdev->private->int_class = IOINT_CIO;
return 0;
}