s390/qdio: improve handling of PENDING buffers for QEBSM devices
authorJulian Wiedmann <jwi@linux.ibm.com>
Sat, 30 Jan 2021 12:04:53 +0000 (13:04 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Sat, 13 Feb 2021 16:17:55 +0000 (17:17 +0100)
For QEBSM devices the 'merge_pending' mechanism in get_buf_states()
doesn't apply, and we can actually get SLSB_P_OUTPUT_PENDING returned.

So for this case propagating the PENDING state to the driver via the
queue's sbal_state doesn't make sense and creates unnecessary overhead.
Instead introduce a new QDIO_ERROR_* flag that gets passed to the
driver, and triggers the same processing as if the buffers were flagged
as QDIO_OUTBUF_STATE_FLAG_PENDING.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/qdio.h
drivers/s390/cio/qdio_main.c
drivers/s390/net/qeth_core_main.c

index f96454f5d4cd18b656da94f0df88785673bd5238..c85f75a3d452dbf37364ce22fbaa80e417aaa934 100644 (file)
@@ -315,6 +315,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
 #define QDIO_ERROR_GET_BUF_STATE               0x0002
 #define QDIO_ERROR_SET_BUF_STATE               0x0004
 #define QDIO_ERROR_SLSB_STATE                  0x0100
+#define QDIO_ERROR_SLSB_PENDING                        0x0200
 
 #define QDIO_ERROR_FATAL                       0x00ff
 #define QDIO_ERROR_TEMPORARY                   0xff00
index 4252f43ef214561046fed922140a0456bfe1e10a..0ad5a4c1bb0865139974dc3331d0fa5252e2ace3 100644 (file)
@@ -571,6 +571,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
                                        unsigned int *error)
 {
        unsigned char state = 0;
+       unsigned int i;
        int count;
 
        q->timestamp = get_tod_clock_fast();
@@ -591,8 +592,14 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
                return 0;
 
        switch (state) {
-       case SLSB_P_OUTPUT_EMPTY:
        case SLSB_P_OUTPUT_PENDING:
+               /* detach the utilized QAOBs: */
+               for (i = 0; i < count; i++)
+                       q->u.out.aobs[QDIO_BUFNR(start + i)] = NULL;
+
+               *error = QDIO_ERROR_SLSB_PENDING;
+               fallthrough;
+       case SLSB_P_OUTPUT_EMPTY:
                /* the adapter got it */
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr,
                        "out empty:%1d %02x", q->nr, count);
@@ -643,7 +650,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start,
        if (count) {
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
 
-               if (q->u.out.use_cq) {
+               if (q->u.out.use_cq && *error != QDIO_ERROR_SLSB_PENDING) {
                        unsigned int i;
 
                        for (i = 0; i < count; i++)
index cf18d87da41e21cbd9e8fbd4703d3c8ed658ad21..13056cc2377bd4de599faa572f7a973da94589a7 100644 (file)
@@ -6068,14 +6068,17 @@ int qeth_poll(struct napi_struct *napi, int budget)
 EXPORT_SYMBOL_GPL(qeth_poll);
 
 static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
-                                unsigned int bidx, bool error, int budget)
+                                unsigned int bidx, unsigned int qdio_error,
+                                int budget)
 {
        struct qeth_qdio_out_buffer *buffer = queue->bufs[bidx];
        u8 sflags = buffer->buffer->element[15].sflags;
        struct qeth_card *card = queue->card;
+       bool error = !!qdio_error;
 
-       if (queue->bufstates && (queue->bufstates[bidx].flags &
-                                QDIO_OUTBUF_STATE_FLAG_PENDING)) {
+       if ((qdio_error == QDIO_ERROR_SLSB_PENDING) ||
+           (queue->bufstates && (queue->bufstates[bidx].flags &
+                                 QDIO_OUTBUF_STATE_FLAG_PENDING))) {
                WARN_ON_ONCE(card->options.cq != QETH_CQ_ENABLED);
 
                QETH_CARD_TEXT_(card, 5, "pel%u", bidx);