diff options
Diffstat (limited to 'drivers/s390/cio/qdio_thinint.c')
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 54 |
1 files changed, 9 insertions, 45 deletions
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 64b59a58a1cd..5c4e741d8221 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
@@ -36,22 +36,8 @@ static u8 *tiqdio_alsi; | |||
36 | 36 | ||
37 | struct indicator_t *q_indicators; | 37 | struct indicator_t *q_indicators; |
38 | 38 | ||
39 | static int css_qdio_omit_svs; | ||
40 | |||
41 | static u64 last_ai_time; | 39 | static u64 last_ai_time; |
42 | 40 | ||
43 | static inline unsigned long do_clear_global_summary(void) | ||
44 | { | ||
45 | register unsigned long __fn asm("1") = 3; | ||
46 | register unsigned long __tmp asm("2"); | ||
47 | register unsigned long __time asm("3"); | ||
48 | |||
49 | asm volatile( | ||
50 | " .insn rre,0xb2650000,2,0" | ||
51 | : "+d" (__fn), "=d" (__tmp), "=d" (__time)); | ||
52 | return __time; | ||
53 | } | ||
54 | |||
55 | /* returns addr for the device state change indicator */ | 41 | /* returns addr for the device state change indicator */ |
56 | static u32 *get_indicator(void) | 42 | static u32 *get_indicator(void) |
57 | { | 43 | { |
@@ -84,10 +70,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) | |||
84 | struct qdio_q *q; | 70 | struct qdio_q *q; |
85 | int i; | 71 | int i; |
86 | 72 | ||
87 | /* No TDD facility? If we must use SIGA-s we can also omit SVS. */ | ||
88 | if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) | ||
89 | css_qdio_omit_svs = 1; | ||
90 | |||
91 | mutex_lock(&tiq_list_lock); | 73 | mutex_lock(&tiq_list_lock); |
92 | for_each_input_queue(irq_ptr, q, i) | 74 | for_each_input_queue(irq_ptr, q, i) |
93 | list_add_rcu(&q->entry, &tiq_list); | 75 | list_add_rcu(&q->entry, &tiq_list); |
@@ -113,9 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) | |||
113 | } | 95 | } |
114 | } | 96 | } |
115 | 97 | ||
116 | static inline int shared_ind_used(void) | 98 | static inline u32 shared_ind_set(void) |
117 | { | 99 | { |
118 | return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count); | 100 | return q_indicators[TIQDIO_SHARED_IND].ind; |
119 | } | 101 | } |
120 | 102 | ||
121 | /** | 103 | /** |
@@ -125,22 +107,12 @@ static inline int shared_ind_used(void) | |||
125 | */ | 107 | */ |
126 | static void tiqdio_thinint_handler(void *alsi, void *data) | 108 | static void tiqdio_thinint_handler(void *alsi, void *data) |
127 | { | 109 | { |
110 | u32 si_used = shared_ind_set(); | ||
128 | struct qdio_q *q; | 111 | struct qdio_q *q; |
129 | 112 | ||
130 | last_ai_time = S390_lowcore.int_clock; | 113 | last_ai_time = S390_lowcore.int_clock; |
131 | kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; | 114 | kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; |
132 | 115 | ||
133 | /* | ||
134 | * SVS only when needed: issue SVS to benefit from iqdio interrupt | ||
135 | * avoidance (SVS clears adapter interrupt suppression overwrite). | ||
136 | */ | ||
137 | if (!css_qdio_omit_svs) | ||
138 | do_clear_global_summary(); | ||
139 | |||
140 | /* reset local summary indicator */ | ||
141 | if (shared_ind_used()) | ||
142 | xchg(tiqdio_alsi, 0); | ||
143 | |||
144 | /* protect tiq_list entries, only changed in activate or shutdown */ | 116 | /* protect tiq_list entries, only changed in activate or shutdown */ |
145 | rcu_read_lock(); | 117 | rcu_read_lock(); |
146 | 118 | ||
@@ -148,7 +120,10 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
148 | list_for_each_entry_rcu(q, &tiq_list, entry) { | 120 | list_for_each_entry_rcu(q, &tiq_list, entry) { |
149 | 121 | ||
150 | /* only process queues from changed sets */ | 122 | /* only process queues from changed sets */ |
151 | if (!*q->irq_ptr->dsci) | 123 | if (unlikely(shared_ind(q->irq_ptr->dsci))) { |
124 | if (!si_used) | ||
125 | continue; | ||
126 | } else if (!*q->irq_ptr->dsci) | ||
152 | continue; | 127 | continue; |
153 | 128 | ||
154 | if (q->u.in.queue_start_poll) { | 129 | if (q->u.in.queue_start_poll) { |
@@ -164,7 +139,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
164 | q->irq_ptr->int_parm); | 139 | q->irq_ptr->int_parm); |
165 | } else { | 140 | } else { |
166 | /* only clear it if the indicator is non-shared */ | 141 | /* only clear it if the indicator is non-shared */ |
167 | if (!shared_ind(q->irq_ptr)) | 142 | if (!shared_ind(q->irq_ptr->dsci)) |
168 | xchg(q->irq_ptr->dsci, 0); | 143 | xchg(q->irq_ptr->dsci, 0); |
169 | /* | 144 | /* |
170 | * Call inbound processing but not directly | 145 | * Call inbound processing but not directly |
@@ -180,13 +155,8 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
180 | * If the shared indicator was used clear it now after all queues | 155 | * If the shared indicator was used clear it now after all queues |
181 | * were processed. | 156 | * were processed. |
182 | */ | 157 | */ |
183 | if (shared_ind_used()) { | 158 | if (si_used && shared_ind_set()) |
184 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); | 159 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); |
185 | |||
186 | /* prevent racing */ | ||
187 | if (*tiqdio_alsi) | ||
188 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); | ||
189 | } | ||
190 | } | 160 | } |
191 | 161 | ||
192 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) | 162 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) |
@@ -271,12 +241,6 @@ int qdio_establish_thinint(struct qdio_irq *irq_ptr) | |||
271 | { | 241 | { |
272 | if (!is_thinint_irq(irq_ptr)) | 242 | if (!is_thinint_irq(irq_ptr)) |
273 | return 0; | 243 | return 0; |
274 | |||
275 | /* Check for aif time delay disablement. If installed, | ||
276 | * omit SVS even under LPAR | ||
277 | */ | ||
278 | if (css_general_characteristics.aif_tdd) | ||
279 | css_qdio_omit_svs = 1; | ||
280 | return set_subchannel_ind(irq_ptr, 0); | 244 | return set_subchannel_ind(irq_ptr, 0); |
281 | } | 245 | } |
282 | 246 | ||