diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 090b32a339c6..1294876bf7b4 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -60,6 +60,7 @@ static int ap_device_probe(struct device *dev); | |||
60 | static void ap_interrupt_handler(void *unused1, void *unused2); | 60 | static void ap_interrupt_handler(void *unused1, void *unused2); |
61 | static void ap_reset(struct ap_device *ap_dev); | 61 | static void ap_reset(struct ap_device *ap_dev); |
62 | static void ap_config_timeout(unsigned long ptr); | 62 | static void ap_config_timeout(unsigned long ptr); |
63 | static int ap_select_domain(void); | ||
63 | 64 | ||
64 | /* | 65 | /* |
65 | * Module description. | 66 | * Module description. |
@@ -109,6 +110,10 @@ static unsigned long long poll_timeout = 250000; | |||
109 | 110 | ||
110 | /* Suspend flag */ | 111 | /* Suspend flag */ |
111 | static int ap_suspend_flag; | 112 | static int ap_suspend_flag; |
113 | /* Flag to check if domain was set through module parameter domain=. This is | ||
114 | * important when supsend and resume is done in a z/VM environment where the | ||
115 | * domain might change. */ | ||
116 | static int user_set_domain = 0; | ||
112 | static struct bus_type ap_bus_type; | 117 | static struct bus_type ap_bus_type; |
113 | 118 | ||
114 | /** | 119 | /** |
@@ -643,6 +648,7 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
643 | destroy_workqueue(ap_work_queue); | 648 | destroy_workqueue(ap_work_queue); |
644 | ap_work_queue = NULL; | 649 | ap_work_queue = NULL; |
645 | } | 650 | } |
651 | |||
646 | tasklet_disable(&ap_tasklet); | 652 | tasklet_disable(&ap_tasklet); |
647 | } | 653 | } |
648 | /* Poll on the device until all requests are finished. */ | 654 | /* Poll on the device until all requests are finished. */ |
@@ -653,7 +659,10 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
653 | spin_unlock_bh(&ap_dev->lock); | 659 | spin_unlock_bh(&ap_dev->lock); |
654 | } while ((flags & 1) || (flags & 2)); | 660 | } while ((flags & 1) || (flags & 2)); |
655 | 661 | ||
656 | ap_device_remove(dev); | 662 | spin_lock_bh(&ap_dev->lock); |
663 | ap_dev->unregistered = 1; | ||
664 | spin_unlock_bh(&ap_dev->lock); | ||
665 | |||
657 | return 0; | 666 | return 0; |
658 | } | 667 | } |
659 | 668 | ||
@@ -666,11 +675,10 @@ static int ap_bus_resume(struct device *dev) | |||
666 | ap_suspend_flag = 0; | 675 | ap_suspend_flag = 0; |
667 | if (!ap_interrupts_available()) | 676 | if (!ap_interrupts_available()) |
668 | ap_interrupt_indicator = NULL; | 677 | ap_interrupt_indicator = NULL; |
669 | ap_device_probe(dev); | 678 | if (!user_set_domain) { |
670 | ap_reset(ap_dev); | 679 | ap_domain_index = -1; |
671 | setup_timer(&ap_dev->timeout, ap_request_timeout, | 680 | ap_select_domain(); |
672 | (unsigned long) ap_dev); | 681 | } |
673 | ap_scan_bus(NULL); | ||
674 | init_timer(&ap_config_timer); | 682 | init_timer(&ap_config_timer); |
675 | ap_config_timer.function = ap_config_timeout; | 683 | ap_config_timer.function = ap_config_timeout; |
676 | ap_config_timer.data = 0; | 684 | ap_config_timer.data = 0; |
@@ -686,12 +694,14 @@ static int ap_bus_resume(struct device *dev) | |||
686 | tasklet_schedule(&ap_tasklet); | 694 | tasklet_schedule(&ap_tasklet); |
687 | if (ap_thread_flag) | 695 | if (ap_thread_flag) |
688 | rc = ap_poll_thread_start(); | 696 | rc = ap_poll_thread_start(); |
689 | } else { | ||
690 | ap_device_probe(dev); | ||
691 | ap_reset(ap_dev); | ||
692 | setup_timer(&ap_dev->timeout, ap_request_timeout, | ||
693 | (unsigned long) ap_dev); | ||
694 | } | 697 | } |
698 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { | ||
699 | spin_lock_bh(&ap_dev->lock); | ||
700 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), | ||
701 | ap_domain_index); | ||
702 | spin_unlock_bh(&ap_dev->lock); | ||
703 | } | ||
704 | queue_work(ap_work_queue, &ap_config_work); | ||
695 | 705 | ||
696 | return rc; | 706 | return rc; |
697 | } | 707 | } |
@@ -1079,6 +1089,8 @@ static void ap_scan_bus(struct work_struct *unused) | |||
1079 | spin_lock_bh(&ap_dev->lock); | 1089 | spin_lock_bh(&ap_dev->lock); |
1080 | if (rc || ap_dev->unregistered) { | 1090 | if (rc || ap_dev->unregistered) { |
1081 | spin_unlock_bh(&ap_dev->lock); | 1091 | spin_unlock_bh(&ap_dev->lock); |
1092 | if (ap_dev->unregistered) | ||
1093 | i--; | ||
1082 | device_unregister(dev); | 1094 | device_unregister(dev); |
1083 | put_device(dev); | 1095 | put_device(dev); |
1084 | continue; | 1096 | continue; |
@@ -1586,6 +1598,12 @@ int __init ap_module_init(void) | |||
1586 | ap_domain_index); | 1598 | ap_domain_index); |
1587 | return -EINVAL; | 1599 | return -EINVAL; |
1588 | } | 1600 | } |
1601 | /* In resume callback we need to know if the user had set the domain. | ||
1602 | * If so, we can not just reset it. | ||
1603 | */ | ||
1604 | if (ap_domain_index >= 0) | ||
1605 | user_set_domain = 1; | ||
1606 | |||
1589 | if (ap_instructions_available() != 0) { | 1607 | if (ap_instructions_available() != 0) { |
1590 | pr_warning("The hardware system does not support " | 1608 | pr_warning("The hardware system does not support " |
1591 | "AP instructions\n"); | 1609 | "AP instructions\n"); |