Skip to content

Commit

Permalink
[S390] qdio: 2nd stage retry on SIGA-W busy conditions
Browse files Browse the repository at this point in the history
The SIGA-W may return with the busy bit set which means the device was
blocked. The busy loop which retries the SIGA-W for 100us may not be
long enough when running under a heavily loaded hypervisor.

Extend the retry mechanism by adding a longer second stage which retries
the SIGA-W for up to 10s. In difference to the first retry loop the second
stage is using mdelay to stop the cpu between the retries and thereby
avoid additional preassure in on the hypervisor.
If the second stage retry is successfull a device reset is avoided.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
  • Loading branch information
Jan Glauber authored and Heiko Carstens committed Aug 3, 2011
1 parent ed8f373 commit be8d97a
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 3 deletions.
2 changes: 2 additions & 0 deletions drivers/s390/cio/qdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include "chsc.h"

#define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */
#define QDIO_BUSY_BIT_RETRY_DELAY 10 /* 10 milliseconds */
#define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */
#define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */

/*
Expand Down
21 changes: 18 additions & 3 deletions drivers/s390/cio/qdio_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
unsigned long schid = *((u32 *) &q->irq_ptr->schid);
unsigned int fc = QDIO_SIGA_WRITE;
u64 start_time = 0;
int cc;
int retries = 0, cc;

if (is_qebsm(q)) {
schid = q->irq_ptr->sch_token;
Expand All @@ -325,6 +325,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
/* hipersocket busy condition */
if (unlikely(*busy_bit)) {
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
retries++;

if (!start_time) {
start_time = get_clock();
Expand All @@ -333,6 +334,11 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
goto again;
}
if (retries) {
DBF_DEV_EVENT(DBF_WARN, q->irq_ptr,
"%4x cc2 BB1:%1d", SCH_NO(q), q->nr);
DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "count:%u", retries);
}
return cc;
}

Expand Down Expand Up @@ -728,13 +734,14 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)

static int qdio_kick_outbound_q(struct qdio_q *q)
{
int retries = 0, cc;
unsigned int busy_bit;
int cc;

if (!need_siga_out(q))
return 0;

DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
retry:
qperf_inc(q, siga_write);

cc = qdio_siga_output(q, &busy_bit);
Expand All @@ -743,7 +750,11 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
break;
case 2:
if (busy_bit) {
DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
while (++retries < QDIO_BUSY_BIT_RETRIES) {
mdelay(QDIO_BUSY_BIT_RETRY_DELAY);
goto retry;
}
DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr);
cc |= QDIO_ERROR_SIGA_BUSY;
} else
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
Expand All @@ -753,6 +764,10 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
break;
}
if (retries) {
DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr);
DBF_ERROR("count:%u", retries);
}
return cc;
}

Expand Down

0 comments on commit be8d97a

Please sign in to comment.