Commit 7c47f5af authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qdio: enable drivers to poll for Output completions

While commit d36deae7 ("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: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Acked-by: default avatarVasily Gorbik <gor@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fbbdbc64
...@@ -416,6 +416,9 @@ extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int, ...@@ -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_start_irq(struct ccw_device *, int);
extern int qdio_stop_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_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_shutdown(struct ccw_device *, int);
extern int qdio_free(struct ccw_device *); extern int qdio_free(struct ccw_device *);
extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *); extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
......
...@@ -647,8 +647,6 @@ static void qdio_kick_handler(struct qdio_q *q, unsigned int count) ...@@ -647,8 +647,6 @@ static void qdio_kick_handler(struct qdio_q *q, unsigned int count)
qperf_inc(q, outbound_handler); qperf_inc(q, outbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
start, count); 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, 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) ...@@ -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); count = get_outbound_buffer_frontier(q, start);
if (count) if (count) {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); 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; return count;
} }
...@@ -1655,6 +1656,44 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) ...@@ -1655,6 +1656,44 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
} }
EXPORT_SYMBOL(qdio_start_irq); 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 * qdio_get_next_buffers - process input buffers
* @cdev: associated ccw_device for the qdio subchannel * @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, ...@@ -1672,13 +1711,10 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
{ {
struct qdio_q *q; struct qdio_q *q;
struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct qdio_irq *irq_ptr = cdev->private->qdio_data;
unsigned int start;
int count;
if (!irq_ptr) if (!irq_ptr)
return -ENODEV; return -ENODEV;
q = irq_ptr->input_qs[nr]; q = irq_ptr->input_qs[nr];
start = q->first_to_check;
/* /*
* Cannot rely on automatic sync after interrupt since queues may * 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, ...@@ -1689,25 +1725,11 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
qdio_check_outbound_pci_queues(irq_ptr); 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 ... */ /* Note: upper-layer MUST stop processing immediately here ... */
if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
return -EIO; return -EIO;
*bufnr = q->first_to_kick; return __qdio_inspect_queue(q, bufnr, error);
*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;
} }
EXPORT_SYMBOL(qdio_get_next_buffers); EXPORT_SYMBOL(qdio_get_next_buffers);
......
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