Commit 5314af69 authored by Felix Beck's avatar Felix Beck Committed by Martin Schwidefsky

[S390] zcrypt: Do not add/remove devices in s/r callbacks

Devices are no longer removed or added in the suspend and resume
callbacks. Instead they are marked unregistered in suspend. In the
resume callback the ap_scan_bus method is scheduled. The bus scan
function will remove the old device and add new ones. This way all
the device handling will be done in only one function. Additionaly
the case where the domain might change during suspend/resume is
caught. In that case the devices qid needs to re-calculated in
order of having it found by the scan method.
Signed-off-by: default avatarFelix Beck <felix.beck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 2573a575
......@@ -60,6 +60,7 @@ 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);
static int ap_select_domain(void);
/*
* Module description.
......@@ -109,6 +110,10 @@ static unsigned long long poll_timeout = 250000;
/* Suspend flag */
static int ap_suspend_flag;
/* Flag to check if domain was set through module parameter domain=. This is
* important when supsend and resume is done in a z/VM environment where the
* domain might change. */
static int user_set_domain = 0;
static struct bus_type ap_bus_type;
/**
......@@ -643,6 +648,7 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state)
destroy_workqueue(ap_work_queue);
ap_work_queue = NULL;
}
tasklet_disable(&ap_tasklet);
}
/* 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)
spin_unlock_bh(&ap_dev->lock);
} while ((flags & 1) || (flags & 2));
ap_device_remove(dev);
spin_lock_bh(&ap_dev->lock);
ap_dev->unregistered = 1;
spin_unlock_bh(&ap_dev->lock);
return 0;
}
......@@ -666,11 +675,10 @@ static int ap_bus_resume(struct device *dev)
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);
if (!user_set_domain) {
ap_domain_index = -1;
ap_select_domain();
}
init_timer(&ap_config_timer);
ap_config_timer.function = ap_config_timeout;
ap_config_timer.data = 0;
......@@ -686,12 +694,14 @@ static int ap_bus_resume(struct device *dev)
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);
}
if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) {
spin_lock_bh(&ap_dev->lock);
ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid),
ap_domain_index);
spin_unlock_bh(&ap_dev->lock);
}
queue_work(ap_work_queue, &ap_config_work);
return rc;
}
......@@ -1079,6 +1089,8 @@ static void ap_scan_bus(struct work_struct *unused)
spin_lock_bh(&ap_dev->lock);
if (rc || ap_dev->unregistered) {
spin_unlock_bh(&ap_dev->lock);
if (ap_dev->unregistered)
i--;
device_unregister(dev);
put_device(dev);
continue;
......@@ -1586,6 +1598,12 @@ int __init ap_module_init(void)
ap_domain_index);
return -EINVAL;
}
/* In resume callback we need to know if the user had set the domain.
* If so, we can not just reset it.
*/
if (ap_domain_index >= 0)
user_set_domain = 1;
if (ap_instructions_available() != 0) {
pr_warning("The hardware system does not support "
"AP instructions\n");
......
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