Skip to content

Commit

Permalink
s390/qeth: avoid control IO completion stalls
Browse files Browse the repository at this point in the history
For control IO, qeth currently tracks the index of the buffer that it
expects to complete the next IO on each qeth_channel. If the channel
presents an IRQ while this buffer has not yet completed, no completion
processing for _any_ completed buffer takes place.
So if the 'next buffer' is skipped for any sort of reason* (eg. when it
is released due to error conditions, before the IO is started), the
buffer obviously won't switch to PROCESSED until it is eventually
allocated for a _different_ IO and completes.
Until this happens, all completion processing on that channel stalls
and pending requests possibly time out.

As a fix, remove the whole 'next buffer' logic and simply process any
IO buffer right when it completes. A channel will never have more than
one IO pending, so there's no risk of processing out-of-sequence.

*Note: currently just one location in the code really handles this problem,
       by advancing the 'next' index manually.

Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Julian Wiedmann authored and David S. Miller committed Apr 22, 2018
1 parent 686c97e commit 901e3f4
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 19 deletions.
2 changes: 0 additions & 2 deletions drivers/s390/net/qeth_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,6 @@ enum qeth_prot_versions {
enum qeth_cmd_buffer_state {
BUF_STATE_FREE,
BUF_STATE_LOCKED,
BUF_STATE_PROCESSED,
};

enum qeth_cq {
Expand Down Expand Up @@ -601,7 +600,6 @@ struct qeth_channel {
struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
atomic_t irq_pending;
int io_buf_no;
int buf_no;
};

/**
Expand Down
22 changes: 5 additions & 17 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,6 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel)

for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
qeth_release_buffer(channel, &channel->iob[cnt]);
channel->buf_no = 0;
channel->io_buf_no = 0;
}
EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
Expand Down Expand Up @@ -924,7 +923,6 @@ static int qeth_setup_channel(struct qeth_channel *channel)
kfree(channel->iob[cnt].data);
return -ENOMEM;
}
channel->buf_no = 0;
channel->io_buf_no = 0;
atomic_set(&channel->irq_pending, 0);
spin_lock_init(&channel->iob_lock);
Expand Down Expand Up @@ -1100,11 +1098,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
{
int rc;
int cstat, dstat;
struct qeth_cmd_buffer *buffer;
struct qeth_channel *channel;
struct qeth_card *card;
struct qeth_cmd_buffer *iob;
__u8 index;

if (__qeth_check_irb_error(cdev, intparm, irb))
return;
Expand Down Expand Up @@ -1182,25 +1178,18 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
channel->state = CH_STATE_RCD_DONE;
goto out;
}
if (intparm) {
buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
buffer->state = BUF_STATE_PROCESSED;
}
if (channel == &card->data)
return;
if (channel == &card->read &&
channel->state == CH_STATE_UP)
__qeth_issue_next_read(card);

iob = channel->iob;
index = channel->buf_no;
while (iob[index].state == BUF_STATE_PROCESSED) {
if (iob[index].callback != NULL)
iob[index].callback(channel, iob + index);

index = (index + 1) % QETH_CMD_BUFFER_NO;
if (intparm) {
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
if (iob->callback)
iob->callback(iob->channel, iob);
}
channel->buf_no = index;

out:
wake_up(&card->wait_q);
return;
Expand Down Expand Up @@ -2214,7 +2203,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
error:
atomic_set(&card->write.irq_pending, 0);
qeth_release_buffer(iob->channel, iob);
card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
rc = reply->rc;
qeth_put_reply(reply);
return rc;
Expand Down

0 comments on commit 901e3f4

Please sign in to comment.