Commit 772f5472 authored by Felix Beck's avatar Felix Beck Committed by Martin Schwidefsky

[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: default avatarFelix Beck <felix.beck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 6618241b
...@@ -54,6 +54,12 @@ static int ap_poll_thread_start(void); ...@@ -54,6 +54,12 @@ static int ap_poll_thread_start(void);
static void ap_poll_thread_stop(void); static void ap_poll_thread_stop(void);
static void ap_request_timeout(unsigned long); static void ap_request_timeout(unsigned long);
static inline void ap_schedule_poll_timer(void); static inline void ap_schedule_poll_timer(void);
static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags);
static int ap_device_remove(struct device *dev);
static int ap_device_probe(struct device *dev);
static void ap_interrupt_handler(void *unused1, void *unused2);
static void ap_reset(struct ap_device *ap_dev);
static void ap_config_timeout(unsigned long ptr);
/* /*
* Module description. * Module description.
...@@ -101,6 +107,10 @@ static struct hrtimer ap_poll_timer; ...@@ -101,6 +107,10 @@ static struct hrtimer ap_poll_timer;
* If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
static unsigned long long poll_timeout = 250000; static unsigned long long poll_timeout = 250000;
/* Suspend flag */
static int ap_suspend_flag;
static struct bus_type ap_bus_type;
/** /**
* ap_using_interrupts() - Returns non-zero if interrupt support is * ap_using_interrupts() - Returns non-zero if interrupt support is
* available. * available.
...@@ -617,10 +627,79 @@ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) ...@@ -617,10 +627,79 @@ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
return retval; return retval;
} }
static int ap_bus_suspend(struct device *dev, pm_message_t state)
{
struct ap_device *ap_dev = to_ap_dev(dev);
unsigned long flags;
if (!ap_suspend_flag) {
ap_suspend_flag = 1;
/* Disable scanning for devices, thus we do not want to scan
* for them after removing.
*/
del_timer_sync(&ap_config_timer);
if (ap_work_queue != NULL) {
destroy_workqueue(ap_work_queue);
ap_work_queue = NULL;
}
tasklet_disable(&ap_tasklet);
}
/* Poll on the device until all requests are finished. */
do {
flags = 0;
__ap_poll_device(ap_dev, &flags);
} while ((flags & 1) || (flags & 2));
ap_device_remove(dev);
return 0;
}
static int ap_bus_resume(struct device *dev)
{
int rc = 0;
struct ap_device *ap_dev = to_ap_dev(dev);
if (ap_suspend_flag) {
ap_suspend_flag = 0;
if (!ap_interrupts_available())
ap_interrupt_indicator = NULL;
ap_device_probe(dev);
ap_reset(ap_dev);
setup_timer(&ap_dev->timeout, ap_request_timeout,
(unsigned long) ap_dev);
ap_scan_bus(NULL);
init_timer(&ap_config_timer);
ap_config_timer.function = ap_config_timeout;
ap_config_timer.data = 0;
ap_config_timer.expires = jiffies + ap_config_time * HZ;
add_timer(&ap_config_timer);
ap_work_queue = create_singlethread_workqueue("kapwork");
if (!ap_work_queue)
return -ENOMEM;
tasklet_enable(&ap_tasklet);
if (!ap_using_interrupts())
ap_schedule_poll_timer();
else
tasklet_schedule(&ap_tasklet);
if (ap_thread_flag)
rc = ap_poll_thread_start();
} else {
ap_device_probe(dev);
ap_reset(ap_dev);
setup_timer(&ap_dev->timeout, ap_request_timeout,
(unsigned long) ap_dev);
}
return rc;
}
static struct bus_type ap_bus_type = { static struct bus_type ap_bus_type = {
.name = "ap", .name = "ap",
.match = &ap_bus_match, .match = &ap_bus_match,
.uevent = &ap_uevent, .uevent = &ap_uevent,
.suspend = ap_bus_suspend,
.resume = ap_bus_resume
}; };
static int ap_device_probe(struct device *dev) static int ap_device_probe(struct device *dev)
...@@ -1066,7 +1145,7 @@ ap_config_timeout(unsigned long ptr) ...@@ -1066,7 +1145,7 @@ ap_config_timeout(unsigned long ptr)
*/ */
static inline void ap_schedule_poll_timer(void) static inline void ap_schedule_poll_timer(void)
{ {
if (ap_using_interrupts()) if (ap_using_interrupts() || ap_suspend_flag)
return; return;
if (hrtimer_is_queued(&ap_poll_timer)) if (hrtimer_is_queued(&ap_poll_timer))
return; return;
...@@ -1384,6 +1463,8 @@ static int ap_poll_thread(void *data) ...@@ -1384,6 +1463,8 @@ static int ap_poll_thread(void *data)
set_user_nice(current, 19); set_user_nice(current, 19);
while (1) { while (1) {
if (ap_suspend_flag)
return 0;
if (need_resched()) { if (need_resched()) {
schedule(); schedule();
continue; continue;
...@@ -1414,7 +1495,7 @@ static int ap_poll_thread_start(void) ...@@ -1414,7 +1495,7 @@ static int ap_poll_thread_start(void)
{ {
int rc; int rc;
if (ap_using_interrupts()) if (ap_using_interrupts() || ap_suspend_flag)
return 0; return 0;
mutex_lock(&ap_poll_thread_mutex); mutex_lock(&ap_poll_thread_mutex);
if (!ap_poll_kthread) { if (!ap_poll_kthread) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment