* [PATCH] s390: qeth performance.
@ 2004-08-05 13:14 Martin Schwidefsky
2004-08-06 12:49 ` Jörn Engel
0 siblings, 1 reply; 3+ messages in thread
From: Martin Schwidefsky @ 2004-08-05 13:14 UTC (permalink / raw)
To: akpm, linux-kernel
[PATCH] s390: qeth performance.
From: Thomas Spatzier <tspat@de.ibm.com>
qeth network driver performance improvements. The ping time on the
HiperSockets interface drops from 250 usecs to 50 usecs and the 1 bytes
request/response test improves from 70000 to 110000 transactions.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diffstat:
arch/s390/Kconfig | 9 ++
arch/s390/defconfig | 1
drivers/s390/cio/qdio.c | 69 +++++++++++++---
drivers/s390/cio/qdio.h | 56 ++++++-------
drivers/s390/net/qeth.h | 12 ++
drivers/s390/net/qeth_main.c | 183 +++++++++++++++++++++++++++++--------------
6 files changed, 230 insertions(+), 100 deletions(-)
diff -urN linux-2.6/arch/s390/Kconfig linux-2.6-s390/arch/s390/Kconfig
--- linux-2.6/arch/s390/Kconfig Thu Aug 5 14:20:32 2004
+++ linux-2.6-s390/arch/s390/Kconfig Thu Aug 5 14:21:02 2004
@@ -181,6 +181,15 @@
If unsure, say N.
+config QDIO_DEBUG
+ bool "Extended debugging information"
+ depends on QDIO
+ help
+ Say Y here to get extended debugging output in /proc/s390dbf/qdio...
+ Warning: this option reduces the performance of the QDIO module.
+
+ If unsure, say N.
+
comment "Misc"
config PREEMPT
diff -urN linux-2.6/arch/s390/defconfig linux-2.6-s390/arch/s390/defconfig
--- linux-2.6/arch/s390/defconfig Thu Aug 5 14:20:59 2004
+++ linux-2.6-s390/arch/s390/defconfig Thu Aug 5 14:21:02 2004
@@ -70,6 +70,7 @@
CONFIG_MACHCHK_WARNING=y
CONFIG_QDIO=y
# CONFIG_QDIO_PERF_STATS is not set
+# CONFIG_QDIO_DEBUG is not set
#
# Misc
diff -urN linux-2.6/drivers/s390/cio/qdio.c linux-2.6-s390/drivers/s390/cio/qdio.c
--- linux-2.6/drivers/s390/cio/qdio.c Thu Aug 5 14:20:39 2004
+++ linux-2.6-s390/drivers/s390/cio/qdio.c Thu Aug 5 14:21:02 2004
@@ -56,7 +56,7 @@
#include "ioasm.h"
#include "chsc.h"
-#define VERSION_QDIO_C "$Revision: 1.83 $"
+#define VERSION_QDIO_C "$Revision: 1.84 $"
/****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -87,10 +87,10 @@
static debug_info_t *qdio_dbf_sbal;
static debug_info_t *qdio_dbf_trace;
static debug_info_t *qdio_dbf_sense;
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
static debug_info_t *qdio_dbf_slsb_out;
static debug_info_t *qdio_dbf_slsb_in;
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
/* iQDIO stuff: */
static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
@@ -514,10 +514,13 @@
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
+#ifdef CONFIG_QDIO_DEBUG
if (no_used) {
sprintf(dbf_text,"oqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
@@ -525,6 +528,7 @@
QDIO_DBF_TEXT4(0,trace,"oqisdone");
}
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
return (no_used==0);
}
@@ -552,10 +556,12 @@
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
QDIO_DBF_TEXT4(0,trace,"kickoutq");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
if (!q->siga_out)
return;
@@ -593,16 +599,18 @@
switch (result) {
case 0:
- /* went smooth this time, reset timestamp */
+ /* went smooth this time, reset timestamp */
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT3(0,trace,"cc2reslv");
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text);
q->timing.busy_start=0;
+#endif /* CONFIG_QDIO_DEBUG */
break;
case (2|QDIO_SIGA_ERROR_B_BIT_SET):
/* cc=2 and busy bit: */
- atomic_inc(&q->busy_siga_counter);
+ atomic_inc(&q->busy_siga_counter);
/* if the last siga was successful, save
* timestamp here */
@@ -616,9 +624,11 @@
break;
}
QDIO_DBF_TEXT2(0,trace,"cc2REPRT");
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
/* else fallthrough and report error */
default:
/* for plain cc=1, 2 or 3: */
@@ -635,7 +645,9 @@
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
start = q->first_element_to_kick;
/* last_move_ftc was just updated */
@@ -645,11 +657,13 @@
count = (end+QDIO_MAX_BUFFERS_PER_Q+1-start)&
(QDIO_MAX_BUFFERS_PER_Q-1);
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"kickouth");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (q->state==QDIO_IRQ_STATE_ACTIVE)
q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT|
@@ -732,7 +746,9 @@
int f,f_mod_no;
volatile char *slsb;
int first_not_to_check;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif /* CONFIG_QDIO_DEBUG */
#ifdef QDIO_USE_PROCESSING_STATE
int last_position=-1;
#endif /* QDIO_USE_PROCESSING_STATE */
@@ -806,8 +822,10 @@
/* P_ERROR means frontier is reached, break and report error */
case SLSB_P_INPUT_ERROR:
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"inperr%2x",f_mod_no);
QDIO_DBF_TEXT3(1,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);
/* kind of process the buffer */
@@ -884,13 +902,16 @@
iqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
/* propagate the change from 82 to 80 through VM */
SYNC_MEMORY;
+#ifdef CONFIG_QDIO_DEBUG
if (no_used) {
sprintf(dbf_text,"iqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
@@ -898,6 +919,7 @@
QDIO_DBF_TEXT4(0,trace,"iniqisdo");
}
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
if (!no_used)
return 1;
@@ -933,7 +955,9 @@
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
@@ -968,16 +992,20 @@
* has (probably) not moved (see qdio_inbound_processing)
*/
if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) {
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisdon");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
return 1;
} else {
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisntd");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
return 0;
}
}
@@ -986,7 +1014,9 @@
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
QDIO_DBF_TEXT4(0,trace,"kickinh");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -1004,8 +1034,10 @@
i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
}
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (likely(q->state==QDIO_IRQ_STATE_ACTIVE))
q->handler(q->cdev,
@@ -1622,11 +1654,13 @@
qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
{
int i;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
QDIO_DBF_TEXT5(0,trace,"newstate");
sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state);
QDIO_DBF_TEXT5(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
irq_ptr->state=state;
for (i=0;i<irq_ptr->no_input_qs;i++)
@@ -1791,9 +1825,11 @@
int cstat,dstat;
char dbf_text[15];
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0, trace, "qint");
sprintf(dbf_text, "%s", cdev->dev.bus_id);
QDIO_DBF_TEXT4(0, trace, dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (!intparm) {
QDIO_PRINT_ERR("got unsolicited interrupt in qdio " \
@@ -1830,8 +1866,10 @@
qdio_irq_check_sense(irq_ptr->irq, irb);
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text, "state:%d", irq_ptr->state);
QDIO_DBF_TEXT4(0, trace, dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
@@ -1872,18 +1910,22 @@
int cc;
struct qdio_q *q;
struct qdio_irq *irq_ptr;
- char dbf_text[15]="SyncXXXX";
void *ptr;
+#ifdef CONFIG_QDIO_DEBUG
+ char dbf_text[15]="SyncXXXX";
+#endif
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
return -ENODEV;
+#ifdef CONFIG_QDIO_DEBUG
*((int*)(&dbf_text[4])) = irq_ptr->irq;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
*((int*)(&dbf_text[0]))=flags;
*((int*)(&dbf_text[4]))=queue_number;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
+#endif /* CONFIG_QDIO_DEBUG */
if (flags&QDIO_FLAG_SYNC_INPUT) {
q=irq_ptr->input_qs[queue_number];
@@ -3083,11 +3125,12 @@
unsigned int count,struct qdio_buffer *buffers)
{
struct qdio_irq *irq_ptr;
-
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[20];
sprintf(dbf_text,"doQD%04x",cdev->private->irq);
- QDIO_DBF_TEXT3(0,trace,dbf_text);
+ QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if ( (qidx>QDIO_MAX_BUFFERS_PER_Q) ||
(count>QDIO_MAX_BUFFERS_PER_Q) ||
@@ -3101,6 +3144,7 @@
if (!irq_ptr)
return -ENODEV;
+#ifdef CONFIG_QDIO_DEBUG
if (callflags&QDIO_FLAG_SYNC_INPUT)
QDIO_DBF_HEX3(0,trace,&irq_ptr->input_qs[queue_number],
sizeof(void*));
@@ -3111,6 +3155,7 @@
QDIO_DBF_TEXT3(0,trace,dbf_text);
sprintf(dbf_text,"qi%02xct%02x",qidx,count);
QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE)
return -EBUSY;
@@ -3261,12 +3306,12 @@
debug_unregister(qdio_dbf_sense);
if (qdio_dbf_trace)
debug_unregister(qdio_dbf_trace);
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
if (qdio_dbf_slsb_out)
debug_unregister(qdio_dbf_slsb_out);
if (qdio_dbf_slsb_in)
debug_unregister(qdio_dbf_slsb_in);
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
}
static int
@@ -3311,7 +3356,7 @@
debug_register_view(qdio_dbf_trace,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_trace,QDIO_DBF_TRACE_LEVEL);
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME,
QDIO_DBF_SLSB_OUT_INDEX,
QDIO_DBF_SLSB_OUT_NR_AREAS,
@@ -3329,7 +3374,7 @@
goto oom;
debug_register_view(qdio_dbf_slsb_in,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_slsb_in,QDIO_DBF_SLSB_IN_LEVEL);
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
return 0;
oom:
QDIO_PRINT_ERR("not enough memory for dbf.\n");
diff -urN linux-2.6/drivers/s390/cio/qdio.h linux-2.6-s390/drivers/s390/cio/qdio.h
--- linux-2.6/drivers/s390/cio/qdio.h Thu Aug 5 14:20:39 2004
+++ linux-2.6-s390/drivers/s390/cio/qdio.h Thu Aug 5 14:21:02 2004
@@ -1,15 +1,13 @@
#ifndef _CIO_QDIO_H
#define _CIO_QDIO_H
-#define VERSION_CIO_QDIO_H "$Revision: 1.24 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.26 $"
-//#define QDIO_DBF_LIKE_HELL
-
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_VERBOSE_LEVEL 9
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_VERBOSE_LEVEL 5
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_USE_PROCESSING_STATE
@@ -103,75 +101,75 @@
#define QDIO_DBF_HEX0(ex,name,addr,len) QDIO_DBF_HEX(ex,name,0,addr,len)
#define QDIO_DBF_HEX1(ex,name,addr,len) QDIO_DBF_HEX(ex,name,1,addr,len)
#define QDIO_DBF_HEX2(ex,name,addr,len) QDIO_DBF_HEX(ex,name,2,addr,len)
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_HEX3(ex,name,addr,len) QDIO_DBF_HEX(ex,name,3,addr,len)
#define QDIO_DBF_HEX4(ex,name,addr,len) QDIO_DBF_HEX(ex,name,4,addr,len)
#define QDIO_DBF_HEX5(ex,name,addr,len) QDIO_DBF_HEX(ex,name,5,addr,len)
#define QDIO_DBF_HEX6(ex,name,addr,len) QDIO_DBF_HEX(ex,name,6,addr,len)
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_HEX3(ex,name,addr,len) do {} while (0)
#define QDIO_DBF_HEX4(ex,name,addr,len) do {} while (0)
#define QDIO_DBF_HEX5(ex,name,addr,len) do {} while (0)
#define QDIO_DBF_HEX6(ex,name,addr,len) do {} while (0)
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_TEXT0(ex,name,text) QDIO_DBF_TEXT(ex,name,0,text)
#define QDIO_DBF_TEXT1(ex,name,text) QDIO_DBF_TEXT(ex,name,1,text)
#define QDIO_DBF_TEXT2(ex,name,text) QDIO_DBF_TEXT(ex,name,2,text)
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_TEXT3(ex,name,text) QDIO_DBF_TEXT(ex,name,3,text)
#define QDIO_DBF_TEXT4(ex,name,text) QDIO_DBF_TEXT(ex,name,4,text)
#define QDIO_DBF_TEXT5(ex,name,text) QDIO_DBF_TEXT(ex,name,5,text)
#define QDIO_DBF_TEXT6(ex,name,text) QDIO_DBF_TEXT(ex,name,6,text)
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_TEXT3(ex,name,text) do {} while (0)
#define QDIO_DBF_TEXT4(ex,name,text) do {} while (0)
#define QDIO_DBF_TEXT5(ex,name,text) do {} while (0)
#define QDIO_DBF_TEXT6(ex,name,text) do {} while (0)
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SETUP_NAME "qdio_setup"
#define QDIO_DBF_SETUP_LEN 8
#define QDIO_DBF_SETUP_INDEX 2
#define QDIO_DBF_SETUP_NR_AREAS 1
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SETUP_LEVEL 6
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SETUP_LEVEL 2
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */
#define QDIO_DBF_SBAL_LEN 256
#define QDIO_DBF_SBAL_INDEX 2
#define QDIO_DBF_SBAL_NR_AREAS 2
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SBAL_LEVEL 6
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SBAL_LEVEL 2
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_TRACE_NAME "qdio_trace"
#define QDIO_DBF_TRACE_LEN 8
#define QDIO_DBF_TRACE_NR_AREAS 2
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_TRACE_INDEX 4
#define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_TRACE_INDEX 2
#define QDIO_DBF_TRACE_LEVEL 2
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SENSE_NAME "qdio_sense"
#define QDIO_DBF_SENSE_LEN 64
#define QDIO_DBF_SENSE_INDEX 1
#define QDIO_DBF_SENSE_NR_AREAS 1
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SENSE_LEVEL 6
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SENSE_LEVEL 2
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define QDIO_TRACE_QTYPE QDIO_ZFCP_QFMT
#define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
@@ -185,7 +183,7 @@
#define QDIO_DBF_SLSB_IN_INDEX 8
#define QDIO_DBF_SLSB_IN_NR_AREAS 1
#define QDIO_DBF_SLSB_IN_LEVEL 6
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_PRINTK_HEADER QDIO_NAME ": "
@@ -494,7 +492,7 @@
#define QDIO_GET_ADDR(x) ((__u32)(long)x)
#endif /* CONFIG_ARCH_S390X */
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
#define set_slsb(x,y) \
if(q->queue_type==QDIO_TRACE_QTYPE) { \
if(q->is_input_q) { \
@@ -511,9 +509,9 @@
QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \
} \
}
-#else /* QDIO_DBF_LIKE_HELL */
+#else /* CONFIG_QDIO_DEBUG */
#define set_slsb(x,y) qdio_set_slsb(x,y)
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
struct qdio_q {
volatile struct slsb slsb;
diff -urN linux-2.6/drivers/s390/net/qeth.h linux-2.6-s390/drivers/s390/net/qeth.h
--- linux-2.6/drivers/s390/net/qeth.h Thu Aug 5 14:20:39 2004
+++ linux-2.6-s390/drivers/s390/net/qeth.h Thu Aug 5 14:21:02 2004
@@ -23,7 +23,7 @@
#include "qeth_mpc.h"
-#define VERSION_QETH_H "$Revision: 1.111 $"
+#define VERSION_QETH_H "$Revision: 1.113 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
@@ -150,6 +150,8 @@
#define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80
+#define atomic_swap(a,b) xchg((int *)a.counter, b)
+
/*
* Common IO related definitions
*/
@@ -425,12 +427,18 @@
struct qeth_card;
+enum qeth_out_q_states {
+ QETH_OUT_Q_UNLOCKED,
+ QETH_OUT_Q_LOCKED,
+ QETH_OUT_Q_LOCKED_FLUSH,
+};
+
struct qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
int queue_no;
struct qeth_card *card;
- spinlock_t lock;
+ atomic_t state;
volatile int do_pack;
/*
* index of buffer to be filled by driver; state EMPTY or PACKING
diff -urN linux-2.6/drivers/s390/net/qeth_main.c linux-2.6-s390/drivers/s390/net/qeth_main.c
--- linux-2.6/drivers/s390/net/qeth_main.c Thu Aug 5 14:20:39 2004
+++ linux-2.6-s390/drivers/s390/net/qeth_main.c Thu Aug 5 14:21:02 2004
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.127 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.130 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
- * $Revision: 1.127 $ $Date: 2004/07/14 21:46:40 $
+ * $Revision: 1.130 $ $Date: 2004/08/05 11:21:50 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -78,7 +78,7 @@
#include "qeth_mpc.h"
#include "qeth_fs.h"
-#define VERSION_QETH_C "$Revision: 1.127 $"
+#define VERSION_QETH_C "$Revision: 1.130 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
@@ -1801,7 +1801,7 @@
}
add_timer(&timer);
wait_event(reply->wait_q, reply->received);
- del_timer(&timer);
+ del_timer_sync(&timer);
rc = reply->rc;
qeth_put_reply(reply);
return rc;
@@ -2105,7 +2105,7 @@
QETH_DBF_TEXT(qerr,2,"unexeob");
QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card));
QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer));
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
card->stats.rx_errors++;
return NULL;
}
@@ -2297,7 +2297,7 @@
qeth_rebuild_skb(card, skb, hdr);
/* is device UP ? */
if (!(card->dev->flags & IFF_UP)){
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
continue;
}
skb->dev = card->dev;
@@ -2311,16 +2311,16 @@
static inline struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card)
{
- struct qeth_buffer_pool_entry *entry, *tmp;
+ struct qeth_buffer_pool_entry *entry;
QETH_DBF_TEXT(trace, 6, "gtbfplen");
- entry = NULL;
- list_for_each_entry_safe(entry, tmp,
- &card->qdio.in_buf_pool.entry_list, list){
+ if (!list_empty(&card->qdio.in_buf_pool.entry_list)) {
+ entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
+ struct qeth_buffer_pool_entry, list);
list_del_init(&entry->list);
- break;
+ return entry;
}
- return entry;
+ return NULL;
}
static inline void
@@ -2367,7 +2367,7 @@
buf->buffer->element[i].flags = 0;
while ((skb = skb_dequeue(&buf->skb_list))){
atomic_dec(&skb->users);
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
}
}
buf->next_element_to_fill = 0;
@@ -2588,14 +2588,9 @@
QETH_DBF_TEXT(trace, 2, "flushbuf");
QETH_DBF_TEXT_(trace, 2, " err%d", rc);
queue->card->stats.tx_errors += count;
- /* ok, since do_QDIO went wrong the buffers have not been given
- * to the hardware. they still belong to us, so we can clear
- * them and reuse then, i.e. set back next_buf_to_fill*/
- for (i = index; i < index + count; ++i) {
- buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
- qeth_clear_output_buffer(queue, buf);
- }
- queue->next_buf_to_fill = index;
+ /* this must not happen under normal circumstances. if it
+ * happens something is really wrong -> recover */
+ qeth_schedule_recovery(queue->card);
return;
}
atomic_add(count, &queue->used_buffers);
@@ -2605,16 +2600,12 @@
}
/*
- * switches between PACKING and non-PACKING state if needed.
- * has to be called holding queue->lock
+ * Switched to packing state if the number of used buffers on a queue
+ * reaches a certain limit.
*/
-static inline int
-qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
+static inline void
+qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
{
- struct qeth_qdio_out_buffer *buffer;
- int flush_count = 0;
-
- QETH_DBF_TEXT(trace, 6, "swipack");
if (!queue->do_pack) {
if (atomic_read(&queue->used_buffers)
>= QETH_HIGH_WATERMARK_PACK){
@@ -2625,7 +2616,22 @@
#endif
queue->do_pack = 1;
}
- } else {
+ }
+}
+
+/*
+ * Switches from packing to non-packing mode. If there is a packing
+ * buffer on the queue this buffer will be prepared to be flushed.
+ * In that case 1 is returned to inform the caller. If no buffer
+ * has to be flushed, zero is returned.
+ */
+static inline int
+qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
+{
+ struct qeth_qdio_out_buffer *buffer;
+ int flush_count = 0;
+
+ if (queue->do_pack) {
if (atomic_read(&queue->used_buffers)
<= QETH_LOW_WATERMARK_PACK) {
/* switch PACKING -> non-PACKING */
@@ -2650,21 +2656,62 @@
return flush_count;
}
-static inline void
-qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int)
+/*
+ * Called to flush a packing buffer if no more pci flags are on the queue.
+ * Checks if there is a packing buffer and prepares it to be flushed.
+ * In that case returns 1, otherwise zero.
+ */
+static inline int
+qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
- int index;
- index = queue->next_buf_to_fill;
- buffer = &queue->bufs[index];
+ buffer = &queue->bufs[queue->next_buf_to_fill];
if((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
(buffer->next_element_to_fill > 0)){
/* it's a packing buffer */
atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q;
- qeth_flush_buffers(queue, under_int, index, 1);
+ return 1;
+ }
+ return 0;
+}
+
+static inline void
+qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
+{
+ int index;
+ int flush_cnt = 0;
+
+ /*
+ * check if weed have to switch to non-packing mode or if
+ * we have to get a pci flag out on the queue
+ */
+ if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) ||
+ !atomic_read(&queue->set_pci_flags_count)){
+ if (atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) ==
+ QETH_OUT_Q_UNLOCKED) {
+ /*
+ * If we get in here, there was no action in
+ * do_send_packet. So, we check if there is a
+ * packing buffer to be flushed here.
+ */
+ /* TODO: try if we get a performance improvement
+ * by calling netif_stop_queue here */
+ /* save start index for flushing */
+ index = queue->next_buf_to_fill;
+ flush_cnt += qeth_switch_to_nonpacking_if_needed(queue);
+ if (!flush_cnt &&
+ !atomic_read(&queue->set_pci_flags_count))
+ flush_cnt +=
+ qeth_flush_buffers_on_no_pci(queue);
+ /* were done with updating critical queue members */
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+ /* flushing can be done outside the lock */
+ if (flush_cnt)
+ qeth_flush_buffers(queue, 1, index, flush_cnt);
+ }
}
}
@@ -2710,6 +2757,8 @@
qeth_clear_output_buffer(queue, buffer);
}
atomic_sub(count, &queue->used_buffers);
+ /* check if we need to do something on this outbound queue */
+ qeth_check_outbound_queue(queue);
netif_wake_queue(card->dev);
#ifdef CONFIG_QETH_PERF_STATS
@@ -2981,7 +3030,8 @@
card->qdio.out_qs[i]->do_pack = 0;
atomic_set(&card->qdio.out_qs[i]->used_buffers,0);
atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0);
- spin_lock_init(&card->qdio.out_qs[i]->lock);
+ atomic_set(&card->qdio.out_qs[i]->state,
+ QETH_OUT_Q_UNLOCKED);
}
return 0;
}
@@ -3295,12 +3345,12 @@
card->perf_stats.outbound_start_time = qeth_get_micros();
#endif
/*
- * dev_queue_xmit should ensure that we are called packet
- * after packet
+ * We only call netif_stop_queue in case of errors. Since we've
+ * got our own synchronization on queues we can keep the stack's
+ * queue running.
*/
- netif_stop_queue(dev);
- if (!(rc = qeth_send_packet(card, skb)))
- netif_wake_queue(dev);
+ if ((rc = qeth_send_packet(card, skb)))
+ netif_stop_queue(dev);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() -
@@ -3714,7 +3764,11 @@
QETH_DBF_TEXT(trace, 6, "dosndpfa");
- spin_lock(&queue->lock);
+ /* spin until we get the queue ... */
+ while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
+ QETH_OUT_Q_LOCKED,
+ &queue->state));
+ /* ... now we've got the queue */
index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill];
/*
@@ -3723,14 +3777,14 @@
*/
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
card->stats.tx_dropped++;
- spin_unlock(&queue->lock);
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
}
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
qeth_flush_buffers(queue, 0, index, 1);
- spin_unlock(&queue->lock);
return 0;
}
@@ -3746,7 +3800,10 @@
QETH_DBF_TEXT(trace, 6, "dosndpkt");
- spin_lock(&queue->lock);
+ /* spin until we get the queue ... */
+ while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
+ QETH_OUT_Q_LOCKED,
+ &queue->state));
start_index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill];
/*
@@ -3755,9 +3812,11 @@
*/
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
card->stats.tx_dropped++;
- spin_unlock(&queue->lock);
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
}
+ /* check if we need to switch packing state of this queue */
+ qeth_switch_to_packing_if_needed(queue);
if (queue->do_pack){
/* does packet fit in current buffer? */
if((QETH_MAX_BUFFER_ELEMENTS(card) -
@@ -3772,11 +3831,10 @@
/* we did a step forward, so check buffer state again */
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
card->stats.tx_dropped++;
- qeth_flush_buffers(queue, 0, start_index, 1);
- spin_unlock(&queue->lock);
/* return EBUSY because we sent old packet, not
* the current one */
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
}
}
@@ -3787,16 +3845,27 @@
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
}
- /* check if we need to switch packing state of this queue */
- flush_count += qeth_switch_packing_state(queue);
-
+ /*
+ * queue->state will go from LOCKED -> UNLOCKED or from
+ * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
+ * (switch packing state or flush buffer to get another pci flag out).
+ * In that case we will enter this loop
+ */
+ while (atomic_dec_return(&queue->state)){
+ /* check if we can go back to non-packing state */
+ flush_count += qeth_switch_to_nonpacking_if_needed(queue);
+ /*
+ * check if we need to flush a packing buffer to get a pci
+ * flag out on the queue
+ */
+ if (!flush_count && !atomic_read(&queue->set_pci_flags_count))
+ flush_count += qeth_flush_buffers_on_no_pci(queue);
+ }
+ /* at this point the queue is UNLOCKED again */
+out:
if (flush_count)
qeth_flush_buffers(queue, 0, start_index, flush_count);
- if (!atomic_read(&queue->set_pci_flags_count))
- qeth_flush_buffers_on_no_pci(queue, 0);
-
- spin_unlock(&queue->lock);
return rc;
}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] s390: qeth performance.
2004-08-05 13:14 [PATCH] s390: qeth performance Martin Schwidefsky
@ 2004-08-06 12:49 ` Jörn Engel
[not found] ` <OFECABF5A6.F2037B97-ON42256EE8.00472EEA-42256EE8.0047790E@de.ibm.com>
0 siblings, 1 reply; 3+ messages in thread
From: Jörn Engel @ 2004-08-06 12:49 UTC (permalink / raw)
To: Martin Schwidefsky; +Cc: akpm, linux-kernel
On Thu, 5 August 2004 15:14:40 +0200, Martin Schwidefsky wrote:
>
> qeth network driver performance improvements. The ping time on the
> HiperSockets interface drops from 250 usecs to 50 usecs and the 1 bytes
> request/response test improves from 70000 to 110000 transactions.
Looks good.
> +config QDIO_DEBUG
> + bool "Extended debugging information"
> + depends on QDIO
> + help
> + Say Y here to get extended debugging output in /proc/s390dbf/qdio...
> + Warning: this option reduces the performance of the QDIO module.
> +
> + If unsure, say N.
> +
> comment "Misc"
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
> +#ifdef CONFIG_QDIO_DEBUG
After 50% of the patch I grew tired of it. Martin, since when do you
like excessive use of #ifdef?
Jörn
--
And spam is a useful source of entropy for /dev/random too!
-- Jasmine Strong
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] s390: qeth performance.
[not found] ` <OFECABF5A6.F2037B97-ON42256EE8.00472EEA-42256EE8.0047790E@de.ibm.com>
@ 2004-08-06 13:09 ` Jörn Engel
0 siblings, 0 replies; 3+ messages in thread
From: Jörn Engel @ 2004-08-06 13:09 UTC (permalink / raw)
To: Martin Schwidefsky; +Cc: akpm, linux-kernel
On Fri, 6 August 2004 15:00:40 +0200, Martin Schwidefsky wrote:
> Jörn Engel <joern@wohnheim.fh-wedel.de> wrote on 06/08/2004 02:49:41 PM:
> >
> > After 50% of the patch I grew tired of it. Martin, since when do you
> > like excessive use of #ifdef?
>
> Well, it isn't so bad. Only 35 #ifdef CONFIG_QDIO_DEBUG.
Maybe our definitions of "isn't so bad" don't match. ;)
Anyway, it's a first step. No new code was added, the old debugging
mess is explicitly marked as such now. Next step would be to either
completely get rid of it or replace it with something less ugly.
Jörn
--
Beware of bugs in the above code; I have only proved it correct, but
not tried it.
-- Donald Knuth
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2004-08-06 13:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-08-05 13:14 [PATCH] s390: qeth performance Martin Schwidefsky
2004-08-06 12:49 ` Jörn Engel
[not found] ` <OFECABF5A6.F2037B97-ON42256EE8.00472EEA-42256EE8.0047790E@de.ibm.com>
2004-08-06 13:09 ` Jörn Engel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®