Commit b7f143d0 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller
Browse files

s390/qdio: implement IQD Multi-Write



This allows IQD drivers to send out multiple SBALs with a single SIGA
instruction.

Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: default avatarAlexandra Winter <wintera@linux.ibm.com>
Acked-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4a956bd2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ enum qdio_irq_states {
#define QDIO_SIGA_WRITE		0x00
#define QDIO_SIGA_READ		0x01
#define QDIO_SIGA_SYNC		0x02
#define QDIO_SIGA_WRITEM	0x03
#define QDIO_SIGA_WRITEQ	0x04
#define QDIO_SIGA_QEBSM_FLAG	0x80

+15 −16
Original line number Diff line number Diff line
@@ -310,18 +310,19 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
		return qdio_siga_sync(q, q->mask, 0);
}

static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit,
	unsigned long aob)
static int qdio_siga_output(struct qdio_q *q, unsigned int count,
			    unsigned int *busy_bit, unsigned long aob)
{
	unsigned long schid = *((u32 *) &q->irq_ptr->schid);
	unsigned int fc = QDIO_SIGA_WRITE;
	u64 start_time = 0;
	int retries = 0, cc;
	unsigned long laob = 0;

	if (aob) {
	if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) {
		if (count > 1)
			fc = QDIO_SIGA_WRITEM;
		else if (aob)
			fc = QDIO_SIGA_WRITEQ;
		laob = aob;
	}

	if (is_qebsm(q)) {
@@ -329,7 +330,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit,
		fc |= QDIO_SIGA_QEBSM_FLAG;
	}
again:
	cc = do_siga_output(schid, q->mask, busy_bit, fc, laob);
	cc = do_siga_output(schid, q->mask, busy_bit, fc, aob);

	/* hipersocket busy condition */
	if (unlikely(*busy_bit)) {
@@ -781,7 +782,8 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start)
	return count;
}

static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob)
static int qdio_kick_outbound_q(struct qdio_q *q, unsigned int count,
				unsigned long aob)
{
	int retries = 0, cc;
	unsigned int busy_bit;
@@ -793,7 +795,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob)
retry:
	qperf_inc(q, siga_write);

	cc = qdio_siga_output(q, &busy_bit, aob);
	cc = qdio_siga_output(q, count, &busy_bit, aob);
	switch (cc) {
	case 0:
		break;
@@ -1526,7 +1528,7 @@ set:
 * @count: how many buffers are filled
 */
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
			   int bufnr, int count)
			   unsigned int bufnr, unsigned int count)
{
	const unsigned int scan_threshold = q->irq_ptr->scan_threshold;
	unsigned char state = 0;
@@ -1549,13 +1551,10 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
	if (queue_type(q) == QDIO_IQDIO_QFMT) {
		unsigned long phys_aob = 0;

		/* One SIGA-W per buffer required for unicast HSI */
		WARN_ON_ONCE(count > 1 && !multicast_outbound(q));

		if (q->u.out.use_cq)
		if (q->u.out.use_cq && count == 1)
			phys_aob = qdio_aob_for_buffer(&q->u.out, bufnr);

		rc = qdio_kick_outbound_q(q, phys_aob);
		rc = qdio_kick_outbound_q(q, count, phys_aob);
	} else if (need_siga_sync(q)) {
		rc = qdio_siga_sync_q(q);
	} else if (count < QDIO_MAX_BUFFERS_PER_Q &&
@@ -1564,7 +1563,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
		/* The previous buffer is not processed yet, tack on. */
		qperf_inc(q, fast_requeue);
	} else {
		rc = qdio_kick_outbound_q(q, 0);
		rc = qdio_kick_outbound_q(q, count, 0);
	}

	/* Let drivers implement their own completion scanning: */