Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2003

kernel-2.6.18-128.1.10.el5.src.rpm

From: Jan Glauber <jglauber@redhat.com>
Subject: Re: [RHEL5.1 PATCH] s390: runtime switch for qdio performance 	statistics
Date: Tue, 15 May 2007 09:34:48 +0000
Bugzilla: 228048
Message-Id: <1179221688.7368.11.camel@localhost.localdomain>
Changelog: [s390] runtime switch for qdio performance statistics

BZ 228048

Add a runtime switch for the qdio performance statistics.

The patch removes CONFIG_QDIO_PERF_STATS and adds a sysfs attribute
instead. We want to have the ability to turn the statistics on/off at
runtime.

Patch is upstream with 2.6.20, tested by IBM.
There should be no need to change the config files since the option is
turned off.

Note: although the config option is CONFIG_QDIO_PERF_STATS the code removes
QDIO_PERFORMANCE_STATS which looks esoteric but is caused by this define in
qdio.h:

#ifdef CONFIG_QDIO_PERF_STATS
#define QDIO_PERFORMANCE_STATS
#endif /* CONFIG_QDIO_PERF_STATS */

Jan

---
 arch/s390/Kconfig       |    8 -
 arch/s390/defconfig     |    1 
 drivers/s390/cio/qdio.c |  303 ++++++++++++++++++++++++++++--------------------
 drivers/s390/cio/qdio.h |   56 +++++---
 4 files changed, 216 insertions(+), 152 deletions(-)

Index: linux-rhel5/arch/s390/Kconfig
===================================================================
--- linux-rhel5.orig/arch/s390/Kconfig	2007-03-15 17:11:51.000000000 +0100
+++ linux-rhel5/arch/s390/Kconfig	2007-05-08 15:54:33.000000000 +0200
@@ -250,14 +250,6 @@ config QDIO
 
 	  If unsure, say Y.
 
-config QDIO_PERF_STATS
-	bool "Performance statistics in /proc"
-	depends on QDIO
-	help
-	  Say Y here to get performance statistics in /proc/qdio_perf
-
-	  If unsure, say N.
-
 config QDIO_DEBUG
 	bool "Extended debugging information"
 	depends on QDIO
Index: linux-rhel5/arch/s390/defconfig
===================================================================
--- linux-rhel5.orig/arch/s390/defconfig	2007-03-15 17:11:51.000000000 +0100
+++ linux-rhel5/arch/s390/defconfig	2007-05-08 15:54:20.000000000 +0200
@@ -127,7 +127,6 @@ CONFIG_RESOURCES_64BIT=y
 #
 CONFIG_MACHCHK_WARNING=y
 CONFIG_QDIO=y
-# CONFIG_QDIO_PERF_STATS is not set
 # CONFIG_QDIO_DEBUG is not set
 
 #
Index: linux-rhel5/drivers/s390/cio/qdio.c
===================================================================
--- linux-rhel5.orig/drivers/s390/cio/qdio.c	2007-03-15 17:11:55.000000000 +0100
+++ linux-rhel5/drivers/s390/cio/qdio.c	2007-05-08 16:29:47.000000000 +0200
@@ -65,12 +65,11 @@ MODULE_LICENSE("GPL");
 /******************** HERE WE GO ***********************************/
 
 static const char version[] = "QDIO base support version 2";
+extern struct bus_type ccw_bus_type;
 
-#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_performance_stats = 0;
 static int proc_perf_file_registration;
-static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
 static struct qdio_perf_stats perf_stats;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 static int hydra_thinints;
 static int is_passthrough = 0;
@@ -111,6 +110,31 @@ qdio_min(int a,int b)
 }
 
 /***************** SCRUBBER HELPER ROUTINES **********************/
+#ifdef CONFIG_64BIT
+static inline void qdio_perf_stat_inc(atomic64_t *count)
+{
+	if (qdio_performance_stats)
+		atomic64_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic64_t *count)
+{
+	if (qdio_performance_stats)
+		atomic64_dec(count);
+}
+#else /* CONFIG_64BIT */
+static inline void qdio_perf_stat_inc(atomic_t *count)
+{
+	if (qdio_performance_stats)
+		atomic_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic_t *count)
+{
+	if (qdio_performance_stats)
+		atomic_dec(count);
+}
+#endif /* CONFIG_64BIT */
 
 static inline __u64 
 qdio_get_micros(void)
