diff options
Diffstat (limited to 'drivers/s390/cio/qdio_thinint.c')
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 56 |
1 files changed, 11 insertions, 45 deletions
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 5d9c66627b6e..5c4e741d8221 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -8,6 +8,7 @@ */ #include <linux/io.h> #include <linux/slab.h> +#include <linux/kernel_stat.h> #include <asm/atomic.h> #include <asm/debug.h> #include <asm/qdio.h> @@ -35,22 +36,8 @@ static u8 *tiqdio_alsi; struct indicator_t *q_indicators; -static int css_qdio_omit_svs; - static u64 last_ai_time; -static inline unsigned long do_clear_global_summary(void) -{ - register unsigned long __fn asm("1") = 3; - register unsigned long __tmp asm("2"); - register unsigned long __time asm("3"); - - asm volatile( - " .insn rre,0xb2650000,2,0" - : "+d" (__fn), "=d" (__tmp), "=d" (__time)); - return __time; -} - /* returns addr for the device state change indicator */ static u32 *get_indicator(void) { @@ -83,10 +70,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) struct qdio_q *q; int i; - /* No TDD facility? If we must use SIGA-s we can also omit SVS. */ - if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) - css_qdio_omit_svs = 1; - mutex_lock(&tiq_list_lock); for_each_input_queue(irq_ptr, q, i) list_add_rcu(&q->entry, &tiq_list); @@ -112,9 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline int shared_ind_used(void) +static inline u32 shared_ind_set(void) { - return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count); + return q_indicators[TIQDIO_SHARED_IND].ind; } /** @@ -124,20 +107,11 @@ static inline int shared_ind_used(void) */ static void tiqdio_thinint_handler(void *alsi, void *data) { + u32 si_used = shared_ind_set(); struct qdio_q *q; last_ai_time = S390_lowcore.int_clock; - - /* - * SVS only when needed: issue SVS to benefit from iqdio interrupt - * avoidance (SVS clears adapter interrupt suppression overwrite). - */ - if (!css_qdio_omit_svs) - do_clear_global_summary(); - - /* reset local summary indicator */ - if (shared_ind_used()) - xchg(tiqdio_alsi, 0); + kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; /* protect tiq_list entries, only changed in activate or shutdown */ rcu_read_lock(); @@ -146,7 +120,10 @@ static void tiqdio_thinint_handler(void *alsi, void *data) list_for_each_entry_rcu(q, &tiq_list, entry) { /* only process queues from changed sets */ - if (!*q->irq_ptr->dsci) + if (unlikely(shared_ind(q->irq_ptr->dsci))) { + if (!si_used) + continue; + } else if (!*q->irq_ptr->dsci) continue; if (q->u.in.queue_start_poll) { @@ -162,7 +139,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) q->irq_ptr->int_parm); } else { /* only clear it if the indicator is non-shared */ - if (!shared_ind(q->irq_ptr)) + if (!shared_ind(q->irq_ptr->dsci)) xchg(q->irq_ptr->dsci, 0); /* * Call inbound processing but not directly @@ -178,13 +155,8 @@ static void tiqdio_thinint_handler(void *alsi, void *data) * If the shared indicator was used clear it now after all queues * were processed. */ - if (shared_ind_used()) { + if (si_used && shared_ind_set()) xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); - - /* prevent racing */ - if (*tiqdio_alsi) - xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); - } } static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) @@ -269,12 +241,6 @@ int qdio_establish_thinint(struct qdio_irq *irq_ptr) { if (!is_thinint_irq(irq_ptr)) return 0; - - /* Check for aif time delay disablement. If installed, - * omit SVS even under LPAR - */ - if (css_general_characteristics.aif_tdd) - css_qdio_omit_svs = 1; return set_subchannel_ind(irq_ptr, 0); } |