]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/s390/cio/qdio_thinint.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / s390 / cio / qdio_thinint.c
index 8daf1b99f15391a27f41e48e0407b1eefa01647c..5d9c66627b6eb7554b63bda327ce62ace37bc590 100644 (file)
  */
 #define TIQDIO_NR_NONSHARED_IND                63
 #define TIQDIO_NR_INDICATORS           (TIQDIO_NR_NONSHARED_IND + 1)
-#define TIQDIO_SHARED_IND              63
 
 /* list of thin interrupt input queues */
 static LIST_HEAD(tiq_list);
 DEFINE_MUTEX(tiq_list_lock);
 
 /* adapter local summary indicator */
-static unsigned char *tiqdio_alsi;
+static u8 *tiqdio_alsi;
 
-/* device state change indicators */
-struct indicator_t {
-       u32 ind;        /* u32 because of compare-and-swap performance */
-       atomic_t count; /* use count, 0 or 1 for non-shared indicators */
-};
-static struct indicator_t *q_indicators;
+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;
@@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
        }
 }
 
-static inline int shared_ind(struct qdio_irq *irq_ptr)
+static inline int shared_ind_used(void)
 {
-       return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+       return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
 }
 
 /**
  * tiqdio_thinint_handler - thin interrupt handler for qdio
- * @ind: pointer to adapter local summary indicator
- * @drv_data: NULL
+ * @alsi: pointer to adapter local summary indicator
+ * @data: NULL
  */
-static void tiqdio_thinint_handler(void *ind, void *drv_data)
+static void tiqdio_thinint_handler(void *alsi, void *data)
 {
        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)
+        * avoidance (SVS clears adapter interrupt suppression overwrite).
         */
        if (!css_qdio_omit_svs)
                do_clear_global_summary();
 
-       /*
-        * reset local summary indicator (tiqdio_alsi) to stop adapter
-        * interrupts for now
-        */
-       xchg((u8 *)ind, 0);
+       /* reset local summary indicator */
+       if (shared_ind_used())
+               xchg(tiqdio_alsi, 0);
 
        /* protect tiq_list entries, only changed in activate or shutdown */
        rcu_read_lock();
 
        /* check for work on all inbound thinint queues */
-       list_for_each_entry_rcu(q, &tiq_list, entry)
+       list_for_each_entry_rcu(q, &tiq_list, entry) {
+
                /* only process queues from changed sets */
-               if (*q->irq_ptr->dsci) {
-                       qperf_inc(q, adapter_int);
+               if (!*q->irq_ptr->dsci)
+                       continue;
 
+               if (q->u.in.queue_start_poll) {
+                       /* skip if polling is enabled or already in work */
+                       if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+                                            &q->u.in.queue_irq_state)) {
+                               qperf_inc(q, int_discarded);
+                               continue;
+                       }
+
+                       /* avoid dsci clear here, done after processing */
+                       q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
+                                                q->irq_ptr->int_parm);
+               } else {
                        /* only clear it if the indicator is non-shared */
                        if (!shared_ind(q->irq_ptr))
                                xchg(q->irq_ptr->dsci, 0);
                        /*
-                        * don't call inbound processing directly since
-                        * that could starve other thinint queues
+                        * Call inbound processing but not directly
+                        * since that could starve other thinint queues.
                         */
                        tasklet_schedule(&q->tasklet);
                }
-
+               qperf_inc(q, adapter_int);
+       }
        rcu_read_unlock();
 
        /*
-        * if we used the shared indicator clear it now after all queues
-        * were processed
+        * If the shared indicator was used clear it now after all queues
+        * were processed.
         */
-       if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) {
+       if (shared_ind_used()) {
                xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
 
                /* prevent racing */
@@ -282,8 +292,8 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
                return;
 
        /* reset adapter interrupt indicators */
-       put_indicator(irq_ptr->dsci);
        set_subchannel_ind(irq_ptr, 1);
+       put_indicator(irq_ptr->dsci);
 }
 
 void __exit tiqdio_unregister_thinints(void)