s390/qdio: implement IQD Multi-Write
This allows IQD drivers to send out multiple SBALs with a single SIGA instruction. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4a956bd22b
commit
b7f143d093
@ -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)
|
|||||||
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)) {
|
||||||
fc = QDIO_SIGA_WRITEQ;
|
if (count > 1)
|
||||||
laob = aob;
|
fc = QDIO_SIGA_WRITEM;
|
||||||
|
else if (aob)
|
||||||
|
fc = QDIO_SIGA_WRITEQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ set:
|
|||||||
* @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,
|
|||||||
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,
|
|||||||
/* 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: */
|
||||||
|
Loading…
Reference in New Issue
Block a user