Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Peter Oberparleiter and committed by
Martin Schwidefsky
de400d6b ce949717

+56 -24
+3
arch/s390/include/asm/ccwdev.h
··· 11 11 #include <linux/device.h> 12 12 #include <linux/mod_devicetable.h> 13 13 #include <asm/fcx.h> 14 + #include <asm/irq.h> 14 15 15 16 /* structs from asm/cio.h */ 16 17 struct irb; ··· 128 127 * @restore: callback for restoring after hibernation 129 128 * @uc_handler: callback for unit check handler 130 129 * @driver: embedded device driver structure 130 + * @int_class: interruption class to use for accounting interrupts 131 131 */ 132 132 struct ccw_driver { 133 133 struct ccw_device_id *ids; ··· 146 144 int (*restore)(struct ccw_device *); 147 145 enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *); 148 146 struct device_driver driver; 147 + enum interruption_class int_class; 149 148 }; 150 149 151 150 extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+1 -1
arch/s390/include/asm/irq.h
··· 17 17 EXTINT_SCP, 18 18 EXTINT_IUC, 19 19 EXTINT_CPM, 20 + IOINT_CIO, 20 21 IOINT_QAI, 21 - IOINT_QDI, 22 22 IOINT_DAS, 23 23 IOINT_C15, 24 24 IOINT_C70,
+1 -1
arch/s390/kernel/irq.c
··· 42 42 {.name = "SCP", .desc = "[EXT] Service Call" }, 43 43 {.name = "IUC", .desc = "[EXT] IUCV" }, 44 44 {.name = "CPM", .desc = "[EXT] CPU Measurement" }, 45 + {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" }, 45 46 {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, 46 - {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, 47 47 {.name = "DAS", .desc = "[I/O] DASD" }, 48 48 {.name = "C15", .desc = "[I/O] 3215" }, 49 49 {.name = "C70", .desc = "[I/O] 3270" },
-2
drivers/s390/block/dasd.c
··· 11 11 #define KMSG_COMPONENT "dasd" 12 12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 13 14 - #include <linux/kernel_stat.h> 15 14 #include <linux/kmod.h> 16 15 #include <linux/init.h> 17 16 #include <linux/interrupt.h> ··· 1593 1594 unsigned long long now; 1594 1595 int expires; 1595 1596 1596 - kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; 1597 1597 if (IS_ERR(irb)) { 1598 1598 switch (PTR_ERR(irb)) { 1599 1599 case -EIO:
+1
drivers/s390/block/dasd_eckd.c
··· 3998 3998 .thaw = dasd_generic_restore_device, 3999 3999 .restore = dasd_generic_restore_device, 4000 4000 .uc_handler = dasd_generic_uc_handler, 4001 + .int_class = IOINT_DAS, 4001 4002 }; 4002 4003 4003 4004 /*
+1
drivers/s390/block/dasd_fba.c
··· 79 79 .freeze = dasd_generic_pm_freeze, 80 80 .thaw = dasd_generic_restore_device, 81 81 .restore = dasd_generic_restore_device, 82 + .int_class = IOINT_DAS, 82 83 }; 83 84 84 85 static void
+1 -2
drivers/s390/char/con3215.c
··· 9 9 * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> 10 10 */ 11 11 12 - #include <linux/kernel_stat.h> 13 12 #include <linux/module.h> 14 13 #include <linux/types.h> 15 14 #include <linux/kdev_t.h> ··· 361 362 int cstat, dstat; 362 363 int count; 363 364 364 - kstat_cpu(smp_processor_id()).irqs[IOINT_C15]++; 365 365 raw = dev_get_drvdata(&cdev->dev); 366 366 req = (struct raw3215_req *) intparm; 367 367 cstat = irb->scsw.cmd.cstat; ··· 774 776 .freeze = &raw3215_pm_stop, 775 777 .thaw = &raw3215_pm_start, 776 778 .restore = &raw3215_pm_start, 779 + .int_class = IOINT_C15, 777 780 }; 778 781 779 782 #ifdef CONFIG_TN3215_CONSOLE
+1 -2
drivers/s390/char/raw3270.c
··· 7 7 * Copyright IBM Corp. 2003, 2009 8 8 */ 9 9 10 - #include <linux/kernel_stat.h> 11 10 #include <linux/module.h> 12 11 #include <linux/err.h> 13 12 #include <linux/init.h> ··· 329 330 struct raw3270_request *rq; 330 331 int rc; 331 332 332 - kstat_cpu(smp_processor_id()).irqs[IOINT_C70]++; 333 333 rp = dev_get_drvdata(&cdev->dev); 334 334 if (!rp) 335 335 return; ··· 1396 1398 .freeze = &raw3270_pm_stop, 1397 1399 .thaw = &raw3270_pm_start, 1398 1400 .restore = &raw3270_pm_start, 1401 + .int_class = IOINT_C70, 1399 1402 }; 1400 1403 1401 1404 static int
+1
drivers/s390/char/tape_34xx.c
··· 1330 1330 .set_online = tape_34xx_online, 1331 1331 .set_offline = tape_generic_offline, 1332 1332 .freeze = tape_generic_pm_suspend, 1333 + .int_class = IOINT_TAP, 1333 1334 }; 1334 1335 1335 1336 static int
+1
drivers/s390/char/tape_3590.c
··· 1762 1762 .set_offline = tape_generic_offline, 1763 1763 .set_online = tape_3590_online, 1764 1764 .freeze = tape_generic_pm_suspend, 1765 + .int_class = IOINT_TAP, 1765 1766 }; 1766 1767 1767 1768 /*
-2
drivers/s390/char/tape_core.c
··· 14 14 #define KMSG_COMPONENT "tape" 15 15 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 16 16 17 - #include <linux/kernel_stat.h> 18 17 #include <linux/module.h> 19 18 #include <linux/init.h> // for kernel parameters 20 19 #include <linux/kmod.h> // for requesting modules ··· 1114 1115 struct tape_request *request; 1115 1116 int rc; 1116 1117 1117 - kstat_cpu(smp_processor_id()).irqs[IOINT_TAP]++; 1118 1118 device = dev_get_drvdata(&cdev->dev); 1119 1119 if (device == NULL) { 1120 1120 return;
+1 -2
drivers/s390/char/vmur.c
··· 11 11 #define KMSG_COMPONENT "vmur" 12 12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 13 14 - #include <linux/kernel_stat.h> 15 14 #include <linux/cdev.h> 16 15 #include <linux/slab.h> 17 16 ··· 73 74 .set_online = ur_set_online, 74 75 .set_offline = ur_set_offline, 75 76 .freeze = ur_pm_suspend, 77 + .int_class = IOINT_VMR, 76 78 }; 77 79 78 80 static DEFINE_MUTEX(vmur_mutex); ··· 305 305 { 306 306 struct urdev *urd; 307 307 308 - kstat_cpu(smp_processor_id()).irqs[IOINT_VMR]++; 309 308 TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", 310 309 intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, 311 310 irb->scsw.cmd.count);
+14 -3
drivers/s390/cio/cio.c
··· 622 622 sch = (struct subchannel *)(unsigned long)tpi_info->intparm; 623 623 if (!sch) { 624 624 /* Clear pending interrupt condition. */ 625 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 625 626 tsch(tpi_info->schid, irb); 626 627 continue; 627 628 } ··· 635 634 /* Call interrupt handler if there is one. */ 636 635 if (sch->driver && sch->driver->irq) 637 636 sch->driver->irq(sch); 638 - } 637 + else 638 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 639 + } else 640 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 639 641 spin_unlock(sch->lock); 640 642 /* 641 643 * Are more interrupts pending? ··· 671 667 tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; 672 668 if (tpi(NULL) != 1) 673 669 return 0; 670 + kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; 674 671 if (tpi_info->adapter_IO) { 675 672 do_adapter_IO(tpi_info->isc); 676 673 return 1; 677 674 } 678 675 irb = (struct irb *)&S390_lowcore.irb; 679 676 /* Store interrupt response block to lowcore. */ 680 - if (tsch(tpi_info->schid, irb) != 0) 677 + if (tsch(tpi_info->schid, irb) != 0) { 681 678 /* Not status pending or not operational. */ 679 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 682 680 return 1; 681 + } 683 682 sch = (struct subchannel *)(unsigned long)tpi_info->intparm; 684 - if (!sch) 683 + if (!sch) { 684 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 685 685 return 1; 686 + } 686 687 irq_context = in_interrupt(); 687 688 if (!irq_context) 688 689 local_bh_disable(); ··· 696 687 memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); 697 688 if (sch->driver && sch->driver->irq) 698 689 sch->driver->irq(sch); 690 + else 691 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 699 692 spin_unlock(sch->lock); 700 693 irq_exit(); 701 694 if (!irq_context)
+13
drivers/s390/cio/device.c
··· 21 21 #include <linux/device.h> 22 22 #include <linux/workqueue.h> 23 23 #include <linux/timer.h> 24 + #include <linux/kernel_stat.h> 24 25 25 26 #include <asm/ccwdev.h> 26 27 #include <asm/cio.h> ··· 748 747 struct ccw_device *cdev) 749 748 { 750 749 cdev->private->cdev = cdev; 750 + cdev->private->int_class = IOINT_CIO; 751 751 atomic_set(&cdev->private->onoff, 0); 752 752 cdev->dev.parent = &sch->dev; 753 753 cdev->dev.release = ccw_device_release; ··· 1012 1010 CIO_TRACE_EVENT(6, dev_name(&sch->dev)); 1013 1011 if (cdev) 1014 1012 dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); 1013 + else 1014 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 1015 1015 } 1016 1016 1017 1017 void io_subchannel_init_config(struct subchannel *sch) ··· 1625 1621 memset(&console_private, 0, sizeof(struct ccw_device_private)); 1626 1622 console_cdev.private = &console_private; 1627 1623 console_private.cdev = &console_cdev; 1624 + console_private.int_class = IOINT_CIO; 1628 1625 ret = ccw_device_console_enable(&console_cdev, sch); 1629 1626 if (ret) { 1630 1627 cio_release_console(); ··· 1707 1702 int ret; 1708 1703 1709 1704 cdev->drv = cdrv; /* to let the driver call _set_online */ 1705 + /* Note: we interpret class 0 in this context as an uninitialized 1706 + * field since it translates to a non-I/O interrupt class. */ 1707 + if (cdrv->int_class != 0) 1708 + cdev->private->int_class = cdrv->int_class; 1709 + else 1710 + cdev->private->int_class = IOINT_CIO; 1710 1711 1711 1712 ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; 1712 1713 1713 1714 if (ret) { 1714 1715 cdev->drv = NULL; 1716 + cdev->private->int_class = IOINT_CIO; 1715 1717 return ret; 1716 1718 } 1717 1719 ··· 1752 1740 } 1753 1741 ccw_device_set_timeout(cdev, 0); 1754 1742 cdev->drv = NULL; 1743 + cdev->private->int_class = IOINT_CIO; 1755 1744 return 0; 1756 1745 } 1757 1746
+12 -1
drivers/s390/cio/device.h
··· 5 5 #include <linux/atomic.h> 6 6 #include <linux/wait.h> 7 7 #include <linux/notifier.h> 8 + #include <linux/kernel_stat.h> 8 9 #include "io_sch.h" 9 10 10 11 /* ··· 57 56 static inline void 58 57 dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) 59 58 { 60 - dev_jumptable[cdev->private->state][dev_event](cdev, dev_event); 59 + int state = cdev->private->state; 60 + 61 + if (dev_event == DEV_EVENT_INTERRUPT) { 62 + if (state == DEV_STATE_ONLINE) 63 + kstat_cpu(smp_processor_id()). 64 + irqs[cdev->private->int_class]++; 65 + else if (state != DEV_STATE_CMFCHANGE && 66 + state != DEV_STATE_CMFUPDATE) 67 + kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; 68 + } 69 + dev_jumptable[state][dev_event](cdev, dev_event); 61 70 } 62 71 63 72 /*
+2
drivers/s390/cio/io_sch.h
··· 4 4 #include <linux/types.h> 5 5 #include <asm/schid.h> 6 6 #include <asm/ccwdev.h> 7 + #include <asm/irq.h> 7 8 #include "css.h" 8 9 #include "orb.h" 9 10 ··· 158 157 struct list_head cmb_list; /* list of measured devices */ 159 158 u64 cmb_start_time; /* clock value of cmb reset */ 160 159 void *cmb_wait; /* deferred cmb enable/disable */ 160 + enum interruption_class int_class; 161 161 }; 162 162 163 163 static inline int rsch(struct subchannel_id schid)
-2
drivers/s390/cio/qdio_main.c
··· 15 15 #include <linux/delay.h> 16 16 #include <linux/gfp.h> 17 17 #include <linux/io.h> 18 - #include <linux/kernel_stat.h> 19 18 #include <linux/atomic.h> 20 19 #include <asm/debug.h> 21 20 #include <asm/qdio.h> ··· 1127 1128 return; 1128 1129 } 1129 1130 1130 - kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++; 1131 1131 if (irq_ptr->perf_stat_enabled) 1132 1132 irq_ptr->perf_stat.qdio_int++; 1133 1133
+1 -2
drivers/s390/net/claw.c
··· 63 63 64 64 #define KMSG_COMPONENT "claw" 65 65 66 - #include <linux/kernel_stat.h> 67 66 #include <asm/ccwdev.h> 68 67 #include <asm/ccwgroup.h> 69 68 #include <asm/debug.h> ··· 290 291 .ids = claw_ids, 291 292 .probe = ccwgroup_probe_ccwdev, 292 293 .remove = ccwgroup_remove_ccwdev, 294 + .int_class = IOINT_CLW, 293 295 }; 294 296 295 297 static ssize_t ··· 645 645 struct claw_env *p_env; 646 646 struct chbk *p_ch_r=NULL; 647 647 648 - kstat_cpu(smp_processor_id()).irqs[IOINT_CLW]++; 649 648 CLAW_DBF_TEXT(4, trace, "clawirq"); 650 649 /* Bypass all 'unsolicited interrupts' */ 651 650 privptr = dev_get_drvdata(&cdev->dev);
+1 -2
drivers/s390/net/ctcm_main.c
··· 24 24 #define KMSG_COMPONENT "ctcm" 25 25 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 26 26 27 - #include <linux/kernel_stat.h> 28 27 #include <linux/module.h> 29 28 #include <linux/init.h> 30 29 #include <linux/kernel.h> ··· 1202 1203 int cstat; 1203 1204 int dstat; 1204 1205 1205 - kstat_cpu(smp_processor_id()).irqs[IOINT_CTC]++; 1206 1206 CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, 1207 1207 "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); 1208 1208 ··· 1767 1769 .ids = ctcm_ids, 1768 1770 .probe = ccwgroup_probe_ccwdev, 1769 1771 .remove = ccwgroup_remove_ccwdev, 1772 + .int_class = IOINT_CTC, 1770 1773 }; 1771 1774 1772 1775 static struct ccwgroup_driver ctcm_group_driver = {
+1 -2
drivers/s390/net/lcs.c
··· 26 26 #define KMSG_COMPONENT "lcs" 27 27 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 28 28 29 - #include <linux/kernel_stat.h> 30 29 #include <linux/module.h> 31 30 #include <linux/if.h> 32 31 #include <linux/netdevice.h> ··· 1398 1399 int rc, index; 1399 1400 int cstat, dstat; 1400 1401 1401 - kstat_cpu(smp_processor_id()).irqs[IOINT_LCS]++; 1402 1402 if (lcs_check_irb_error(cdev, irb)) 1403 1403 return; 1404 1404 ··· 2397 2399 .ids = lcs_ids, 2398 2400 .probe = ccwgroup_probe_ccwdev, 2399 2401 .remove = ccwgroup_remove_ccwdev, 2402 + .int_class = IOINT_LCS, 2400 2403 }; 2401 2404 2402 2405 /**