@@ -275,9 +299,7 @@ qdio_siga_sync(struct qdio_q *q, unsigne
 	QDIO_DBF_TEXT4(0,trace,"sigasync");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.siga_syncs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.siga_syncs);
 
 	cc = do_siga_sync(q->schid, gpr2, gpr3);
 	if (cc)
@@ -322,9 +344,7 @@ qdio_siga_output(struct qdio_q *q)
 	__u32 busy_bit;
 	__u64 start_time=0;
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.siga_outs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.siga_outs);
 
 	QDIO_DBF_TEXT4(0,trace,"sigaout");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -358,9 +378,7 @@ qdio_siga_input(struct qdio_q *q)
 	QDIO_DBF_TEXT4(0,trace,"sigain");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.siga_ins++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.siga_ins);
 
 	cc = do_siga_input(q->schid, q->mask);
 	
@@ -954,9 +972,7 @@ __qdio_outbound_processing(struct qdio_q
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-		o_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+		qdio_perf_stat_inc(&perf_stats.outbound_tl_runs_resched);
 		/* as we're sissies, we'll check next time */
 		if (likely(!atomic_read(&q->is_in_shutdown))) {
 			qdio_mark_q(q);
@@ -964,10 +980,8 @@ __qdio_outbound_processing(struct qdio_q
 		}
 		return;
 	}
-#ifdef QDIO_PERFORMANCE_STATS
-	o_p_nc++;
-	perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.outbound_tl_runs);
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 	/* see comment in qdio_kick_outbound_q */
 	siga_attempts=atomic_read(&q->busy_siga_counter);
