]>
Commit | Line | Data |
---|---|---|
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 | |
4 | ||
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. | |
10 | ||
11 | Acked-by: John Jolly <jjolly@suse.de> | |
12 | --- | |
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(-) | |
17 | ||
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 */ | |
24 | int polling; | |
25 | ||
26 | + /* first ACK'ed buffer */ | |
27 | + int ack_start; | |
28 | + | |
29 | /* how much sbals are acknowledged with qebsm */ | |
30 | int ack_count; | |
31 | ||
32 | @@ -231,7 +234,7 @@ struct qdio_q { | |
33 | int first_to_check; | |
34 | ||
35 | /* first_to_check of the last time */ | |
36 | - int last_move_ftc; | |
37 | + int last_move; | |
38 | ||
39 | /* beginning position for calling the program */ | |
40 | int first_to_kick; | |
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 | |
61 | ||
62 | /* show the card that we are not polling anymore */ | |
63 | if (is_qebsm(q)) { | |
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, | |
66 | q->u.in.ack_count); | |
67 | q->u.in.ack_count = 0; | |
68 | } else | |
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); | |
71 | } | |
72 | ||
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) { | |
76 | q->u.in.polling = 1; | |
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; | |
80 | return; | |
81 | } | |
82 | ||
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, | |
86 | q->u.in.ack_count); | |
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; | |
90 | return; | |
91 | } | |
92 | ||
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); | |
98 | - } | |
99 | - else { | |
100 | + set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); | |
101 | + } else { | |
102 | q->u.in.polling = 1; | |
103 | - set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); | |
104 | + set_buf_state(q, new, SLSB_P_INPUT_ACK); | |
105 | } | |
106 | ||
107 | - q->last_move_ftc = new; | |
108 | + q->u.in.ack_start = new; | |
109 | count--; | |
110 | if (!count) | |
111 | return; | |
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. | |
115 | */ | |
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, | |
118 | count); | |
119 | } | |
120 | ||
121 | @@ -514,7 +513,8 @@ int qdio_inbound_q_moved(struct qdio_q * | |
122 | ||
123 | bufnr = get_inbound_buffer_frontier(q); | |
124 | ||
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(); | |
130 | ||
131 | @@ -689,8 +689,8 @@ static inline int qdio_outbound_q_moved( | |
132 | ||
133 | bufnr = get_outbound_buffer_frontier(q); | |
134 | ||
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); | |
140 | return 1; | |
141 | } else | |
142 | @@ -732,7 +732,7 @@ static void qdio_kick_outbound_handler(s | |
143 | int start, end, count; | |
144 | ||
145 | start = q->first_to_kick; | |
146 | - end = q->last_move_ftc; | |
147 | + end = q->last_move; | |
148 | if (end >= start) | |
149 | count = end - start; | |
150 | else | |
151 | @@ -748,7 +748,7 @@ static void qdio_kick_outbound_handler(s | |
152 | q->irq_ptr->int_parm); | |
153 | ||
154 | /* for the next time: */ | |
155 | - q->first_to_kick = q->last_move_ftc; | |
156 | + q->first_to_kick = q->last_move; | |
157 | q->qdio_error = 0; | |
158 | } | |
159 | ||
160 | @@ -1453,19 +1453,18 @@ static int handle_inbound(struct qdio_q | |
161 | q->u.in.polling = 0; | |
162 | q->u.in.ack_count = 0; | |
163 | goto set; | |
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)) { | |
166 | if (is_qebsm(q)) { | |
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) { | |
174 | q->u.in.polling = 0; | |
175 | q->u.in.ack_count = 0; | |
176 | - /* TODO: must we set last_move_ftc to something meaningful? */ | |
177 | goto set; | |
178 | } | |
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); | |
181 | } | |
182 | else | |
183 | /* the only ACK will be deleted, so stop polling */ |