Commit 772f54720ab82a6e88f0a8a84d76e7af15ca1f0c

Authored by Felix Beck
Committed by Martin Schwidefsky
1 parent 6618241b47

[S390] ap/zcrypt: Suspend/Resume ap bus and zcrypt

Add Suspend/Resume support to ap bus and zcrypt. All enhancements are
done in the ap bus. No changes in the crypto card specific part are
necessary.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

Showing 1 changed file with 83 additions and 2 deletions Side-by-side Diff

drivers/s390/crypto/ap_bus.c
... ... @@ -54,6 +54,12 @@
54 54 static void ap_poll_thread_stop(void);
55 55 static void ap_request_timeout(unsigned long);
56 56 static inline void ap_schedule_poll_timer(void);
  57 +static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags);
  58 +static int ap_device_remove(struct device *dev);
  59 +static int ap_device_probe(struct device *dev);
  60 +static void ap_interrupt_handler(void *unused1, void *unused2);
  61 +static void ap_reset(struct ap_device *ap_dev);
  62 +static void ap_config_timeout(unsigned long ptr);
57 63  
58 64 /*
59 65 * Module description.
... ... @@ -101,6 +107,10 @@
101 107 * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
102 108 static unsigned long long poll_timeout = 250000;
103 109  
  110 +/* Suspend flag */
  111 +static int ap_suspend_flag;
  112 +static struct bus_type ap_bus_type;
  113 +
104 114 /**
105 115 * ap_using_interrupts() - Returns non-zero if interrupt support is
106 116 * available.
107 117  
... ... @@ -617,10 +627,79 @@
617 627 return retval;
618 628 }
619 629  
  630 +static int ap_bus_suspend(struct device *dev, pm_message_t state)
  631 +{
  632 + struct ap_device *ap_dev = to_ap_dev(dev);
  633 + unsigned long flags;
  634 +
  635 + if (!ap_suspend_flag) {
  636 + ap_suspend_flag = 1;
  637 +
  638 + /* Disable scanning for devices, thus we do not want to scan
  639 + * for them after removing.
  640 + */
  641 + del_timer_sync(&ap_config_timer);
  642 + if (ap_work_queue != NULL) {
  643 + destroy_workqueue(ap_work_queue);
  644 + ap_work_queue = NULL;
  645 + }
  646 + tasklet_disable(&ap_tasklet);
  647 + }
  648 + /* Poll on the device until all requests are finished. */
  649 + do {
  650 + flags = 0;
  651 + __ap_poll_device(ap_dev, &flags);
  652 + } while ((flags & 1) || (flags & 2));
  653 +
  654 + ap_device_remove(dev);
  655 + return 0;
  656 +}
  657 +
  658 +static int ap_bus_resume(struct device *dev)
  659 +{
  660 + int rc = 0;
  661 + struct ap_device *ap_dev = to_ap_dev(dev);
  662 +
  663 + if (ap_suspend_flag) {
  664 + ap_suspend_flag = 0;
  665 + if (!ap_interrupts_available())
  666 + ap_interrupt_indicator = NULL;
  667 + ap_device_probe(dev);
  668 + ap_reset(ap_dev);
  669 + setup_timer(&ap_dev->timeout, ap_request_timeout,
  670 + (unsigned long) ap_dev);
  671 + ap_scan_bus(NULL);
  672 + init_timer(&ap_config_timer);
  673 + ap_config_timer.function = ap_config_timeout;
  674 + ap_config_timer.data = 0;
  675 + ap_config_timer.expires = jiffies + ap_config_time * HZ;
  676 + add_timer(&ap_config_timer);
  677 + ap_work_queue = create_singlethread_workqueue("kapwork");
  678 + if (!ap_work_queue)
  679 + return -ENOMEM;
  680 + tasklet_enable(&ap_tasklet);
  681 + if (!ap_using_interrupts())
  682 + ap_schedule_poll_timer();
  683 + else
  684 + tasklet_schedule(&ap_tasklet);
  685 + if (ap_thread_flag)
  686 + rc = ap_poll_thread_start();
  687 + } else {
  688 + ap_device_probe(dev);
  689 + ap_reset(ap_dev);
  690 + setup_timer(&ap_dev->timeout, ap_request_timeout,
  691 + (unsigned long) ap_dev);
  692 + }
  693 +
  694 + return rc;
  695 +}
  696 +
620 697 static struct bus_type ap_bus_type = {
621 698 .name = "ap",
622 699 .match = &ap_bus_match,
623 700 .uevent = &ap_uevent,
  701 + .suspend = ap_bus_suspend,
  702 + .resume = ap_bus_resume
624 703 };
625 704  
626 705 static int ap_device_probe(struct device *dev)
... ... @@ -1066,7 +1145,7 @@
1066 1145 */
1067 1146 static inline void ap_schedule_poll_timer(void)
1068 1147 {
1069   - if (ap_using_interrupts())
  1148 + if (ap_using_interrupts() || ap_suspend_flag)
1070 1149 return;
1071 1150 if (hrtimer_is_queued(&ap_poll_timer))
1072 1151 return;
... ... @@ -1384,6 +1463,8 @@
1384 1463  
1385 1464 set_user_nice(current, 19);
1386 1465 while (1) {
  1466 + if (ap_suspend_flag)
  1467 + return 0;
1387 1468 if (need_resched()) {
1388 1469 schedule();
1389 1470 continue;
... ... @@ -1414,7 +1495,7 @@
1414 1495 {
1415 1496 int rc;
1416 1497  
1417   - if (ap_using_interrupts())
  1498 + if (ap_using_interrupts() || ap_suspend_flag)
1418 1499 return 0;
1419 1500 mutex_lock(&ap_poll_thread_mutex);
1420 1501 if (!ap_poll_kthread) {