summaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/ap_bus.c
diff options
context:
space:
mode:
authorFelix Beck <felix.beck@de.ibm.com>2009-09-22 22:58:51 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-09-22 22:58:46 +0200
commit5314af693da5149c2361d290bb184cf18ee21cdd (patch)
tree17a34e85f22a2316cc95ead2739df8729e3767b3 /drivers/s390/crypto/ap_bus.c
parent2573a575304c5ce4765fc88f9d09ed4dbf8d04bf (diff)
[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: Felix Beck <felix.beck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r--drivers/s390/crypto/ap_bus.c40
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 090b32a339c..1294876bf7b 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);
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");