@@ -1142,16 +1156,6 @@ qdio_has_inbound_q_moved(struct qdio_q *
 {
 	int i;
 
-#ifdef QDIO_PERFORMANCE_STATS
-	static int old_pcis=0;
-	static int old_thinints=0;
-
-	if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
-		perf_stats.start_time_inbound=NOW;
-	else
-		old_pcis=perf_stats.pcis;
-#endif /* QDIO_PERFORMANCE_STATS */
-
 	i=qdio_get_inbound_buffer_frontier(q);
 	if ( (i!=GET_SAVED_FRONTIER(q)) ||
 	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {
@@ -1340,10 +1344,7 @@ qdio_kick_inbound_handler(struct qdio_q 
 	q->siga_error=0;
 	q->error_status_flags=0;
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
-	perf_stats.inbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.inbound_cnt);
 }
 
 static inline void
@@ -1363,9 +1364,7 @@ __tiqdio_inbound_processing(struct qdio_
 	 */
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-		ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+		qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
 		/* 
 		 * as we might just be about to stop polling, we make
 		 * sure that we check again at least once more 
@@ -1373,9 +1372,7 @@ __tiqdio_inbound_processing(struct qdio_
 		tiqdio_sched_tl();
 		return;
 	}
-#ifdef QDIO_PERFORMANCE_STATS
-	ii_p_nc++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs);
 	if (unlikely(atomic_read(&q->is_in_shutdown))) {
 		qdio_unmark_q(q);
 		goto out;
@@ -1416,11 +1413,10 @@ __tiqdio_inbound_processing(struct qdio_
 		irq_ptr = (struct qdio_irq*)q->irq_ptr;
 		for (i=0;i<irq_ptr->no_output_qs;i++) {
 			oq = irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
-			perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
-			if (!qdio_is_outbound_q_done(oq))
+			if (!qdio_is_outbound_q_done(oq)) {
+				qdio_perf_stat_dec(&perf_stats.tl_runs);
 				__qdio_outbound_processing(oq);
+			}
 		}
 	}
 
@@ -1457,9 +1453,7 @@ __qdio_inbound_processing(struct qdio_q 
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-		i_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+		qdio_perf_stat_inc(&perf_stats.inbound_tl_runs_resched);
 		/* as we're sissies, we'll check next time */
 		if (likely(!atomic_read(&q->is_in_shutdown))) {
 			qdio_mark_q(q);
@@ -1467,10 +1461,8 @@ __qdio_inbound_processing(struct qdio_q 
 		}
 		return;
 	}
-#ifdef QDIO_PERFORMANCE_STATS
-	i_p_nc++;
-	perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.inbound_tl_runs);
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 again:
 	if (qdio_has_inbound_q_moved(q)) {
@@ -1516,9 +1508,7 @@ tiqdio_reset_processing_state(struct qdi
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-		ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+		qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
 		/* 
 		 * as we might just be about to stop polling, we make
 		 * sure that we check again at least once more 
@@ -1609,9 +1599,7 @@ tiqdio_tl(unsigned long data)
 {
 	QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 	tiqdio_inbound_checks();
 }
@@ -1918,10 +1906,7 @@ tiqdio_thinint_handler(void)
 {
 	QDIO_DBF_TEXT4(0,trace,"thin_int");
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.thinints++;
-	perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.thinints);
 
 	/* SVS only when needed:
 	 * issue SVS to benefit from iqdio interrupt avoidance
@@ -1976,18 +1961,13 @@ qdio_handle_pci(struct qdio_irq *irq_ptr
 	int i;
 	struct qdio_q *q;
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.pcis++;
-	perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.pcis);
 	for (i=0;i<irq_ptr->no_input_qs;i++) {
 		q=irq_ptr->input_qs[i];
 		if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
 			qdio_mark_q(q);
 		else {
-#ifdef QDIO_PERFORMANCE_STATS
-			perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
+			qdio_perf_stat_dec(&perf_stats.tl_runs);
 			__qdio_inbound_processing(q);
 		}
 	}
@@ -1995,11 +1975,9 @@ qdio_handle_pci(struct qdio_irq *irq_ptr
 		return;
 	for (i=0;i<irq_ptr->no_output_qs;i++) {
 		q=irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
-		perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
 		if (qdio_is_outbound_q_done(q))
 			continue;
+		qdio_perf_stat_dec(&perf_stats.tl_runs);
 		if (!irq_ptr->sync_done_on_outb_pcis)
 			SYNC_MEMORY;
 		__qdio_outbound_processing(q);
@@ -3458,19 +3436,13 @@ do_qdio_handle_outbound(struct qdio_q *q
 	struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
 
 	/* This is the outbound handling of queues */
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.start_time_outbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 	qdio_do_qdio_fill_output(q,qidx,count,buffers);
 
 	used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 
 	if (callflags&QDIO_FLAG_DONT_SIGA) {
-#ifdef QDIO_PERFORMANCE_STATS
-		perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-		perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+		qdio_perf_stat_inc(&perf_stats.outbound_cnt);
 		return;
 	}
 	if (q->is_iqdio_q) {
@@ -3500,9 +3472,7 @@ do_qdio_handle_outbound(struct qdio_q *q
 				qdio_kick_outbound_q(q);
 			} else {
 				QDIO_DBF_TEXT3(0,trace, "fast-req");
-#ifdef QDIO_PERFORMANCE_STATS
-				perf_stats.fast_reqs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+				qdio_perf_stat_inc(&perf_stats.fast_reqs);
 			}
 		}
 		/* 
@@ -3513,10 +3483,7 @@ do_qdio_handle_outbound(struct qdio_q *q
 		__qdio_outbound_processing(q);
 	}
 
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-	perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+	qdio_perf_stat_inc(&perf_stats.outbound_cnt);
 }
 
 /* count must be 1 in iqdio */
@@ -3574,7 +3541,6 @@ do_QDIO(struct ccw_device *cdev,unsigned
 	return 0;
 }
 
-#ifdef QDIO_PERFORMANCE_STATS
 static int
 qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
 			int buffer_length, int *eof, void *data)
@@ -3587,45 +3553,77 @@ qdio_perf_procfile_read(char *buffer, ch
 		return 0;
 
 #define _OUTP_IT(x...) c+=sprintf(buffer+c,x)
-	_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
-	_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
-	_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
-	_OUTP_IT("Number of tasklet runs (total)                  : %u\n",
-		 perf_stats.tl_runs);
+#ifdef CONFIG_64BIT
+	_OUTP_IT("Number of tasklet runs (total)                  : %li\n",
+		 (long)atomic64_read(&perf_stats.tl_runs));
+	_OUTP_IT("Inbound tasklet runs      tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.inbound_tl_runs),
+		 (long)atomic64_read(&perf_stats.inbound_tl_runs_resched));
+	_OUTP_IT("Inbound-thin tasklet runs tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.inbound_thin_tl_runs),
+		 (long)atomic64_read(&perf_stats.inbound_thin_tl_runs_resched));
+	_OUTP_IT("Outbound tasklet runs     tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.outbound_tl_runs),
+		 (long)atomic64_read(&perf_stats.outbound_tl_runs_resched));
+	_OUTP_IT("\n");
+	_OUTP_IT("Number of SIGA sync's issued                    : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_syncs));
+	_OUTP_IT("Number of SIGA in's issued                      : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_ins));
+	_OUTP_IT("Number of SIGA out's issued                     : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_outs));
+	_OUTP_IT("Number of PCIs caught                           : %li\n",
+		 (long)atomic64_read(&perf_stats.pcis));
+	_OUTP_IT("Number of adapter interrupts caught             : %li\n",
+		 (long)atomic64_read(&perf_stats.thinints));
+	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %li\n",
+		 (long)atomic64_read(&perf_stats.fast_reqs));
 	_OUTP_IT("\n");
-	_OUTP_IT("Number of SIGA sync's issued                    : %u\n",
-		 perf_stats.siga_syncs);
-	_OUTP_IT("Number of SIGA in's issued                      : %u\n",
-		 perf_stats.siga_ins);
-	_OUTP_IT("Number of SIGA out's issued                     : %u\n",
-		 perf_stats.siga_outs);
-	_OUTP_IT("Number of PCIs caught                           : %u\n",
-		 perf_stats.pcis);
-	_OUTP_IT("Number of adapter interrupts caught             : %u\n",
-		 perf_stats.thinints);
-	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %u\n",
-		 perf_stats.fast_reqs);
+	_OUTP_IT("Number of inbound transfers                     : %li\n",
+		 (long)atomic64_read(&perf_stats.inbound_cnt));
+	_OUTP_IT("Number of do_QDIOs outbound                     : %li\n",
+		 (long)atomic64_read(&perf_stats.outbound_cnt));
+#else /* CONFIG_64BIT */
+	_OUTP_IT("Number of tasklet runs (total)                  : %i\n",
+		 atomic_read(&perf_stats.tl_runs));
+	_OUTP_IT("Inbound tasklet runs      tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.inbound_tl_runs),
+		 atomic_read(&perf_stats.inbound_tl_runs_resched));
+	_OUTP_IT("Inbound-thin tasklet runs tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.inbound_thin_tl_runs),
+		 atomic_read(&perf_stats.inbound_thin_tl_runs_resched));
+	_OUTP_IT("Outbound tasklet runs     tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.outbound_tl_runs),
+		 atomic_read(&perf_stats.outbound_tl_runs_resched));
 	_OUTP_IT("\n");
-	_OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
-		 perf_stats.inbound_time);
-	_OUTP_IT("Number of inbound transfers                     : %u\n",
-		 perf_stats.inbound_cnt);
-	_OUTP_IT("Total time of all outbound do_QDIOs (us)        : %u\n",
-		 perf_stats.outbound_time);
-	_OUTP_IT("Number of do_QDIOs outbound                     : %u\n",
-		 perf_stats.outbound_cnt);
+	_OUTP_IT("Number of SIGA sync's issued                    : %i\n",
+		 atomic_read(&perf_stats.siga_syncs));
+	_OUTP_IT("Number of SIGA in's issued                      : %i\n",
+		 atomic_read(&perf_stats.siga_ins));
+	_OUTP_IT("Number of SIGA out's issued                     : %i\n",
+		 atomic_read(&perf_stats.siga_outs));
+	_OUTP_IT("Number of PCIs caught                           : %i\n",
+		 atomic_read(&perf_stats.pcis));
+	_OUTP_IT("Number of adapter interrupts caught             : %i\n",
+		 atomic_read(&perf_stats.thinints));
+	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %i\n",
+		 atomic_read(&perf_stats.fast_reqs));
+	_OUTP_IT("\n");
+	_OUTP_IT("Number of inbound transfers                     : %i\n",
+		 atomic_read(&perf_stats.inbound_cnt));
+	_OUTP_IT("Number of do_QDIOs outbound                     : %i\n",
+		 atomic_read(&perf_stats.outbound_cnt));
+#endif /* CONFIG_64BIT */
 	_OUTP_IT("\n");
 
         return c;
 }
 
 static struct proc_dir_entry *qdio_perf_proc_file;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 static void
 qdio_add_procfs_entry(void)
 {
-#ifdef QDIO_PERFORMANCE_STATS
         proc_perf_file_registration=0;
 	qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
 					      S_IFREG|0444,&proc_root);
@@ -3637,20 +3635,81 @@ qdio_add_procfs_entry(void)
                 QDIO_PRINT_WARN("was not able to register perf. " \
 				"proc-file (%i).\n",
 				proc_perf_file_registration);
-#endif /* QDIO_PERFORMANCE_STATS */
 }
 
 static void
 qdio_remove_procfs_entry(void)
 {
-#ifdef QDIO_PERFORMANCE_STATS
-	perf_stats.tl_runs=0;
-
         if (!proc_perf_file_registration) /* means if it went ok earlier */
 		remove_proc_entry(QDIO_PERF,&proc_root);
-#endif /* QDIO_PERFORMANCE_STATS */
 }
 
+/**
+ * attributes in sysfs
+ *****************************************************************************/
+
+static ssize_t
+qdio_performance_stats_show(struct bus_type *bus, char *buf)
+{
+	return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
+}
+
+static ssize_t
+qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
+{
+	char *tmp;
+	int i;
+
+	i = simple_strtoul(buf, &tmp, 16);
+	if ((i == 0) || (i == 1)) {
+		if (i == qdio_performance_stats)
+			return count;
+		qdio_performance_stats = i;
+		if (i==0) {
+			/* reset perf. stat. info */
+#ifdef CONFIG_64BIT
+			atomic64_set(&perf_stats.tl_runs, 0);
+			atomic64_set(&perf_stats.outbound_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_tl_runs_resched, 0);
+			atomic64_set(&perf_stats.inbound_thin_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_thin_tl_runs_resched,
+				     0);
+			atomic64_set(&perf_stats.siga_outs, 0);
+			atomic64_set(&perf_stats.siga_ins, 0);
+			atomic64_set(&perf_stats.siga_syncs, 0);
+			atomic64_set(&perf_stats.pcis, 0);
+			atomic64_set(&perf_stats.thinints, 0);
+			atomic64_set(&perf_stats.fast_reqs, 0);
+			atomic64_set(&perf_stats.outbound_cnt, 0);
+			atomic64_set(&perf_stats.inbound_cnt, 0);
+#else /* CONFIG_64BIT */
+			atomic_set(&perf_stats.tl_runs, 0);
+			atomic_set(&perf_stats.outbound_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_tl_runs_resched, 0);
+			atomic_set(&perf_stats.inbound_thin_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_thin_tl_runs_resched, 0);
+			atomic_set(&perf_stats.siga_outs, 0);
+			atomic_set(&perf_stats.siga_ins, 0);
+			atomic_set(&perf_stats.siga_syncs, 0);
+			atomic_set(&perf_stats.pcis, 0);
+			atomic_set(&perf_stats.thinints, 0);
+			atomic_set(&perf_stats.fast_reqs, 0);
+			atomic_set(&perf_stats.outbound_cnt, 0);
+			atomic_set(&perf_stats.inbound_cnt, 0);
+#endif /* CONFIG_64BIT */
+		}
+	} else {
+		QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
+		return -EINVAL;
+	}
+	return count;
+}
+
+static BUS_ATTR(qdio_performance_stats, 0644, qdio_performance_stats_show,
+			qdio_performance_stats_store);
+
 static void
 tiqdio_register_thinints(void)
 {
@@ -3796,9 +3855,7 @@ static int __init
 init_QDIO(void)
 {
 	int res;
-#ifdef QDIO_PERFORMANCE_STATS
 	void *ptr;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 	printk("qdio: loading %s\n",version);
 
@@ -3811,13 +3868,12 @@ init_QDIO(void)
 		return res;
 
 	QDIO_DBF_TEXT0(0,setup,"initQDIO");
+	res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
 
-#ifdef QDIO_PERFORMANCE_STATS
-       	memset((void*)&perf_stats,0,sizeof(perf_stats));
+	memset((void*)&perf_stats,0,sizeof(perf_stats));
 	QDIO_DBF_TEXT0(0,setup,"perfstat");
 	ptr=&perf_stats;
 	QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
-#endif /* QDIO_PERFORMANCE_STATS */
 
 	qdio_add_procfs_entry();
 
@@ -3841,8 +3897,9 @@ cleanup_QDIO(void)
 	qdio_release_qdio_memory();
 	qdio_unregister_dbf_views();
 	mempool_destroy(qdio_mempool_scssc);
+	bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
 
-  	printk("qdio: %s: module removed\n",version);
+	printk("qdio: %s: module removed\n",version);
 }
 
 module_init(init_QDIO);
Index: linux-rhel5/drivers/s390/cio/qdio.h
===================================================================
--- linux-rhel5.orig/drivers/s390/cio/qdio.h	2007-03-15 17:11:55.000000000 +0100
+++ linux-rhel5/drivers/s390/cio/qdio.h	2007-05-08 15:55:00.000000000 +0200
@@ -12,10 +12,6 @@
 #endif /* CONFIG_QDIO_DEBUG */
 #define QDIO_USE_PROCESSING_STATE
 
-#ifdef CONFIG_QDIO_PERF_STATS
-#define QDIO_PERFORMANCE_STATS
-#endif /* CONFIG_QDIO_PERF_STATS */
-
 #define QDIO_MINIMAL_BH_RELIEF_TIME 16
 #define QDIO_TIMER_POLL_VALUE 1
 #define IQDIO_TIMER_POLL_VALUE 1
@@ -503,25 +499,45 @@ do_clear_global_summary(void)
 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
 
-#ifdef QDIO_PERFORMANCE_STATS
 struct qdio_perf_stats {
-	unsigned int tl_runs;
+#ifdef CONFIG_64BIT
+	atomic64_t tl_runs;
+	atomic64_t outbound_tl_runs;
+	atomic64_t outbound_tl_runs_resched;
+	atomic64_t inbound_tl_runs;
+	atomic64_t inbound_tl_runs_resched;
+	atomic64_t inbound_thin_tl_runs;
+	atomic64_t inbound_thin_tl_runs_resched;
+
+	atomic64_t siga_outs;
+	atomic64_t siga_ins;
+	atomic64_t siga_syncs;
+	atomic64_t pcis;
+	atomic64_t thinints;
+	atomic64_t fast_reqs;
 
-	unsigned int siga_outs;
-	unsigned int siga_ins;
-	unsigned int siga_syncs;
-	unsigned int pcis;
-	unsigned int thinints;
-	unsigned int fast_reqs;
-
-	__u64 start_time_outbound;
-	unsigned int outbound_cnt;
-	unsigned int outbound_time;
-	__u64 start_time_inbound;
-	unsigned int inbound_cnt;
-	unsigned int inbound_time;
+	atomic64_t outbound_cnt;
+	atomic64_t inbound_cnt;
+#else /* CONFIG_64BIT */
+	atomic_t tl_runs;
+	atomic_t outbound_tl_runs;
+	atomic_t outbound_tl_runs_resched;
+	atomic_t inbound_tl_runs;
+	atomic_t inbound_tl_runs_resched;
+	atomic_t inbound_thin_tl_runs;
+	atomic_t inbound_thin_tl_runs_resched;
+
+	atomic_t siga_outs;
+	atomic_t siga_ins;
+	atomic_t siga_syncs;
+	atomic_t pcis;
+	atomic_t thinints;
+	atomic_t fast_reqs;
+
+	atomic_t outbound_cnt;
+	atomic_t inbound_cnt;
+#endif /* CONFIG_64BIT */
 };
-#endif /* QDIO_PERFORMANCE_STATS */
 
 #define atomic_swap(a,b) xchg((int*)a.counter,b)