]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
s390/qdio: enable drivers to poll for Output completions
authorJulian Wiedmann <jwi@linux.ibm.com>
Fri, 23 Aug 2019 09:48:47 +0000 (11:48 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 24 Aug 2019 23:39:18 +0000 (16:39 -0700)
While commit d36deae75011 ("qdio: extend API to allow polling") enhanced
the qdio layer so that drivers can poll their Input Queues, we don't
have the corresponding infrastructure for Output Queues yet.

Factor out a helper that scans a single QDIO Queue, so that qeth can
implement TX NAPI on top of it.
While doing so, remove the duplicated tracking of the next-to-scan index
(q->first_to_check vs q->first_to_kick) in this code path.

qdio_handle_aobs() needs to move slightly upwards in the code hierarchy,
so that it's still called from the polling path.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Acked-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/s390/include/asm/qdio.h
drivers/s390/cio/qdio_main.c

index f647d565bd6dc1374151f65ab2f76f84d7322e16..79b4a3e9dc5d5d52139380dbde00a6cdc6e52ef1 100644 (file)
@@ -416,6 +416,9 @@ extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
 extern int qdio_start_irq(struct ccw_device *, int);
 extern int qdio_stop_irq(struct ccw_device *, int);
 extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
+extern int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr,
+                             bool is_input, unsigned int *bufnr,
+                             unsigned int *error);
 extern int qdio_shutdown(struct ccw_device *, int);
 extern int qdio_free(struct ccw_device *);
 extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
index 4142c85e77d8baa37d7def40b88c35c48e82bd70..5efba0d29190e0f31ca43821a93d95c1589ffcb3 100644 (file)
@@ -647,8 +647,6 @@ static void qdio_kick_handler(struct qdio_q *q, unsigned int count)
                qperf_inc(q, outbound_handler);
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
                              start, count);
-               if (q->u.out.use_cq)
-                       qdio_handle_aobs(q, start, count);
        }
 
        q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
@@ -774,8 +772,11 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start)
 
        count = get_outbound_buffer_frontier(q, start);
 
-       if (count)
+       if (count) {
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
+               if (q->u.out.use_cq)
+                       qdio_handle_aobs(q, start, count);
+       }
 
        return count;
 }
@@ -1655,6 +1656,44 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
 }
 EXPORT_SYMBOL(qdio_start_irq);
 
+static int __qdio_inspect_queue(struct qdio_q *q, unsigned int *bufnr,
+                               unsigned int *error)
+{
+       unsigned int start = q->first_to_check;
+       int count;
+
+       count = q->is_input_q ? qdio_inbound_q_moved(q, start) :
+                               qdio_outbound_q_moved(q, start);
+       if (count == 0)
+               return 0;
+
+       *bufnr = start;
+       *error = q->qdio_error;
+
+       /* for the next time */
+       q->first_to_check = add_buf(start, count);
+       q->qdio_error = 0;
+
+       return count;
+}
+
+int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, bool is_input,
+                      unsigned int *bufnr, unsigned int *error)
+{
+       struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+       struct qdio_q *q;
+
+       if (!irq_ptr)
+               return -ENODEV;
+       q = is_input ? irq_ptr->input_qs[nr] : irq_ptr->output_qs[nr];
+
+       if (need_siga_sync(q))
+               qdio_siga_sync_q(q);
+
+       return __qdio_inspect_queue(q, bufnr, error);
+}
+EXPORT_SYMBOL_GPL(qdio_inspect_queue);
+
 /**
  * qdio_get_next_buffers - process input buffers
  * @cdev: associated ccw_device for the qdio subchannel
@@ -1672,13 +1711,10 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
 {
        struct qdio_q *q;
        struct qdio_irq *irq_ptr = cdev->private->qdio_data;
-       unsigned int start;
-       int count;
 
        if (!irq_ptr)
                return -ENODEV;
        q = irq_ptr->input_qs[nr];
-       start = q->first_to_check;
 
        /*
         * Cannot rely on automatic sync after interrupt since queues may
@@ -1689,25 +1725,11 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
 
        qdio_check_outbound_pci_queues(irq_ptr);
 
-       count = qdio_inbound_q_moved(q, start);
-       if (count == 0)
-               return 0;
-
-       start = add_buf(start, count);
-       q->first_to_check = start;
-
        /* Note: upper-layer MUST stop processing immediately here ... */
        if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
                return -EIO;
 
-       *bufnr = q->first_to_kick;
-       *error = q->qdio_error;
-
-       /* for the next time */
-       q->first_to_kick = add_buf(q->first_to_kick, count);
-       q->qdio_error = 0;
-
-       return count;
+       return __qdio_inspect_queue(q, bufnr, error);
 }
 EXPORT_SYMBOL(qdio_get_next_buffers);