s390/zcrypt: get rid of ap_poll_requests
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 21 Sep 2016 12:12:53 +0000 (14:12 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 14 Dec 2016 15:33:38 +0000 (16:33 +0100)
The poll thread of the AP bus is burning CPU while waiting for
crypto requests to complete. We can as well burn a few more cycles
in the poll thread to check if there are pending requests and
remove the atomic operations with the ap_poll_requests.
This improves the code if the machine has adapter interrupts.

Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/crypto/ap_bus.c

index f6de22a4f7d9b8664d0b2529ea73b4e63d09ecc5..fe1cfa4b22c9469e8542130f62d71966df2fc5e1 100644 (file)
@@ -91,7 +91,6 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus);
  */
 static void ap_tasklet_fn(unsigned long);
 static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0);
-static atomic_t ap_poll_requests = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
 static struct task_struct *ap_poll_kthread = NULL;
 static DEFINE_MUTEX(ap_poll_thread_mutex);
@@ -419,7 +418,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev)
                         ap_dev->reply->message, ap_dev->reply->length);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
-               atomic_dec(&ap_poll_requests);
                ap_dev->queue_count--;
                if (ap_dev->queue_count > 0)
                        mod_timer(&ap_dev->timeout,
@@ -436,7 +434,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev)
                if (!status.queue_empty || ap_dev->queue_count <= 0)
                        break;
                /* The card shouldn't forget requests but who knows. */
-               atomic_sub(ap_dev->queue_count, &ap_poll_requests);
                ap_dev->queue_count = 0;
                list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
                ap_dev->requestq_count += ap_dev->pendingq_count;
@@ -524,7 +521,6 @@ static enum ap_wait ap_sm_write(struct ap_device *ap_dev)
                           ap_msg->message, ap_msg->length, ap_msg->special);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
-               atomic_inc(&ap_poll_requests);
                ap_dev->queue_count++;
                if (ap_dev->queue_count == 1)
                        mod_timer(&ap_dev->timeout,
@@ -796,6 +792,27 @@ static void ap_tasklet_fn(unsigned long dummy)
        ap_sm_wait(wait);
 }
 
+static int ap_pending_requests(void)
+{
+       struct ap_device *ap_dev;
+       int id, pending = 0;
+
+       for (id = 0; pending == 0 && id < AP_DEVICES; id++) {
+               spin_lock_bh(&ap_device_list_lock);
+               list_for_each_entry(ap_dev, &ap_device_list, list) {
+                       spin_lock_bh(&ap_dev->lock);
+                       if (ap_dev->queue_count)
+                               pending = 1;
+                       spin_unlock_bh(&ap_dev->lock);
+                       if (pending)
+                               break;
+               }
+               spin_unlock_bh(&ap_device_list_lock);
+       }
+
+       return pending;
+}
+
 /**
  * ap_poll_thread(): Thread that polls for finished requests.
  * @data: Unused pointer
@@ -815,8 +832,7 @@ static int ap_poll_thread(void *data)
        while (!kthread_should_stop()) {
                add_wait_queue(&ap_poll_wait, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
-               if (ap_suspend_flag ||
-                   atomic_read(&ap_poll_requests) <= 0) {
+               if (ap_suspend_flag || !ap_pending_requests()) {
                        schedule();
                        try_to_freeze();
                }
@@ -828,7 +844,8 @@ static int ap_poll_thread(void *data)
                        continue;
                }
                ap_tasklet_fn(0);
-       } while (!kthread_should_stop());
+       }
+
        return 0;
 }
 
@@ -1267,9 +1284,6 @@ static int ap_device_remove(struct device *dev)
        spin_unlock_bh(&ap_device_list_lock);
        if (ap_drv->remove)
                ap_drv->remove(ap_dev);
-       spin_lock_bh(&ap_dev->lock);
-       atomic_sub(ap_dev->queue_count, &ap_poll_requests);
-       spin_unlock_bh(&ap_dev->lock);
        return 0;
 }