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

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
...@@ -82,6 +82,7 @@ enum qdio_irq_states { ...@@ -82,6 +82,7 @@ enum qdio_irq_states {
#define QDIO_SIGA_WRITE 0x00 #define QDIO_SIGA_WRITE 0x00
#define QDIO_SIGA_READ 0x01 #define QDIO_SIGA_READ 0x01
#define QDIO_SIGA_SYNC 0x02 #define QDIO_SIGA_SYNC 0x02
#define QDIO_SIGA_WRITEM 0x03
#define QDIO_SIGA_WRITEQ 0x04 #define QDIO_SIGA_WRITEQ 0x04
#define QDIO_SIGA_QEBSM_FLAG 0x80 #define QDIO_SIGA_QEBSM_FLAG 0x80
......
...@@ -310,18 +310,19 @@ static inline int qdio_siga_sync_q(struct qdio_q *q) ...@@ -310,18 +310,19 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
return qdio_siga_sync(q, q->mask, 0); return qdio_siga_sync(q, q->mask, 0);
} }
static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit, static int qdio_siga_output(struct qdio_q *q, unsigned int count,
unsigned long aob) unsigned int *busy_bit, unsigned long aob)
{ {
unsigned long schid = *((u32 *) &q->irq_ptr->schid); unsigned long schid = *((u32 *) &q->irq_ptr->schid);
unsigned int fc = QDIO_SIGA_WRITE; unsigned int fc = QDIO_SIGA_WRITE;
u64 start_time = 0; u64 start_time = 0;
int retries = 0, cc; 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; fc = QDIO_SIGA_WRITEQ;
laob = aob;
} }
if (is_qebsm(q)) { if (is_qebsm(q)) {
...@@ -329,7 +330,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit, ...@@ -329,7 +330,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit,
fc |= QDIO_SIGA_QEBSM_FLAG; fc |= QDIO_SIGA_QEBSM_FLAG;
} }
again: 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 */ /* hipersocket busy condition */
if (unlikely(*busy_bit)) { if (unlikely(*busy_bit)) {
...@@ -781,7 +782,8 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start) ...@@ -781,7 +782,8 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q, unsigned int start)
return count; 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; int retries = 0, cc;
unsigned int busy_bit; unsigned int busy_bit;
...@@ -793,7 +795,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob) ...@@ -793,7 +795,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob)
retry: retry:
qperf_inc(q, siga_write); qperf_inc(q, siga_write);
cc = qdio_siga_output(q, &busy_bit, aob); cc = qdio_siga_output(q, count, &busy_bit, aob);
switch (cc) { switch (cc) {
case 0: case 0:
break; break;
...@@ -1526,7 +1528,7 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags, ...@@ -1526,7 +1528,7 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags,
* @count: how many buffers are filled * @count: how many buffers are filled
*/ */
static int handle_outbound(struct qdio_q *q, unsigned int callflags, 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; const unsigned int scan_threshold = q->irq_ptr->scan_threshold;
unsigned char state = 0; unsigned char state = 0;
...@@ -1549,13 +1551,10 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, ...@@ -1549,13 +1551,10 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
if (queue_type(q) == QDIO_IQDIO_QFMT) { if (queue_type(q) == QDIO_IQDIO_QFMT) {
unsigned long phys_aob = 0; unsigned long phys_aob = 0;
/* One SIGA-W per buffer required for unicast HSI */ if (q->u.out.use_cq && count == 1)
WARN_ON_ONCE(count > 1 && !multicast_outbound(q));
if (q->u.out.use_cq)
phys_aob = qdio_aob_for_buffer(&q->u.out, bufnr); 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)) { } else if (need_siga_sync(q)) {
rc = qdio_siga_sync_q(q); rc = qdio_siga_sync_q(q);
} else if (count < QDIO_MAX_BUFFERS_PER_Q && } else if (count < QDIO_MAX_BUFFERS_PER_Q &&
...@@ -1564,7 +1563,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, ...@@ -1564,7 +1563,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
/* The previous buffer is not processed yet, tack on. */ /* The previous buffer is not processed yet, tack on. */
qperf_inc(q, fast_requeue); qperf_inc(q, fast_requeue);
} else { } else {
rc = qdio_kick_outbound_q(q, 0); rc = qdio_kick_outbound_q(q, count, 0);
} }
/* Let drivers implement their own completion scanning: */ /* Let drivers implement their own completion scanning: */
......
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