From d5f1f2ec452acda0e7f876c97d4aa463de657c8d Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 13 Oct 2011 17:52:28 +0200 Subject: [PATCH] [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 Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ccwdev.h | 3 +++ arch/s390/include/asm/irq.h | 2 +- arch/s390/kernel/irq.c | 2 +- drivers/s390/block/dasd.c | 2 -- drivers/s390/block/dasd_eckd.c | 1 + drivers/s390/block/dasd_fba.c | 1 + drivers/s390/char/con3215.c | 3 +-- drivers/s390/char/raw3270.c | 3 +-- drivers/s390/char/tape_34xx.c | 1 + drivers/s390/char/tape_3590.c | 1 + drivers/s390/char/tape_core.c | 2 -- drivers/s390/char/vmur.c | 3 +-- drivers/s390/cio/cio.c | 17 ++++++++++++++--- drivers/s390/cio/device.c | 13 +++++++++++++ drivers/s390/cio/device.h | 13 ++++++++++++- drivers/s390/cio/io_sch.h | 2 ++ drivers/s390/cio/qdio_main.c | 2 -- drivers/s390/net/claw.c | 3 +-- drivers/s390/net/ctcm_main.c | 3 +-- drivers/s390/net/lcs.c | 3 +-- 20 files changed, 56 insertions(+), 24 deletions(-) diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index 623f2fb71774..9381c92cc779 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -11,6 +11,7 @@ #include #include #include +#include /* structs from asm/cio.h */ struct irb; @@ -127,6 +128,7 @@ enum uc_todo { * @restore: callback for restoring after hibernation * @uc_handler: callback for unit check handler * @driver: embedded device driver structure + * @int_class: interruption class to use for accounting interrupts */ struct ccw_driver { struct ccw_device_id *ids; @@ -144,6 +146,7 @@ struct ccw_driver { int (*restore)(struct ccw_device *); enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *); struct device_driver driver; + enum interruption_class int_class; }; extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index ba7b01c726a3..1f686059f293 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -17,8 +17,8 @@ enum interruption_class { EXTINT_SCP, EXTINT_IUC, EXTINT_CPM, + IOINT_CIO, IOINT_QAI, - IOINT_QDI, IOINT_DAS, IOINT_C15, IOINT_C70, diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1f4050d45f78..d382f9db3df5 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -42,8 +42,8 @@ static const struct irq_class intrclass_names[] = { {.name = "SCP", .desc = "[EXT] Service Call" }, {.name = "IUC", .desc = "[EXT] IUCV" }, {.name = "CPM", .desc = "[EXT] CPU Measurement" }, + {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" }, {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, - {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, {.name = "DAS", .desc = "[I/O] DASD" }, {.name = "C15", .desc = "[I/O] 3215" }, {.name = "C70", .desc = "[I/O] 3270" }, diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a1d3ddba99cc..46054c75cf31 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -11,7 +11,6 @@ #define KMSG_COMPONENT "dasd" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include #include #include #include @@ -1594,7 +1593,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, unsigned long long now; int expires; - kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 6e835c9fdfcb..0e9c4dcf1452 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3998,6 +3998,7 @@ static struct ccw_driver dasd_eckd_driver = { .thaw = dasd_generic_restore_device, .restore = dasd_generic_restore_device, .uc_handler = dasd_generic_uc_handler, + .int_class = IOINT_DAS, }; /* diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 4b71b1164868..a62a75358eb9 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -79,6 +79,7 @@ static struct ccw_driver dasd_fba_driver = { .freeze = dasd_generic_pm_freeze, .thaw = dasd_generic_restore_device, .restore = dasd_generic_restore_device, + .int_class = IOINT_DAS, }; static void diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 694464c65fcd..934458ad55e5 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -9,7 +9,6 @@ * Dan Morrison, IBM Corporation */ -#include #include #include #include @@ -362,7 +361,6 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, int cstat, dstat; int count; - kstat_cpu(smp_processor_id()).irqs[IOINT_C15]++; raw = dev_get_drvdata(&cdev->dev); req = (struct raw3215_req *) intparm; cstat = irb->scsw.cmd.cstat; @@ -776,6 +774,7 @@ static struct ccw_driver raw3215_ccw_driver = { .freeze = &raw3215_pm_stop, .thaw = &raw3215_pm_start, .restore = &raw3215_pm_start, + .int_class = IOINT_C15, }; #ifdef CONFIG_TN3215_CONSOLE diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 810ac38631c3..e5cb9248a442 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -7,7 +7,6 @@ * Copyright IBM Corp. 2003, 2009 */ -#include #include #include #include @@ -330,7 +329,6 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3270_request *rq; int rc; - kstat_cpu(smp_processor_id()).irqs[IOINT_C70]++; rp = dev_get_drvdata(&cdev->dev); if (!rp) return; @@ -1398,6 +1396,7 @@ static struct ccw_driver raw3270_ccw_driver = { .freeze = &raw3270_pm_stop, .thaw = &raw3270_pm_start, .restore = &raw3270_pm_start, + .int_class = IOINT_C70, }; static int diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 9eff2df70ddb..934ef33eb9a4 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1330,6 +1330,7 @@ static struct ccw_driver tape_34xx_driver = { .set_online = tape_34xx_online, .set_offline = tape_generic_offline, .freeze = tape_generic_pm_suspend, + .int_class = IOINT_TAP, }; static int diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index a7d570728882..49c6aab7ad78 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -1762,6 +1762,7 @@ static struct ccw_driver tape_3590_driver = { .set_offline = tape_generic_offline, .set_online = tape_3590_online, .freeze = tape_generic_pm_suspend, + .int_class = IOINT_TAP, }; /* diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 7978a0adeaf3..b3a3e8e8656e 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -14,7 +14,6 @@ #define KMSG_COMPONENT "tape" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include #include #include // for kernel parameters #include // for requesting modules @@ -1115,7 +1114,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct tape_request *request; int rc; - kstat_cpu(smp_processor_id()).irqs[IOINT_TAP]++; device = dev_get_drvdata(&cdev->dev); if (device == NULL) { return; diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index f6b00c3df425..d291a54acfad 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -11,7 +11,6 @@ #define KMSG_COMPONENT "vmur" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include #include #include @@ -74,6 +73,7 @@ static struct ccw_driver ur_driver = { .set_online = ur_set_online, .set_offline = ur_set_offline, .freeze = ur_pm_suspend, + .int_class = IOINT_VMR, }; static DEFINE_MUTEX(vmur_mutex); @@ -305,7 +305,6 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, { struct urdev *urd; - kstat_cpu(smp_processor_id()).irqs[IOINT_VMR]++; TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, irb->scsw.cmd.count); 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) sch = (struct subchannel *)(unsigned long)tpi_info->intparm; if (!sch) { /* Clear pending interrupt condition. */ + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; tsch(tpi_info->schid, irb); continue; } @@ -634,7 +635,10 @@ void __irq_entry do_IRQ(struct pt_regs *regs) /* Call interrupt handler if there is one. */ if (sch->driver && sch->driver->irq) sch->driver->irq(sch); - } + else + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; + } else + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; spin_unlock(sch->lock); /* * Are more interrupts pending? @@ -667,18 +671,23 @@ static int cio_tpi(void) tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; if (tpi(NULL) != 1) return 0; + kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; if (tpi_info->adapter_IO) { do_adapter_IO(tpi_info->isc); return 1; } irb = (struct irb *)&S390_lowcore.irb; /* Store interrupt response block to lowcore. */ - if (tsch(tpi_info->schid, irb) != 0) + if (tsch(tpi_info->schid, irb) != 0) { /* Not status pending or not operational. */ + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; return 1; + } sch = (struct subchannel *)(unsigned long)tpi_info->intparm; - if (!sch) + if (!sch) { + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; return 1; + } irq_context = in_interrupt(); if (!irq_context) local_bh_disable(); @@ -687,6 +696,8 @@ static int cio_tpi(void) memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); if (sch->driver && sch->driver->irq) sch->driver->irq(sch); + else + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; spin_unlock(sch->lock); irq_exit(); 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 @@ #include #include #include +#include #include #include @@ -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; } 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 @@ #include #include #include +#include #include "io_sch.h" /* @@ -56,7 +57,17 @@ extern fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS]; static inline void dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) { - dev_jumptable[cdev->private->state][dev_event](cdev, dev_event); + int state = cdev->private->state; + + if (dev_event == DEV_EVENT_INTERRUPT) { + if (state == DEV_STATE_ONLINE) + kstat_cpu(smp_processor_id()). + irqs[cdev->private->int_class]++; + else if (state != DEV_STATE_CMFCHANGE && + state != DEV_STATE_CMFUPDATE) + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; + } + dev_jumptable[state][dev_event](cdev, dev_event); } /* 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 @@ #include #include #include +#include #include "css.h" #include "orb.h" @@ -157,6 +158,7 @@ struct ccw_device_private { struct list_head cmb_list; /* list of measured devices */ u64 cmb_start_time; /* clock value of cmb reset */ void *cmb_wait; /* deferred cmb enable/disable */ + enum interruption_class int_class; }; 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 288c9140290e..d7b5f422d28a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -995,7 +994,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } - kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++; if (irq_ptr->perf_stat_enabled) irq_ptr->perf_stat.qdio_int++; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f1fa2483ae6b..b41fae37d3af 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -63,7 +63,6 @@ #define KMSG_COMPONENT "claw" -#include #include #include #include @@ -291,6 +290,7 @@ static struct ccw_driver claw_ccw_driver = { .ids = claw_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, + .int_class = IOINT_CLW, }; static ssize_t @@ -645,7 +645,6 @@ claw_irq_handler(struct ccw_device *cdev, struct claw_env *p_env; struct chbk *p_ch_r=NULL; - kstat_cpu(smp_processor_id()).irqs[IOINT_CLW]++; CLAW_DBF_TEXT(4, trace, "clawirq"); /* Bypass all 'unsolicited interrupts' */ privptr = dev_get_drvdata(&cdev->dev); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 426787efc492..5cb93a8e3403 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -24,7 +24,6 @@ #define KMSG_COMPONENT "ctcm" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include #include #include #include @@ -1203,7 +1202,6 @@ static void ctcm_irq_handler(struct ccw_device *cdev, int cstat; int dstat; - kstat_cpu(smp_processor_id()).irqs[IOINT_CTC]++; CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); @@ -1769,6 +1767,7 @@ static struct ccw_driver ctcm_ccw_driver = { .ids = ctcm_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, + .int_class = IOINT_CTC, }; static struct ccwgroup_driver ctcm_group_driver = { diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index c3b8064a102d..4b562a6f1f5a 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -26,7 +26,6 @@ #define KMSG_COMPONENT "lcs" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include #include #include #include @@ -1399,7 +1398,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) int rc, index; int cstat, dstat; - kstat_cpu(smp_processor_id()).irqs[IOINT_LCS]++; if (lcs_check_irb_error(cdev, irb)) return; @@ -2399,6 +2397,7 @@ static struct ccw_driver lcs_ccw_driver = { .ids = lcs_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, + .int_class = IOINT_LCS, }; /** -- 2.39.5