Commit 741f21e8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6:
  [S390] Update default configuration.
  [S390] Have param.h simply include <asm-generic/param.h>.
  [S390] qdio: convert global statistics to per-device stats
parents d4d3b192 cc4707b3
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
# Tue Sep 22 17:43:13 2009
# Linux kernel version: 2.6.33-rc2
# Mon Jan 4 09:03:07 2010
#
CONFIG_SCHED_MC=y
CONFIG_MMU=y
......@@ -51,6 +51,7 @@ CONFIG_AUDIT=y
#
CONFIG_TREE_RCU=y
# CONFIG_TREE_PREEMPT_RCU is not set
# CONFIG_TINY_RCU is not set
# CONFIG_RCU_TRACE is not set
CONFIG_RCU_FANOUT=64
# CONFIG_RCU_FANOUT_EXACT is not set
......@@ -113,7 +114,6 @@ CONFIG_HAVE_PERF_EVENTS=y
# CONFIG_PERF_EVENTS is not set
# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
# CONFIG_SLUB is not set
......@@ -149,21 +149,78 @@ CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
CONFIG_BLK_DEV_BSG=y
# CONFIG_BLK_DEV_INTEGRITY is not set
# CONFIG_BLK_CGROUP is not set
CONFIG_BLOCK_COMPAT=y
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_DEFAULT_AS is not set
# CONFIG_CFQ_GROUP_IOSCHED is not set
CONFIG_DEFAULT_DEADLINE=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="deadline"
CONFIG_PREEMPT_NOTIFIERS=y
CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y
CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y
CONFIG_ARCH_INLINE_SPIN_LOCK=y
CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y
CONFIG_ARCH_INLINE_SPIN_UNLOCK=y
CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y
CONFIG_ARCH_INLINE_READ_TRYLOCK=y
CONFIG_ARCH_INLINE_READ_LOCK=y
CONFIG_ARCH_INLINE_READ_LOCK_BH=y
CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y
CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y
CONFIG_ARCH_INLINE_READ_UNLOCK=y
CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y
CONFIG_ARCH_INLINE_WRITE_TRYLOCK=y
CONFIG_ARCH_INLINE_WRITE_LOCK=y
CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y
CONFIG_ARCH_INLINE_WRITE_UNLOCK=y
CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y
# CONFIG_INLINE_SPIN_TRYLOCK is not set
# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK is not set
# CONFIG_INLINE_SPIN_LOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
# CONFIG_INLINE_SPIN_UNLOCK is not set
# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
# CONFIG_INLINE_READ_TRYLOCK is not set
# CONFIG_INLINE_READ_LOCK is not set
# CONFIG_INLINE_READ_LOCK_BH is not set
# CONFIG_INLINE_READ_LOCK_IRQ is not set
# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
# CONFIG_INLINE_READ_UNLOCK is not set
# CONFIG_INLINE_READ_UNLOCK_BH is not set
# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
# CONFIG_INLINE_WRITE_TRYLOCK is not set
# CONFIG_INLINE_WRITE_LOCK is not set
# CONFIG_INLINE_WRITE_LOCK_BH is not set
# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
# CONFIG_INLINE_WRITE_UNLOCK is not set
# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
# CONFIG_MUTEX_SPIN_ON_OWNER is not set
CONFIG_FREEZER=y
#
......@@ -227,14 +284,13 @@ CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_SPARSE=y
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_MIGRATION=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
#
......@@ -339,6 +395,7 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=y
CONFIG_INET6_XFRM_MODE_BEET=y
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_SIT=y
# CONFIG_IPV6_SIT_6RD is not set
CONFIG_IPV6_NDISC_NODETYPE=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
......@@ -504,6 +561,10 @@ CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
#
# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
#
CONFIG_BLK_DEV_NBD=m
# CONFIG_BLK_DEV_OSD is not set
CONFIG_BLK_DEV_RAM=y
......@@ -710,7 +771,6 @@ CONFIG_S390_VMUR=m
# CONFIG_PPS is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
# CONFIG_REGULATOR is not set
# CONFIG_MEMSTICK is not set
......@@ -864,6 +924,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
......@@ -931,7 +992,6 @@ CONFIG_BRANCH_PROFILE_NONE=y
CONFIG_SAMPLES=y
# CONFIG_SAMPLE_KOBJECT is not set
# CONFIG_SAMPLE_KPROBES is not set
# CONFIG_KMEMCHECK is not set
#
# Security options
......@@ -939,7 +999,11 @@ CONFIG_SAMPLES=y
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
# CONFIG_DEFAULT_SECURITY_SELINUX is not set
# CONFIG_DEFAULT_SECURITY_SMACK is not set
# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_DEFAULT_SECURITY=""
CONFIG_CRYPTO=y
#
......
/*
* include/asm-s390/param.h
*
* S390 version
*
* Derived from "include/asm-i386/param.h"
*/
#ifndef _ASMS390_PARAM_H
#define _ASMS390_PARAM_H
#ifdef __KERNEL__
# define HZ CONFIG_HZ /* Internal kernel timer frequency */
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif
#ifndef HZ
#define HZ 100
#endif
#define EXEC_PAGESIZE 4096
#ifndef NOGROUP
#define NOGROUP (-1)
#endif
#define MAXHOSTNAMELEN 64 /* max length of hostname */
#include <asm-generic/param.h>
#endif
#endif /* _ASMS390_PARAM_H */
......@@ -10,5 +10,5 @@ obj-y += ccw_device.o cmf.o
obj-$(CONFIG_CHSC_SCH) += chsc_sch.o
obj-$(CONFIG_CCWGROUP) += ccwgroup.o
qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_perf.o qdio_setup.o
qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o
obj-$(CONFIG_QDIO) += qdio.o
......@@ -182,6 +182,34 @@ struct scssc_area {
u32:32;
} __attribute__ ((packed));
struct qdio_dev_perf_stat {
unsigned int adapter_int;
unsigned int qdio_int;
unsigned int pci_request_int;
unsigned int tasklet_inbound;
unsigned int tasklet_inbound_resched;
unsigned int tasklet_inbound_resched2;
unsigned int tasklet_outbound;
unsigned int siga_read;
unsigned int siga_write;
unsigned int siga_sync;
unsigned int inbound_call;
unsigned int inbound_handler;
unsigned int stop_polling;
unsigned int inbound_queue_full;
unsigned int outbound_call;
unsigned int outbound_handler;
unsigned int fast_requeue;
unsigned int target_full;
unsigned int eqbs;
unsigned int eqbs_partial;
unsigned int sqbs;
unsigned int sqbs_partial;
};
struct qdio_input_q {
/* input buffer acknowledgement flag */
int polling;
......@@ -269,6 +297,7 @@ struct qdio_irq {
u32 *dsci; /* address of device state change indicator */
struct ccw_device *cdev;
struct dentry *debugfs_dev;
struct dentry *debugfs_perf;
unsigned long int_parm;
struct subchannel_id schid;
......@@ -286,9 +315,10 @@ struct qdio_irq {
struct ciw aqueue;
struct qdio_ssqd_desc ssqd_desc;
void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
struct qdio_dev_perf_stat perf_stat;
int perf_stat_enabled;
/*
* Warning: Leave these members together at the end so they won't be
* cleared in qdio_setup_irq.
......@@ -311,6 +341,10 @@ struct qdio_irq {
(irq->qib.qfmt == QDIO_IQDIO_QFMT || \
css_general_characteristics.aif_osa)
#define qperf(qdev,attr) qdev->perf_stat.attr
#define qperf_inc(q,attr) if (q->irq_ptr->perf_stat_enabled) \
q->irq_ptr->perf_stat.attr++
/* the highest iqdio queue is used for multicast */
static inline int multicast_outbound(struct qdio_q *q)
{
......
......@@ -55,13 +55,11 @@ static int qstat_show(struct seq_file *m, void *v)
if (!q)
return 0;
seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
seq_printf(m, "ftc: %d\n", q->first_to_check);
seq_printf(m, "last_move: %d\n", q->last_move);
seq_printf(m, "polling: %d\n", q->u.in.polling);
seq_printf(m, "ack start: %d\n", q->u.in.ack_start);
seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
seq_printf(m, "DSCI: %d nr_used: %d\n",
*(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
seq_printf(m, "slsb buffer states:\n");
seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
......@@ -110,7 +108,6 @@ static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
if (!q)
return 0;
if (q->is_input_q)
xchg(q->irq_ptr->dsci, 1);
local_bh_disable();
......@@ -134,6 +131,98 @@ static const struct file_operations debugfs_fops = {
.release = single_release,
};
static char *qperf_names[] = {
"Assumed adapter interrupts",
"QDIO interrupts",
"Requested PCIs",
"Inbound tasklet runs",
"Inbound tasklet resched",
"Inbound tasklet resched2",
"Outbound tasklet runs",
"SIGA read",
"SIGA write",
"SIGA sync",
"Inbound calls",
"Inbound handler",
"Inbound stop_polling",
"Inbound queue full",
"Outbound calls",
"Outbound handler",
"Outbound fast_requeue",
"Outbound target_full",
"QEBSM eqbs",
"QEBSM eqbs partial",
"QEBSM sqbs",
"QEBSM sqbs partial"
};
static int qperf_show(struct seq_file *m, void *v)
{
struct qdio_irq *irq_ptr = m->private;
unsigned int *stat;
int i;
if (!irq_ptr)
return 0;
if (!irq_ptr->perf_stat_enabled) {
seq_printf(m, "disabled\n");
return 0;
}
stat = (unsigned int *)&irq_ptr->perf_stat;
for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
seq_printf(m, "%26s:\t%u\n",
qperf_names[i], *(stat + i));
return 0;
}
static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *off)
{
struct seq_file *seq = file->private_data;
struct qdio_irq *irq_ptr = seq->private;
unsigned long val;
char buf[8];
int ret;
if (!irq_ptr)
return 0;
if (count >= sizeof(buf))
return -EINVAL;
if (copy_from_user(&buf, ubuf, count))
return -EFAULT;
buf[count] = 0;
ret = strict_strtoul(buf, 10, &val);
if (ret < 0)
return ret;
switch (val) {
case 0:
irq_ptr->perf_stat_enabled = 0;
memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
break;
case 1:
irq_ptr->perf_stat_enabled = 1;
break;
}
return count;
}
static int qperf_seq_open(struct inode *inode, struct file *filp)
{
return single_open(filp, qperf_show,
filp->f_path.dentry->d_inode->i_private);
}
static struct file_operations debugfs_perf_fops = {
.owner = THIS_MODULE,
.open = qperf_seq_open,
.read = seq_read,
.write = qperf_seq_write,
.llseek = seq_lseek,
.release = single_release,
};
static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
{
char name[QDIO_DEBUGFS_NAME_LEN];
......@@ -156,6 +245,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
debugfs_root);
if (IS_ERR(irq_ptr->debugfs_dev))
irq_ptr->debugfs_dev = NULL;
irq_ptr->debugfs_perf = debugfs_create_file("statistics",
S_IFREG | S_IRUGO | S_IWUSR,
irq_ptr->debugfs_dev, irq_ptr,
&debugfs_perf_fops);
if (IS_ERR(irq_ptr->debugfs_perf))
irq_ptr->debugfs_perf = NULL;
for_each_input_queue(irq_ptr, q, i)
setup_debugfs_entry(q, cdev);
for_each_output_queue(irq_ptr, q, i)
......@@ -171,6 +268,7 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd
debugfs_remove(q->debugfs_q);
for_each_output_queue(irq_ptr, q, i)
debugfs_remove(q->debugfs_q);
debugfs_remove(irq_ptr->debugfs_perf);
debugfs_remove(irq_ptr->debugfs_dev);
}
......
......@@ -22,7 +22,6 @@
#include "device.h"
#include "qdio.h"
#include "qdio_debug.h"
#include "qdio_perf.h"
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\
"Jan Glauber <jang@linux.vnet.ibm.com>");
......@@ -126,7 +125,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
int rc;
BUG_ON(!q->irq_ptr->sch_token);
qdio_perf_stat_inc(&perf_stats.debug_eqbs_all);
qperf_inc(q, eqbs);
if (!q->is_input_q)
nr += q->irq_ptr->nr_input_qs;
......@@ -139,7 +138,7 @@ again:
* buffers later.
*/
if ((ccq == 96) && (count != tmp_count)) {
qdio_perf_stat_inc(&perf_stats.debug_eqbs_incomplete);
qperf_inc(q, eqbs_partial);
return (count - tmp_count);
}
......@@ -182,7 +181,7 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start,
return 0;
BUG_ON(!q->irq_ptr->sch_token);
qdio_perf_stat_inc(&perf_stats.debug_sqbs_all);
qperf_inc(q, sqbs);
if (!q->is_input_q)
nr += q->irq_ptr->nr_input_qs;
......@@ -191,7 +190,7 @@ again:
rc = qdio_check_ccq(q, ccq);
if (rc == 1) {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq);
qdio_perf_stat_inc(&perf_stats.debug_sqbs_incomplete);
qperf_inc(q, sqbs_partial);
goto again;
}
if (rc < 0) {
......@@ -285,7 +284,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
return 0;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
qdio_perf_stat_inc(&perf_stats.siga_sync);
qperf_inc(q, siga_sync);
cc = do_siga_sync(q->irq_ptr->schid, output, input);
if (cc)
......@@ -350,7 +349,7 @@ static inline int qdio_siga_input(struct qdio_q *q)
int cc;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr);
qdio_perf_stat_inc(&perf_stats.siga_in);
qperf_inc(q, siga_read);
cc = do_siga_input(q->irq_ptr->schid, q->mask);
if (cc)
......@@ -382,7 +381,7 @@ static inline void qdio_stop_polling(struct qdio_q *q)
return;
q->u.in.polling = 0;
qdio_perf_stat_inc(&perf_stats.debug_stop_polling);
qperf_inc(q, stop_polling);
/* show the card that we are not polling anymore */
if (is_qebsm(q)) {
......@@ -400,7 +399,7 @@ static void announce_buffer_error(struct qdio_q *q, int count)
/* special handling for no target buffer empty */
if ((!q->is_input_q &&
(q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) {
qdio_perf_stat_inc(&perf_stats.outbound_target_full);
qperf_inc(q, target_full);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x",
q->first_to_check);
return;
......@@ -487,7 +486,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
inbound_primed(q, count);
q->first_to_check = add_buf(q->first_to_check, count);
if (atomic_sub(count, &q->nr_buf_used) == 0)
qdio_perf_stat_inc(&perf_stats.inbound_queue_full);
qperf_inc(q, inbound_queue_full);
break;
case SLSB_P_INPUT_ERROR:
announce_buffer_error(q, count);
......@@ -567,9 +566,10 @@ static void qdio_kick_handler(struct qdio_q *q)
count = sub_buf(end, start);
if (q->is_input_q) {
qdio_perf_stat_inc(&perf_stats.inbound_handler);
qperf_inc(q, inbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count);
} else
qperf_inc(q, outbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
start, count);
......@@ -583,24 +583,28 @@ static void qdio_kick_handler(struct qdio_q *q)
static void __qdio_inbound_processing(struct qdio_q *q)
{
qdio_perf_stat_inc(&perf_stats.tasklet_inbound);
qperf_inc(q, tasklet_inbound);
again:
if (!qdio_inbound_q_moved(q))
return;
qdio_kick_handler(q);
if (!qdio_inbound_q_done(q))
if (!qdio_inbound_q_done(q)) {
/* means poll time is not yet over */
qperf_inc(q, tasklet_inbound_resched);
goto again;
}
qdio_stop_polling(q);
/*
* We need to check again to not lose initiative after
* resetting the ACK state.
*/
if (!qdio_inbound_q_done(q))
if (!qdio_inbound_q_done(q)) {
qperf_inc(q, tasklet_inbound_resched2);
goto again;
}
}
void qdio_inbound_processing(unsigned long data)
......@@ -688,7 +692,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
return 0;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
qdio_perf_stat_inc(&perf_stats.siga_out);
qperf_inc(q, siga_write);
cc = qdio_siga_output(q, &busy_bit);
switch (cc) {
......@@ -711,7 +715,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
static void __qdio_outbound_processing(struct qdio_q *q)
{
qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
qperf_inc(q, tasklet_outbound);
BUG_ON(atomic_read(&q->nr_buf_used) < 0);
if (qdio_outbound_q_moved(q))
......@@ -739,12 +743,9 @@ static void __qdio_outbound_processing(struct qdio_q *q)
*/
if (qdio_outbound_q_done(q))
del_timer(&q->u.out.timer);
else {
if (!timer_pending(&q->u.out.timer)) {
else
if (!timer_pending(&q->u.out.timer))
mod_timer(&q->u.out.timer, jiffies + 10 * HZ);
qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer);
}
}
return;
sched:
......@@ -784,7 +785,7 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
static void __tiqdio_inbound_processing(struct qdio_q *q)
{
qdio_perf_stat_inc(&perf_stats.thinint_inbound);
qperf_inc(q, tasklet_inbound);
qdio_sync_after_thinint(q);
/*
......@@ -799,7 +800,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
qdio_kick_handler(q);
if (!qdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
qperf_inc(q, tasklet_inbound_resched);
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
tasklet_schedule(&q->tasklet);
return;
......@@ -812,7 +813,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
* resetting the ACK state.
*/
if (!qdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2);
qperf_inc(q, tasklet_inbound_resched2);
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
tasklet_schedule(&q->tasklet);
}
......@@ -851,8 +852,6 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
return;
qdio_perf_stat_inc(&perf_stats.pci_int);
for_each_input_queue(irq_ptr, q, i)
tasklet_schedule(&q->tasklet);
......@@ -923,8 +922,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
struct qdio_irq *irq_ptr = cdev->private->qdio_data;
int cstat, dstat;
qdio_perf_stat_inc(&perf_stats.qdio_int);
if (!intparm || !irq_ptr) {
DBF_ERROR("qint:%4x", cdev->private->schid.sch_no);
return;
......@@ -1383,6 +1380,8 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags,
{
int used, diff;
qperf_inc(q, inbound_call);
if (!q->u.in.polling)
goto set;
......@@ -1438,14 +1437,16 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
unsigned char state;
int used, rc = 0;
qdio_perf_stat_inc(&perf_stats.outbound_handler);
qperf_inc(q, outbound_call);
count = set_buf_states(q, bufnr, SLSB_CU_OUTPUT_PRIMED, count);
used = atomic_add_return(count, &q->nr_buf_used);
BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q);
if (callflags & QDIO_FLAG_PCI_OUT)
if (callflags & QDIO_FLAG_PCI_OUT) {
q->u.out.pci_out_enabled = 1;
qperf_inc(q, pci_request_int);
}
else
q->u.out.pci_out_enabled = 0;
......@@ -1484,7 +1485,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
if (state != SLSB_CU_OUTPUT_PRIMED)
rc = qdio_kick_outbound_q(q);
else
qdio_perf_stat_inc(&perf_stats.fast_requeue);
qperf_inc(q, fast_requeue);
out:
tasklet_schedule(&q->tasklet);
......@@ -1540,16 +1541,11 @@ static int __init init_QDIO(void)
rc = qdio_debug_init();
if (rc)
goto out_ti;
rc = qdio_setup_perf_stats();
if (rc)
goto out_debug;
rc = tiqdio_register_thinints();
if (rc)
goto out_perf;
goto out_debug;
return 0;
out_perf:
qdio_remove_perf_stats();
out_debug:
qdio_debug_exit();
out_ti:
......@@ -1563,7 +1559,6 @@ static void __exit exit_QDIO(void)
{
tiqdio_unregister_thinints();
tiqdio_free_memory();
qdio_remove_perf_stats();
qdio_debug_exit();
qdio_setup_exit();
}
......
/*
* drivers/s390/cio/qdio_perf.c
*
* Copyright IBM Corp. 2008
*
* Author: Jan Glauber (jang@linux.vnet.ibm.com)
*/
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/ccwdev.h>
#include "cio.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
#include "chsc.h"
#include "qdio_debug.h"
#include "qdio_perf.h"
int qdio_performance_stats;
struct qdio_perf_stats perf_stats;
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *qdio_perf_pde;
#endif
/*
* procfs functions
*/
static int qdio_perf_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "Number of qdio interrupts\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.qdio_int));
seq_printf(m, "Number of PCI interrupts\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.pci_int));
seq_printf(m, "Number of adapter interrupts\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.thin_int));
seq_printf(m, "\n");
seq_printf(m, "Inbound tasklet runs\t\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.tasklet_inbound));
seq_printf(m, "Outbound tasklet runs\t\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.tasklet_outbound));
seq_printf(m, "Adapter interrupt tasklet runs/loops\t\t: %li/%li\n",
(long)atomic_long_read(&perf_stats.tasklet_thinint),
(long)atomic_long_read(&perf_stats.tasklet_thinint_loop));
seq_printf(m, "Adapter interrupt inbound tasklet runs/loops\t: %li/%li\n",
(long)atomic_long_read(&perf_stats.thinint_inbound),
(long)atomic_long_read(&perf_stats.thinint_inbound_loop));
seq_printf(m, "\n");
seq_printf(m, "Number of SIGA In issued\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.siga_in));
seq_printf(m, "Number of SIGA Out issued\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.siga_out));
seq_printf(m, "Number of SIGA Sync issued\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.siga_sync));
seq_printf(m, "\n");
seq_printf(m, "Number of inbound transfers\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.inbound_handler));
seq_printf(m, "Number of outbound transfers\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.outbound_handler));
seq_printf(m, "\n");
seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n",
(long)atomic_long_read(&perf_stats.fast_requeue));
seq_printf(m, "Number of outbound target full condition\t: %li\n",
(long)atomic_long_read(&perf_stats.outbound_target_full));
seq_printf(m, "Number of inbound queue full condition\t\t: %li\n",
(long)atomic_long_read(&perf_stats.inbound_queue_full));
seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
(long)atomic_long_read(&perf_stats.debug_tl_out_timer));
seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
(long)atomic_long_read(&perf_stats.debug_stop_polling));
seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n",
(long)atomic_long_read(&perf_stats.thinint_inbound_loop2));
seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n",
(long)atomic_long_read(&perf_stats.debug_eqbs_all),
(long)atomic_long_read(&perf_stats.debug_eqbs_incomplete));
seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n",
(long)atomic_long_read(&perf_stats.debug_sqbs_all),
(long)atomic_long_read(&perf_stats.debug_sqbs_incomplete));
seq_printf(m, "\n");
return 0;
}
static int qdio_perf_seq_open(struct inode *inode, struct file *filp)
{
return single_open(filp, qdio_perf_proc_show, NULL);
}
static const struct file_operations qdio_perf_proc_fops = {
.owner = THIS_MODULE,
.open = qdio_perf_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* sysfs functions
*/
static ssize_t qdio_perf_stats_show(struct bus_type *bus, char *buf)
{
return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
}
static ssize_t qdio_perf_stats_store(struct bus_type *bus,
const char *buf, size_t count)
{
unsigned long i;
if (strict_strtoul(buf, 16, &i) != 0)
return -EINVAL;
if ((i != 0) && (i != 1))
return -EINVAL;
if (i == qdio_performance_stats)
return count;
qdio_performance_stats = i;
/* reset performance statistics */
if (i == 0)
memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
return count;
}
static BUS_ATTR(qdio_performance_stats, 0644, qdio_perf_stats_show,
qdio_perf_stats_store);
int __init qdio_setup_perf_stats(void)
{
int rc;
rc = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
if (rc)
return rc;
#ifdef CONFIG_PROC_FS
memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
qdio_perf_pde = proc_create("qdio_perf", S_IFREG | S_IRUGO,
NULL, &qdio_perf_proc_fops);
#endif
return 0;
}
void qdio_remove_perf_stats(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("qdio_perf", NULL);
#endif
bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
}
/*
* drivers/s390/cio/qdio_perf.h
*
* Copyright IBM Corp. 2008
*
* Author: Jan Glauber (jang@linux.vnet.ibm.com)
*/
#ifndef QDIO_PERF_H
#define QDIO_PERF_H
#include <linux/types.h>
#include <asm/atomic.h>
struct qdio_perf_stats {
/* interrupt handler calls */
atomic_long_t qdio_int;
atomic_long_t pci_int;
atomic_long_t thin_int;
/* tasklet runs */
atomic_long_t tasklet_inbound;
atomic_long_t tasklet_outbound;
atomic_long_t tasklet_thinint;
atomic_long_t tasklet_thinint_loop;
atomic_long_t thinint_inbound;
atomic_long_t thinint_inbound_loop;
atomic_long_t thinint_inbound_loop2;
/* signal adapter calls */
atomic_long_t siga_out;
atomic_long_t siga_in;
atomic_long_t siga_sync;
/* misc */
atomic_long_t inbound_handler;
atomic_long_t outbound_handler;
atomic_long_t fast_requeue;
atomic_long_t outbound_target_full;
atomic_long_t inbound_queue_full;
/* for debugging */
atomic_long_t debug_tl_out_timer;
atomic_long_t debug_stop_polling;
atomic_long_t debug_eqbs_all;
atomic_long_t debug_eqbs_incomplete;
atomic_long_t debug_sqbs_all;
atomic_long_t debug_sqbs_incomplete;
};
extern struct qdio_perf_stats perf_stats;
extern int qdio_performance_stats;
static inline void qdio_perf_stat_inc(atomic_long_t *count)
{
if (qdio_performance_stats)
atomic_long_inc(count);
}
int qdio_setup_perf_stats(void);
void qdio_remove_perf_stats(void);
#endif
/*
* linux/drivers/s390/cio/thinint_qdio.c
*
* thin interrupt support for qdio
*
* Copyright 2000-2008 IBM Corp.
* Copyright 2000,2009 IBM Corp.
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
* Jan Glauber <jang@linux.vnet.ibm.com>
......@@ -19,7 +17,6 @@
#include "ioasm.h"
#include "qdio.h"
#include "qdio_debug.h"
#include "qdio_perf.h"
/*
* Restriction: only 63 iqdio subchannels would have its own indicator,
......@@ -132,8 +129,6 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data)
{
struct qdio_q *q;
qdio_perf_stat_inc(&perf_stats.thin_int);
/*
* SVS only when needed: issue SVS to benefit from iqdio interrupt
* avoidance (SVS clears adapter interrupt suppression overwrite)
......@@ -154,6 +149,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data)
list_for_each_entry_rcu(q, &tiq_list, entry)
/* only process queues from changed sets */
if (*q->irq_ptr->dsci) {
qperf_inc(q, adapter_int);
/* only clear it if the indicator is non-shared */
if (!shared_ind(q->irq_ptr))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment