Commit 772f54720ab82a6e88f0a8a84d76e7af15ca1f0c
Committed by
Martin Schwidefsky
1 parent
6618241b47
Exists in
master
and in
39 other branches
[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) { |