qdio: support asynchronous delivery of storage blocks
[pandora-kernel.git] / drivers / s390 / cio / qdio_thinint.c
index 2a1d4df..a3e3949 100644 (file)
@@ -67,12 +67,9 @@ static void put_indicator(u32 *addr)
 
 void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
 {
-       struct qdio_q *q;
-       int i;
-
        mutex_lock(&tiq_list_lock);
-       for_each_input_queue(irq_ptr, q, i)
-               list_add_rcu(&q->entry, &tiq_list);
+       BUG_ON(irq_ptr->nr_input_qs < 1);
+       list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list);
        mutex_unlock(&tiq_list_lock);
        xchg(irq_ptr->dsci, 1 << 7);
 }
@@ -80,19 +77,17 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
 void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
 {
        struct qdio_q *q;
-       int i;
 
-       for (i = 0; i < irq_ptr->nr_input_qs; i++) {
-               q = irq_ptr->input_qs[i];
-               /* if establish triggered an error */
-               if (!q || !q->entry.prev || !q->entry.next)
-                       continue;
+       BUG_ON(irq_ptr->nr_input_qs < 1);
+       q = irq_ptr->input_qs[0];
+       /* if establish triggered an error */
+       if (!q || !q->entry.prev || !q->entry.next)
+               return;
 
-               mutex_lock(&tiq_list_lock);
-               list_del_rcu(&q->entry);
-               mutex_unlock(&tiq_list_lock);
-               synchronize_rcu();
-       }
+       mutex_lock(&tiq_list_lock);
+       list_del_rcu(&q->entry);
+       mutex_unlock(&tiq_list_lock);
+       synchronize_rcu();
 }
 
 static inline u32 clear_shared_ind(void)
@@ -102,6 +97,40 @@ static inline u32 clear_shared_ind(void)
        return xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
 }
 
+static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
+{
+       struct qdio_q *q;
+       int i;
+
+       for_each_input_queue(irq, q, i) {
+               if (!references_shared_dsci(irq) &&
+                   has_multiple_inq_on_dsci(irq))
+                       xchg(q->irq_ptr->dsci, 0);
+
+               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 {
+                       if (!shared_ind(q))
+                               xchg(q->irq_ptr->dsci, 0);
+
+                       /*
+                        * Call inbound processing but not directly
+                        * since that could starve other thinint queues.
+                        */
+                       tasklet_schedule(&q->tasklet);
+               }
+       }
+}
+
 /**
  * tiqdio_thinint_handler - thin interrupt handler for qdio
  * @alsi: pointer to adapter local summary indicator
@@ -120,35 +149,18 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
 
        /* check for work on all inbound thinint queues */
        list_for_each_entry_rcu(q, &tiq_list, entry) {
+               struct qdio_irq *irq;
 
                /* only process queues from changed sets */
-               if (unlikely(shared_ind(q->irq_ptr->dsci))) {
+               irq = q->irq_ptr;
+               if (unlikely(references_shared_dsci(irq))) {
                        if (!si_used)
                                continue;
-               } else if (!*q->irq_ptr->dsci)
+               } else if (!*irq->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;
-                       }
+               tiqdio_call_inq_handlers(irq);
 
-                       /* 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->dsci))
-                               xchg(q->irq_ptr->dsci, 0);
-                       /*
-                        * 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();