forked from Minki/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>
This commit is contained in:
parent
ce949717b5
commit
de400d6b78
@ -11,6 +11,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <asm/fcx.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
/* 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,
|
||||
|
@ -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,
|
||||
|
@ -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" },
|
||||
|
@ -11,7 +11,6 @@
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -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:
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -9,7 +9,6 @@
|
||||
* Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu>
|
||||
*/
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kdev_t.h>
|
||||
@ -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
|
||||
|
@ -7,7 +7,6 @@
|
||||
* Copyright IBM Corp. 2003, 2009
|
||||
*/
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -14,7 +14,6 @@
|
||||
#define KMSG_COMPONENT "tape"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h> // for kernel parameters
|
||||
#include <linux/kmod.h> // 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;
|
||||
|
@ -11,7 +11,6 @@
|
||||
#define KMSG_COMPONENT "vmur"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <asm/schid.h>
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/irq.h>
|
||||
#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)
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/qdio.h>
|
||||
@ -1128,7 +1127,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++;
|
||||
|
||||
|
@ -63,7 +63,6 @@
|
||||
|
||||
#define KMSG_COMPONENT "claw"
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/ccwgroup.h>
|
||||
#include <asm/debug.h>
|
||||
@ -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);
|
||||
|
@ -24,7 +24,6 @@
|
||||
#define KMSG_COMPONENT "ctcm"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -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 = {
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define KMSG_COMPONENT "lcs"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netdevice.h>
|
||||
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user