1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: qdio: move ACK to newest buffer for devices without QEBSM
3 References: bnc#484767,LTC#52208
5 Symptom: Lower performance of non-QEBSM qdio devices under heavy traffic
6 Problem: The ACKnowledgement state is set on the first SBAL so in case of
7 multiple PRIMED buffers the firmware has to scan all buffers.
8 Solution: The ACKnowledgement state is set on the newest SBAL so an
9 adapter interrupt surpression check needs to scan fewer SBALs.
11 Acked-by: John Jolly <jjolly@suse.de>
13 drivers/s390/cio/qdio.h | 5 ++++-
14 drivers/s390/cio/qdio_debug.c | 3 ++-
15 drivers/s390/cio/qdio_main.c | 41 ++++++++++++++++++++---------------------
16 3 files changed, 26 insertions(+), 23 deletions(-)
18 Index: linux-sles11/drivers/s390/cio/qdio.h
19 ===================================================================
20 --- linux-sles11.orig/drivers/s390/cio/qdio.h
21 +++ linux-sles11/drivers/s390/cio/qdio.h
22 @@ -186,6 +186,9 @@ struct qdio_input_q {
23 /* input buffer acknowledgement flag */
26 + /* first ACK'ed buffer */
29 /* how much sbals are acknowledged with qebsm */
32 @@ -231,7 +234,7 @@ struct qdio_q {
35 /* first_to_check of the last time */
39 /* beginning position for calling the program */
41 Index: linux-sles11/drivers/s390/cio/qdio_debug.c
42 ===================================================================
43 --- linux-sles11.orig/drivers/s390/cio/qdio_debug.c
44 +++ linux-sles11/drivers/s390/cio/qdio_debug.c
45 @@ -62,8 +62,9 @@ static int qstat_show(struct seq_file *m
46 seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
47 seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
48 seq_printf(m, "ftc: %d\n", q->first_to_check);
49 - seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc);
50 + seq_printf(m, "last_move: %d\n", q->last_move);
51 seq_printf(m, "polling: %d\n", q->u.in.polling);
52 + seq_printf(m, "ack start: %d\n", q->u.in.ack_start);
53 seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
54 seq_printf(m, "slsb buffer states:\n");
55 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
56 Index: linux-sles11/drivers/s390/cio/qdio_main.c
57 ===================================================================
58 --- linux-sles11.orig/drivers/s390/cio/qdio_main.c
59 +++ linux-sles11/drivers/s390/cio/qdio_main.c
60 @@ -371,11 +371,11 @@ inline void qdio_stop_polling(struct qdi
62 /* show the card that we are not polling anymore */
64 - set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
65 + set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
67 q->u.in.ack_count = 0;
69 - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
70 + set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
73 static void announce_buffer_error(struct qdio_q *q, int count)
74 @@ -410,15 +410,15 @@ static inline void inbound_primed(struct
75 if (!q->u.in.polling) {
77 q->u.in.ack_count = count;
78 - q->last_move_ftc = q->first_to_check;
79 + q->u.in.ack_start = q->first_to_check;
83 /* delete the previous ACK's */
84 - set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
85 + set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
87 q->u.in.ack_count = count;
88 - q->last_move_ftc = q->first_to_check;
89 + q->u.in.ack_start = q->first_to_check;
93 @@ -430,14 +430,13 @@ static inline void inbound_primed(struct
94 if (q->u.in.polling) {
95 /* reset the previous ACK but first set the new one */
96 set_buf_state(q, new, SLSB_P_INPUT_ACK);
97 - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
100 + set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
103 - set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK);
104 + set_buf_state(q, new, SLSB_P_INPUT_ACK);
107 - q->last_move_ftc = new;
108 + q->u.in.ack_start = new;
112 @@ -446,7 +445,7 @@ static inline void inbound_primed(struct
113 * Need to change all PRIMED buffers to NOT_INIT, otherwise
114 * we're loosing initiative in the thinint code.
116 - set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT,
117 + set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT,
121 @@ -514,7 +513,8 @@ int qdio_inbound_q_moved(struct qdio_q *
123 bufnr = get_inbound_buffer_frontier(q);
125 - if ((bufnr != q->last_move_ftc) || q->qdio_error) {
126 + if ((bufnr != q->last_move) || q->qdio_error) {
127 + q->last_move = bufnr;
128 if (!need_siga_sync(q) && !pci_out_supported(q))
129 q->u.in.timestamp = get_usecs();
131 @@ -689,8 +689,8 @@ static inline int qdio_outbound_q_moved(
133 bufnr = get_outbound_buffer_frontier(q);
135 - if ((bufnr != q->last_move_ftc) || q->qdio_error) {
136 - q->last_move_ftc = bufnr;
137 + if ((bufnr != q->last_move) || q->qdio_error) {
138 + q->last_move = bufnr;
139 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
142 @@ -732,7 +732,7 @@ static void qdio_kick_outbound_handler(s
143 int start, end, count;
145 start = q->first_to_kick;
146 - end = q->last_move_ftc;
147 + end = q->last_move;
151 @@ -748,7 +748,7 @@ static void qdio_kick_outbound_handler(s
152 q->irq_ptr->int_parm);
154 /* for the next time: */
155 - q->first_to_kick = q->last_move_ftc;
156 + q->first_to_kick = q->last_move;
160 @@ -1453,19 +1453,18 @@ static int handle_inbound(struct qdio_q
162 q->u.in.ack_count = 0;
164 - } else if (buf_in_between(q->last_move_ftc, bufnr, count)) {
165 + } else if (buf_in_between(q->u.in.ack_start, bufnr, count)) {
167 - /* partial overwrite, just update last_move_ftc */
168 + /* partial overwrite, just update ack_start */
169 diff = add_buf(bufnr, count);
170 - diff = sub_buf(diff, q->last_move_ftc);
171 + diff = sub_buf(diff, q->u.in.ack_start);
172 q->u.in.ack_count -= diff;
173 if (q->u.in.ack_count <= 0) {
175 q->u.in.ack_count = 0;
176 - /* TODO: must we set last_move_ftc to something meaningful? */
179 - q->last_move_ftc = add_buf(q->last_move_ftc, diff);
180 + q->u.in.ack_start = add_buf(q->u.in.ack_start, diff);
183 /* the only ACK will be deleted, so stop polling */