Commit c70d82e9 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by Vasily Gorbik
Browse files

s390/qdio: add IRQ reduction for error SBALs



SBALs in PRIMED or ERROR state represent new work on the Input Queue.
But while inbound_primed() does all sorts of ACK management for new
PRIMED work, the same handling is currently missing for ERROR work.
In particular the path for ERROR work doesn't clear up _old_ ACKs.

Treat ERROR work the same as PRIMED work, but consider that the QEBSM
auto-ACK feature doesn't apply here. So we need to set the ACK manually,
as if it was a non-QEBSM device.

Note that this doesn't aspire to actually improve performance, the main
goal is to just unify the code paths and have consistent behaviour.

Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 1db85d0e
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -438,15 +438,12 @@ static void process_buffer_error(struct qdio_q *q, unsigned int start,
		  q->sbal[start]->element[15].sflags);
}

static inline void inbound_primed(struct qdio_q *q, unsigned int start,
				  int count)
static inline void inbound_handle_work(struct qdio_q *q, unsigned int start,
				       int count, bool auto_ack)
{
	int new;

	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr, count);

	/* for QEBSM the ACK was already set by EQBS */
	if (is_qebsm(q)) {
	if (auto_ack) {
		if (!q->u.in.ack_count) {
			q->u.in.ack_count = count;
			q->u.in.ack_start = start;
@@ -507,19 +504,21 @@ static int get_inbound_buffer_frontier(struct qdio_q *q, unsigned int start)

	switch (state) {
	case SLSB_P_INPUT_PRIMED:
		inbound_primed(q, start, count);
		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr,
			      count);

		inbound_handle_work(q, start, count, is_qebsm(q));
		if (atomic_sub_return(count, &q->nr_buf_used) == 0)
			qperf_inc(q, inbound_queue_full);
		if (q->irq_ptr->perf_stat_enabled)
			account_sbals(q, count);
		return count;
	case SLSB_P_INPUT_ERROR:
		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in err:%1d %02x", q->nr,
			      count);

		process_buffer_error(q, start, count);
		/*
		 * Interrupts may be avoided as long as the error is present
		 * so change the buffer state immediately to avoid starvation.
		 */
		set_buf_states(q, start, SLSB_P_INPUT_NOT_INIT, count);
		inbound_handle_work(q, start, count, false);
		if (atomic_sub_return(count, &q->nr_buf_used) == 0)
			qperf_inc(q, inbound_queue_full);
		if (q->irq_ptr->perf_stat_enabled)