Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+83 −2
Original line number Diff line number Diff line
@@ -54,6 +54,12 @@ static int ap_poll_thread_start(void);
static void ap_poll_thread_stop(void);
static void ap_request_timeout(unsigned long);
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.
@@ -101,6 +107,10 @@ static struct hrtimer ap_poll_timer;
 * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
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
 * available.
@@ -617,10 +627,79 @@ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
	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 = {
	.name = "ap",
	.match = &ap_bus_match,
	.uevent = &ap_uevent,
	.suspend = ap_bus_suspend,
	.resume = ap_bus_resume
};

static int ap_device_probe(struct device *dev)
@@ -1066,7 +1145,7 @@ ap_config_timeout(unsigned long ptr)
 */
static inline void ap_schedule_poll_timer(void)
{
	if (ap_using_interrupts())
	if (ap_using_interrupts() || ap_suspend_flag)
		return;
	if (hrtimer_is_queued(&ap_poll_timer))
		return;
@@ -1384,6 +1463,8 @@ static int ap_poll_thread(void *data)

	set_user_nice(current, 19);
	while (1) {
		if (ap_suspend_flag)
			return 0;
		if (need_resched()) {
			schedule();
			continue;
@@ -1414,7 +1495,7 @@ static int ap_poll_thread_start(void)
{
	int rc;

	if (ap_using_interrupts())
	if (ap_using_interrupts() || ap_suspend_flag)
		return 0;
	mutex_lock(&ap_poll_thread_mutex);
	if (!ap_poll_kthread) {