summaryrefslogtreecommitdiff
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.ibm.com>2021-01-30 15:22:56 +0300
committerVasily Gorbik <gor@linux.ibm.com>2021-02-13 19:17:55 +0300
commit2223318c2862edc7f5b282939b850b19fc934ec4 (patch)
tree108313403728d793c2de3223f6082d11d0ea006b /drivers/s390/cio
parent7940eaf2e956ce3d67ac9efb5b621adbb823e049 (diff)
downloadlinux-2223318c2862edc7f5b282939b850b19fc934ec4.tar.xz
s390/qdio: remove 'merge_pending' mechanism
For non-QEBSM devices, get_buf_states() merges PENDING and EMPTY buffers into a single group of finished buffers. To allow the upper-layer driver to differentiate between the two states, qdio_check_pending() looks at each buffer's state again and sets the sbal_state flag to QDIO_OUTBUF_STATE_FLAG_PENDING accordingly. So effectively we're spending overhead on _every_ Output Queue inspection, just to avoid some additional TX completion calls in case a group of buffers has completed with mixed EMPTY / PENDING state. Given that PENDING buffers should rarely occur, this is a bad trade-off. In particular so as the additional checks in get_buf_states() affect _all_ device types (even those that don't use the PENDING state). Rip it all out, and just report the PENDING completions separately as we already do for QEBSM devices. 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>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/qdio_main.c59
1 files changed, 9 insertions, 50 deletions
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 0ad5a4c1bb08..03a011619908 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -202,7 +202,7 @@ again:
*/
static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
unsigned char *state, unsigned int count,
- int auto_ack, int merge_pending)
+ int auto_ack)
{
unsigned char __state = 0;
int i = 1;
@@ -217,18 +217,9 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
if (__state & SLSB_OWNER_CU)
goto out;
- if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
- __state = SLSB_P_OUTPUT_EMPTY;
-
for (; i < count; i++) {
bufnr = next_buf(bufnr);
- /* merge PENDING into EMPTY: */
- if (merge_pending &&
- q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING &&
- __state == SLSB_P_OUTPUT_EMPTY)
- continue;
-
/* stop if next state differs from initial state: */
if (q->slsb.val[bufnr] != __state)
break;
@@ -242,7 +233,7 @@ out:
static inline int get_buf_state(struct qdio_q *q, unsigned int bufnr,
unsigned char *state, int auto_ack)
{
- return get_buf_states(q, bufnr, state, 1, auto_ack, 0);
+ return get_buf_states(q, bufnr, state, 1, auto_ack);
}
/* wrap-around safe setting of slsb states, returns number of changed buffers */
@@ -464,7 +455,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q, unsigned int start,
* No siga sync here, as a PCI or we after a thin interrupt
* already sync'ed the queues.
*/
- count = get_buf_states(q, start, &state, count, 1, 0);
+ count = get_buf_states(q, start, &state, count, 1);
if (!count)
return 0;
@@ -541,7 +532,6 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
WARN_ON_ONCE(phys_aob & 0xFF);
}
- q->sbal_state[bufnr].flags = 0;
return phys_aob;
}
@@ -554,19 +544,6 @@ static inline int qdio_tasklet_schedule(struct qdio_q *q)
return -EPERM;
}
-static void qdio_check_pending(struct qdio_q *q, unsigned int index)
-{
- unsigned char state;
-
- if (get_buf_state(q, index, &state, 0) > 0 &&
- state == SLSB_P_OUTPUT_PENDING &&
- q->u.out.aobs[index]) {
- q->u.out.sbal_state[index].flags |=
- QDIO_OUTBUF_STATE_FLAG_PENDING;
- q->u.out.aobs[index] = NULL;
- }
-}
-
static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
unsigned int *error)
{
@@ -587,7 +564,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
if (!count)
return 0;
- count = get_buf_states(q, start, &state, count, 0, q->u.out.use_cq);
+ count = get_buf_states(q, start, &state, count, 0);
if (!count)
return 0;
@@ -609,6 +586,9 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
account_sbals(q, count);
return count;
case SLSB_P_OUTPUT_ERROR:
+ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out error:%1d %02x",
+ q->nr, count);
+
*error = QDIO_ERROR_SLSB_STATE;
process_buffer_error(q, start, count);
atomic_sub(count, &q->nr_buf_used);
@@ -640,27 +620,6 @@ static inline int qdio_outbound_q_done(struct qdio_q *q)
return atomic_read(&q->nr_buf_used) == 0;
}
-static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start,
- unsigned int *error)
-{
- int count;
-
- count = get_outbound_buffer_frontier(q, start, error);
-
- if (count) {
- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
-
- if (q->u.out.use_cq && *error != QDIO_ERROR_SLSB_PENDING) {
- unsigned int i;
-
- for (i = 0; i < count; i++)
- qdio_check_pending(q, QDIO_BUFNR(start + i));
- }
- }
-
- return count;
-}
-
static int qdio_kick_outbound_q(struct qdio_q *q, unsigned int count,
unsigned long aob)
{
@@ -715,7 +674,7 @@ void qdio_outbound_tasklet(struct tasklet_struct *t)
qperf_inc(q, tasklet_outbound);
WARN_ON_ONCE(atomic_read(&q->nr_buf_used) < 0);
- count = qdio_outbound_q_moved(q, start, &error);
+ count = get_outbound_buffer_frontier(q, start, &error);
if (count) {
q->first_to_check = add_buf(start, count);
@@ -1482,7 +1441,7 @@ static int __qdio_inspect_queue(struct qdio_q *q, unsigned int *bufnr,
*error = 0;
count = q->is_input_q ? get_inbound_buffer_frontier(q, start, error) :
- qdio_outbound_q_moved(q, start, error);
+ get_outbound_buffer_frontier(q, start, error);
if (count == 0)
return 0;