Commit 0815adc2 authored by Thomas Spatzier's avatar Thomas Spatzier Committed by Linus Torvalds

[PATCH] s390: qeth performance.

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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 618310db
...@@ -181,6 +181,15 @@ config QDIO_PERF_STATS ...@@ -181,6 +181,15 @@ config QDIO_PERF_STATS
If unsure, say N. 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" comment "Misc"
config PREEMPT config PREEMPT
......
...@@ -70,6 +70,7 @@ CONFIG_MATHEMU=y ...@@ -70,6 +70,7 @@ CONFIG_MATHEMU=y
CONFIG_MACHCHK_WARNING=y CONFIG_MACHCHK_WARNING=y
CONFIG_QDIO=y CONFIG_QDIO=y
# CONFIG_QDIO_PERF_STATS is not set # CONFIG_QDIO_PERF_STATS is not set
# CONFIG_QDIO_DEBUG is not set
# #
# Misc # Misc
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h" #include "chsc.h"
#define VERSION_QDIO_C "$Revision: 1.83 $" #define VERSION_QDIO_C "$Revision: 1.84 $"
/****************** MODULE PARAMETER VARIABLES ********************/ /****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
...@@ -87,10 +87,10 @@ static debug_info_t *qdio_dbf_setup; ...@@ -87,10 +87,10 @@ static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal; static debug_info_t *qdio_dbf_sbal;
static debug_info_t *qdio_dbf_trace; static debug_info_t *qdio_dbf_trace;
static debug_info_t *qdio_dbf_sense; 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_out;
static debug_info_t *qdio_dbf_slsb_in; static debug_info_t *qdio_dbf_slsb_in;
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
/* iQDIO stuff: */ /* iQDIO stuff: */
static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
...@@ -514,10 +514,13 @@ inline static int ...@@ -514,10 +514,13 @@ inline static int
qdio_is_outbound_q_done(struct qdio_q *q) qdio_is_outbound_q_done(struct qdio_q *q)
{ {
int no_used; int no_used;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif
no_used=atomic_read(&q->number_of_buffers_used); no_used=atomic_read(&q->number_of_buffers_used);
#ifdef CONFIG_QDIO_DEBUG
if (no_used) { if (no_used) {
sprintf(dbf_text,"oqisnt%02x",no_used); sprintf(dbf_text,"oqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
...@@ -525,6 +528,7 @@ qdio_is_outbound_q_done(struct qdio_q *q) ...@@ -525,6 +528,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
QDIO_DBF_TEXT4(0,trace,"oqisdone"); QDIO_DBF_TEXT4(0,trace,"oqisdone");
} }
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
#endif /* CONFIG_QDIO_DEBUG */
return (no_used==0); return (no_used==0);
} }
...@@ -552,10 +556,12 @@ inline static void ...@@ -552,10 +556,12 @@ inline static void
qdio_kick_outbound_q(struct qdio_q *q) qdio_kick_outbound_q(struct qdio_q *q)
{ {
int result; int result;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
QDIO_DBF_TEXT4(0,trace,"kickoutq"); QDIO_DBF_TEXT4(0,trace,"kickoutq");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
#endif /* CONFIG_QDIO_DEBUG */
if (!q->siga_out) if (!q->siga_out)
return; return;
...@@ -594,11 +600,13 @@ qdio_kick_outbound_q(struct qdio_q *q) ...@@ -594,11 +600,13 @@ qdio_kick_outbound_q(struct qdio_q *q)
switch (result) { switch (result) {
case 0: case 0:
/* went smooth this time, reset timestamp */ /* went smooth this time, reset timestamp */
#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT3(0,trace,"cc2reslv"); QDIO_DBF_TEXT3(0,trace,"cc2reslv");
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no, sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter)); atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text); QDIO_DBF_TEXT3(0,trace,dbf_text);
q->timing.busy_start=0; q->timing.busy_start=0;
#endif /* CONFIG_QDIO_DEBUG */
break; break;
case (2|QDIO_SIGA_ERROR_B_BIT_SET): case (2|QDIO_SIGA_ERROR_B_BIT_SET):
/* cc=2 and busy bit: */ /* cc=2 and busy bit: */
...@@ -616,9 +624,11 @@ qdio_kick_outbound_q(struct qdio_q *q) ...@@ -616,9 +624,11 @@ qdio_kick_outbound_q(struct qdio_q *q)
break; break;
} }
QDIO_DBF_TEXT2(0,trace,"cc2REPRT"); QDIO_DBF_TEXT2(0,trace,"cc2REPRT");
#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no, sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter)); atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text); QDIO_DBF_TEXT3(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
/* else fallthrough and report error */ /* else fallthrough and report error */
default: default:
/* for plain cc=1, 2 or 3: */ /* for plain cc=1, 2 or 3: */
...@@ -635,7 +645,9 @@ inline static void ...@@ -635,7 +645,9 @@ inline static void
qdio_kick_outbound_handler(struct qdio_q *q) qdio_kick_outbound_handler(struct qdio_q *q)
{ {
int start, end, real_end, count; int start, end, real_end, count;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif
start = q->first_element_to_kick; start = q->first_element_to_kick;
/* last_move_ftc was just updated */ /* last_move_ftc was just updated */
...@@ -645,11 +657,13 @@ qdio_kick_outbound_handler(struct qdio_q *q) ...@@ -645,11 +657,13 @@ qdio_kick_outbound_handler(struct qdio_q *q)
count = (end+QDIO_MAX_BUFFERS_PER_Q+1-start)& count = (end+QDIO_MAX_BUFFERS_PER_Q+1-start)&
(QDIO_MAX_BUFFERS_PER_Q-1); (QDIO_MAX_BUFFERS_PER_Q-1);
#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"kickouth"); QDIO_DBF_TEXT4(0,trace,"kickouth");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"s=%2xc=%2x",start,count); sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
if (q->state==QDIO_IRQ_STATE_ACTIVE) if (q->state==QDIO_IRQ_STATE_ACTIVE)
q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT| q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT|
...@@ -732,7 +746,9 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -732,7 +746,9 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
int f,f_mod_no; int f,f_mod_no;
volatile char *slsb; volatile char *slsb;
int first_not_to_check; int first_not_to_check;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif /* CONFIG_QDIO_DEBUG */
#ifdef QDIO_USE_PROCESSING_STATE #ifdef QDIO_USE_PROCESSING_STATE
int last_position=-1; int last_position=-1;
#endif /* QDIO_USE_PROCESSING_STATE */ #endif /* QDIO_USE_PROCESSING_STATE */
...@@ -806,8 +822,10 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -806,8 +822,10 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
/* P_ERROR means frontier is reached, break and report error */ /* P_ERROR means frontier is reached, break and report error */
case SLSB_P_INPUT_ERROR: case SLSB_P_INPUT_ERROR:
#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"inperr%2x",f_mod_no); sprintf(dbf_text,"inperr%2x",f_mod_no);
QDIO_DBF_TEXT3(1,trace,dbf_text); QDIO_DBF_TEXT3(1,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256); QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);
/* kind of process the buffer */ /* kind of process the buffer */
...@@ -884,13 +902,16 @@ inline static int ...@@ -884,13 +902,16 @@ inline static int
iqdio_is_inbound_q_done(struct qdio_q *q) iqdio_is_inbound_q_done(struct qdio_q *q)
{ {
int no_used; int no_used;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif
no_used=atomic_read(&q->number_of_buffers_used); no_used=atomic_read(&q->number_of_buffers_used);
/* propagate the change from 82 to 80 through VM */ /* propagate the change from 82 to 80 through VM */
SYNC_MEMORY; SYNC_MEMORY;
#ifdef CONFIG_QDIO_DEBUG
if (no_used) { if (no_used) {
sprintf(dbf_text,"iqisnt%02x",no_used); sprintf(dbf_text,"iqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
...@@ -898,6 +919,7 @@ iqdio_is_inbound_q_done(struct qdio_q *q) ...@@ -898,6 +919,7 @@ iqdio_is_inbound_q_done(struct qdio_q *q)
QDIO_DBF_TEXT4(0,trace,"iniqisdo"); QDIO_DBF_TEXT4(0,trace,"iniqisdo");
} }
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
#endif /* CONFIG_QDIO_DEBUG */
if (!no_used) if (!no_used)
return 1; return 1;
...@@ -933,7 +955,9 @@ inline static int ...@@ -933,7 +955,9 @@ inline static int
qdio_is_inbound_q_done(struct qdio_q *q) qdio_is_inbound_q_done(struct qdio_q *q)
{ {
int no_used; int no_used;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif
no_used=atomic_read(&q->number_of_buffers_used); no_used=atomic_read(&q->number_of_buffers_used);
...@@ -968,16 +992,20 @@ qdio_is_inbound_q_done(struct qdio_q *q) ...@@ -968,16 +992,20 @@ qdio_is_inbound_q_done(struct qdio_q *q)
* has (probably) not moved (see qdio_inbound_processing) * has (probably) not moved (see qdio_inbound_processing)
*/ */
if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) { if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) {
#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisdon"); QDIO_DBF_TEXT4(0,trace,"inqisdon");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used); sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
return 1; return 1;
} else { } else {
#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisntd"); QDIO_DBF_TEXT4(0,trace,"inqisntd");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used); sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
return 0; return 0;
} }
} }
...@@ -986,7 +1014,9 @@ inline static void ...@@ -986,7 +1014,9 @@ inline static void
qdio_kick_inbound_handler(struct qdio_q *q) qdio_kick_inbound_handler(struct qdio_q *q)
{ {
int count, start, end, real_end, i; int count, start, end, real_end, i;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
#endif
QDIO_DBF_TEXT4(0,trace,"kickinh"); QDIO_DBF_TEXT4(0,trace,"kickinh");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
...@@ -1004,8 +1034,10 @@ qdio_kick_inbound_handler(struct qdio_q *q) ...@@ -1004,8 +1034,10 @@ qdio_kick_inbound_handler(struct qdio_q *q)
i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1); i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
} }
#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"s=%2xc=%2x",start,count); sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text); QDIO_DBF_TEXT4(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
if (likely(q->state==QDIO_IRQ_STATE_ACTIVE)) if (likely(q->state==QDIO_IRQ_STATE_ACTIVE))
q->handler(q->cdev, q->handler(q->cdev,
...@@ -1622,11 +1654,13 @@ static void ...@@ -1622,11 +1654,13 @@ static void
qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
{ {
int i; int i;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]; char dbf_text[15];
QDIO_DBF_TEXT5(0,trace,"newstate"); QDIO_DBF_TEXT5(0,trace,"newstate");
sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state); sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state);
QDIO_DBF_TEXT5(0,trace,dbf_text); QDIO_DBF_TEXT5(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
irq_ptr->state=state; irq_ptr->state=state;
for (i=0;i<irq_ptr->no_input_qs;i++) for (i=0;i<irq_ptr->no_input_qs;i++)
...@@ -1791,9 +1825,11 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1791,9 +1825,11 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
int cstat,dstat; int cstat,dstat;
char dbf_text[15]; char dbf_text[15];
#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0, trace, "qint"); QDIO_DBF_TEXT4(0, trace, "qint");
sprintf(dbf_text, "%s", cdev->dev.bus_id); sprintf(dbf_text, "%s", cdev->dev.bus_id);
QDIO_DBF_TEXT4(0, trace, dbf_text); QDIO_DBF_TEXT4(0, trace, dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
if (!intparm) { if (!intparm) {
QDIO_PRINT_ERR("got unsolicited interrupt in qdio " \ QDIO_PRINT_ERR("got unsolicited interrupt in qdio " \
...@@ -1830,8 +1866,10 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1830,8 +1866,10 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
qdio_irq_check_sense(irq_ptr->irq, irb); qdio_irq_check_sense(irq_ptr->irq, irb);
#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text, "state:%d", irq_ptr->state); sprintf(dbf_text, "state:%d", irq_ptr->state);
QDIO_DBF_TEXT4(0, trace, dbf_text); QDIO_DBF_TEXT4(0, trace, dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
cstat = irb->scsw.cstat; cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat; dstat = irb->scsw.dstat;
...@@ -1872,18 +1910,22 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, ...@@ -1872,18 +1910,22 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
int cc; int cc;
struct qdio_q *q; struct qdio_q *q;
struct qdio_irq *irq_ptr; struct qdio_irq *irq_ptr;
char dbf_text[15]="SyncXXXX";
void *ptr; void *ptr;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15]="SyncXXXX";
#endif
irq_ptr = cdev->private->qdio_data; irq_ptr = cdev->private->qdio_data;
if (!irq_ptr) if (!irq_ptr)
return -ENODEV; return -ENODEV;
#ifdef CONFIG_QDIO_DEBUG
*((int*)(&dbf_text[4])) = irq_ptr->irq; *((int*)(&dbf_text[4])) = irq_ptr->irq;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN); QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
*((int*)(&dbf_text[0]))=flags; *((int*)(&dbf_text[0]))=flags;
*((int*)(&dbf_text[4]))=queue_number; *((int*)(&dbf_text[4]))=queue_number;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN); QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
#endif /* CONFIG_QDIO_DEBUG */
if (flags&QDIO_FLAG_SYNC_INPUT) { if (flags&QDIO_FLAG_SYNC_INPUT) {
q=irq_ptr->input_qs[queue_number]; q=irq_ptr->input_qs[queue_number];
...@@ -3083,11 +3125,12 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags, ...@@ -3083,11 +3125,12 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
unsigned int count,struct qdio_buffer *buffers) unsigned int count,struct qdio_buffer *buffers)
{ {
struct qdio_irq *irq_ptr; struct qdio_irq *irq_ptr;
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[20]; char dbf_text[20];
sprintf(dbf_text,"doQD%04x",cdev->private->irq); 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) || if ( (qidx>QDIO_MAX_BUFFERS_PER_Q) ||
(count>QDIO_MAX_BUFFERS_PER_Q) || (count>QDIO_MAX_BUFFERS_PER_Q) ||
...@@ -3101,6 +3144,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags, ...@@ -3101,6 +3144,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
if (!irq_ptr) if (!irq_ptr)
return -ENODEV; return -ENODEV;
#ifdef CONFIG_QDIO_DEBUG
if (callflags&QDIO_FLAG_SYNC_INPUT) if (callflags&QDIO_FLAG_SYNC_INPUT)
QDIO_DBF_HEX3(0,trace,&irq_ptr->input_qs[queue_number], QDIO_DBF_HEX3(0,trace,&irq_ptr->input_qs[queue_number],
sizeof(void*)); sizeof(void*));
...@@ -3111,6 +3155,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags, ...@@ -3111,6 +3155,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
QDIO_DBF_TEXT3(0,trace,dbf_text); QDIO_DBF_TEXT3(0,trace,dbf_text);
sprintf(dbf_text,"qi%02xct%02x",qidx,count); sprintf(dbf_text,"qi%02xct%02x",qidx,count);
QDIO_DBF_TEXT3(0,trace,dbf_text); QDIO_DBF_TEXT3(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE) if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE)
return -EBUSY; return -EBUSY;
...@@ -3261,12 +3306,12 @@ qdio_unregister_dbf_views(void) ...@@ -3261,12 +3306,12 @@ qdio_unregister_dbf_views(void)
debug_unregister(qdio_dbf_sense); debug_unregister(qdio_dbf_sense);
if (qdio_dbf_trace) if (qdio_dbf_trace)
debug_unregister(qdio_dbf_trace); debug_unregister(qdio_dbf_trace);
#ifdef QDIO_DBF_LIKE_HELL #ifdef CONFIG_QDIO_DEBUG
if (qdio_dbf_slsb_out) if (qdio_dbf_slsb_out)
debug_unregister(qdio_dbf_slsb_out); debug_unregister(qdio_dbf_slsb_out);
if (qdio_dbf_slsb_in) if (qdio_dbf_slsb_in)
debug_unregister(qdio_dbf_slsb_in); debug_unregister(qdio_dbf_slsb_in);
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
} }
static int static int
...@@ -3311,7 +3356,7 @@ qdio_register_dbf_views(void) ...@@ -3311,7 +3356,7 @@ qdio_register_dbf_views(void)
debug_register_view(qdio_dbf_trace,&debug_hex_ascii_view); debug_register_view(qdio_dbf_trace,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_trace,QDIO_DBF_TRACE_LEVEL); 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=debug_register(QDIO_DBF_SLSB_OUT_NAME,
QDIO_DBF_SLSB_OUT_INDEX, QDIO_DBF_SLSB_OUT_INDEX,
QDIO_DBF_SLSB_OUT_NR_AREAS, QDIO_DBF_SLSB_OUT_NR_AREAS,
...@@ -3329,7 +3374,7 @@ qdio_register_dbf_views(void) ...@@ -3329,7 +3374,7 @@ qdio_register_dbf_views(void)
goto oom; goto oom;
debug_register_view(qdio_dbf_slsb_in,&debug_hex_ascii_view); debug_register_view(qdio_dbf_slsb_in,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_slsb_in,QDIO_DBF_SLSB_IN_LEVEL); debug_set_level(qdio_dbf_slsb_in,QDIO_DBF_SLSB_IN_LEVEL);
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
return 0; return 0;
oom: oom:
QDIO_PRINT_ERR("not enough memory for dbf.\n"); QDIO_PRINT_ERR("not enough memory for dbf.\n");
......
#ifndef _CIO_QDIO_H #ifndef _CIO_QDIO_H
#define _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 CONFIG_QDIO_DEBUG
#ifdef QDIO_DBF_LIKE_HELL
#define QDIO_VERBOSE_LEVEL 9 #define QDIO_VERBOSE_LEVEL 9
#else /* QDIO_DBF_LIKE_HELL */ #else /* CONFIG_QDIO_DEBUG */
#define QDIO_VERBOSE_LEVEL 5 #define QDIO_VERBOSE_LEVEL 5
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
#define QDIO_USE_PROCESSING_STATE #define QDIO_USE_PROCESSING_STATE
...@@ -103,75 +101,75 @@ enum qdio_irq_states { ...@@ -103,75 +101,75 @@ enum qdio_irq_states {
#define QDIO_DBF_HEX0(ex,name,addr,len) QDIO_DBF_HEX(ex,name,0,addr,len) #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_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) #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_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_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_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) #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_HEX3(ex,name,addr,len) do {} while (0)
#define QDIO_DBF_HEX4(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_HEX5(ex,name,addr,len) do {} while (0)
#define QDIO_DBF_HEX6(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_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_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) #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_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_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_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) #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_TEXT3(ex,name,text) do {} while (0)
#define QDIO_DBF_TEXT4(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_TEXT5(ex,name,text) do {} while (0)
#define QDIO_DBF_TEXT6(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_NAME "qdio_setup"
#define QDIO_DBF_SETUP_LEN 8 #define QDIO_DBF_SETUP_LEN 8
#define QDIO_DBF_SETUP_INDEX 2 #define QDIO_DBF_SETUP_INDEX 2
#define QDIO_DBF_SETUP_NR_AREAS 1 #define QDIO_DBF_SETUP_NR_AREAS 1
#ifdef QDIO_DBF_LIKE_HELL #ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SETUP_LEVEL 6 #define QDIO_DBF_SETUP_LEVEL 6
#else /* QDIO_DBF_LIKE_HELL */ #else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SETUP_LEVEL 2 #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_NAME "qdio_labs" /* sbal */
#define QDIO_DBF_SBAL_LEN 256 #define QDIO_DBF_SBAL_LEN 256
#define QDIO_DBF_SBAL_INDEX 2 #define QDIO_DBF_SBAL_INDEX 2
#define QDIO_DBF_SBAL_NR_AREAS 2 #define QDIO_DBF_SBAL_NR_AREAS 2
#ifdef QDIO_DBF_LIKE_HELL #ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SBAL_LEVEL 6 #define QDIO_DBF_SBAL_LEVEL 6
#else /* QDIO_DBF_LIKE_HELL */ #else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SBAL_LEVEL 2 #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_NAME "qdio_trace"
#define QDIO_DBF_TRACE_LEN 8 #define QDIO_DBF_TRACE_LEN 8
#define QDIO_DBF_TRACE_NR_AREAS 2 #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_INDEX 4
#define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */ #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_INDEX 2
#define QDIO_DBF_TRACE_LEVEL 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_NAME "qdio_sense"
#define QDIO_DBF_SENSE_LEN 64 #define QDIO_DBF_SENSE_LEN 64
#define QDIO_DBF_SENSE_INDEX 1 #define QDIO_DBF_SENSE_INDEX 1
#define QDIO_DBF_SENSE_NR_AREAS 1 #define QDIO_DBF_SENSE_NR_AREAS 1
#ifdef QDIO_DBF_LIKE_HELL #ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SENSE_LEVEL 6 #define QDIO_DBF_SENSE_LEVEL 6
#else /* QDIO_DBF_LIKE_HELL */ #else /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SENSE_LEVEL 2 #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_TRACE_QTYPE QDIO_ZFCP_QFMT
#define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out" #define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
...@@ -185,7 +183,7 @@ enum qdio_irq_states { ...@@ -185,7 +183,7 @@ enum qdio_irq_states {
#define QDIO_DBF_SLSB_IN_INDEX 8 #define QDIO_DBF_SLSB_IN_INDEX 8
#define QDIO_DBF_SLSB_IN_NR_AREAS 1 #define QDIO_DBF_SLSB_IN_NR_AREAS 1
#define QDIO_DBF_SLSB_IN_LEVEL 6 #define QDIO_DBF_SLSB_IN_LEVEL 6
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
#define QDIO_PRINTK_HEADER QDIO_NAME ": " #define QDIO_PRINTK_HEADER QDIO_NAME ": "
...@@ -494,7 +492,7 @@ struct qdio_perf_stats { ...@@ -494,7 +492,7 @@ struct qdio_perf_stats {
#define QDIO_GET_ADDR(x) ((__u32)(long)x) #define QDIO_GET_ADDR(x) ((__u32)(long)x)
#endif /* CONFIG_ARCH_S390X */ #endif /* CONFIG_ARCH_S390X */
#ifdef QDIO_DBF_LIKE_HELL #ifdef CONFIG_QDIO_DEBUG
#define set_slsb(x,y) \ #define set_slsb(x,y) \
if(q->queue_type==QDIO_TRACE_QTYPE) { \ if(q->queue_type==QDIO_TRACE_QTYPE) { \
if(q->is_input_q) { \ if(q->is_input_q) { \
...@@ -511,9 +509,9 @@ struct qdio_perf_stats { ...@@ -511,9 +509,9 @@ struct qdio_perf_stats {
QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \ 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) #define set_slsb(x,y) qdio_set_slsb(x,y)
#endif /* QDIO_DBF_LIKE_HELL */ #endif /* CONFIG_QDIO_DEBUG */
struct qdio_q { struct qdio_q {
volatile struct slsb slsb; volatile struct slsb slsb;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.111 $" #define VERSION_QETH_H "$Revision: 1.113 $"
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6" #define QETH_VERSION_IPV6 ":IPv6"
...@@ -150,6 +150,8 @@ qeth_hex_dump(unsigned char *buf, size_t len) ...@@ -150,6 +150,8 @@ qeth_hex_dump(unsigned char *buf, size_t len)
#define SENSE_RESETTING_EVENT_BYTE 1 #define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80 #define SENSE_RESETTING_EVENT_FLAG 0x80
#define atomic_swap(a,b) xchg((int *)a.counter, b)
/* /*
* Common IO related definitions * Common IO related definitions
*/ */
...@@ -425,12 +427,18 @@ struct qeth_qdio_out_buffer { ...@@ -425,12 +427,18 @@ struct qeth_qdio_out_buffer {
struct qeth_card; 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 qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
int queue_no; int queue_no;
struct qeth_card *card; struct qeth_card *card;
spinlock_t lock; atomic_t state;
volatile int do_pack; volatile int do_pack;
/* /*
* index of buffer to be filled by driver; state EMPTY or PACKING * index of buffer to be filled by driver; state EMPTY or PACKING
......
/* /*
* *
* 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 * Linux on zSeries OSA Express and HiperSockets support
* *
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com> * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -78,7 +78,7 @@ qeth_eyecatcher(void) ...@@ -78,7 +78,7 @@ qeth_eyecatcher(void)
#include "qeth_mpc.h" #include "qeth_mpc.h"
#include "qeth_fs.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"; static const char *version = "qeth S/390 OSA-Express driver";
/** /**
...@@ -1801,7 +1801,7 @@ qeth_send_control_data(struct qeth_card *card, int len, ...@@ -1801,7 +1801,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
} }
add_timer(&timer); add_timer(&timer);
wait_event(reply->wait_q, reply->received); wait_event(reply->wait_q, reply->received);
del_timer(&timer); del_timer_sync(&timer);
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
...@@ -2105,7 +2105,7 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, ...@@ -2105,7 +2105,7 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
QETH_DBF_TEXT(qerr,2,"unexeob"); QETH_DBF_TEXT(qerr,2,"unexeob");
QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card)); QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card));
QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer)); QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer));
dev_kfree_skb_irq(skb); dev_kfree_skb_any(skb);
card->stats.rx_errors++; card->stats.rx_errors++;
return NULL; return NULL;
} }
...@@ -2297,7 +2297,7 @@ qeth_process_inbound_buffer(struct qeth_card *card, ...@@ -2297,7 +2297,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
qeth_rebuild_skb(card, skb, hdr); qeth_rebuild_skb(card, skb, hdr);
/* is device UP ? */ /* is device UP ? */
if (!(card->dev->flags & IFF_UP)){ if (!(card->dev->flags & IFF_UP)){
dev_kfree_skb_irq(skb); dev_kfree_skb_any(skb);
continue; continue;
} }
skb->dev = card->dev; skb->dev = card->dev;
...@@ -2311,16 +2311,16 @@ qeth_process_inbound_buffer(struct qeth_card *card, ...@@ -2311,16 +2311,16 @@ qeth_process_inbound_buffer(struct qeth_card *card,
static inline struct qeth_buffer_pool_entry * static inline struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card) 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"); QETH_DBF_TEXT(trace, 6, "gtbfplen");
entry = NULL; if (!list_empty(&card->qdio.in_buf_pool.entry_list)) {
list_for_each_entry_safe(entry, tmp, entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
&card->qdio.in_buf_pool.entry_list, list){ struct qeth_buffer_pool_entry, list);
list_del_init(&entry->list); list_del_init(&entry->list);
break;
}
return entry; return entry;
}
return NULL;
} }
static inline void static inline void
...@@ -2367,7 +2367,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, ...@@ -2367,7 +2367,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
buf->buffer->element[i].flags = 0; buf->buffer->element[i].flags = 0;
while ((skb = skb_dequeue(&buf->skb_list))){ while ((skb = skb_dequeue(&buf->skb_list))){
atomic_dec(&skb->users); atomic_dec(&skb->users);
dev_kfree_skb_irq(skb); dev_kfree_skb_any(skb);
} }
} }
buf->next_element_to_fill = 0; buf->next_element_to_fill = 0;
...@@ -2588,14 +2588,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2588,14 +2588,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
QETH_DBF_TEXT(trace, 2, "flushbuf"); QETH_DBF_TEXT(trace, 2, "flushbuf");
QETH_DBF_TEXT_(trace, 2, " err%d", rc); QETH_DBF_TEXT_(trace, 2, " err%d", rc);
queue->card->stats.tx_errors += count; queue->card->stats.tx_errors += count;
/* ok, since do_QDIO went wrong the buffers have not been given /* this must not happen under normal circumstances. if it
* to the hardware. they still belong to us, so we can clear * happens something is really wrong -> recover */
* them and reuse then, i.e. set back next_buf_to_fill*/ qeth_schedule_recovery(queue->card);
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;
return; return;
} }
atomic_add(count, &queue->used_buffers); atomic_add(count, &queue->used_buffers);
...@@ -2605,16 +2600,12 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2605,16 +2600,12 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
} }
/* /*
* switches between PACKING and non-PACKING state if needed. * Switched to packing state if the number of used buffers on a queue
* has to be called holding queue->lock * reaches a certain limit.
*/ */
static inline int static inline void
qeth_switch_packing_state(struct qeth_qdio_out_q *queue) 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 (!queue->do_pack) {
if (atomic_read(&queue->used_buffers) if (atomic_read(&queue->used_buffers)
>= QETH_HIGH_WATERMARK_PACK){ >= QETH_HIGH_WATERMARK_PACK){
...@@ -2625,7 +2616,22 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) ...@@ -2625,7 +2616,22 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
#endif #endif
queue->do_pack = 1; 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) if (atomic_read(&queue->used_buffers)
<= QETH_LOW_WATERMARK_PACK) { <= QETH_LOW_WATERMARK_PACK) {
/* switch PACKING -> non-PACKING */ /* switch PACKING -> non-PACKING */
...@@ -2650,21 +2656,62 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) ...@@ -2650,21 +2656,62 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
return flush_count; 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; struct qeth_qdio_out_buffer *buffer;
int index;
index = queue->next_buf_to_fill; buffer = &queue->bufs[queue->next_buf_to_fill];
buffer = &queue->bufs[index];
if((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && if((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
(buffer->next_element_to_fill > 0)){ (buffer->next_element_to_fill > 0)){
/* it's a packing buffer */ /* it's a packing buffer */
atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
queue->next_buf_to_fill = queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; (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_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, ...@@ -2710,6 +2757,8 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
qeth_clear_output_buffer(queue, buffer); qeth_clear_output_buffer(queue, buffer);
} }
atomic_sub(count, &queue->used_buffers); 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); netif_wake_queue(card->dev);
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
...@@ -2981,7 +3030,8 @@ qeth_init_qdio_queues(struct qeth_card *card) ...@@ -2981,7 +3030,8 @@ qeth_init_qdio_queues(struct qeth_card *card)
card->qdio.out_qs[i]->do_pack = 0; 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]->used_buffers,0);
atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 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; return 0;
} }
...@@ -3295,12 +3345,12 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3295,12 +3345,12 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.outbound_start_time = qeth_get_micros(); card->perf_stats.outbound_start_time = qeth_get_micros();
#endif #endif
/* /*
* dev_queue_xmit should ensure that we are called packet * We only call netif_stop_queue in case of errors. Since we've
* after packet * got our own synchronization on queues we can keep the stack's
* queue running.
*/ */
if ((rc = qeth_send_packet(card, skb)))
netif_stop_queue(dev); netif_stop_queue(dev);
if (!(rc = qeth_send_packet(card, skb)))
netif_wake_queue(dev);
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() - card->perf_stats.outbound_time += qeth_get_micros() -
...@@ -3714,7 +3764,11 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3714,7 +3764,11 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
QETH_DBF_TEXT(trace, 6, "dosndpfa"); 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; index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill]; buffer = &queue->bufs[queue->next_buf_to_fill];
/* /*
...@@ -3723,14 +3777,14 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3723,14 +3777,14 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
*/ */
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
card->stats.tx_dropped++; card->stats.tx_dropped++;
spin_unlock(&queue->lock); atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY; return -EBUSY;
} }
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q; QDIO_MAX_BUFFERS_PER_Q;
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
qeth_fill_buffer(queue, buffer, (char *)hdr, skb); qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
qeth_flush_buffers(queue, 0, index, 1); qeth_flush_buffers(queue, 0, index, 1);
spin_unlock(&queue->lock);
return 0; return 0;
} }
...@@ -3746,7 +3800,10 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3746,7 +3800,10 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
QETH_DBF_TEXT(trace, 6, "dosndpkt"); 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; start_index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill]; buffer = &queue->bufs[queue->next_buf_to_fill];
/* /*
...@@ -3755,9 +3812,11 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3755,9 +3812,11 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
*/ */
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
card->stats.tx_dropped++; card->stats.tx_dropped++;
spin_unlock(&queue->lock); atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY; return -EBUSY;
} }
/* check if we need to switch packing state of this queue */
qeth_switch_to_packing_if_needed(queue);
if (queue->do_pack){ if (queue->do_pack){
/* does packet fit in current buffer? */ /* does packet fit in current buffer? */
if((QETH_MAX_BUFFER_ELEMENTS(card) - if((QETH_MAX_BUFFER_ELEMENTS(card) -
...@@ -3772,11 +3831,10 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3772,11 +3831,10 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
/* we did a step forward, so check buffer state again */ /* we did a step forward, so check buffer state again */
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
card->stats.tx_dropped++; card->stats.tx_dropped++;
qeth_flush_buffers(queue, 0, start_index, 1);
spin_unlock(&queue->lock);
/* return EBUSY because we sent old packet, not /* return EBUSY because we sent old packet, not
* the current one */ * the current one */
return -EBUSY; rc = -EBUSY;
goto out;
} }
} }
} }
...@@ -3787,16 +3845,27 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, ...@@ -3787,16 +3845,27 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q; 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) if (flush_count)
qeth_flush_buffers(queue, 0, start_index, 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; return rc;
} }
......
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